summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorstorri <storri@ae88bc3d-4319-0410-8dbf-d08b4c9d3795>2002-01-12 00:02:33 +0000
committerstorri <storri@ae88bc3d-4319-0410-8dbf-d08b4c9d3795>2002-01-12 00:02:33 +0000
commitad0434eb2b6f4c300594dffec1defac3ef62baff (patch)
tree43549f9b121632f15352d474708021e8c84a611b
parent5a041dae3274f8dabf8f00a2210a6a24a4cebdfc (diff)
downloadATCD-ad0434eb2b6f4c300594dffec1defac3ef62baff.tar.gz
Updates for directory structure
-rw-r--r--ace/Streams/Codeset_IBM1047.cpp284
-rw-r--r--ace/Streams/Codeset_IBM1047.h112
-rw-r--r--ace/Streams/Message_Queue.cpp442
-rw-r--r--ace/Streams/Message_Queue.h523
-rw-r--r--ace/Streams/Message_Queue.i224
-rw-r--r--ace/Streams/Message_Queue_T.cpp1858
-rw-r--r--ace/Streams/Message_Queue_T.h1053
-rw-r--r--ace/Streams/Message_Queue_T.i303
-rw-r--r--ace/Streams/Module.cpp266
-rw-r--r--ace/Streams/Module.h207
-rw-r--r--ace/Streams/Module.i62
-rw-r--r--ace/Streams/Notification_Strategy.cpp18
-rw-r--r--ace/Streams/Notification_Strategy.h63
-rw-r--r--ace/Streams/Notification_Strategy.inl26
-rw-r--r--ace/Streams/Read_Buffer.cpp162
-rw-r--r--ace/Streams/Read_Buffer.h114
-rw-r--r--ace/Streams/Read_Buffer.i28
-rw-r--r--ace/Streams/Stream.cpp614
-rw-r--r--ace/Streams/Stream.h232
-rw-r--r--ace/Streams/Stream.i49
-rw-r--r--ace/Streams/Stream_Modules.cpp369
-rw-r--r--ace/Streams/Stream_Modules.h144
-rw-r--r--ace/Streams/Task.cpp227
-rw-r--r--ace/Streams/Task.h265
-rw-r--r--ace/Streams/Task.i114
-rw-r--r--ace/Streams/Task_T.cpp105
-rw-r--r--ace/Streams/Task_T.h174
-rw-r--r--ace/Streams/Task_T.i103
-rw-r--r--ace/Streams/Typed_SV_Message.cpp26
-rw-r--r--ace/Streams/Typed_SV_Message.h94
-rw-r--r--ace/Streams/Typed_SV_Message.i91
-rw-r--r--ace/Streams/Typed_SV_Message_Queue.cpp53
-rw-r--r--ace/Streams/Typed_SV_Message_Queue.h86
-rw-r--r--ace/Streams/Typed_SV_Message_Queue.i77
-rw-r--r--ace/Streams/streams.h149
-rw-r--r--ace/Svcconf/DLL.cpp188
-rw-r--r--ace/Svcconf/DLL.h115
-rw-r--r--ace/Svcconf/Dynamic_Service.cpp19
-rw-r--r--ace/Svcconf/Dynamic_Service.h52
-rw-r--r--ace/Svcconf/Dynamic_Service.i8
-rw-r--r--ace/Svcconf/Dynamic_Service_Base.cpp39
-rw-r--r--ace/Svcconf/Dynamic_Service_Base.h40
-rw-r--r--ace/Svcconf/Dynamic_Service_Base.i2
-rw-r--r--ace/Svcconf/Parse_Node.cpp652
-rw-r--r--ace/Svcconf/Parse_Node.h343
-rw-r--r--ace/Svcconf/Parse_Node.i19
-rw-r--r--ace/Svcconf/Service_Config.cpp884
-rw-r--r--ace/Svcconf/Service_Config.h516
-rw-r--r--ace/Svcconf/Service_Config.i101
-rw-r--r--ace/Svcconf/Service_Manager.cpp367
-rw-r--r--ace/Svcconf/Service_Manager.h120
-rw-r--r--ace/Svcconf/Service_Manager.i10
-rw-r--r--ace/Svcconf/Service_Object.cpp96
-rw-r--r--ace/Svcconf/Service_Object.h164
-rw-r--r--ace/Svcconf/Service_Object.i87
-rw-r--r--ace/Svcconf/Service_Repository.cpp416
-rw-r--r--ace/Svcconf/Service_Repository.h203
-rw-r--r--ace/Svcconf/Service_Repository.i31
-rw-r--r--ace/Svcconf/Service_Templates.cpp74
-rw-r--r--ace/Svcconf/Service_Templates.h29
-rw-r--r--ace/Svcconf/Service_Types.cpp454
-rw-r--r--ace/Svcconf/Service_Types.h196
-rw-r--r--ace/Svcconf/Service_Types.i64
-rw-r--r--ace/Svcconf/Shared_Object.cpp46
-rw-r--r--ace/Svcconf/Shared_Object.h51
-rw-r--r--ace/Svcconf/Shared_Object.i9
-rw-r--r--ace/Svcconf/Svc_Conf.h208
-rw-r--r--ace/Svcconf/Svc_Conf.l140
-rw-r--r--ace/Svcconf/Svc_Conf.y464
-rw-r--r--ace/Svcconf/Svc_Conf_Lexer_Guard.cpp36
-rw-r--r--ace/Svcconf/Svc_Conf_Lexer_Guard.h79
-rw-r--r--ace/Svcconf/Svc_Conf_Tokens.h16
-rw-r--r--ace/Svcconf/Svc_Conf_l.cpp1841
-rw-r--r--ace/Svcconf/Svc_Conf_y.cpp1406
-rw-r--r--ace/Svcconf/Svc_Handler.cpp512
-rw-r--r--ace/Svcconf/Svc_Handler.h322
-rw-r--r--ace/Svcconf/svc_export.h44
-rw-r--r--ace/Threads/Activation_Queue.cpp109
-rw-r--r--ace/Threads/Activation_Queue.h109
-rw-r--r--ace/Threads/Activation_Queue.i22
-rw-r--r--ace/Threads/Atomic_Op.cpp83
-rw-r--r--ace/Threads/Atomic_Op.h191
-rw-r--r--ace/Threads/Atomic_Op.i219
-rw-r--r--ace/Threads/File_Lock.cpp78
-rw-r--r--ace/Threads/File_Lock.h164
-rw-r--r--ace/Threads/File_Lock.inl89
-rw-r--r--ace/Threads/Makefile65
-rw-r--r--ace/Threads/Process.cpp893
-rw-r--r--ace/Threads/Process.h557
-rw-r--r--ace/Threads/Process.i379
-rw-r--r--ace/Threads/Process_Manager.cpp941
-rw-r--r--ace/Threads/Process_Manager.h398
-rw-r--r--ace/Threads/Process_Manager.i8
-rw-r--r--ace/Threads/Process_Mutex.cpp76
-rw-r--r--ace/Threads/Process_Mutex.h195
-rw-r--r--ace/Threads/Process_Mutex.inl85
-rw-r--r--ace/Threads/Process_Semaphore.cpp91
-rw-r--r--ace/Threads/Process_Semaphore.h142
-rw-r--r--ace/Threads/Process_Semaphore.inl61
-rw-r--r--ace/Threads/RW_Process_Mutex.cpp59
-rw-r--r--ace/Threads/RW_Process_Mutex.h114
-rw-r--r--ace/Threads/RW_Process_Mutex.inl72
-rw-r--r--ace/Threads/Synch.cpp902
-rw-r--r--ace/Threads/Synch.h1753
-rw-r--r--ace/Threads/Synch.h~1753
-rw-r--r--ace/Threads/Synch.i965
-rw-r--r--ace/Threads/Synch_Options.cpp105
-rw-r--r--ace/Threads/Synch_Options.h154
-rw-r--r--ace/Threads/Synch_Options.i9
-rw-r--r--ace/Threads/Synch_T.cpp895
-rw-r--r--ace/Threads/Synch_T.cpp~895
-rw-r--r--ace/Threads/Synch_T.h903
-rw-r--r--ace/Threads/Synch_T.h~903
-rw-r--r--ace/Threads/Synch_T.i452
-rw-r--r--ace/Threads/Synch_T.i~452
-rw-r--r--ace/Threads/Thread.cpp90
-rw-r--r--ace/Threads/Thread.h240
-rw-r--r--ace/Threads/Thread.i272
-rw-r--r--ace/Threads/Thread_Adapter.cpp252
-rw-r--r--ace/Threads/Thread_Adapter.h92
-rw-r--r--ace/Threads/Thread_Adapter.inl7
-rw-r--r--ace/Threads/Thread_Control.cpp90
-rw-r--r--ace/Threads/Thread_Control.h101
-rw-r--r--ace/Threads/Thread_Control.inl42
-rw-r--r--ace/Threads/Thread_Exit.cpp144
-rw-r--r--ace/Threads/Thread_Exit.h110
-rw-r--r--ace/Threads/Thread_Manager.cpp2238
-rw-r--r--ace/Threads/Thread_Manager.h1008
-rw-r--r--ace/Threads/Thread_Manager.i322
-rw-r--r--ace/Threads/Token.cpp545
-rw-r--r--ace/Threads/Token.h290
-rw-r--r--ace/Threads/Token.i123
-rw-r--r--ace/Timer/Basic_Stats.cpp73
-rw-r--r--ace/Timer/Basic_Stats.h87
-rw-r--r--ace/Timer/Basic_Stats.inl59
-rw-r--r--ace/Timer/High_Res_Timer.cpp525
-rw-r--r--ace/Timer/High_Res_Timer.h308
-rw-r--r--ace/Timer/High_Res_Timer.i158
-rw-r--r--ace/Timer/Profile_Timer.cpp418
-rw-r--r--ace/Timer/Profile_Timer.h133
-rw-r--r--ace/Timer/Profile_Timer.i104
-rw-r--r--ace/Timer/System_Time.cpp141
-rw-r--r--ace/Timer/System_Time.h87
-rw-r--r--ace/Timer/Time_Request_Reply.cpp188
-rw-r--r--ace/Timer/Time_Request_Reply.h121
-rw-r--r--ace/Timer/Time_Value.h28
-rw-r--r--ace/Timer/Timeprobe.cpp44
-rw-r--r--ace/Timer/Timeprobe.h176
-rw-r--r--ace/Timer/Timeprobe.i8
-rw-r--r--ace/Timer/Timeprobe_T.cpp300
-rw-r--r--ace/Timer/Timeprobe_T.h188
-rw-r--r--ace/Timer/Timer_Hash.cpp123
-rw-r--r--ace/Timer/Timer_Hash.h71
-rw-r--r--ace/Timer/Timer_Hash_T.cpp622
-rw-r--r--ace/Timer/Timer_Hash_T.h283
-rw-r--r--ace/Timer/Timer_Heap.cpp43
-rw-r--r--ace/Timer/Timer_Heap.h38
-rw-r--r--ace/Timer/Timer_Heap_T.cpp785
-rw-r--r--ace/Timer/Timer_Heap_T.h329
-rw-r--r--ace/Timer/Timer_List.cpp44
-rw-r--r--ace/Timer/Timer_List.h38
-rw-r--r--ace/Timer/Timer_List_T.cpp342
-rw-r--r--ace/Timer/Timer_List_T.h217
-rw-r--r--ace/Timer/Timer_Queue.cpp60
-rw-r--r--ace/Timer/Timer_Queue.h45
-rw-r--r--ace/Timer/Timer_Queue_Adapters.cpp310
-rw-r--r--ace/Timer/Timer_Queue_Adapters.h230
-rw-r--r--ace/Timer/Timer_Queue_Adapters.i37
-rw-r--r--ace/Timer/Timer_Queue_T.cpp354
-rw-r--r--ace/Timer/Timer_Queue_T.h498
-rw-r--r--ace/Timer/Timer_Queue_T.i188
-rw-r--r--ace/Timer/Timer_Wheel.cpp23
-rw-r--r--ace/Timer/Timer_Wheel.h39
-rw-r--r--ace/Timer/Timer_Wheel_T.cpp820
-rw-r--r--ace/Timer/Timer_Wheel_T.h211
-rw-r--r--ace/Token/Local_Tokens.cpp1446
-rw-r--r--ace/Token/Local_Tokens.h1098
-rw-r--r--ace/Token/Local_Tokens.i458
-rw-r--r--ace/Token/Remote_Tokens.cpp438
-rw-r--r--ace/Token/Remote_Tokens.h316
-rw-r--r--ace/Token/Remote_Tokens.i122
-rw-r--r--ace/Token/Token_Collection.cpp302
-rw-r--r--ace/Token/Token_Collection.h234
-rw-r--r--ace/Token/Token_Collection.i12
-rw-r--r--ace/Token/Token_Invariants.cpp368
-rw-r--r--ace/Token/Token_Invariants.h228
-rw-r--r--ace/Token/Token_Manager.cpp280
-rw-r--r--ace/Token/Token_Manager.h135
-rw-r--r--ace/Token/Token_Manager.i20
-rw-r--r--ace/Token/Token_Request_Reply.cpp178
-rw-r--r--ace/Token/Token_Request_Reply.h247
-rw-r--r--ace/Token/Token_Request_Reply.i196
-rw-r--r--ace/Utils/ARGV.cpp344
-rw-r--r--ace/Utils/ARGV.h169
-rw-r--r--ace/Utils/ARGV.i68
-rw-r--r--ace/Utils/Active_Map_Manager.cpp9
-rw-r--r--ace/Utils/Active_Map_Manager.cpp~10
-rw-r--r--ace/Utils/Active_Map_Manager.h106
-rw-r--r--ace/Utils/Active_Map_Manager.h~106
-rw-r--r--ace/Utils/Active_Map_Manager.i87
-rw-r--r--ace/Utils/Active_Map_Manager_T.cpp20
-rw-r--r--ace/Utils/Active_Map_Manager_T.h205
-rw-r--r--ace/Utils/Active_Map_Manager_T.h~205
-rw-r--r--ace/Utils/Active_Map_Manager_T.i303
-rw-r--r--ace/Utils/Arg_Shifter.cpp203
-rw-r--r--ace/Utils/Arg_Shifter.h192
-rw-r--r--ace/Utils/Capabilities.cpp368
-rw-r--r--ace/Utils/Capabilities.h199
-rw-r--r--ace/Utils/Capabilities.i47
-rw-r--r--ace/Utils/Configuration.cpp2055
-rw-r--r--ace/Utils/Configuration.h759
-rw-r--r--ace/Utils/Configuration_Import_Export.cpp610
-rw-r--r--ace/Utils/Configuration_Import_Export.h216
-rw-r--r--ace/Utils/Connection_Recycling_Strategy.cpp13
-rw-r--r--ace/Utils/Connection_Recycling_Strategy.h67
-rw-r--r--ace/Utils/Containers.cpp23
-rw-r--r--ace/Utils/Containers.h72
-rw-r--r--ace/Utils/Containers.i25
-rw-r--r--ace/Utils/Dirent.cpp11
-rw-r--r--ace/Utils/Dirent.h115
-rw-r--r--ace/Utils/Dirent.i95
-rw-r--r--ace/Utils/Dirent_Selector.cpp44
-rw-r--r--ace/Utils/Dirent_Selector.h66
-rw-r--r--ace/Utils/Dirent_Selector.inl15
-rw-r--r--ace/Utils/Dynamic.cpp39
-rw-r--r--ace/Utils/Dynamic.h74
-rw-r--r--ace/Utils/Dynamic.i32
-rw-r--r--ace/Utils/Filecache.cpp774
-rw-r--r--ace/Utils/Filecache.h353
-rw-r--r--ace/Utils/Flag_Manip.cpp80
-rw-r--r--ace/Utils/Flag_Manip.h47
-rw-r--r--ace/Utils/Flag_Manip.i20
-rw-r--r--ace/Utils/Functor.cpp48
-rw-r--r--ace/Utils/Functor.h363
-rw-r--r--ace/Utils/Functor.i188
-rw-r--r--ace/Utils/Functor_T.cpp49
-rw-r--r--ace/Utils/Functor_T.h152
-rw-r--r--ace/Utils/Functor_T.i28
-rw-r--r--ace/Utils/Future.cpp448
-rw-r--r--ace/Utils/Future.h371
-rw-r--r--ace/Utils/Future_Set.cpp137
-rw-r--r--ace/Utils/Future_Set.h123
-rw-r--r--ace/Utils/Get_Opt.cpp608
-rw-r--r--ace/Utils/Get_Opt.h357
-rw-r--r--ace/Utils/Get_Opt.i34
-rw-r--r--ace/Utils/Hash_Map_Manager.cpp19
-rw-r--r--ace/Utils/Hash_Map_Manager.h28
-rw-r--r--ace/Utils/Hashable.cpp8
-rw-r--r--ace/Utils/Hashable.h64
-rw-r--r--ace/Utils/Hashable.inl27
-rw-r--r--ace/Utils/IO_Cntl_Msg.cpp38
-rw-r--r--ace/Utils/IO_Cntl_Msg.h95
-rw-r--r--ace/Utils/Init_ACE.cpp44
-rw-r--r--ace/Utils/Init_ACE.h65
-rw-r--r--ace/Utils/Init_ACE.i1
-rw-r--r--ace/Utils/Lib_Find.cpp562
-rw-r--r--ace/Utils/Lib_Find.h106
-rw-r--r--ace/Utils/Lib_Find.i1
-rw-r--r--ace/Utils/Makefile89
-rw-r--r--ace/Utils/Map.cpp19
-rw-r--r--ace/Utils/Map.h28
-rw-r--r--ace/Utils/Message_Block.cpp1293
-rw-r--r--ace/Utils/Message_Block.h979
-rw-r--r--ace/Utils/Message_Block.i627
-rw-r--r--ace/Utils/Method_Request.cpp27
-rw-r--r--ace/Utils/Method_Request.h66
-rw-r--r--ace/Utils/Multiplexor.cpp14
-rw-r--r--ace/Utils/Multiplexor.h81
-rw-r--r--ace/Utils/Multiplexor.i88
-rw-r--r--ace/Utils/NT_Service.cpp516
-rw-r--r--ace/Utils/NT_Service.h398
-rw-r--r--ace/Utils/NT_Service.i79
-rw-r--r--ace/Utils/Object_Manager.cpp874
-rw-r--r--ace/Utils/Object_Manager.h480
-rw-r--r--ace/Utils/Object_Manager.i35
-rw-r--r--ace/Utils/Pair.cpp19
-rw-r--r--ace/Utils/Pair.h28
-rw-r--r--ace/Utils/Recyclable.cpp19
-rw-r--r--ace/Utils/Recyclable.h78
-rw-r--r--ace/Utils/Recyclable.inl19
-rw-r--r--ace/Utils/Refcountable.cpp8
-rw-r--r--ace/Utils/Refcountable.h58
-rw-r--r--ace/Utils/Refcountable.inl30
-rw-r--r--ace/Utils/Refcounted_Auto_Ptr.h192
-rw-r--r--ace/Utils/Refcounted_Auto_Ptr.i222
-rw-r--r--ace/Utils/Registry.cpp1142
-rw-r--r--ace/Utils/Registry.h560
-rw-r--r--ace/Utils/SString.cpp549
-rw-r--r--ace/Utils/SString.h479
-rw-r--r--ace/Utils/SString.i284
-rw-r--r--ace/Utils/Sample_History.cpp56
-rw-r--r--ace/Utils/Sample_History.h86
-rw-r--r--ace/Utils/Sample_History.inl20
-rw-r--r--ace/Utils/Stats.cpp612
-rw-r--r--ace/Utils/Stats.h270
-rw-r--r--ace/Utils/Stats.i95
-rw-r--r--ace/Utils/String_Base_Const.cpp5
-rw-r--r--ace/Utils/String_Base_Const.h32
-rw-r--r--ace/Utils/Templates/Array_Base.cpp204
-rw-r--r--ace/Utils/Templates/Array_Base.h206
-rw-r--r--ace/Utils/Templates/Array_Base.inl84
-rw-r--r--ace/Utils/Templates/Auto_IncDec_T.cpp30
-rw-r--r--ace/Utils/Templates/Auto_IncDec_T.h84
-rw-r--r--ace/Utils/Templates/Auto_IncDec_T.i21
-rw-r--r--ace/Utils/Templates/Auto_Ptr.cpp42
-rw-r--r--ace/Utils/Templates/Auto_Ptr.h172
-rw-r--r--ace/Utils/Templates/Auto_Ptr.i144
-rw-r--r--ace/Utils/Templates/Cache_Map_Manager_T.cpp420
-rw-r--r--ace/Utils/Templates/Cache_Map_Manager_T.h425
-rw-r--r--ace/Utils/Templates/Cache_Map_Manager_T.i273
-rw-r--r--ace/Utils/Templates/Cached_Connect_Strategy_T.cpp775
-rw-r--r--ace/Utils/Templates/Cached_Connect_Strategy_T.h259
-rw-r--r--ace/Utils/Templates/Caching_Utility_T.cpp500
-rw-r--r--ace/Utils/Templates/Caching_Utility_T.h343
-rw-r--r--ace/Utils/Templates/Cleanup_Strategies_T.cpp89
-rw-r--r--ace/Utils/Templates/Cleanup_Strategies_T.h148
-rw-r--r--ace/Utils/Templates/Containers_T.cpp1813
-rw-r--r--ace/Utils/Templates/Containers_T.h1495
-rw-r--r--ace/Utils/Templates/Containers_T.i469
-rw-r--r--ace/Utils/Templates/Env_Value_T.cpp14
-rw-r--r--ace/Utils/Templates/Env_Value_T.h161
-rw-r--r--ace/Utils/Templates/Env_Value_T.i51
-rw-r--r--ace/Utils/Templates/Free_List.cpp90
-rw-r--r--ace/Utils/Templates/Free_List.h148
-rw-r--r--ace/Utils/Templates/Free_List.i76
-rw-r--r--ace/Utils/Templates/Hash_Cache_Map_Manager_T.cpp230
-rw-r--r--ace/Utils/Templates/Hash_Cache_Map_Manager_T.h215
-rw-r--r--ace/Utils/Templates/Hash_Cache_Map_Manager_T.i68
-rw-r--r--ace/Utils/Templates/Hash_Map_Manager_T.cpp520
-rw-r--r--ace/Utils/Templates/Hash_Map_Manager_T.h914
-rw-r--r--ace/Utils/Templates/Hash_Map_Manager_T.i960
-rw-r--r--ace/Utils/Templates/Hash_Map_With_Allocator_T.cpp32
-rw-r--r--ace/Utils/Templates/Hash_Map_With_Allocator_T.h102
-rw-r--r--ace/Utils/Templates/Hash_Map_With_Allocator_T.i73
-rw-r--r--ace/Utils/Templates/Intrusive_List.cpp151
-rw-r--r--ace/Utils/Templates/Intrusive_List.h131
-rw-r--r--ace/Utils/Templates/Intrusive_List.inl19
-rw-r--r--ace/Utils/Templates/Intrusive_List_Node.cpp25
-rw-r--r--ace/Utils/Templates/Intrusive_List_Node.h81
-rw-r--r--ace/Utils/Templates/Intrusive_List_Node.inl25
-rw-r--r--ace/Utils/Templates/Managed_Object.cpp23
-rw-r--r--ace/Utils/Templates/Managed_Object.h160
-rw-r--r--ace/Utils/Templates/Managed_Object.i18
-rw-r--r--ace/Utils/Templates/Map_Manager.cpp692
-rw-r--r--ace/Utils/Templates/Map_Manager.h700
-rw-r--r--ace/Utils/Templates/Map_Manager.h~700
-rw-r--r--ace/Utils/Templates/Map_Manager.i713
-rw-r--r--ace/Utils/Templates/Map_T.cpp18
-rw-r--r--ace/Utils/Templates/Map_T.h1602
-rw-r--r--ace/Utils/Templates/Map_T.i1723
-rw-r--r--ace/Utils/Templates/Message_Block_T.cpp46
-rw-r--r--ace/Utils/Templates/Message_Block_T.h83
-rw-r--r--ace/Utils/Templates/Message_Block_T.i29
-rw-r--r--ace/Utils/Templates/Node.cpp46
-rw-r--r--ace/Utils/Templates/Node.h77
-rw-r--r--ace/Utils/Templates/Pair_T.cpp18
-rw-r--r--ace/Utils/Templates/Pair_T.h111
-rw-r--r--ace/Utils/Templates/Pair_T.i72
-rw-r--r--ace/Utils/Templates/RB_Tree.cpp1078
-rw-r--r--ace/Utils/Templates/RB_Tree.h798
-rw-r--r--ace/Utils/Templates/RB_Tree.i1152
-rw-r--r--ace/Utils/Templates/Singleton.cpp385
-rw-r--r--ace/Utils/Templates/Singleton.h250
-rw-r--r--ace/Utils/Templates/Singleton.i27
-rw-r--r--ace/Utils/Templates/String_Base.cpp181
-rw-r--r--ace/Utils/Templates/String_Base.h235
-rw-r--r--ace/Utils/Templates/String_Base.i358
-rw-r--r--ace/Utils/Test_and_Set.cpp49
-rw-r--r--ace/Utils/Test_and_Set.h76
-rw-r--r--ace/Utils/Test_and_Set.i1
-rw-r--r--ace/Utils/Unbounded_Queue.cpp426
-rw-r--r--ace/Utils/Unbounded_Queue.h234
-rw-r--r--ace/Utils/Unbounded_Queue.inl21
-rw-r--r--ace/Utils/Unbounded_Set.cpp443
-rw-r--r--ace/Utils/Unbounded_Set.h257
-rw-r--r--ace/Utils/Unbounded_Set.inl16
-rw-r--r--ace/Utils/libACE_Utils.a1
377 files changed, 103128 insertions, 0 deletions
diff --git a/ace/Streams/Codeset_IBM1047.cpp b/ace/Streams/Codeset_IBM1047.cpp
new file mode 100644
index 00000000000..45ae7932665
--- /dev/null
+++ b/ace/Streams/Codeset_IBM1047.cpp
@@ -0,0 +1,284 @@
+// -*- C++ -*-
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// ace
+//
+// = FILENAME
+// Codeset_IBM1047.cpp
+//
+// = DESCRIPTION
+// Defines the arrays required to convert between ISO8859 (aka
+// Latin/1) and IBM1047 (aka EBCDIC).
+//
+// = AUTHOR
+// Jim Rogers (jrogers@viasoft.com)
+//
+// ============================================================================
+
+#include "ace/Codeset_IBM1047.h"
+
+#if defined(ACE_MVS)
+
+ACE_RCSID(ace, Codeset_IBM1047, "$Id$")
+
+// ****************************************************************
+
+ACE_IBM1047_ISO8859::ACE_IBM1047_ISO8859 (void)
+{
+}
+
+ACE_IBM1047_ISO8859::~ACE_IBM1047_ISO8859 (void)
+{
+}
+
+ACE_CDR::Boolean
+ACE_IBM1047_ISO8859::read_char (ACE_InputCDR &in,
+ ACE_CDR::Char &x)
+{
+ if (this->read_1 (in, ACE_reinterpret_cast (ACE_CDR::Octet*, &x)))
+ {
+ x = ACE_to_IBM1047[x];
+ return 1;
+ }
+ return 0;
+}
+
+ACE_CDR::Boolean
+ACE_IBM1047_ISO8859::read_string (ACE_InputCDR& in,
+ ACE_CDR::Char *& x)
+{
+ ACE_CDR::ULong len;
+
+ in.read_ulong (len);
+
+ if (len > 0)
+ {
+ ACE_NEW_RETURN (x,
+ ACE_CDR::Char[len],
+ 0);
+
+ if (this->read_char_array (in, x, len))
+ return 1;
+
+ delete [] x;
+ }
+
+ x = 0;
+ return 0;
+}
+
+ACE_CDR::Boolean
+ACE_IBM1047_ISO8859::read_char_array (ACE_InputCDR& in,
+ ACE_CDR::Char* x,
+ ACE_CDR::ULong len)
+{
+ if (this->read_array (in,
+ x,
+ ACE_CDR::OCTET_SIZE,
+ ACE_CDR::OCTET_ALIGN,
+ len))
+ {
+ for (ACE_CDR::ULong i = 0; i != len; ++i)
+ x[i] = ACE_to_IBM1047[x[i]];
+
+ return 1;
+ }
+
+ return 0;
+}
+
+ACE_CDR::Boolean
+ACE_IBM1047_ISO8859::write_char (ACE_OutputCDR& out,
+ ACE_CDR::Char x)
+{
+ return this->write_1 (out,
+ ACE_reinterpret_cast (const ACE_CDR::Octet*,
+ &ACE_from_IBM1047[x]));
+}
+
+ACE_CDR::Boolean
+ACE_IBM1047_ISO8859::write_string (ACE_OutputCDR& out,
+ ACE_CDR::ULong len,
+ const ACE_CDR::Char* x)
+{
+ if (out.write_ulong (len + 1))
+ return this->write_char_array (out, x, len + 1);
+ return 0;
+}
+
+ACE_CDR::Boolean
+ACE_IBM1047_ISO8859::write_char_array (ACE_OutputCDR& out,
+ const ACE_CDR::Char* x,
+ ACE_CDR::ULong len)
+{
+ char *buf;
+ if (this->adjust (out, len, 1, buf) == 0)
+ {
+ ACE_OS::memcpy (buf, x, len);
+
+ for (ACE_CDR::ULong i = 0; i != len; ++i)
+ buf[i] = ACE_from_IBM1047[buf[i]];
+
+ return 1;
+ }
+
+ this->good_bit(out, 0);
+ return 0;
+}
+
+// ****************************************************************
+
+ACE_ISO8859_IBM1047::ACE_ISO8859_IBM1047 (void)
+{
+}
+
+ACE_ISO8859_IBM1047::~ACE_ISO8859_IBM1047 (void)
+{
+}
+
+ACE_CDR::Boolean
+ACE_ISO8859_IBM1047::read_char (ACE_InputCDR& in,
+ ACE_CDR::Char& x)
+{
+ if (this->read_1 (in, ACE_reinterpret_cast (ACE_CDR::Octet*, &x)))
+ {
+ x = ACE_from_IBM1047[x];
+ return 1;
+ }
+ return 0;
+}
+
+ACE_CDR::Boolean
+ACE_ISO8859_IBM1047::read_string (ACE_InputCDR &in,
+ ACE_CDR::Char *&x)
+{
+ ACE_CDR::ULong len;
+
+ in.read_ulong (len);
+
+ if (len > 0)
+ {
+ ACE_NEW_RETURN (x,
+ ACE_CDR::Char[len],
+ 0);
+
+ if (this->read_char_array (in, x, len))
+ return 1;
+
+ delete [] x;
+ }
+
+ x = 0;
+ return 0;
+}
+
+ACE_CDR::Boolean
+ACE_ISO8859_IBM1047::read_char_array (ACE_InputCDR &in,
+ ACE_CDR::Char *x,
+ ACE_CDR::ULong len)
+{
+ if (this->read_array (in,
+ x,
+ ACE_CDR::OCTET_SIZE,
+ ACE_CDR::OCTET_ALIGN,
+ len))
+ {
+ for (ACE_CDR::ULong i = 0; i != len; ++i)
+ x[i] = ACE_from_IBM1047[x[i]];
+
+ return 1;
+ }
+
+ return 0;
+}
+
+ACE_CDR::Boolean
+ACE_ISO8859_IBM1047::write_char (ACE_OutputCDR &out,
+ ACE_CDR::Char x)
+{
+ return this->write_1 (out,
+ ACE_reinterpret_cast (const ACE_CDR::Octet *,
+ &ACE_to_IBM1047[x]));
+}
+
+ACE_CDR::Boolean
+ACE_ISO8859_IBM1047::write_string (ACE_OutputCDR& out,
+ ACE_CDR::ULong len,
+ const ACE_CDR::Char* x)
+{
+ if (out.write_ulong (len + 1))
+ return this->write_char_array (out, x, len + 1);
+ else
+ return 0;
+}
+
+ACE_CDR::Boolean
+ACE_ISO8859_IBM1047::write_char_array (ACE_OutputCDR &out,
+ const ACE_CDR::Char *x,
+ ACE_CDR::ULong len)
+{
+ char *buf;
+
+ if (this->adjust (out, len, 1, buf) == 0)
+ {
+ ACE_OS::memcpy (buf, x, len);
+
+ for (ACE_CDR::ULong i = 0; i != len; ++i)
+ buf[i] = ACE_to_IBM1047[buf[i]];
+
+ return 1;
+ }
+
+ this->good_bit (out, 0);
+ return 0;
+}
+
+// ****************************************************************
+
+char ACE_to_IBM1047[257] =
+{
+ "\x00\x01\x02\x03\x37\x2D\x2E\x2F\x16\x05\x25\x0B\x0C\x0D\x0E\x0F" // 00-0F
+ "\x10\x11\x12\x13\x3C\x3D\x32\x26\x18\x19\x3F\x27\x22\x1D\x35\x1F" // 10-1F
+ "\x40\x5A\x7F\x7B\x5B\x6C\x50\x7D\x4D\x5D\x5C\x4E\x6B\x60\x4B\x61" // 20-2F
+ "\xF0\xF1\xF2\xF3\xF4\xF5\xF6\xF7\xF8\xF9\x7A\x5E\x4C\x7E\x6E\x6F" // 30-3F
+ "\x7C\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xD1\xD2\xD3\xD4\xD5\xD6" // 40-4F
+ "\xD7\xD8\xD9\xE2\xE3\xE4\xE5\xE6\xE7\xE8\xE9\xAD\xE0\xBD\x5F\x6D" // 50-5F
+ "\x79\x81\x82\x83\x84\x85\x86\x87\x88\x89\x91\x92\x93\x94\x95\x96" // 60-6F
+ "\x97\x98\x99\xA2\xA3\xA4\xA5\xA6\xA7\xA8\xA9\xC0\x4F\xD0\xA1\x07" // 70-7F
+ "\x43\x20\x21\x1C\x23\xEB\x24\x9B\x71\x28\x38\x49\x90\xBA\xEC\xDF" // 80-8F
+ "\x45\x29\x2A\x9D\x72\x2B\x8A\x9A\x67\x56\x64\x4A\x53\x68\x59\x46" // 90-9F
+ "\xEA\xDA\x2C\xDE\x8B\x55\x41\xFE\x58\x51\x52\x48\x69\xDB\x8E\x8D" // A0-AF
+ "\x73\x74\x75\xFA\x15\xB0\xB1\xB3\xB4\xB5\x6A\xB7\xB8\xB9\xCC\xBC" // B0-BF
+ "\xAB\x3E\x3B\x0A\xBF\x8F\x3A\x14\xA0\x17\xCB\xCA\x1A\x1B\x9C\x04" // C0-CF
+ "\x34\xEF\x1E\x06\x08\x09\x77\x70\xBE\xBB\xAC\x54\x63\x65\x66\x62" // D0-DF
+ "\x30\x42\x47\x57\xEE\x33\xB6\xE1\xCD\xED\x36\x44\xCE\xCF\x31\xAA" // E0-EF
+ "\xFC\x9E\xAE\x8C\xDD\xDC\x39\xFB\x80\xAF\xFD\x78\x76\xB2\x9F\xFF" // F0-FF
+};
+
+char ACE_from_IBM1047[257] =
+{
+ "\x00\x01\x02\x03\xCF\x09\xD3\x7F\xD4\xD5\xC3\x0B\x0C\x0D\x0E\x0F" // 00-0F
+ "\x10\x11\x12\x13\xC7\xB4\x08\xC9\x18\x19\xCC\xCD\x83\x1D\xD2\x1F" // 10-1F
+ "\x81\x82\x1C\x84\x86\x0A\x17\x1B\x89\x91\x92\x95\xA2\x05\x06\x07" // 20-2F
+ "\x20\xEE\x16\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\xC1\x1A" // 30-3F
+ "\x20\xA6\xE1\x80\xEB\x90\x9F\xE2\xAB\x8B\x9B\x2E\x3C\x28\x2B\x7C" // 40-4F
+ "\x26\xA9\xAA\x9C\xDB\xA5\x99\xE3\xA8\x9E\x21\x24\x2A\x29\x3B\x5E" // 50-5F
+ "\x2D\x2F\xDF\xDC\x9A\xDD\xDE\x98\x9D\xAC\xBA\x2C\x25\x5F\x3E\x3F" // 60-6F
+ "\xD7\x88\x94\xB0\xB1\xB2\xFC\xD6\xFB\x60\x3A\x23\x40\x27\x3D\x22" // 70-7F
+ "\xF8\x61\x62\x63\x64\x65\x66\x67\x68\x69\x96\xA4\xF3\xAF\xAE\xC5" // 80-8F
+ "\x8C\x6A\x6B\x6C\x6D\x6E\x6F\x70\x71\x72\x97\x87\xCE\x93\xF1\xFE" // 90-9F
+ "\xC8\x7E\x73\x74\x75\x76\x77\x78\x79\x7A\xEF\xC0\xDA\x5B\xF2\xF9" // A0-AF
+ "\xB5\xB6\xFD\xB7\xB8\xB9\xE6\xBB\xBC\xBD\x8D\xD9\xBF\x5D\xD8\xC4" // B0-BF
+ "\x7B\x41\x42\x43\x44\x45\x46\x47\x48\x49\xCB\xCA\xBE\xE8\xEC\xED" // C0-CF
+ "\x7D\x4A\x4B\x4C\x4D\x4E\x4F\x50\x51\x52\xA1\xAD\xF5\xF4\xA3\x8F" // D0-DF
+ "\x5C\xE7\x53\x54\x55\x56\x57\x58\x59\x5A\xA0\x85\x8E\xE9\xE4\xD1" // E0-EF
+ "\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\xB3\xF7\xF0\xFA\xA7\xFF" // F0-FF
+};
+
+#elif defined (__HP_aCC)
+// Make aC++ stop complaining about an empty translation unit
+static int shut_up_aCC = 0;
+#endif /* ACE_MVS */
diff --git a/ace/Streams/Codeset_IBM1047.h b/ace/Streams/Codeset_IBM1047.h
new file mode 100644
index 00000000000..575b3d2f2e9
--- /dev/null
+++ b/ace/Streams/Codeset_IBM1047.h
@@ -0,0 +1,112 @@
+// -*- C++ -*-
+
+//=============================================================================
+/**
+ * @file Codeset_IBM1047.h
+ *
+ * $Id$
+ *
+ * Declares the arrays required to convert between ISO8859 (aka
+ * Latin/1) and IBM1047 (aka EBCDIC).
+ *
+ *
+ * @author Jim Rogers (jrogers@viasoft.com)
+ */
+//=============================================================================
+
+
+#ifndef ACE_CODESET_IMB1047_H
+#define ACE_CODESET_IMB1047_H
+#include "ace/pre.h"
+
+#include "ace/config-all.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#if defined(ACE_MVS)
+
+#include "ace/CDR_Stream.h"
+
+extern ACE_Export char ACE_to_IBM1047[257];
+extern ACE_Export char ACE_from_IBM1047[257];
+
+// ****************************************************************
+
+/**
+ * @class ACE_IBM1047_ISO8859
+ *
+ * @brief Codeset translation specialization.
+ *
+ * This class performs the codeset translation:
+ * - Native: IBM_1047 (i.e. EBCDIC)
+ * - Stream: ISO-8859 (i.e. Latin/1)
+ */
+class ACE_Export ACE_IBM1047_ISO8859 : public ACE_Char_Codeset_Translator
+{
+public:
+ /// A do nothing constructor.
+ ACE_IBM1047_ISO8859 (void);
+
+ /// Virtual destruction
+ virtual ~ACE_IBM1047_ISO8859 (void);
+
+ // = Documented in $ACE_ROOT/ace/CDR_Stream.h
+ virtual ACE_CDR::Boolean read_char (ACE_InputCDR &,
+ ACE_CDR::Char &);
+ virtual ACE_CDR::Boolean read_string (ACE_InputCDR &,
+ ACE_CDR::Char *&);
+ virtual ACE_CDR::Boolean read_char_array (ACE_InputCDR &,
+ ACE_CDR::Char *,
+ ACE_CDR::ULong);
+ virtual ACE_CDR::Boolean write_char (ACE_OutputCDR &,
+ ACE_CDR::Char);
+ virtual ACE_CDR::Boolean write_string (ACE_OutputCDR &,
+ ACE_CDR::ULong,
+ const ACE_CDR::Char *);
+ virtual ACE_CDR::Boolean write_char_array (ACE_OutputCDR &,
+ const ACE_CDR::Char *,
+ ACE_CDR::ULong);
+};
+
+/**
+ * @class ACE_ISO8859_IBM1047
+ *
+ * @brief Codeset translation specialization.
+ *
+ * This class performs the codeset translation:
+ * - Native: ISO-8859 (i.e. Latin/1)
+ * - Stream: IBM-1047 (i.e. EBCDIC)
+ */
+class ACE_Export ACE_ISO8859_IBM1047 : public ACE_Char_Codeset_Translator
+{
+public:
+ /// A do nothing constructor.
+ ACE_ISO8859_IBM1047 (void);
+
+ /// Virtual destruction
+ virtual ~ACE_ISO8859_IBM1047 (void);
+
+ // = Documented in $ACE_ROOT/ace/CDR_Stream.h
+ virtual ACE_CDR::Boolean read_char (ACE_InputCDR &,
+ ACE_CDR::Char &);
+ virtual ACE_CDR::Boolean read_string (ACE_InputCDR &,
+ ACE_CDR::Char *&);
+ virtual ACE_CDR::Boolean read_char_array (ACE_InputCDR &,
+ ACE_CDR::Char *,
+ ACE_CDR::ULong);
+ virtual ACE_CDR::Boolean write_char (ACE_OutputCDR &,
+ ACE_CDR::Char);
+ virtual ACE_CDR::Boolean write_string (ACE_OutputCDR &,
+ ACE_CDR::ULong,
+ const ACE_CDR::Char *);
+ virtual ACE_CDR::Boolean write_char_array (ACE_OutputCDR &,
+ const ACE_CDR::Char *,
+ ACE_CDR::ULong);
+};
+
+#endif /* ACE_MVS */
+
+#include "ace/post.h"
+#endif /* ACE_CODESET_IMB1047_H */
diff --git a/ace/Streams/Message_Queue.cpp b/ace/Streams/Message_Queue.cpp
new file mode 100644
index 00000000000..bd4189d2f3c
--- /dev/null
+++ b/ace/Streams/Message_Queue.cpp
@@ -0,0 +1,442 @@
+// $Id$
+
+#if !defined (ACE_MESSAGE_QUEUE_C)
+#define ACE_MESSAGE_QUEUE_C
+
+#include "ace/Message_Queue.h"
+
+#if !defined (__ACE_INLINE__)
+#include "ace/Message_Queue.i"
+#endif /* __ACE_INLINE__ */
+
+ACE_RCSID(ace, Message_Queue, "$Id$")
+
+#if defined (VXWORKS)
+
+////////////////////////////////
+// class ACE_Message_Queue_Vx //
+////////////////////////////////
+
+void
+ACE_Message_Queue_Vx::dump (void) const
+{
+ ACE_TRACE ("ACE_Message_Queue_Vx::dump");
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_LIB_TEXT ("deactivated = %d\n")
+ ACE_LIB_TEXT ("low_water_mark = %d\n")
+ ACE_LIB_TEXT ("high_water_mark = %d\n")
+ ACE_LIB_TEXT ("cur_bytes = %d\n")
+ ACE_LIB_TEXT ("cur_length = %d\n")
+ ACE_LIB_TEXT ("cur_count = %d\n")
+ ACE_LIB_TEXT ("head_ = %u\n")
+ ACE_LIB_TEXT ("MSG_Q_ID = %u\n"),
+ this->deactivated_,
+ this->low_water_mark_,
+ this->high_water_mark_,
+ this->cur_bytes_,
+ this->cur_length_,
+ this->cur_count_,
+ this->head_,
+ this->tail_));
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+ACE_Message_Queue_Vx::ACE_Message_Queue_Vx (size_t max_messages,
+ size_t max_message_length,
+ ACE_Notification_Strategy *ns)
+ : ACE_Message_Queue<ACE_NULL_SYNCH> (0, 0, ns),
+ max_messages_ (ACE_static_cast (int, max_messages)),
+ max_message_length_ (ACE_static_cast (int, max_message_length))
+{
+ ACE_TRACE ("ACE_Message_Queue_Vx::ACE_Message_Queue_Vx");
+
+ if (this->open (max_messages_, max_message_length_, ns) == -1)
+ ACE_ERROR ((LM_ERROR, ACE_LIB_TEXT ("open")));
+}
+
+ACE_Message_Queue_Vx::~ACE_Message_Queue_Vx (void)
+{
+ ACE_TRACE ("ACE_Message_Queue_Vx::~ACE_Message_Queue_Vx");
+
+ if (this->tail_ != 0 && this->close () == -1)
+ ACE_ERROR ((LM_ERROR, ACE_LIB_TEXT ("close")));
+}
+
+// Don't bother locking since if someone calls this function more than
+// once for the same queue, we're in bigger trouble than just
+// concurrency control!
+
+int
+ACE_Message_Queue_Vx::open (size_t max_messages,
+ size_t max_message_length,
+ ACE_Notification_Strategy *ns)
+{
+ ACE_TRACE ("ACE_Message_Queue_Vx::open");
+ this->high_water_mark_ = 0;
+ this->low_water_mark_ = 0;
+ this->deactivated_ = 0;
+ this->cur_bytes_ = 0;
+ this->cur_length_ = 0;
+ this->cur_count_ = 0;
+ this->head_ = 0;
+ this->notification_strategy_ = ns;
+ this->max_messages_ = ACE_static_cast (int, max_messages);
+ this->max_message_length_ = ACE_static_cast (int, max_message_length);
+
+ if (tail_)
+ {
+ // Had already created a msgQ, so delete it.
+ close ();
+ activate_i ();
+ }
+
+ return (this->tail_ =
+ ACE_reinterpret_cast (ACE_Message_Block *,
+ ::msgQCreate (max_messages_,
+ max_message_length_,
+ MSG_Q_FIFO))) == NULL ? -1 : 0;
+}
+
+// Implementation of the public deactivate() method
+// (assumes locks are held).
+
+int
+ACE_Message_Queue_Vx::deactivate_i (void)
+{
+ ACE_TRACE ("ACE_Message_Queue_Vx::deactivate_i");
+
+ int current_status =
+ this->deactivated_ ? WAS_INACTIVE : WAS_ACTIVE;
+
+ this->deactivated_ = 1;
+
+ return current_status;
+}
+
+int
+ACE_Message_Queue_Vx::activate_i (void)
+{
+ ACE_TRACE ("ACE_Message_Queue_Vx::activate_i");
+ int current_status =
+ this->deactivated_ ? WAS_INACTIVE : WAS_ACTIVE;
+ this->deactivated_ = 0;
+ return current_status;
+}
+
+// Clean up the queue if we have not already done so!
+
+int
+ACE_Message_Queue_Vx::close (void)
+{
+ ACE_TRACE ("ACE_Message_Queue_Vx::close");
+ // Don't lock, because we don't have a lock. It shouldn't be
+ // necessary, anyways.
+
+ this->deactivate_i ();
+
+ // Don't bother to free up the remaining message on the list,
+ // because we don't have any way to iterate over what's in the
+ // queue.
+
+ return ::msgQDelete (msgq ());
+}
+
+int
+ACE_Message_Queue_Vx::signal_enqueue_waiters (void)
+{
+ // No-op.
+ return 0;
+}
+
+int
+ACE_Message_Queue_Vx::signal_dequeue_waiters (void)
+{
+ // No-op.
+ return 0;
+}
+
+int
+ACE_Message_Queue_Vx::enqueue_tail_i (ACE_Message_Block *new_item)
+{
+ ACE_TRACE ("ACE_Message_Queue_Vx::enqueue_tail_i");
+
+ if (new_item == 0)
+ return -1;
+
+ // Don't try to send a composite message!!!! Only the first
+ // block will be sent.
+
+ this->cur_count_++;
+
+ // Always use this method to actually send a message on the queue.
+ if (::msgQSend (msgq (),
+ new_item->rd_ptr (),
+ new_item->size (),
+ WAIT_FOREVER,
+ MSG_PRI_NORMAL) == OK)
+ return ::msgQNumMsgs (msgq ());
+ else
+ return -1;
+}
+
+int
+ACE_Message_Queue_Vx::enqueue_head_i (ACE_Message_Block *new_item)
+{
+ ACE_TRACE ("ACE_Message_Queue_Vx::enqueue_head_i");
+
+ // Just delegate to enqueue_tail_i.
+ return enqueue_tail_i (new_item);
+}
+
+int
+ACE_Message_Queue_Vx::enqueue_i (ACE_Message_Block *new_item)
+{
+ ACE_TRACE ("ACE_Message_Queue_Vx::enqueue_i");
+
+ if (new_item == 0)
+ return -1;
+
+ if (this->head_ == 0)
+ // Should always take this branch.
+ return this->enqueue_head_i (new_item);
+ else
+ ACE_NOTSUP_RETURN (-1);
+}
+
+// Actually get the first ACE_Message_Block (no locking, so must be
+// called with locks held). This method assumes that the queue has at
+// least one item in it when it is called.
+
+int
+ACE_Message_Queue_Vx::dequeue_head_i (ACE_Message_Block *&first_item)
+{
+ ACE_TRACE ("ACE_Message_Queue_Vx::dequeue_head_i");
+
+ // We don't allocate a new Message_Block: the caller must provide
+ // it, and must ensure that it is big enough (without chaining).
+
+ if (first_item == 0 || first_item->wr_ptr () == 0)
+ return -1;
+
+ if (::msgQReceive (msgq (),
+ first_item->wr_ptr (),
+ first_item->size (),
+ WAIT_FOREVER) == ERROR)
+ return -1;
+ else
+ return ::msgQNumMsgs (msgq ());
+}
+
+// Take a look at the first item without removing it.
+
+int
+ACE_Message_Queue_Vx::wait_not_full_cond (ACE_Guard<ACE_Null_Mutex> &mon,
+ ACE_Time_Value *tv)
+{
+ // Always return here, and let the VxWorks message queue handle blocking.
+ ACE_UNUSED_ARG (mon);
+ ACE_UNUSED_ARG (tv);
+
+ return 0;
+}
+
+int
+ACE_Message_Queue_Vx::wait_not_empty_cond (ACE_Guard<ACE_Null_Mutex> &mon,
+ ACE_Time_Value *tv)
+{
+ // Always return here, and let the VxWorks message queue handle blocking.
+ ACE_UNUSED_ARG (mon);
+ ACE_UNUSED_ARG (tv);
+
+ return 0;
+}
+
+#if ! defined (ACE_NEEDS_FUNC_DEFINITIONS)
+int
+ACE_Message_Queue_Vx::peek_dequeue_head (ACE_Message_Block *&,
+ ACE_Time_Value *tv)
+{
+ ACE_UNUSED_ARG (tv);
+ ACE_NOTSUP_RETURN (-1);
+}
+#endif /* ! ACE_NEEDS_FUNC_DEFINITIONS */
+
+#endif /* VXWORKS */
+
+#if defined (ACE_WIN32) && (ACE_HAS_WINNT4 != 0)
+
+ACE_Message_Queue_NT::ACE_Message_Queue_NT (size_t max_threads)
+ : max_cthrs_ (max_threads),
+ cur_thrs_ (0),
+ cur_bytes_ (0),
+ cur_length_ (0),
+ cur_count_ (0),
+ deactivated_ (0),
+ completion_port_ (ACE_INVALID_HANDLE)
+{
+ ACE_TRACE ("ACE_Message_Queue_NT::ACE_Message_Queue_NT");
+ this->open (max_threads);
+}
+
+int
+ACE_Message_Queue_NT::open (size_t max_threads)
+{
+ ACE_TRACE ("ACE_Message_Queue_NT::open");
+ this->max_cthrs_ = max_threads;
+ this->completion_port_ = ::CreateIoCompletionPort (ACE_INVALID_HANDLE,
+ NULL,
+ ACE_Message_Queue_Base::WAS_ACTIVE,
+ max_threads);
+ return (this->completion_port_ == NULL ? -1 : 0);
+}
+
+int
+ACE_Message_Queue_NT::close (void)
+{
+ ACE_TRACE ("ACE_Message_Queue_NT::close");
+ ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1);
+ this->deactivate ();
+ return (::CloseHandle (this->completion_port_) ? 0 : -1 );
+}
+
+ACE_Message_Queue_NT::~ACE_Message_Queue_NT (void)
+{
+ ACE_TRACE ("ACE_Message_Queue_NT::~ACE_Message_Queue_NT");
+ this->close ();
+}
+
+int
+ACE_Message_Queue_NT::enqueue (ACE_Message_Block *new_item,
+ ACE_Time_Value *)
+{
+ ACE_TRACE ("ACE_Message_Queue_NT::enqueue");
+ ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1);
+ if (!this->deactivated_)
+ {
+ size_t msize = new_item->total_size ();
+ size_t mlength = new_item->total_length ();
+ if (::PostQueuedCompletionStatus (this->completion_port_,
+ msize,
+ this->deactivated_,
+ ACE_reinterpret_cast (LPOVERLAPPED, new_item)))
+ {
+ // Update the states once I succeed.
+ this->cur_bytes_ += msize;
+ this->cur_length_ += mlength;
+ return ++this->cur_count_;
+ }
+ }
+ else
+ errno = ESHUTDOWN;
+
+ // Fail to enqueue the message.
+ return -1;
+}
+
+int
+ACE_Message_Queue_NT::dequeue (ACE_Message_Block *&first_item,
+ ACE_Time_Value *timeout)
+{
+ ACE_TRACE ("ACE_Message_Queue_NT::dequeue_head");
+
+ {
+ ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1);
+ if (this->deactivated_) // Make sure the MQ is not deactivated before
+ { // I proceed.
+ errno = ESHUTDOWN; // Operation on deactivated MQ not allowed.
+ return -1;
+ }
+ else
+ ++this->cur_thrs_; // Increase the waiting thread count.
+ }
+
+ DWORD shutdown;
+ DWORD msize;
+ // Get a message from the completion port.
+ int retv = ::GetQueuedCompletionStatus (this->completion_port_,
+ &msize,
+ &shutdown,
+ ACE_reinterpret_cast (LPOVERLAPPED *, &first_item),
+ (timeout == 0 ? INFINITE : timeout->msec ()));
+ {
+ ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1);
+ --this->cur_thrs_; // Decrease waiting thread count.
+ if (retv)
+ {
+ if (!shutdown)
+ { // Really get a valid MB from the queue.
+ --this->cur_count_;
+ this->cur_bytes_ -= msize;
+ this->cur_length_ -= first_item->total_length ();
+ return this->cur_count_;
+ }
+ else // I am woken up by deactivate ().
+ errno = ESHUTDOWN;
+ }
+ }
+ return -1;
+}
+
+int
+ACE_Message_Queue_NT::deactivate (void)
+{
+ ACE_TRACE ("ACE_Message_Queue_NT::deactivate");
+ ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1);
+
+ if (this->deactivated_) // Check if I have been deactivated already.
+ return ACE_Message_Queue_Base::WAS_INACTIVE;
+
+ this->deactivated_ = 1;
+
+ // Get the number of shutdown messages necessary to wake up
+ // all waiting threads.
+
+ for (size_t cntr = this->cur_thrs_ - this->cur_count_;
+ cntr > 0; cntr++)
+ ::PostQueuedCompletionStatus (this->completion_port_,
+ 0,
+ this->deactivated_,
+ NULL);
+ return ACE_Message_Queue_Base::WAS_ACTIVE;
+}
+
+int
+ACE_Message_Queue_NT::activate (void)
+{
+ ACE_TRACE ("ACE_Message_Queue_NT::activate");
+ ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1);
+ if (!this->deactivated_)
+ return ACE_Message_Queue_Base::WAS_ACTIVE;
+
+ this->deactivated_ = 0;
+ return ACE_Message_Queue_Base::WAS_INACTIVE;
+}
+
+void
+ACE_Message_Queue_NT::dump (void) const
+{
+ ACE_TRACE ("ACE_Message_Queue_NT::dump");
+
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_LIB_TEXT ("deactivated = %d\n")
+ ACE_LIB_TEXT ("max_cthrs_ = %d\n")
+ ACE_LIB_TEXT ("cur_thrs_ = %d\n")
+ ACE_LIB_TEXT ("cur_bytes = %d\n")
+ ACE_LIB_TEXT ("cur_length = %d\n")
+ ACE_LIB_TEXT ("cur_count = %d\n")
+ ACE_LIB_TEXT ("completion_port_ = %x\n"),
+ this->deactivated_,
+ this->max_cthrs_,
+ this->cur_thrs_,
+ this->cur_bytes_,
+ this->cur_length_,
+ this->cur_count_,
+ this->completion_port_));
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+#endif /* ACE_WIN32 && ACE_HAS_WINNT4 != 0 */
+
+#endif /* ACE_MESSAGE_QUEUE_C */
diff --git a/ace/Streams/Message_Queue.h b/ace/Streams/Message_Queue.h
new file mode 100644
index 00000000000..ffa2bd77780
--- /dev/null
+++ b/ace/Streams/Message_Queue.h
@@ -0,0 +1,523 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Message_Queue.h
+ *
+ * $Id$
+ *
+ * @author Douglas C. Schmidt <schmidt@cs.wustl.edu>
+ */
+//=============================================================================
+
+#ifndef ACE_MESSAGE_QUEUE_H
+#define ACE_MESSAGE_QUEUE_H
+#include "ace/pre.h"
+
+#include "ace/Message_Block.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "ace/IO_Cntl_Msg.h"
+
+// Forward decls.
+class ACE_Notification_Strategy;
+template <ACE_SYNCH_DECL> class ACE_Message_Queue_Iterator;
+template <ACE_SYNCH_DECL> class ACE_Message_Queue_Reverse_Iterator;
+
+/**
+ * @class ACE_Message_Queue_Base
+ *
+ * @brief Base class for <ACE_Message_Queue>, which is the central
+ * queueing facility for messages in the ACE framework.
+ *
+ * For all the <ACE_Time_Value> pointer parameters the caller will
+ * block until action is possible if <timeout> == 0. Otherwise, it
+ * will wait until the absolute time specified in *<timeout>
+ * elapses.
+ */
+class ACE_Export ACE_Message_Queue_Base
+{
+public:
+ // = Default high and low water marks.
+ enum
+ {
+ /// Default high watermark (16 K).
+ DEFAULT_HWM = 16 * 1024,
+ /// Default low watermark (same as high water mark).
+ DEFAULT_LWM = 16 * 1024,
+ /// Message queue was active before <activate> or <deactivate>.
+ WAS_ACTIVE = 1,
+ /// Message queue was inactive before <activate> or <deactivate>.
+ WAS_INACTIVE = 2
+ };
+
+ ACE_Message_Queue_Base (void);
+
+ /// Close down the message queue and release all resources.
+ virtual int close (void) = 0;
+
+ /// Close down the message queue and release all resources.
+ virtual ~ACE_Message_Queue_Base (void);
+
+ // = Enqueue and dequeue methods.
+
+ /**
+ * Retrieve the first <ACE_Message_Block> without removing it. Note
+ * that <timeout> uses <{absolute}> time rather than <{relative}>
+ * time. If the <timeout> elapses without receiving a message -1 is
+ * returned and <errno> is set to <EWOULDBLOCK>. If the queue is
+ * deactivated -1 is returned and <errno> is set to <ESHUTDOWN>.
+ * Otherwise, returns -1 on failure, else the number of items still
+ * on the queue.
+ */
+ virtual int peek_dequeue_head (ACE_Message_Block *&first_item,
+ ACE_Time_Value *timeout = 0) = 0;
+
+ /**
+ * Enqueue a <ACE_Message_Block *> into the tail of the queue.
+ * Returns number of items in queue if the call succeeds or -1
+ * otherwise. These calls return -1 when queue is closed,
+ * deactivated (in which case <errno> == <ESHUTDOWN>), when a signal
+ * occurs (in which case <errno> == <EINTR>, or if the time
+ * specified in timeout elapses (in which case <errno> ==
+ * <EWOULDBLOCK>).
+ */
+ virtual int enqueue_tail (ACE_Message_Block *new_item,
+ ACE_Time_Value *timeout = 0) = 0;
+ virtual int enqueue (ACE_Message_Block *new_item,
+ ACE_Time_Value *timeout = 0) = 0;
+
+ /**
+ * Dequeue and return the <ACE_Message_Block *> at the head of the
+ * queue. Returns number of items in queue if the call succeeds or
+ * -1 otherwise. These calls return -1 when queue is closed,
+ * deactivated (in which case <errno> == <ESHUTDOWN>), when a signal
+ * occurs (in which case <errno> == <EINTR>, or if the time
+ * specified in timeout elapses (in which case <errno> ==
+ * <EWOULDBLOCK>).
+ */
+ virtual int dequeue_head (ACE_Message_Block *&first_item,
+ ACE_Time_Value *timeout = 0) = 0;
+ virtual int dequeue (ACE_Message_Block *&first_item,
+ ACE_Time_Value *timeout = 0) = 0;
+
+ // = Check if queue is full/empty.
+ /// True if queue is full, else false.
+ /// True if queue is empty, else false.
+ virtual int is_full (void) = 0;
+ virtual int is_empty (void) = 0;
+
+ // = Queue statistic methods.
+
+ /// Number of total bytes on the queue, i.e., sum of the message
+ /// block sizes.
+ virtual size_t message_bytes (void) = 0;
+
+ /// Number of total length on the queue, i.e., sum of the message
+ /// block lengths.
+ virtual size_t message_length (void) = 0;
+
+ /// Number of total messages on the queue.
+ virtual size_t message_count (void) = 0;
+
+ /// New value of the number of total bytes on the queue, i.e.,
+ /// sum of the message block sizes.
+ virtual void message_bytes (size_t new_size) = 0;
+
+ /// New value of the number of total length on the queue, i.e.,
+ /// sum of the message block lengths.
+ virtual void message_length (size_t new_length) = 0;
+
+ // = Activation control methods.
+
+ /**
+ * Deactivate the queue and wakeup all threads waiting on the queue
+ * so they can continue. No messages are removed from the queue,
+ * however. Any other operations called until the queue is
+ * activated again will immediately return -1 with <errno> ==
+ * ESHUTDOWN. Returns WAS_INACTIVE if queue was inactive before the
+ * call and WAS_ACTIVE if queue was active before the call.
+ */
+ virtual int deactivate (void) = 0;
+
+ /**
+ * Reactivate the queue so that threads can enqueue and dequeue
+ * messages again. Returns WAS_INACTIVE if queue was inactive
+ * before the call and WAS_ACTIVE if queue was active before the
+ * call.
+ */
+ virtual int activate (void) = 0;
+
+ /// Returns true if <deactivated_> is enabled.
+ virtual int deactivated (void) = 0;
+
+ // = Get/set the notification strategy for the <Message_Queue>
+ virtual ACE_Notification_Strategy *notification_strategy (void) = 0;
+ virtual void notification_strategy (ACE_Notification_Strategy *s) = 0;
+
+ // = Notification hook.
+
+ /// Dump the state of an object.
+ virtual void dump (void) const = 0;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+private:
+ // = Disallow these operations.
+ ACE_UNIMPLEMENTED_FUNC (void operator= (const ACE_Message_Queue_Base &))
+ ACE_UNIMPLEMENTED_FUNC (ACE_Message_Queue_Base (const ACE_Message_Queue_Base &))
+};
+
+// Include the templates here.
+#include "ace/Message_Queue_T.h"
+
+#if defined (VXWORKS)
+# include /**/ <msgQLib.h>
+
+/**
+ * @class ACE_Message_Queue_Vx
+ *
+ * @brief Wrapper for VxWorks message queues.
+ *
+ * Specialization of ACE_Message_Queue to simply wrap VxWorks
+ * MsgQ. It does not use any synchronization, because it relies
+ * on the native MsgQ implementation to take care of that. The
+ * only system calls that it uses are VxWorks msgQLib calls, so
+ * it is suitable for use in interrupt service routines.
+ * NOTE: *Many* ACE_Message_Queue features are not supported with
+ * this specialization, including:
+ * * The two size arguments to the constructor and <open> are
+ * interpreted differently. The first is interpreted as the
+ * maximum number of bytes in a message. The second is
+ * interpreted as the maximum number of messages that can be
+ * queued.
+ * * <dequeue_head> *requires* that the ACE_Message_Block
+ * pointer argument point to an ACE_Message_Block that was
+ * allocated by the caller. It must be big enough to support
+ * the received message, without using continutation. The
+ * pointer argument is not modified.
+ * * Message priority. MSG_Q_FIFO is hard-coded.
+ * * enqueue method timeouts.
+ * * <peek_dequeue_head>.
+ * * <ACE_Message_Queue_Iterators>.
+ * * The ability to change low and high water marks after creation.
+ * * <Message_Block> chains. The continuation field of <ACE_Message_Block>
+ * * is ignored; only the first block of a fragment chain is
+ * * recognized.
+ */
+class ACE_Message_Queue_Vx : public ACE_Message_Queue<ACE_NULL_SYNCH>
+{
+public:
+ // = Initialization and termination methods.
+ ACE_Message_Queue_Vx (size_t max_messages,
+ size_t max_message_length,
+ ACE_Notification_Strategy * = 0);
+
+ // Create a message queue with all the defaults.
+ /// Create a message queue with all the defaults.
+ virtual int open (size_t max_messages,
+ size_t max_message_length,
+ ACE_Notification_Strategy * = 0);
+
+ /// Close down the message queue and release all resources.
+ virtual int close (void);
+
+ /// Close down the message queue and release all resources.
+ virtual ~ACE_Message_Queue_Vx (void);
+
+ // = Queue statistic methods.
+ /**
+ * Number of total bytes on the queue, i.e., sum of the message
+ * block sizes.
+ * Number of total length on the queue, i.e., sum of the message
+ * block lengths.
+ * Number of total messages on the queue.
+ */
+ virtual size_t message_bytes (void);
+ virtual size_t message_length (void);
+ virtual size_t message_count (void);
+
+ // = Manual changes to these stats (used when queued message blocks
+ // change size or lengths).
+ /**
+ * New value of the number of total bytes on the queue, i.e., sum of
+ * the message block sizes.
+ * New value of the number of total length on the queue, i.e., sum
+ * of the message block lengths.
+ */
+ virtual void message_bytes (size_t new_size);
+ virtual void message_length (size_t new_length);
+
+ // = Flow control routines
+ /**
+ * Get high watermark.
+ * Set high watermark.
+ * Get low watermark.
+ * Set low watermark.
+ */
+ virtual size_t high_water_mark (void);
+ virtual void high_water_mark (size_t hwm);
+ virtual size_t low_water_mark (void);
+ virtual void low_water_mark (size_t lwm);
+
+ // = Activation control methods.
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+protected:
+ /// Enqueue an <ACE_Message_Block *> in accordance with its priority.
+ virtual int enqueue_i (ACE_Message_Block *new_item);
+
+ /// Enqueue an <ACE_Message_Block *> at the end of the queue.
+ virtual int enqueue_tail_i (ACE_Message_Block *new_item);
+
+ /// Enqueue an <ACE_Message_Block *> at the head of the queue.
+ virtual int enqueue_head_i (ACE_Message_Block *new_item);
+
+ /// Dequeue and return the <ACE_Message_Block *> at the head of the
+ /// queue.
+ virtual int dequeue_head_i (ACE_Message_Block *&first_item);
+
+ // = Check the boundary conditions (assumes locks are held).
+ /// True if queue is full, else false.
+ /// True if queue is empty, else false.
+ virtual int is_full_i (void);
+ virtual int is_empty_i (void);
+
+ // = Implementation of public <activate>/<deactivate> methods above.
+
+ // These methods assume locks are held.
+
+ /// Deactivate the queue.
+ /// Activate the queue.
+ virtual int deactivate_i (void);
+ virtual int activate_i (void);
+
+ // = Helper methods to factor out common #ifdef code.
+ /// Wait for the queue to become non-full.
+ virtual int wait_not_full_cond (ACE_Guard<ACE_Null_Mutex> &mon,
+ ACE_Time_Value *tv);
+
+ /// Wait for the queue to become non-empty.
+ virtual int wait_not_empty_cond (ACE_Guard<ACE_Null_Mutex> &mon,
+ ACE_Time_Value *tv);
+
+ /// Inform any threads waiting to enqueue that they can procede.
+ virtual int signal_enqueue_waiters (void);
+
+ /// Inform any threads waiting to dequeue that they can procede.
+ virtual int signal_dequeue_waiters (void);
+
+ /// Access the underlying msgQ.
+ MSG_Q_ID msgq (void);
+
+private:
+ /// Maximum number of messages that can be queued.
+ int max_messages_;
+
+ /// Maximum message size, in bytes.
+ int max_message_length_;
+
+ /// Native message queue options.
+ int options_;
+
+ // = Disallow these operations.
+ ACE_UNIMPLEMENTED_FUNC (void operator= (const ACE_Message_Queue_Vx &))
+ ACE_UNIMPLEMENTED_FUNC (ACE_Message_Queue_Vx (const ACE_Message_Queue_Vx &))
+
+ ACE_UNIMPLEMENTED_FUNC (virtual int peek_dequeue_head
+ (ACE_Message_Block *&first_item,
+ ACE_Time_Value *tv = 0))
+};
+#endif /* VXWORKS */
+
+#if defined (ACE_WIN32) && (ACE_HAS_WINNT4 != 0)
+/**
+ * @class ACE_Message_Queue_NT
+ *
+ * @brief Message Queue implementation using IO completion port on NT.
+ *
+ * Implementation of a strip-downed ACE_Message_Queue using NT's
+ * IO completion port mechanism.
+ * NOTE: *Many* ACE_Message_Queue features are not supported with
+ * this implementation, including:
+ * * <open> method have different signatures.
+ * * <dequeue_head> *requires* that the <ACE_Message_Block>
+ * pointer argument point to an <ACE_Message_Block> that was
+ * allocated by the caller.
+ * * <peek_dequeue_head>.
+ * * <ACE_Message_Queue_Iterators>.
+ * * No flow control.
+ */
+class ACE_Export ACE_Message_Queue_NT : public ACE_Message_Queue_Base
+{
+public:
+ // = Initialization and termination methods.
+ ACE_Message_Queue_NT (size_t max_threads = ACE_Message_Queue_Base::DEFAULT_HWM);
+
+ /**
+ * Initialize the Message Queue by creating a new NT I/O completion
+ * port. The first arguemnt specifies the number of threads
+ * released by the MQ that are allowed to run concurrently. Return
+ * 0 when succeeds, -1 otherwise.
+ */
+ virtual int open (size_t max_threads = ACE_Message_Queue_Base::DEFAULT_HWM);
+
+ /// Close down the underlying I/O completion port. You need to
+ /// re-open the MQ after this function is executed.
+ virtual int close (void);
+
+ /// Close down the message queue and release all resources.
+ virtual ~ACE_Message_Queue_NT (void);
+
+ // = Enqueue and dequeue methods.
+
+ /**
+ * Enqueue an <ACE_Message_Block *> at the end of the queue.
+ * Returns -1 on failure, else the number of items still on the
+ * queue.
+ */
+ virtual int enqueue_tail (ACE_Message_Block *new_item,
+ ACE_Time_Value *timeout = 0);
+ virtual int enqueue (ACE_Message_Block *new_item,
+ ACE_Time_Value *timeout = 0);
+
+ /**
+ * Dequeue and return the <ACE_Message_Block *> at the head of the
+ * queue. Returns -1 on failure, else the number of items still on
+ * the queue.
+ */
+ virtual int dequeue_head (ACE_Message_Block *&first_item,
+ ACE_Time_Value *timeout = 0);
+ virtual int dequeue (ACE_Message_Block *&first_item,
+ ACE_Time_Value *timeout = 0);
+
+ // = Check if queue is full/empty.
+ /**
+ * Always return false.
+ * True if queue is empty, else false. Notice the return value is
+ * only transient.
+ */
+ virtual int is_full (void);
+ virtual int is_empty (void);
+
+ // = Queue statistic methods (transient.)
+ /**
+ * Number of total bytes on the queue, i.e., sum of the message
+ * block sizes.
+ * Number of total length on the queue, i.e., sum of the message
+ * block lengths.
+ * Number of total messages on the queue.
+ */
+ virtual size_t message_bytes (void);
+ virtual size_t message_length (void);
+ virtual size_t message_count (void);
+
+ // = Manual changes to these stats (used when queued message blocks
+ // change size or lengths).
+ /**
+ * New value of the number of total bytes on the queue, i.e., sum of
+ * the message block sizes.
+ * New value of the number of total length on the queue, i.e., sum
+ * of the message block lengths.
+ */
+ virtual void message_bytes (size_t new_size);
+ virtual void message_length (size_t new_length);
+
+ /// Get the max concurrent thread number.
+ virtual size_t max_threads (void);
+
+ // = Activation control methods.
+
+ /**
+ * Deactivate the queue and wakeup all threads waiting on the queue
+ * so they can continue. Messages already in the queue get removed.
+ * If there are more messages in the queue than there are threads
+ * waiting on the queue, the left over messages will not be removed.
+ * Any other enqueue/dequeue operations called until the queue is
+ * activated again will immediately return -1 with <errno> ==
+ * ESHUTDOWN. Returns WAS_INACTIVE if queue was inactive before the
+ * call and WAS_ACTIVE if queue was active before the call.
+ */
+ virtual int deactivate (void);
+
+ /**
+ * Reactivate the queue so that threads can enqueue and dequeue
+ * messages again. Returns WAS_INACTIVE if queue was inactive
+ * before the call and WAS_ACTIVE if queue was active before the
+ * call.
+ */
+ virtual int activate (void);
+
+ /// Returns true if <deactivated_> is enabled.
+ virtual int deactivated (void);
+
+ // = Not currently implemented...
+ int peek_dequeue_head (ACE_Message_Block *&first_item,
+ ACE_Time_Value *timeout = 0);
+ ACE_Notification_Strategy *notification_strategy (void);
+ void notification_strategy (ACE_Notification_Strategy *s);
+
+ // = Notification hook.
+
+ /// Dump the state of an object.
+ virtual void dump (void) const;
+
+ /// Get the handle to the underlying completion port.
+ virtual ACE_HANDLE completion_port (void);
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+private:
+ // = Internal states.
+
+ /// Maximum threads that can be released (and run) concurrently.
+ size_t max_cthrs_;
+
+ /// Current number of threads waiting to dequeue messages.
+ size_t cur_thrs_;
+
+ /// Current number of bytes in queue.
+ size_t cur_bytes_;
+
+ /// Current length of messages in queue.
+ size_t cur_length_;
+
+ /// Current number of messages in the queue.
+ size_t cur_count_;
+
+ /**
+ * Synchronizer. This should really be an ACE_Recursive_Thread_Mutex
+ * but since this class is only supported on NT, it's okay to use
+ * ACE_Thread_Mutex here.
+ */
+ ACE_Thread_Mutex lock_;
+
+ /// Indicates that the queue is inactive.
+ int deactivated_;
+
+ /// Underlying NT IoCompletionPort.
+ ACE_HANDLE completion_port_;
+
+ // = Disallow these operations.
+ ACE_UNIMPLEMENTED_FUNC (void operator= (const ACE_Message_Queue_NT &))
+ ACE_UNIMPLEMENTED_FUNC (ACE_Message_Queue_NT (const ACE_Message_Queue_NT &))
+};
+#endif /* ACE_WIN32 && ACE_HAS_WINNT4 != 0 */
+
+
+#if defined (__ACE_INLINE__)
+#include "ace/Message_Queue.i"
+#endif /* __ACE_INLINE__ */
+
+#include "ace/post.h"
+#endif /* ACE_MESSAGE_QUEUE_H */
diff --git a/ace/Streams/Message_Queue.i b/ace/Streams/Message_Queue.i
new file mode 100644
index 00000000000..8cf619653a8
--- /dev/null
+++ b/ace/Streams/Message_Queue.i
@@ -0,0 +1,224 @@
+/* -*- C++ -*- */
+// $Id$
+
+ACE_INLINE
+ACE_Message_Queue_Base::ACE_Message_Queue_Base (void)
+{
+}
+
+ACE_INLINE
+ACE_Message_Queue_Base::~ACE_Message_Queue_Base (void)
+{
+}
+
+#if defined (VXWORKS)
+// Specialization to use native VxWorks Message Queues.
+
+ACE_INLINE MSG_Q_ID
+ACE_Message_Queue_Vx::msgq ()
+{
+ // Hijack the tail_ field to store the MSG_Q_ID.
+ return ACE_reinterpret_cast (MSG_Q_ID, tail_);
+}
+
+ACE_INLINE int
+ACE_Message_Queue_Vx::is_empty_i (void)
+{
+ ACE_TRACE ("ACE_Message_Queue_Vx::is_empty_i");
+ return ::msgQNumMsgs (msgq ()) == 0;
+}
+
+ACE_INLINE int
+ACE_Message_Queue_Vx::is_full_i (void)
+{
+ ACE_TRACE ("ACE_Message_Queue_Vx::is_full_i");
+ return ::msgQNumMsgs (msgq ()) >= max_messages_;
+}
+
+ACE_INLINE size_t
+ACE_Message_Queue_Vx::high_water_mark (void)
+{
+ ACE_TRACE ("ACE_Message_Queue_Vx::high_water_mark");
+ ACE_NOTSUP_RETURN ((size_t) -1);
+}
+
+ACE_INLINE void
+ACE_Message_Queue_Vx::high_water_mark (size_t)
+{
+ ACE_TRACE ("ACE_Message_Queue_Vx::high_water_mark");
+ ACE_NOTSUP;
+}
+
+ACE_INLINE size_t
+ACE_Message_Queue_Vx::low_water_mark (void)
+{
+ ACE_TRACE ("ACE_Message_Queue_Vx::low_water_mark");
+ // Don't need to guard, because this is fixed.
+
+ ACE_NOTSUP_RETURN ((size_t) -1);
+}
+
+ACE_INLINE void
+ACE_Message_Queue_Vx::low_water_mark (size_t)
+{
+ ACE_TRACE ("ACE_Message_Queue_Vx::low_water_mark");
+ ACE_NOTSUP;
+}
+
+ACE_INLINE size_t
+ACE_Message_Queue_Vx::message_bytes (void)
+{
+ ACE_TRACE ("ACE_Message_Queue_Vx::message_bytes");
+ ACE_NOTSUP_RETURN ((size_t) -1);
+}
+
+ACE_INLINE size_t
+ACE_Message_Queue_Vx::message_length (void)
+{
+ ACE_TRACE ("ACE_Message_Queue_Vx::message_length");
+ ACE_NOTSUP_RETURN ((size_t) -1);
+}
+
+ACE_INLINE size_t
+ACE_Message_Queue_Vx::message_count (void)
+{
+ ACE_TRACE ("ACE_Message_Queue_Vx::message_count");
+ // Don't need to guard, because this is a system call.
+
+ return ::msgQNumMsgs (msgq ());
+}
+
+ACE_INLINE void
+ACE_Message_Queue_Vx::message_bytes (size_t)
+{
+ ACE_TRACE ("ACE_Message_Queue_Vx::message_bytes");
+ ACE_NOTSUP;
+}
+
+ACE_INLINE void
+ACE_Message_Queue_Vx::message_length (size_t)
+{
+ ACE_TRACE ("ACE_Message_Queue_Vx::message_length");
+ ACE_NOTSUP;
+}
+
+#endif /* VXWORKS */
+
+#if defined (ACE_WIN32) && (ACE_HAS_WINNT4 != 0)
+ACE_INLINE int
+ACE_Message_Queue_NT::enqueue_tail (ACE_Message_Block *new_item,
+ ACE_Time_Value *timeout)
+{
+ ACE_TRACE ("ACE_Message_Queue_NT::enqueue_tail");
+ return this->enqueue (new_item, timeout);
+}
+
+ACE_INLINE int
+ACE_Message_Queue_NT::dequeue_head (ACE_Message_Block *&first_item,
+ ACE_Time_Value *timeout)
+{
+ ACE_TRACE ("ACE_Message_Queue_NT::dequeue_head");
+ return this->dequeue (first_item, timeout);
+}
+
+ACE_INLINE int
+ACE_Message_Queue_NT::is_full (void)
+{
+ ACE_TRACE ("ACE_Message_Queue_NT::is_full");
+ return 0; // Always not full.
+}
+
+ACE_INLINE int
+ACE_Message_Queue_NT::is_empty (void)
+{
+ ACE_TRACE ("ACE_Message_Queue_NT::is_empty");
+ ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, 0);
+
+ return (this->cur_bytes_ > 0 && this->cur_count_ > 0 ? 1 : 0);
+}
+
+ACE_INLINE size_t
+ACE_Message_Queue_NT::message_bytes (void)
+{
+ ACE_TRACE ("ACE_Message_Queue_NT::message_bytes");
+ // Accessing to size_t must be atomic.
+ return this->cur_bytes_;
+}
+
+ACE_INLINE size_t
+ACE_Message_Queue_NT::message_length (void)
+{
+ ACE_TRACE ("ACE_Message_Queue_NT::message_length");
+ // Accessing to size_t must be atomic.
+ return this->cur_length_;
+}
+
+ACE_INLINE size_t
+ACE_Message_Queue_NT::message_count (void)
+{
+ ACE_TRACE ("ACE_Message_Queue_NT::message_count");
+ // Accessing to size_t must be atomic.
+ return this->cur_count_;
+}
+
+ACE_INLINE void
+ACE_Message_Queue_NT::message_bytes (size_t new_value)
+{
+ ACE_TRACE ("ACE_Message_Queue_NT::message_bytes");
+ ACE_GUARD (ACE_Thread_Mutex, ace_mon, this->lock_);
+
+ this->cur_bytes_ = new_value;
+}
+
+ACE_INLINE void
+ACE_Message_Queue_NT::message_length (size_t new_value)
+{
+ ACE_TRACE ("ACE_Message_Queue_NT::message_length");
+ ACE_GUARD (ACE_Thread_Mutex, ace_mon, this->lock_);
+
+ this->cur_length_ = new_value;
+}
+
+ACE_INLINE size_t
+ACE_Message_Queue_NT::max_threads (void)
+{
+ ACE_TRACE ("ACE_Message_Queue_NT::max_threads");
+ return this->max_cthrs_;
+}
+
+ACE_INLINE int
+ACE_Message_Queue_NT::deactivated (void)
+{
+ ACE_TRACE ("ACE_Message_Queue_NT::deactivated");
+ // Accessing to int must be atomic.
+ return this->deactivated_;
+}
+
+ACE_INLINE ACE_HANDLE
+ACE_Message_Queue_NT::completion_port (void)
+{
+ ACE_TRACE ("ACE_Message_Queue_NT::completion_port");
+ return this->completion_port_;
+}
+
+ACE_INLINE int
+ACE_Message_Queue_NT::peek_dequeue_head (ACE_Message_Block *&first_item,
+ ACE_Time_Value *timeout)
+{
+ ACE_UNUSED_ARG(first_item);
+ ACE_UNUSED_ARG(timeout);
+ ACE_NOTSUP_RETURN (-1);
+}
+
+ACE_INLINE ACE_Notification_Strategy *
+ACE_Message_Queue_NT::notification_strategy (void)
+{
+ ACE_NOTSUP_RETURN (0);
+}
+
+ACE_INLINE void
+ACE_Message_Queue_NT::notification_strategy (ACE_Notification_Strategy *)
+{
+}
+
+#endif /* ACE_WIN32 && ACE_HAS_WINNT4 != 0 */
diff --git a/ace/Streams/Message_Queue_T.cpp b/ace/Streams/Message_Queue_T.cpp
new file mode 100644
index 00000000000..6b7a7dd288a
--- /dev/null
+++ b/ace/Streams/Message_Queue_T.cpp
@@ -0,0 +1,1858 @@
+// $Id$
+
+#ifndef ACE_MESSAGE_QUEUE_T_C
+#define ACE_MESSAGE_QUEUE_T_C
+
+// #include Message_Queue.h instead of Message_Queue_T.h to avoid
+// circular include problems.
+#include "ace/Message_Queue.h"
+
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#if !defined (__ACE_INLINE__)
+#include "ace/Message_Queue_T.i"
+#endif /* __ACE_INLINE__ */
+
+#include "ace/Notification_Strategy.h"
+
+ACE_RCSID(ace, Message_Queue_T, "$Id$")
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Message_Queue)
+ACE_ALLOC_HOOK_DEFINE(ACE_Dynamic_Message_Queue)
+ACE_ALLOC_HOOK_DEFINE(ACE_Message_Queue_Ex)
+
+template <class ACE_MESSAGE_TYPE, ACE_SYNCH_DECL> void
+ACE_Message_Queue_Ex<ACE_MESSAGE_TYPE, ACE_SYNCH_USE>::dump (void) const
+{
+ ACE_TRACE ("ACE_Message_Queue_Ex<ACE_MESSAGE_TYPE, ACE_SYNCH_USE>::dump");
+
+ this->queue_.dump ();
+}
+
+template <class ACE_MESSAGE_TYPE, ACE_SYNCH_DECL> void
+ACE_Message_Queue_Ex<ACE_MESSAGE_TYPE, ACE_SYNCH_USE>::message_bytes (size_t new_value)
+{
+ ACE_TRACE ("ACE_Message_Queue_Ex<ACE_MESSAGE_TYPE, ACE_SYNCH_USE>::message_bytes");
+
+ this->queue_.message_bytes (new_value);
+}
+
+template <class ACE_MESSAGE_TYPE, ACE_SYNCH_DECL> void
+ACE_Message_Queue_Ex<ACE_MESSAGE_TYPE, ACE_SYNCH_USE>::message_length (size_t new_value)
+{
+ ACE_TRACE ("ACE_Message_Queue_Ex<ACE_MESSAGE_TYPE, ACE_SYNCH_USE>::message_length");
+
+ this->queue_.message_length (new_value);
+}
+
+template <class ACE_MESSAGE_TYPE, ACE_SYNCH_DECL>
+ACE_Message_Queue_Ex<ACE_MESSAGE_TYPE, ACE_SYNCH_USE>::ACE_Message_Queue_Ex (size_t hwm,
+ size_t lwm,
+ ACE_Notification_Strategy *ns)
+{
+ ACE_TRACE ("ACE_Message_Queue_Ex<ACE_MESSAGE_TYPE, ACE_SYNCH_USE>::ACE_Message_Queue_Ex");
+
+ if (this->queue_.open (hwm, lwm, ns) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("ACE_Message_Queue_Ex")));
+}
+
+template <class ACE_MESSAGE_TYPE, ACE_SYNCH_DECL>
+ACE_Message_Queue_Ex<ACE_MESSAGE_TYPE, ACE_SYNCH_USE>::~ACE_Message_Queue_Ex (void)
+{
+ ACE_TRACE ("ACE_Message_Queue_Ex<ACE_MESSAGE_TYPE, ACE_SYNCH_USE>::~ACE_Message_Queue_Ex");
+}
+
+template <class ACE_MESSAGE_TYPE, ACE_SYNCH_DECL> int
+ACE_Message_Queue_Ex<ACE_MESSAGE_TYPE, ACE_SYNCH_USE>::open (size_t hwm,
+ size_t lwm,
+ ACE_Notification_Strategy *ns)
+{
+ ACE_TRACE ("ACE_Message_Queue_Ex<ACE_MESSAGE_TYPE, ACE_SYNCH_USE>::open");
+
+ return this->queue_.open (hwm, lwm, ns);
+}
+
+// Clean up the queue if we have not already done so!
+
+template <class ACE_MESSAGE_TYPE, ACE_SYNCH_DECL> int
+ACE_Message_Queue_Ex<ACE_MESSAGE_TYPE, ACE_SYNCH_USE>::close (void)
+{
+ ACE_TRACE ("ACE_Message_Queue_Ex<ACE_MESSAGE_TYPE, ACE_SYNCH_USE>::close");
+
+ return this->queue_.close ();
+}
+
+// Take a look at the first item without removing it.
+
+template <class ACE_MESSAGE_TYPE, ACE_SYNCH_DECL> int
+ACE_Message_Queue_Ex<ACE_MESSAGE_TYPE, ACE_SYNCH_USE>::peek_dequeue_head (ACE_MESSAGE_TYPE *&first_item,
+ ACE_Time_Value *timeout)
+{
+ ACE_TRACE ("ACE_Message_Queue_Ex<ACE_MESSAGE_TYPE, ACE_SYNCH_USE>::peek_dequeue_head");
+
+ ACE_Message_Block *mb;
+
+ int cur_count = this->queue_.peek_dequeue_head (mb, timeout);
+
+ if (cur_count != -1)
+ first_item = ACE_reinterpret_cast (ACE_MESSAGE_TYPE *, mb->base ());
+
+ return cur_count;
+}
+
+template <class ACE_MESSAGE_TYPE, ACE_SYNCH_DECL> int
+ACE_Message_Queue_Ex<ACE_MESSAGE_TYPE, ACE_SYNCH_USE>::enqueue_head (ACE_MESSAGE_TYPE *new_item,
+ ACE_Time_Value *timeout)
+{
+ ACE_TRACE ("ACE_Message_Queue_Ex<ACE_MESSAGE_TYPE, ACE_SYNCH_USE>::enqueue_head");
+
+ ACE_Message_Block *mb;
+
+ ACE_NEW_RETURN (mb,
+ ACE_Message_Block ((char *) new_item,
+ sizeof (*new_item),
+ DEFAULT_PRIORITY),
+ -1);
+
+ int result = this->queue_.enqueue_head (mb, timeout);
+ if (result == -1)
+ // Zap the message.
+ mb->release ();
+ return result;
+}
+
+// Enqueue an <ACE_MESSAGE_TYPE *> into the <Message_Queue> in
+// accordance with its <msg_priority> (0 is lowest priority). Returns
+// -1 on failure, else the number of items still on the queue.
+
+template <class ACE_MESSAGE_TYPE, ACE_SYNCH_DECL> int
+ACE_Message_Queue_Ex<ACE_MESSAGE_TYPE, ACE_SYNCH_USE>::enqueue (ACE_MESSAGE_TYPE *new_item,
+ ACE_Time_Value *timeout)
+{
+ ACE_TRACE ("ACE_Message_Queue_Ex<ACE_MESSAGE_TYPE, ACE_SYNCH_USE>::enqueue_prio");
+
+ return this->enqueue_prio (new_item, timeout);
+}
+
+template <class ACE_MESSAGE_TYPE, ACE_SYNCH_DECL> int
+ACE_Message_Queue_Ex<ACE_MESSAGE_TYPE, ACE_SYNCH_USE>::enqueue_prio (ACE_MESSAGE_TYPE *new_item,
+ ACE_Time_Value *timeout)
+{
+ ACE_TRACE ("ACE_Message_Queue_Ex<ACE_MESSAGE_TYPE, ACE_SYNCH_USE>::enqueue_prio");
+
+ ACE_Message_Block *mb;
+
+ ACE_NEW_RETURN (mb,
+ ACE_Message_Block ((char *) new_item,
+ sizeof (*new_item),
+ DEFAULT_PRIORITY),
+ -1);
+
+ int result = this->queue_.enqueue_prio (mb, timeout);
+ if (result == -1)
+ // Zap the message.
+ mb->release ();
+
+ return result;
+}
+
+// Block indefinitely waiting for an item to arrive,
+// does not ignore alerts (e.g., signals).
+
+template <class ACE_MESSAGE_TYPE, ACE_SYNCH_DECL> int
+ACE_Message_Queue_Ex<ACE_MESSAGE_TYPE, ACE_SYNCH_USE>::enqueue_tail (ACE_MESSAGE_TYPE *new_item,
+ ACE_Time_Value *timeout)
+{
+ ACE_TRACE ("ACE_Message_Queue_Ex<ACE_MESSAGE_TYPE, ACE_SYNCH_USE>::enqueue_tail");
+
+ ACE_Message_Block *mb;
+
+ ACE_NEW_RETURN (mb,
+ ACE_Message_Block ((char *) new_item,
+ sizeof (*new_item),
+ DEFAULT_PRIORITY),
+ -1);
+
+ int result = this->queue_.enqueue_tail (mb, timeout);
+ if (result == -1)
+ // Zap the message.
+ mb->release ();
+ return result;
+}
+
+// Remove an item from the front of the queue. If timeout == 0 block
+// indefinitely (or until an alert occurs). Otherwise, block for upto
+// the amount of time specified by timeout.
+
+template <class ACE_MESSAGE_TYPE, ACE_SYNCH_DECL> int
+ACE_Message_Queue_Ex<ACE_MESSAGE_TYPE, ACE_SYNCH_USE>::dequeue_head (ACE_MESSAGE_TYPE *&first_item,
+ ACE_Time_Value *timeout)
+{
+ ACE_TRACE ("ACE_Message_Queue_Ex<ACE_MESSAGE_TYPE, ACE_SYNCH_USE>::dequeue_head");
+
+ ACE_Message_Block *mb;
+
+ int cur_count = this->queue_.dequeue_head (mb, timeout);
+
+ // Dequeue the message.
+ if (cur_count != -1)
+ {
+ first_item = ACE_reinterpret_cast (ACE_MESSAGE_TYPE *, mb->base ());
+ // Delete the message block.
+ mb->release ();
+ return cur_count;
+ }
+ else
+ return -1;
+}
+
+template <class ACE_MESSAGE_TYPE, ACE_SYNCH_DECL> int
+ACE_Message_Queue_Ex<ACE_MESSAGE_TYPE, ACE_SYNCH_USE>::notify (void)
+{
+ ACE_TRACE ("ACE_Message_Queue_Ex<ACE_MESSAGE_TYPE, ACE_SYNCH_USE>::notify");
+
+ return this->queue_.notify ();
+}
+
+template <ACE_SYNCH_DECL>
+ACE_Message_Queue_Iterator<ACE_SYNCH_USE>::ACE_Message_Queue_Iterator (ACE_Message_Queue <ACE_SYNCH_USE> &q)
+ : queue_ (q),
+ curr_ (q.head_)
+{
+}
+
+template <ACE_SYNCH_DECL> int
+ACE_Message_Queue_Iterator<ACE_SYNCH_USE>::next (ACE_Message_Block *&entry)
+{
+ ACE_READ_GUARD_RETURN (ACE_SYNCH_MUTEX_T, m, this->queue_.lock_, -1)
+
+ if (this->curr_ != 0)
+ {
+ entry = this->curr_;
+ return 1;
+ }
+
+ return 0;
+}
+
+template <ACE_SYNCH_DECL> int
+ACE_Message_Queue_Iterator<ACE_SYNCH_USE>::done (void) const
+{
+ ACE_READ_GUARD_RETURN (ACE_SYNCH_MUTEX_T, m, this->queue_.lock_, -1)
+
+ return this->curr_ == 0;
+}
+
+template <ACE_SYNCH_DECL> int
+ACE_Message_Queue_Iterator<ACE_SYNCH_USE>::advance (void)
+{
+ ACE_READ_GUARD_RETURN (ACE_SYNCH_MUTEX_T, m, this->queue_.lock_, -1)
+
+ if (this->curr_)
+ this->curr_ = this->curr_->next ();
+ return this->curr_ != 0;
+}
+
+template <ACE_SYNCH_DECL> void
+ACE_Message_Queue_Iterator<ACE_SYNCH_USE>::dump (void) const
+{
+}
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Message_Queue_Iterator)
+
+template <ACE_SYNCH_DECL>
+ACE_Message_Queue_Reverse_Iterator<ACE_SYNCH_USE>::ACE_Message_Queue_Reverse_Iterator (ACE_Message_Queue <ACE_SYNCH_USE> &q)
+ : queue_ (q),
+ curr_ (queue_.tail_)
+{
+}
+
+template <ACE_SYNCH_DECL> int
+ACE_Message_Queue_Reverse_Iterator<ACE_SYNCH_USE>::next (ACE_Message_Block *&entry)
+{
+ ACE_READ_GUARD_RETURN (ACE_SYNCH_MUTEX_T, m, this->queue_.lock_, -1)
+
+ if (this->curr_ != 0)
+ {
+ entry = this->curr_;
+ return 1;
+ }
+
+ return 0;
+}
+
+template <ACE_SYNCH_DECL> int
+ACE_Message_Queue_Reverse_Iterator<ACE_SYNCH_USE>::done (void) const
+{
+ ACE_READ_GUARD_RETURN (ACE_SYNCH_MUTEX_T, m, this->queue_.lock_, -1)
+
+ return this->curr_ == 0;
+}
+
+template <ACE_SYNCH_DECL> int
+ACE_Message_Queue_Reverse_Iterator<ACE_SYNCH_USE>::advance (void)
+{
+ ACE_READ_GUARD_RETURN (ACE_SYNCH_MUTEX_T, m, this->queue_.lock_, -1)
+
+ if (this->curr_)
+ this->curr_ = this->curr_->prev ();
+ return this->curr_ != 0;
+}
+
+template <ACE_SYNCH_DECL> void
+ACE_Message_Queue_Reverse_Iterator<ACE_SYNCH_USE>::dump (void) const
+{
+}
+
+template <ACE_SYNCH_DECL> void
+ACE_Message_Queue<ACE_SYNCH_USE>::dump (void) const
+{
+ ACE_TRACE ("ACE_Message_Queue<ACE_SYNCH_USE>::dump");
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_LIB_TEXT ("deactivated = %d\n")
+ ACE_LIB_TEXT ("low_water_mark = %d\n")
+ ACE_LIB_TEXT ("high_water_mark = %d\n")
+ ACE_LIB_TEXT ("cur_bytes = %d\n")
+ ACE_LIB_TEXT ("cur_length = %d\n")
+ ACE_LIB_TEXT ("cur_count = %d\n")
+ ACE_LIB_TEXT ("head_ = %u\n")
+ ACE_LIB_TEXT ("tail_ = %u\n"),
+ this->deactivated_,
+ this->low_water_mark_,
+ this->high_water_mark_,
+ this->cur_bytes_,
+ this->cur_length_,
+ this->cur_count_,
+ this->head_,
+ this->tail_));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("not_full_cond: \n")));
+ not_full_cond_.dump ();
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("not_empty_cond: \n")));
+ not_empty_cond_.dump ();
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+template <ACE_SYNCH_DECL> void
+ACE_Message_Queue<ACE_SYNCH_USE>::message_bytes (size_t new_value)
+{
+ ACE_TRACE ("ACE_Message_Queue<ACE_SYNCH_USE>::message_bytes");
+ ACE_GUARD (ACE_SYNCH_MUTEX_T, ace_mon, this->lock_);
+
+ this->cur_bytes_ = new_value;
+}
+
+template <ACE_SYNCH_DECL> void
+ACE_Message_Queue<ACE_SYNCH_USE>::message_length (size_t new_value)
+{
+ ACE_TRACE ("ACE_Message_Queue<ACE_SYNCH_USE>::message_length");
+ ACE_GUARD (ACE_SYNCH_MUTEX_T, ace_mon, this->lock_);
+
+ this->cur_length_ = new_value;
+}
+
+template <ACE_SYNCH_DECL>
+ACE_Message_Queue<ACE_SYNCH_USE>::ACE_Message_Queue (size_t hwm,
+ size_t lwm,
+ ACE_Notification_Strategy *ns)
+#if defined (ACE_HAS_OPTIMIZED_MESSAGE_QUEUE)
+ : not_empty_cond_ (0),
+ not_full_cond_ (0),
+ enqueue_waiters_ (0),
+ dequeue_waiters_ (0)
+#else
+ : not_empty_cond_ (this->lock_),
+ not_full_cond_ (this->lock_)
+#endif /* ACE_HAS_OPTIMIZED_MESSAGE_QUEUE */
+{
+ ACE_TRACE ("ACE_Message_Queue<ACE_SYNCH_USE>::ACE_Message_Queue");
+
+ if (this->open (hwm, lwm, ns) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("open")));
+}
+
+template <ACE_SYNCH_DECL>
+ACE_Message_Queue<ACE_SYNCH_USE>::~ACE_Message_Queue (void)
+{
+ ACE_TRACE ("ACE_Message_Queue<ACE_SYNCH_USE>::~ACE_Message_Queue");
+ if (this->head_ != 0 && this->close () == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("close")));
+}
+
+// Don't bother locking since if someone calls this function more than
+// once for the same queue, we're in bigger trouble than just
+// concurrency control!
+
+template <ACE_SYNCH_DECL> int
+ACE_Message_Queue<ACE_SYNCH_USE>::open (size_t hwm,
+ size_t lwm,
+ ACE_Notification_Strategy *ns)
+{
+ ACE_TRACE ("ACE_Message_Queue<ACE_SYNCH_USE>::open");
+ this->high_water_mark_ = hwm;
+ this->low_water_mark_ = lwm;
+ this->deactivated_ = 0;
+ this->cur_bytes_ = 0;
+ this->cur_length_ = 0;
+ this->cur_count_ = 0;
+ this->tail_ = 0;
+ this->head_ = 0;
+ this->notification_strategy_ = ns;
+ return 0;
+}
+
+// Implementation of the public deactivate() method
+// (assumes locks are held).
+
+template <ACE_SYNCH_DECL> int
+ACE_Message_Queue<ACE_SYNCH_USE>::deactivate_i (void)
+{
+ ACE_TRACE ("ACE_Message_Queue<ACE_SYNCH_USE>::deactivate_i");
+ int current_status =
+ this->deactivated_ ? WAS_INACTIVE : WAS_ACTIVE;
+
+ // Wakeup all waiters.
+#if !defined (ACE_HAS_OPTIMIZED_MESSAGE_QUEUE)
+ this->not_empty_cond_.broadcast ();
+ this->not_full_cond_.broadcast ();
+#endif /* ACE_HAS_OPTIMIZED_MESSAGE_QUEUE */
+
+ this->deactivated_ = 1;
+ return current_status;
+}
+
+template <ACE_SYNCH_DECL> int
+ACE_Message_Queue<ACE_SYNCH_USE>::activate_i (void)
+{
+ ACE_TRACE ("ACE_Message_Queue<ACE_SYNCH_USE>::activate_i");
+ int current_status =
+ this->deactivated_ ? WAS_INACTIVE : WAS_ACTIVE;
+ this->deactivated_ = 0;
+ return current_status;
+}
+
+// Clean up the queue if we have not already done so!
+
+template <ACE_SYNCH_DECL> int
+ACE_Message_Queue<ACE_SYNCH_USE>::close (void)
+{
+ ACE_TRACE ("ACE_Message_Queue<ACE_SYNCH_USE>::close");
+ ACE_GUARD_RETURN (ACE_SYNCH_MUTEX_T, ace_mon, this->lock_, -1);
+
+ int result = this->deactivate_i ();
+
+ // Free up the remaining messages on the queue.
+
+ for (this->tail_ = 0; this->head_ != 0; )
+ {
+ this->cur_count_--;
+
+ this->cur_bytes_ -= this->head_->total_size ();
+ this->cur_length_ -= this->head_->total_length ();
+
+ ACE_Message_Block *temp = this->head_;
+ this->head_ = this->head_->next ();
+
+ // Make sure to use <release> rather than <delete> since this is
+ // reference counted.
+ temp->release ();
+ }
+
+ return result;
+}
+
+template <ACE_SYNCH_DECL> int
+ACE_Message_Queue<ACE_SYNCH_USE>::signal_enqueue_waiters (void)
+{
+#if !defined (ACE_HAS_OPTIMIZED_MESSAGE_QUEUE)
+ if (this->not_full_cond_.signal () != 0)
+ return -1;
+#else
+ if (this->enqueue_waiters_ > 0)
+ {
+ --this->enqueue_waiters_;
+ return this->not_full_cond_.release ();
+ }
+#endif /* ACE_HAS_OPTIMIZED_MESSAGE_QUEUE */
+ return 0;
+}
+
+template <ACE_SYNCH_DECL> int
+ACE_Message_Queue<ACE_SYNCH_USE>::signal_dequeue_waiters (void)
+{
+#if !defined (ACE_HAS_OPTIMIZED_MESSAGE_QUEUE)
+ // Tell any blocked threads that the queue has a new item!
+ if (this->not_empty_cond_.signal () != 0)
+ return -1;
+#else
+ if (this->dequeue_waiters_ > 0)
+ {
+ --this->dequeue_waiters_;
+ return this->not_empty_cond_.release ();
+ }
+#endif /* ACE_HAS_OPTIMIZED_MESSAGE_QUEUE */
+ return 0;
+}
+
+// Actually put the node at the end (no locking so must be called with
+// locks held).
+
+template <ACE_SYNCH_DECL> int
+ACE_Message_Queue<ACE_SYNCH_USE>::enqueue_tail_i (ACE_Message_Block *new_item)
+{
+ ACE_TRACE ("ACE_Message_Queue<ACE_SYNCH_USE>::enqueue_tail_i");
+
+ if (new_item == 0)
+ return -1;
+
+ // List was empty, so build a new one.
+ if (this->tail_ == 0)
+ {
+ this->head_ = new_item;
+ this->tail_ = new_item;
+ new_item->next (0);
+ new_item->prev (0);
+ }
+ // Link at the end.
+ else
+ {
+ new_item->next (0);
+ this->tail_->next (new_item);
+ new_item->prev (this->tail_);
+ this->tail_ = new_item;
+ }
+
+ // Make sure to count all the bytes in a composite message!!!
+ this->cur_bytes_ += new_item->total_size ();
+ this->cur_length_ += new_item->total_length ();
+
+ this->cur_count_++;
+
+ if (this->signal_dequeue_waiters () == -1)
+ return -1;
+ else
+ return this->cur_count_;
+}
+
+// Actually put the node at the head (no locking)
+
+template <ACE_SYNCH_DECL> int
+ACE_Message_Queue<ACE_SYNCH_USE>::enqueue_head_i (ACE_Message_Block *new_item)
+{
+ ACE_TRACE ("ACE_Message_Queue<ACE_SYNCH_USE>::enqueue_head_i");
+
+ if (new_item == 0)
+ return -1;
+
+ new_item->prev (0);
+ new_item->next (this->head_);
+
+ if (this->head_ != 0)
+ this->head_->prev (new_item);
+ else
+ this->tail_ = new_item;
+
+ this->head_ = new_item;
+
+ // Make sure to count all the bytes in a composite message!!!
+ this->cur_bytes_ += new_item->total_size ();
+ this->cur_length_ += new_item->total_length ();
+
+ this->cur_count_++;
+
+ if (this->signal_dequeue_waiters () == -1)
+ return -1;
+ else
+ return this->cur_count_;
+}
+
+// Actually put the node at its proper position relative to its
+// priority.
+
+template <ACE_SYNCH_DECL> int
+ACE_Message_Queue<ACE_SYNCH_USE>::enqueue_i (ACE_Message_Block *new_item)
+{
+ ACE_TRACE ("ACE_Message_Queue<ACE_SYNCH_USE>::enqueue_i");
+
+ if (new_item == 0)
+ return -1;
+
+ if (this->head_ == 0)
+ // Check for simple case of an empty queue, where all we need to
+ // do is insert <new_item> into the head.
+ return this->enqueue_head_i (new_item);
+ else
+ {
+ ACE_Message_Block *temp;
+
+ // Figure out where the new item goes relative to its priority.
+ // We start looking from the highest priority to the lowest
+ // priority.
+
+ for (temp = this->tail_;
+ temp != 0;
+ temp = temp->prev ())
+ if (temp->msg_priority () >= new_item->msg_priority ())
+ // Break out when we've located an item that has
+ // greater or equal priority.
+ break;
+
+ if (temp == 0)
+ // Check for simple case of inserting at the head of the queue,
+ // where all we need to do is insert <new_item> before the
+ // current head.
+ return this->enqueue_head_i (new_item);
+ else if (temp->next () == 0)
+ // Check for simple case of inserting at the tail of the
+ // queue, where all we need to do is insert <new_item> after
+ // the current tail.
+ return this->enqueue_tail_i (new_item);
+ else
+ {
+ // Insert the new message behind the message of
+ // greater or equal priority. This ensures that FIFO order is
+ // maintained when messages of the same priority are
+ // inserted consecutively.
+ new_item->prev (temp);
+ new_item->next (temp->next ());
+ temp->next ()->prev (new_item);
+ temp->next (new_item);
+ }
+ }
+
+ // Make sure to count all the bytes in a composite message!!!
+ this->cur_bytes_ += new_item->total_size ();
+ this->cur_length_ += new_item->total_length ();
+
+ this->cur_count_++;
+
+ if (this->signal_dequeue_waiters () == -1)
+ return -1;
+ else
+ return this->cur_count_;
+}
+
+// Actually get the first ACE_Message_Block (no locking, so must be
+// called with locks held). This method assumes that the queue has at
+// least one item in it when it is called.
+
+template <ACE_SYNCH_DECL> int
+ACE_Message_Queue<ACE_SYNCH_USE>::dequeue_head_i (ACE_Message_Block *&first_item)
+{
+ if (this->head_ ==0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_LIB_TEXT ("Attempting to dequeue from empty queue")),
+ -1);
+ ACE_TRACE ("ACE_Message_Queue<ACE_SYNCH_USE>::dequeue_head_i");
+ first_item = this->head_;
+ this->head_ = this->head_->next ();
+
+ if (this->head_ == 0)
+ this->tail_ = 0;
+ else
+ // The prev pointer of the first message block has to point to
+ // NULL...
+ this->head_->prev (0);
+
+ // Subtract off all of the bytes associated with this message.
+ this->cur_bytes_ -= first_item->total_size ();
+ this->cur_length_ -= first_item->total_length ();
+
+ this->cur_count_--;
+
+ if (this->cur_count_ == 0 && this->head_ == this->tail_)
+ this->head_ = this->tail_ = 0;
+
+ // Only signal enqueueing threads if we've fallen below the low
+ // water mark.
+ if (this->cur_bytes_ <= this->low_water_mark_
+ && this->signal_enqueue_waiters () == -1)
+ return -1;
+ else
+ return this->cur_count_;
+}
+
+// Take a look at the first item without removing it.
+
+template <ACE_SYNCH_DECL> int
+ACE_Message_Queue<ACE_SYNCH_USE>::peek_dequeue_head (ACE_Message_Block *&first_item,
+ ACE_Time_Value *timeout)
+{
+ ACE_TRACE ("ACE_Message_Queue<ACE_SYNCH_USE>::peek_dequeue_head");
+ ACE_GUARD_RETURN (ACE_SYNCH_MUTEX_T, ace_mon, this->lock_, -1);
+
+ if (this->deactivated_)
+ {
+ errno = ESHUTDOWN;
+ return -1;
+ }
+
+ // Wait for at least one item to become available.
+
+ if (this->wait_not_empty_cond (ace_mon, timeout) == -1)
+ return -1;
+
+ first_item = this->head_;
+ return this->cur_count_;
+}
+
+template <ACE_SYNCH_DECL> int
+ACE_Message_Queue<ACE_SYNCH_USE>::wait_not_full_cond (ACE_Guard<ACE_SYNCH_MUTEX_T> &mon,
+ ACE_Time_Value *timeout)
+{
+ int result = 0;
+#if defined (ACE_HAS_OPTIMIZED_MESSAGE_QUEUE)
+ while (this->is_full_i () && result != -1)
+ {
+ ++this->enqueue_waiters_;
+ // @@ Need to add sanity checks for failure...
+ mon.release ();
+ result = this->not_full_cond_.acquire (timeout);
+
+ if (result == -1 && errno == ETIME)
+ {
+ --this->enqueue_waiters_;
+ errno = EWOULDBLOCK;
+ }
+
+ // Save/restore errno.
+ ACE_Errno_Guard error (errno);
+ mon.acquire ();
+ }
+#else
+ ACE_UNUSED_ARG (mon);
+
+ // Wait while the queue is full.
+
+ while (this->is_full_i ())
+ {
+ if (this->not_full_cond_.wait (timeout) == -1)
+ {
+ if (errno == ETIME)
+ errno = EWOULDBLOCK;
+ result = -1;
+ break;
+ }
+ if (this->deactivated_)
+ {
+ errno = ESHUTDOWN;
+ result = -1;
+ break;
+ }
+ }
+#endif /* ACE_HAS_OPTIMIZED_MESSAGE_QUEUE */
+ return result;
+}
+
+template <ACE_SYNCH_DECL> int
+ACE_Message_Queue<ACE_SYNCH_USE>::wait_not_empty_cond (ACE_Guard<ACE_SYNCH_MUTEX_T> &mon,
+ ACE_Time_Value *timeout)
+{
+ int result = 0;
+#if defined (ACE_HAS_OPTIMIZED_MESSAGE_QUEUE)
+ while (this->is_empty_i () && result != -1)
+ {
+ ++this->dequeue_waiters_;
+ // @@ Need to add sanity checks for failure...
+ mon.release ();
+ result = this->not_empty_cond_.acquire (timeout);
+
+ if (result == -1 && errno == ETIME)
+ {
+ --this->dequeue_waiters_;
+ errno = EWOULDBLOCK;
+ }
+
+ // Save/restore errno.
+ ACE_Errno_Guard error (errno);
+ mon.acquire ();
+ }
+#else
+ ACE_UNUSED_ARG (mon);
+
+ // Wait while the queue is empty.
+
+ while (this->is_empty_i ())
+ {
+ if (this->not_empty_cond_.wait (timeout) == -1)
+ {
+ if (errno == ETIME)
+ errno = EWOULDBLOCK;
+ result = -1;
+ break;
+ }
+ if (this->deactivated_)
+ {
+ errno = ESHUTDOWN;
+ result = -1;
+ break;
+ }
+ }
+#endif /* ACE_HAS_OPTIMIZED_MESSAGE_QUEUE */
+ return result;
+}
+
+// Block indefinitely waiting for an item to arrive, does not ignore
+// alerts (e.g., signals).
+
+template <ACE_SYNCH_DECL> int
+ACE_Message_Queue<ACE_SYNCH_USE>::enqueue_head (ACE_Message_Block *new_item,
+ ACE_Time_Value *timeout)
+{
+ ACE_TRACE ("ACE_Message_Queue<ACE_SYNCH_USE>::enqueue_head");
+ ACE_GUARD_RETURN (ACE_SYNCH_MUTEX_T, ace_mon, this->lock_, -1);
+
+ if (this->deactivated_)
+ {
+ errno = ESHUTDOWN;
+ return -1;
+ }
+
+ if (this->wait_not_full_cond (ace_mon, timeout) == -1)
+ return -1;
+
+ int queue_count = this->enqueue_head_i (new_item);
+
+ if (queue_count == -1)
+ return -1;
+
+ this->notify ();
+ return queue_count;
+}
+
+// Enqueue an <ACE_Message_Block *> into the <Message_Queue> in
+// accordance with its <msg_priority> (0 is lowest priority). Returns
+// -1 on failure, else the number of items still on the queue.
+
+template <ACE_SYNCH_DECL> int
+ACE_Message_Queue<ACE_SYNCH_USE>::enqueue_prio (ACE_Message_Block *new_item,
+ ACE_Time_Value *timeout)
+{
+ ACE_TRACE ("ACE_Message_Queue<ACE_SYNCH_USE>::enqueue_prio");
+ ACE_GUARD_RETURN (ACE_SYNCH_MUTEX_T, ace_mon, this->lock_, -1);
+
+ if (this->deactivated_)
+ {
+ errno = ESHUTDOWN;
+ return -1;
+ }
+
+ if (this->wait_not_full_cond (ace_mon, timeout) == -1)
+ return -1;
+
+ int queue_count = this->enqueue_i (new_item);
+
+ if (queue_count == -1)
+ return -1;
+
+ this->notify ();
+ return queue_count;
+}
+
+template <ACE_SYNCH_DECL> int
+ACE_Message_Queue<ACE_SYNCH_USE>::enqueue (ACE_Message_Block *new_item,
+ ACE_Time_Value *timeout)
+{
+ ACE_TRACE ("ACE_Message_Queue<ACE_SYNCH_USE>::enqueue");
+ return this->enqueue_prio (new_item, timeout);
+}
+
+// Block indefinitely waiting for an item to arrive,
+// does not ignore alerts (e.g., signals).
+
+template <ACE_SYNCH_DECL> int
+ACE_Message_Queue<ACE_SYNCH_USE>::enqueue_tail (ACE_Message_Block *new_item,
+ ACE_Time_Value *timeout)
+{
+ ACE_TRACE ("ACE_Message_Queue<ACE_SYNCH_USE>::enqueue_tail");
+ ACE_GUARD_RETURN (ACE_SYNCH_MUTEX_T, ace_mon, this->lock_, -1);
+
+ if (this->deactivated_)
+ {
+ errno = ESHUTDOWN;
+ return -1;
+ }
+
+ if (this->wait_not_full_cond (ace_mon, timeout) == -1)
+ return -1;
+
+ int queue_count = this->enqueue_tail_i (new_item);
+
+ if (queue_count == -1)
+ return -1;
+
+ this->notify ();
+ return queue_count;
+}
+
+// Remove an item from the front of the queue. If timeout == 0 block
+// indefinitely (or until an alert occurs). Otherwise, block for upto
+// the amount of time specified by timeout.
+
+template <ACE_SYNCH_DECL> int
+ACE_Message_Queue<ACE_SYNCH_USE>::dequeue_head (ACE_Message_Block *&first_item,
+ ACE_Time_Value *timeout)
+{
+ ACE_TRACE ("ACE_Message_Queue<ACE_SYNCH_USE>::dequeue_head");
+ ACE_GUARD_RETURN (ACE_SYNCH_MUTEX_T, ace_mon, this->lock_, -1);
+
+ if (this->deactivated_)
+ {
+ errno = ESHUTDOWN;
+ return -1;
+ }
+
+ if (this->wait_not_empty_cond (ace_mon, timeout) == -1)
+ return -1;
+
+ return this->dequeue_head_i (first_item);
+}
+
+template <ACE_SYNCH_DECL> int
+ACE_Message_Queue<ACE_SYNCH_USE>::notify (void)
+{
+ ACE_TRACE ("ACE_Message_Queue<ACE_SYNCH_USE>::notify");
+
+ // By default, don't do anything.
+ if (this->notification_strategy_ == 0)
+ return 0;
+ else
+ return this->notification_strategy_->notify ();
+}
+
+
+// = Initialization and termination methods.
+template <ACE_SYNCH_DECL>
+ACE_Dynamic_Message_Queue<ACE_SYNCH_USE>::ACE_Dynamic_Message_Queue (ACE_Dynamic_Message_Strategy & message_strategy,
+ size_t hwm,
+ size_t lwm,
+ ACE_Notification_Strategy *ns)
+ : ACE_Message_Queue<ACE_SYNCH_USE> (hwm, lwm, ns),
+ pending_head_ (0),
+ pending_tail_ (0),
+ late_head_ (0),
+ late_tail_ (0),
+ beyond_late_head_ (0),
+ beyond_late_tail_ (0),
+ message_strategy_ (message_strategy)
+{
+ // Note, the ACE_Dynamic_Message_Queue assumes full responsibility
+ // for the passed ACE_Dynamic_Message_Strategy object, and deletes
+ // it in its own dtor
+}
+
+// dtor: free message strategy and let base class dtor do the rest.
+
+template <ACE_SYNCH_DECL>
+ACE_Dynamic_Message_Queue<ACE_SYNCH_USE>::~ACE_Dynamic_Message_Queue (void)
+{
+ delete &this->message_strategy_;
+}
+
+template <ACE_SYNCH_DECL> int
+ACE_Dynamic_Message_Queue<ACE_SYNCH_USE>::remove_messages (ACE_Message_Block *&list_head,
+ ACE_Message_Block *&list_tail,
+ u_int status_flags)
+{
+ // start with an empty list
+ list_head = 0;
+ list_tail = 0;
+
+ // Get the current time
+ ACE_Time_Value current_time = ACE_OS::gettimeofday ();
+
+ // Refresh priority status boundaries in the queue.
+ int result = this->refresh_queue (current_time);
+ if (result < 0)
+ return result;
+
+ if (ACE_BIT_ENABLED (status_flags,
+ (u_int) ACE_Dynamic_Message_Strategy::PENDING)
+ && this->pending_head_
+ && this->pending_tail_)
+ {
+ // patch up pointers for the new tail of the queue
+ if (this->pending_head_->prev ())
+ {
+ this->tail_ = this->pending_head_->prev ();
+ this->pending_head_->prev ()->next (0);
+ }
+ else
+ {
+ // the list has become empty
+ this->head_ = 0;
+ this->tail_ = 0;
+ }
+
+ // point to the head and tail of the list
+ list_head = this->pending_head_;
+ list_tail = this->pending_tail_;
+
+ // cut the pending messages out of the queue entirely
+ this->pending_head_->prev (0);
+ this->pending_head_ = 0;
+ this->pending_tail_ = 0;
+ }
+
+ if (ACE_BIT_ENABLED (status_flags,
+ (u_int) ACE_Dynamic_Message_Strategy::LATE)
+ && this->late_head_
+ && this->late_tail_)
+ {
+ // Patch up pointers for the (possibly) new head and tail of the
+ // queue.
+ if (this->late_tail_->next ())
+ this->late_tail_->next ()->prev (this->late_head_->prev ());
+ else
+ this->tail_ = this->late_head_->prev ();
+
+ if (this->late_head_->prev ())
+ this->late_head_->prev ()->next (this->late_tail_->next ());
+ else
+ this->head_ = this->late_tail_->next ();
+
+ // put late messages behind pending messages (if any) being returned
+ this->late_head_->prev (list_tail);
+ if (list_tail)
+ list_tail->next (this->late_head_);
+ else
+ list_head = this->late_head_;
+
+ list_tail = this->late_tail_;
+
+ this->late_tail_->next (0);
+ this->late_head_ = 0;
+ this->late_tail_ = 0;
+ }
+
+ if (ACE_BIT_ENABLED (status_flags,
+ (u_int) ACE_Dynamic_Message_Strategy::BEYOND_LATE)
+ && this->beyond_late_head_
+ && this->beyond_late_tail_)
+ {
+ // Patch up pointers for the new tail of the queue
+ if (this->beyond_late_tail_->next ())
+ {
+ this->head_ = this->beyond_late_tail_->next ();
+ this->beyond_late_tail_->next ()->prev (0);
+ }
+ else
+ {
+ // the list has become empty
+ this->head_ = 0;
+ this->tail_ = 0;
+ }
+
+ // Put beyond late messages at the end of the list being
+ // returned.
+ if (list_tail)
+ {
+ this->beyond_late_head_->prev (list_tail);
+ list_tail->next (this->beyond_late_head_);
+ }
+ else
+ list_head = this->beyond_late_head_;
+
+ list_tail = this->beyond_late_tail_;
+
+ this->beyond_late_tail_->next (0);
+ this->beyond_late_head_ = 0;
+ this->beyond_late_tail_ = 0;
+ }
+
+ // Decrement message and size counts for removed messages.
+ ACE_Message_Block *temp1;
+
+ for (temp1 = list_head;
+ temp1 != 0;
+ temp1 = temp1->next ())
+ {
+ this->cur_count_--;
+
+ this->cur_bytes_ -= temp1->total_size ();
+ this->cur_length_ -= temp1->total_length ();
+ }
+
+ return result;
+}
+
+// Detach all messages with status given in the passed flags from the
+// queue and return them by setting passed head and tail pointers to
+// the linked list they comprise. This method is intended primarily
+// as a means of periodically harvesting messages that have missed
+// their deadlines, but is available in its most general form. All
+// messages are returned in priority order, from head to tail, as of
+// the time this method was called.
+
+template <ACE_SYNCH_DECL> int
+ACE_Dynamic_Message_Queue<ACE_SYNCH_USE>::dequeue_head (ACE_Message_Block *&first_item,
+ ACE_Time_Value *timeout)
+{
+ ACE_TRACE ("ACE_Dynamic_Message_Queue<ACE_SYNCH_USE>::dequeue_head");
+
+ ACE_GUARD_RETURN (ACE_SYNCH_MUTEX_T, ace_mon, this->lock_, -1);
+
+ if (this->deactivated_)
+ {
+ errno = ESHUTDOWN;
+ return -1;
+ }
+
+ int result;
+
+ // get the current time
+ ACE_Time_Value current_time = ACE_OS::gettimeofday ();
+
+ // refresh priority status boundaries in the queue
+ result = this->refresh_queue (current_time);
+ if (result < 0)
+ return result;
+
+ // *now* it's appropriate to wait for an enqueued item
+ result = this->wait_not_empty_cond (ace_mon, timeout);
+ if (result == -1)
+ return result;
+
+ // call the internal dequeue method, which selects an item from the
+ // highest priority status portion of the queue that has messages
+ // enqueued.
+ result = this->dequeue_head_i (first_item);
+
+ return result;
+}
+
+// Dequeue and return the <ACE_Message_Block *> at the (logical) head
+// of the queue.
+
+template <ACE_SYNCH_DECL> void
+ACE_Dynamic_Message_Queue<ACE_SYNCH_USE>::dump (void) const
+{
+ ACE_TRACE ("ACE_Dynamic_Message_Queue<ACE_SYNCH_USE>::dump");
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("ACE_Message_Queue<ACE_SYNCH_USE> (base class): \n")));
+ this->ACE_Message_Queue<ACE_SYNCH_USE>::dump ();
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_LIB_TEXT ("pending_head_ = %u\n")
+ ACE_LIB_TEXT ("pending_tail_ = %u\n")
+ ACE_LIB_TEXT ("late_head_ = %u\n")
+ ACE_LIB_TEXT ("late_tail_ = %u\n")
+ ACE_LIB_TEXT ("beyond_late_head_ = %u\n")
+ ACE_LIB_TEXT ("beyond_late_tail_ = %u\n"),
+ this->pending_head_,
+ this->pending_tail_,
+ this->late_head_,
+ this->late_tail_,
+ this->beyond_late_head_,
+ this->beyond_late_tail_));
+
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("message_strategy_ : \n")));
+ message_strategy_.dump ();
+
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+ // dump the state of the queue
+
+template <ACE_SYNCH_DECL> int
+ACE_Dynamic_Message_Queue<ACE_SYNCH_USE>::enqueue_i (ACE_Message_Block *new_item)
+{
+ ACE_TRACE ("ACE_Dynamic_Message_Queue<ACE_SYNCH_USE>::enqueue_i");
+
+ if (new_item == 0)
+ return -1;
+
+ int result = 0;
+
+ // Get the current time.
+ ACE_Time_Value current_time = ACE_OS::gettimeofday ();
+
+ // Refresh priority status boundaries in the queue.
+
+ result = this->refresh_queue (current_time);
+ if (result < 0)
+ return result;
+
+ // Where we enqueue depends on the message's priority status.
+ switch (message_strategy_.priority_status (*new_item,
+ current_time))
+ {
+ case ACE_Dynamic_Message_Strategy::PENDING:
+ if (this->pending_tail_ == 0)
+ {
+ // Check for simple case of an empty pending queue, where
+ // all we need to do is insert <new_item> into the tail of
+ // the queue.
+ pending_head_ = new_item;
+ pending_tail_ = pending_head_;
+ return this->enqueue_tail_i (new_item);
+ }
+ else
+ {
+ // Enqueue the new message in priority order in the pending
+ // sublist
+ result = sublist_enqueue_i (new_item,
+ current_time,
+ this->pending_head_,
+ this->pending_tail_,
+ ACE_Dynamic_Message_Strategy::PENDING);
+ }
+ break;
+
+ case ACE_Dynamic_Message_Strategy::LATE:
+ if (this->late_tail_ == 0)
+ {
+ late_head_ = new_item;
+ late_tail_ = late_head_;
+
+ if (this->pending_head_ == 0)
+ // Check for simple case of an empty pending queue,
+ // where all we need to do is insert <new_item> into the
+ // tail of the queue.
+ return this->enqueue_tail_i (new_item);
+ else if (this->beyond_late_tail_ == 0)
+ // Check for simple case of an empty beyond late queue, where all
+ // we need to do is insert <new_item> into the head of the queue.
+ return this->enqueue_head_i (new_item);
+ else
+ {
+ // Otherwise, we can just splice the new message in
+ // between the pending and beyond late portions of the
+ // queue.
+ this->beyond_late_tail_->next (new_item);
+ new_item->prev (this->beyond_late_tail_);
+ this->pending_head_->prev (new_item);
+ new_item->next (this->pending_head_);
+ }
+ }
+ else
+ {
+ // Enqueue the new message in priority order in the late
+ // sublist
+ result = sublist_enqueue_i (new_item,
+ current_time,
+ this->late_head_,
+ this->late_tail_,
+ ACE_Dynamic_Message_Strategy::LATE);
+ }
+ break;
+
+ case ACE_Dynamic_Message_Strategy::BEYOND_LATE:
+ if (this->beyond_late_tail_ == 0)
+ {
+ // Check for simple case of an empty beyond late queue,
+ // where all we need to do is insert <new_item> into the
+ // head of the queue.
+ beyond_late_head_ = new_item;
+ beyond_late_tail_ = beyond_late_head_;
+ return this->enqueue_head_i (new_item);
+ }
+ else
+ {
+ // all beyond late messages have the same (zero) priority,
+ // so just put the new one at the end of the beyond late
+ // messages
+ if (this->beyond_late_tail_->next ())
+ this->beyond_late_tail_->next ()->prev (new_item);
+ else
+ this->tail_ = new_item;
+
+ new_item->next (this->beyond_late_tail_->next ());
+ this->beyond_late_tail_->next (new_item);
+ new_item->prev (this->beyond_late_tail_);
+ this->beyond_late_tail_ = new_item;
+ }
+
+ break;
+
+ // should never get here, but just in case...
+ default:
+ result = -1;
+ break;
+ }
+
+ if (result < 0)
+ return result;
+
+ this->cur_bytes_ += new_item->total_size ();
+ this->cur_length_ += new_item->total_length ();
+
+ this->cur_count_++;
+
+ if (this->signal_dequeue_waiters () == -1)
+ return -1;
+ else
+ return this->cur_count_;
+}
+
+// Enqueue an <ACE_Message_Block *> in accordance with its priority.
+// priority may be *dynamic* or *static* or a combination or *both* It
+// calls the priority evaluation function passed into the Dynamic
+// Message Queue constructor to update the priorities of all enqueued
+// messages.
+
+template <ACE_SYNCH_DECL> int
+ACE_Dynamic_Message_Queue<ACE_SYNCH_USE>::sublist_enqueue_i (ACE_Message_Block *new_item,
+ const ACE_Time_Value &current_time,
+ ACE_Message_Block *&sublist_head,
+ ACE_Message_Block *&sublist_tail,
+ ACE_Dynamic_Message_Strategy::Priority_Status status)
+{
+ int result = 0;
+ ACE_Message_Block *current_item = 0;
+
+ // Find message after which to enqueue new item, based on message
+ // priority and priority status.
+ for (current_item = sublist_tail;
+ current_item;
+ current_item = current_item->prev ())
+ {
+ if (message_strategy_.priority_status (*current_item, current_time) == status)
+ {
+ if (current_item->msg_priority () >= new_item->msg_priority ())
+ break;
+ }
+ else
+ {
+ sublist_head = new_item;
+ break;
+ }
+ }
+
+ if (current_item == 0)
+ {
+ // If the new message has highest priority of any, put it at the
+ // head of the list (and sublist).
+ new_item->prev (0);
+ new_item->next (this->head_);
+ if (this->head_ != 0)
+ this->head_->prev (new_item);
+ else
+ {
+ this->tail_ = new_item;
+ sublist_tail = new_item;
+ }
+ this->head_ = new_item;
+ sublist_head = new_item;
+ }
+ else
+ {
+ // insert the new item into the list
+ new_item->next (current_item->next ());
+ new_item->prev (current_item);
+
+ if (current_item->next ())
+ current_item->next ()->prev (new_item);
+ else
+ this->tail_ = new_item;
+
+ current_item->next (new_item);
+
+ // If the new item has lowest priority of any in the sublist,
+ // move the tail pointer of the sublist back to the new item
+ if (current_item == sublist_tail)
+ sublist_tail = new_item;
+ }
+
+ return result;
+}
+
+// Enqueue a message in priority order within a given priority status
+// sublist.
+
+template <ACE_SYNCH_DECL> int
+ACE_Dynamic_Message_Queue<ACE_SYNCH_USE>::dequeue_head_i (ACE_Message_Block *&first_item)
+{
+ ACE_TRACE ("ACE_Dynamic_Message_Queue<ACE_SYNCH_USE>::dequeue_head_i");
+
+ int result = 0;
+ int last_in_subqueue = 0;
+
+ // first, try to dequeue from the head of the pending list
+ if (this->pending_head_)
+ {
+ first_item = this->pending_head_;
+
+ if (0 == this->pending_head_->prev ())
+ this->head_ = this->pending_head_->next ();
+ else
+ this->pending_head_->prev ()->next (this->pending_head_->next ());
+
+ if (0 == this->pending_head_->next ())
+ {
+ this->tail_ = this->pending_head_->prev ();
+ this->pending_head_ = 0;
+ this->pending_tail_ = 0;
+ }
+ else
+ {
+ this->pending_head_->next ()->prev (this->pending_head_->prev ());
+ this->pending_head_ = this->pending_head_->next ();
+ }
+
+ first_item->prev (0);
+ first_item->next (0);
+ }
+
+ // Second, try to dequeue from the head of the late list
+ else if (this->late_head_)
+ {
+ last_in_subqueue = this->late_head_ == this->late_tail_ ? 1 : 0;
+
+ first_item = this->late_head_;
+
+ if (0 == this->late_head_->prev ())
+ this->head_ = this->late_head_->next ();
+ else
+ this->late_head_->prev ()->next (this->late_head_->next ());
+
+ if (0 == this->late_head_->next ())
+ this->tail_ = this->late_head_->prev ();
+ else
+ {
+ this->late_head_->next ()->prev (this->late_head_->prev ());
+ this->late_head_ = this->late_head_->next ();
+ }
+
+ if (last_in_subqueue)
+ {
+ this->late_head_ = 0;
+ this->late_tail_ = 0;
+ }
+
+ first_item->prev (0);
+ first_item->next (0);
+ }
+ // finally, try to dequeue from the head of the beyond late list
+ else if (this->beyond_late_head_)
+ {
+ last_in_subqueue =
+ (this->beyond_late_head_ == this->beyond_late_tail_) ? 1 : 0;
+
+ first_item = this->beyond_late_head_;
+ this->head_ = this->beyond_late_head_->next ();
+
+ if (0 == this->beyond_late_head_->next ())
+ this->tail_ = this->beyond_late_head_->prev ();
+ else
+ {
+ this->beyond_late_head_->next ()->prev (this->beyond_late_head_->prev ());
+ this->beyond_late_head_ = this->beyond_late_head_->next ();
+ }
+
+ if (last_in_subqueue)
+ {
+ this->beyond_late_head_ = 0;
+ this->beyond_late_tail_ = 0;
+ }
+
+ first_item->prev (0);
+ first_item->next (0);
+ }
+ else
+ {
+ // nothing to dequeue: set the pointer to zero and return an error code
+ first_item = 0;
+ result = -1;
+ }
+
+ if (result < 0)
+ return result;
+
+ // Make sure to subtract off all of the bytes associated with this
+ // message.
+ this->cur_bytes_ -= first_item->total_size ();
+ this->cur_length_ -= first_item->total_length ();
+
+ this->cur_count_--;
+
+ // Only signal enqueueing threads if we've fallen below the low
+ // water mark.
+ if (this->cur_bytes_ <= this->low_water_mark_
+ && this->signal_enqueue_waiters () == -1)
+ return -1;
+ else
+ return this->cur_count_;
+}
+
+// Dequeue and return the <ACE_Message_Block *> at the head of the
+// logical queue. Attempts first to dequeue from the pending portion
+// of the queue, or if that is empty from the late portion, or if that
+// is empty from the beyond late portion, or if that is empty just
+// sets the passed pointer to zero and returns -1.
+
+template <ACE_SYNCH_DECL> int
+ACE_Dynamic_Message_Queue<ACE_SYNCH_USE>::refresh_queue (const ACE_Time_Value &current_time)
+{
+ int result;
+
+ result = refresh_pending_queue (current_time);
+
+ if (result != -1)
+ result = refresh_late_queue (current_time);
+
+ return result;
+}
+
+// Refresh the queue using the strategy specific priority status
+// function.
+
+template <ACE_SYNCH_DECL> int
+ACE_Dynamic_Message_Queue<ACE_SYNCH_USE>::refresh_pending_queue (const ACE_Time_Value &current_time)
+{
+ ACE_Dynamic_Message_Strategy::Priority_Status current_status;
+
+ // refresh priority status boundaries in the queue
+ if (this->pending_head_)
+ {
+ current_status = message_strategy_.priority_status (*this->pending_head_,
+ current_time);
+ switch (current_status)
+ {
+ case ACE_Dynamic_Message_Strategy::BEYOND_LATE:
+ // Make sure the head of the beyond late queue is set (there
+ // may not have been any beyond late messages previously)
+ this->beyond_late_head_ = this->head_;
+
+ // Zero out the late queue pointers, and set them only if
+ // there turn out to be late messages in the pending sublist
+ this->late_head_ = 0;
+ this->late_tail_ = 0;
+
+ // Advance through the beyond late messages in the pending queue
+ do
+ {
+ this->pending_head_ = this->pending_head_->next ();
+
+ if (this->pending_head_)
+ current_status = message_strategy_.priority_status (*this->pending_head_,
+ current_time);
+ else
+ break; // do while
+
+ }
+ while (current_status == ACE_Dynamic_Message_Strategy::BEYOND_LATE);
+
+ if (this->pending_head_)
+ {
+ // point tail of beyond late sublist to previous item
+ this->beyond_late_tail_ = this->pending_head_->prev ();
+
+ if (current_status == ACE_Dynamic_Message_Strategy::PENDING)
+ // there are no late messages left in the queue
+ break; // switch
+ else if (current_status != ACE_Dynamic_Message_Strategy::LATE)
+ {
+ // if we got here, something is *seriously* wrong with the queue
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_LIB_TEXT ("Unexpected message priority status [%d] (expected LATE)"),
+ (int) current_status),
+ -1);
+ }
+ /* FALLTHRU */
+ }
+ else
+ {
+ // There are no pending or late messages left in the
+ // queue.
+ this->beyond_late_tail_ = this->tail_;
+ this->pending_head_ = 0;
+ this->pending_tail_ = 0;
+ break; // switch
+ }
+
+ case ACE_Dynamic_Message_Strategy::LATE:
+ // Make sure the head of the late queue is set (there may
+ // not have been any late messages previously, or they may
+ // have all become beyond late).
+ if (this->late_head_ == 0)
+ this->late_head_ = this->pending_head_;
+
+ // advance through the beyond late messages in the pending queue
+ do
+ {
+ this->pending_head_ = this->pending_head_->next ();
+
+ if (this->pending_head_)
+ current_status = message_strategy_.priority_status (*this->pending_head_,
+ current_time);
+ else
+ break; // do while
+
+ }
+ while (current_status == ACE_Dynamic_Message_Strategy::LATE);
+
+ if (this->pending_head_)
+ {
+ if (current_status != ACE_Dynamic_Message_Strategy::PENDING)
+ // if we got here, something is *seriously* wrong with the queue
+ ACE_ERROR_RETURN((LM_ERROR,
+ ACE_LIB_TEXT ("Unexpected message priority status [%d] (expected PENDING)"),
+ (int) current_status),
+ -1);
+
+ // Point tail of late sublist to previous item
+ this->late_tail_ = this->pending_head_->prev ();
+ }
+ else
+ {
+ // there are no pending messages left in the queue
+ this->late_tail_ = this->tail_;
+ this->pending_head_ = 0;
+ this->pending_tail_ = 0;
+ }
+
+ break; // switch
+ case ACE_Dynamic_Message_Strategy::PENDING:
+ // do nothing - the pending queue is unchanged
+ break; // switch
+ default:
+ // if we got here, something is *seriously* wrong with the queue
+ ACE_ERROR_RETURN((LM_ERROR,
+ ACE_LIB_TEXT ("Unknown message priority status [%d]"),
+ (int) current_status),
+ -1);
+ }
+ }
+ return 0;
+}
+
+// Refresh the pending queue using the strategy specific priority
+// status function.
+
+template <ACE_SYNCH_DECL> int
+ACE_Dynamic_Message_Queue<ACE_SYNCH_USE>::refresh_late_queue (const ACE_Time_Value &current_time)
+{
+ ACE_Dynamic_Message_Strategy::Priority_Status current_status;
+
+ if (this->late_head_)
+ {
+ current_status = message_strategy_.priority_status (*this->late_head_,
+ current_time);
+ switch (current_status)
+ {
+ case ACE_Dynamic_Message_Strategy::BEYOND_LATE:
+
+ // make sure the head of the beyond late queue is set
+ // (there may not have been any beyond late messages previously)
+ this->beyond_late_head_ = this->head_;
+
+ // advance through the beyond late messages in the late queue
+ do
+ {
+ this->late_head_ = this->late_head_->next ();
+
+ if (this->late_head_)
+ current_status = message_strategy_.priority_status (*this->late_head_,
+ current_time);
+ else
+ break; // do while
+
+ }
+ while (current_status == ACE_Dynamic_Message_Strategy::BEYOND_LATE);
+
+ if (this->late_head_)
+ {
+ // point tail of beyond late sublist to previous item
+ this->beyond_late_tail_ = this->late_head_->prev ();
+
+ if (current_status == ACE_Dynamic_Message_Strategy::PENDING)
+ {
+ // there are no late messages left in the queue
+ this->late_head_ = 0;
+ this->late_tail_ = 0;
+ }
+ else if (current_status != ACE_Dynamic_Message_Strategy::LATE)
+ // if we got here, something is *seriously* wrong with the queue
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_LIB_TEXT ("Unexpected message priority status [%d] (expected LATE)"),
+ (int) current_status),
+ -1);
+ }
+ else
+ {
+ // there are no late messages left in the queue
+ this->beyond_late_tail_ = this->tail_;
+ this->late_head_ = 0;
+ this->late_tail_ = 0;
+ }
+
+ break; // switch
+
+ case ACE_Dynamic_Message_Strategy::LATE:
+ // do nothing - the late queue is unchanged
+ break; // switch
+
+ case ACE_Dynamic_Message_Strategy::PENDING:
+ // if we got here, something is *seriously* wrong with the queue
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_LIB_TEXT ("Unexpected message priority status ")
+ ACE_LIB_TEXT ("[%d] (expected LATE or BEYOND_LATE)"),
+ (int) current_status),
+ -1);
+ default:
+ // if we got here, something is *seriously* wrong with the queue
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_LIB_TEXT ("Unknown message priority status [%d]"),
+ (int) current_status),
+ -1);
+ }
+ }
+
+ return 0;
+}
+
+// Refresh the late queue using the strategy specific priority status
+// function.
+
+template <ACE_SYNCH_DECL> int
+ACE_Dynamic_Message_Queue<ACE_SYNCH_USE>::peek_dequeue_head (ACE_Message_Block *&first_item,
+ ACE_Time_Value *timeout)
+{
+ return ACE_Message_Queue<ACE_SYNCH_USE>::peek_dequeue_head (first_item,
+ timeout);
+}
+
+// Private method to hide public base class method: just calls base
+// class method.
+
+template <ACE_SYNCH_DECL> int
+ACE_Dynamic_Message_Queue<ACE_SYNCH_USE>::enqueue_tail (ACE_Message_Block *new_item,
+ ACE_Time_Value *timeout)
+{
+ ACE_TRACE ("ACE_Dynamic_Message_Queue<ACE_SYNCH_USE>::enqueue_tail");
+ return this->enqueue_prio (new_item, timeout);
+}
+
+// Just call priority enqueue method: tail enqueue semantics for
+// dynamic message queues are unstable: the message may or may not be
+// where it was placed after the queue is refreshed prior to the next
+// enqueue or dequeue operation.
+
+template <ACE_SYNCH_DECL> int
+ACE_Dynamic_Message_Queue<ACE_SYNCH_USE>::enqueue_head (ACE_Message_Block *new_item,
+ ACE_Time_Value *timeout)
+{
+ ACE_TRACE ("ACE_Dynamic_Message_Queue<ACE_SYNCH_USE>::enqueue_head");
+ return this->enqueue_prio (new_item, timeout);
+}
+
+// Just call priority enqueue method: head enqueue semantics for
+// dynamic message queues are unstable: the message may or may not be
+// where it was placed after the queue is refreshed prior to the next
+// enqueue or dequeue operation.
+
+template <ACE_SYNCH_DECL>
+ACE_Message_Queue<ACE_SYNCH_USE> *
+ACE_Message_Queue_Factory<ACE_SYNCH_USE>::create_static_message_queue (size_t hwm,
+ size_t lwm,
+ ACE_Notification_Strategy *ns)
+{
+ ACE_Message_Queue<ACE_SYNCH_USE> *tmp;
+
+ ACE_NEW_RETURN (tmp,
+ ACE_Message_Queue<ACE_SYNCH_USE> (hwm, lwm, ns),
+ 0);
+ return tmp;
+}
+
+// Factory method for a statically prioritized ACE_Message_Queue.
+
+template <ACE_SYNCH_DECL>
+ACE_Dynamic_Message_Queue<ACE_SYNCH_USE> *
+ACE_Message_Queue_Factory<ACE_SYNCH_USE>::create_deadline_message_queue (size_t hwm,
+ size_t lwm,
+ ACE_Notification_Strategy *ns,
+ u_long static_bit_field_mask,
+ u_long static_bit_field_shift,
+ u_long dynamic_priority_max,
+ u_long dynamic_priority_offset)
+{
+ ACE_Deadline_Message_Strategy *adms;
+
+ ACE_NEW_RETURN (adms,
+ ACE_Deadline_Message_Strategy (static_bit_field_mask,
+ static_bit_field_shift,
+ dynamic_priority_max,
+ dynamic_priority_offset),
+ 0);
+
+ ACE_Dynamic_Message_Queue<ACE_SYNCH_USE> *tmp;
+ ACE_NEW_RETURN (tmp,
+ ACE_Dynamic_Message_Queue<ACE_SYNCH_USE> (*adms, hwm, lwm, ns),
+ 0);
+ return tmp;
+}
+
+// Factory method for a dynamically prioritized (by time to deadline)
+// ACE_Dynamic_Message_Queue.
+
+template <ACE_SYNCH_DECL>
+ACE_Dynamic_Message_Queue<ACE_SYNCH_USE> *
+ACE_Message_Queue_Factory<ACE_SYNCH_USE>::create_laxity_message_queue (size_t hwm,
+ size_t lwm,
+ ACE_Notification_Strategy *ns,
+ u_long static_bit_field_mask,
+ u_long static_bit_field_shift,
+ u_long dynamic_priority_max,
+ u_long dynamic_priority_offset)
+{
+ ACE_Laxity_Message_Strategy *alms;
+
+ ACE_NEW_RETURN (alms,
+ ACE_Laxity_Message_Strategy (static_bit_field_mask,
+ static_bit_field_shift,
+ dynamic_priority_max,
+ dynamic_priority_offset),
+ 0);
+
+ ACE_Dynamic_Message_Queue<ACE_SYNCH_USE> *tmp;
+ ACE_NEW_RETURN (tmp,
+ ACE_Dynamic_Message_Queue<ACE_SYNCH_USE> (*alms, hwm, lwm, ns),
+ 0);
+ return tmp;
+}
+
+// Factory method for a dynamically prioritized (by laxity)
+// <ACE_Dynamic_Message_Queue>.
+
+#if defined (VXWORKS)
+
+template <ACE_SYNCH_DECL>
+ACE_Message_Queue_Vx *
+ACE_Message_Queue_Factory<ACE_SYNCH_USE>::create_Vx_message_queue (size_t max_messages,
+ size_t max_message_length,
+ ACE_Notification_Strategy *ns)
+{
+ ACE_Message_Queue_Vx *tmp;
+
+ ACE_NEW_RETURN (tmp,
+ ACE_Message_Queue_Vx (max_messages, max_message_length, ns),
+ 0);
+ return tmp;
+}
+ // factory method for a wrapped VxWorks message queue
+
+#if defined (ACE_WIN32) && (ACE_HAS_WINNT4 != 0)
+
+template <ACE_SYNCH_DECL>
+ACE_Message_Queue_NT *
+ACE_Message_Queue_Factory<ACE_SYNCH_USE>::create_NT_message_queue (size_t max_threads)
+{
+ ACE_Message_Queue_NT *tmp;
+
+ ACE_NEW_RETURN (tmp,
+ ACE_Message_Queue_NT (max_threads);
+ 0);
+ return tmp;
+}
+
+#endif /* ACE_WIN32 && ACE_HAS_WINNT4 != 0 */
+#endif /* defined (VXWORKS) */
+#endif /* ACE_MESSAGE_QUEUE_T_C */
diff --git a/ace/Streams/Message_Queue_T.h b/ace/Streams/Message_Queue_T.h
new file mode 100644
index 00000000000..f8155eeed2c
--- /dev/null
+++ b/ace/Streams/Message_Queue_T.h
@@ -0,0 +1,1053 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Message_Queue_T.h
+ *
+ * $Id$
+ *
+ * @author Douglas C. Schmidt <schmidt@cs.wustl.edu>
+ */
+//=============================================================================
+
+#ifndef ACE_MESSAGE_QUEUE_T_H
+#define ACE_MESSAGE_QUEUE_T_H
+#include "ace/pre.h"
+
+#include "ace/Message_Queue.h"
+#include "ace/Synch.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#if defined (VXWORKS)
+class ACE_Message_Queue_Vx;
+#endif /* defined (VXWORKS) */
+
+#if defined (ACE_WIN32) && (ACE_HAS_WINNT4 != 0)
+class ACE_Message_Queue_NT;
+#endif /* ACE_WIN32 && ACE_HAS_WINNT4 != 0 */
+
+/**
+ * @class ACE_Message_Queue
+ *
+ * @brief A threaded message queueing facility, modeled after the
+ * queueing facilities in System V STREAMs.
+ *
+ * An <ACE_Message_Queue> is the central queueing facility for
+ * messages in the ACE framework. If <ACE_SYNCH_DECL> is
+ * <ACE_MT_SYNCH> then all operations are thread-safe.
+ * Otherwise, if it's <ACE_NULL_SYNCH> then there's no locking
+ * overhead.
+ */
+template <ACE_SYNCH_DECL>
+class ACE_Message_Queue : public ACE_Message_Queue_Base
+{
+public:
+ friend class ACE_Message_Queue_Iterator<ACE_SYNCH_USE>;
+ friend class ACE_Message_Queue_Reverse_Iterator<ACE_SYNCH_USE>;
+
+ // = Traits
+ typedef ACE_Message_Queue_Iterator<ACE_SYNCH_USE>
+ ITERATOR;
+ typedef ACE_Message_Queue_Reverse_Iterator<ACE_SYNCH_USE>
+ REVERSE_ITERATOR;
+
+ // = Initialization and termination methods.
+ /**
+ * Initialize an <ACE_Message_Queue>. The <high_water_mark>
+ * determines how many bytes can be stored in a queue before it's
+ * considered "full." Supplier threads must block until the queue
+ * is no longer full. The <low_water_mark> determines how many
+ * bytes must be in the queue before supplier threads are allowed to
+ * enqueue additional <ACE_Message_Block>s. By default, the
+ * <high_water_mark> equals the <low_water_mark>, which means that
+ * suppliers will be able to enqueue new messages as soon as a
+ * consumer removes any message from the queue. Making the
+ * <low_water_mark> smaller than the <high_water_mark> forces
+ * consumers to drain more messages from the queue before suppliers
+ * can enqueue new messages, which can minimize the "silly window
+ * syndrome."
+ */
+ ACE_Message_Queue (size_t high_water_mark = ACE_Message_Queue_Base::DEFAULT_HWM,
+ size_t low_water_mark = ACE_Message_Queue_Base::DEFAULT_LWM,
+ ACE_Notification_Strategy * = 0);
+
+ /**
+ * Initialize an <ACE_Message_Queue>. The <high_water_mark>
+ * determines how many bytes can be stored in a queue before it's
+ * considered "full." Supplier threads must block until the queue
+ * is no longer full. The <low_water_mark> determines how many
+ * bytes must be in the queue before supplier threads are allowed to
+ * enqueue additional <ACE_Message_Block>s. By default, the
+ * <high_water_mark> equals the <low_water_mark>, which means that
+ * suppliers will be able to enqueue new messages as soon as a
+ * consumer removes any message from the queue. Making the
+ * <low_water_mark> smaller than the <high_water_mark> forces
+ * consumers to drain more messages from the queue before suppliers
+ * can enqueue new messages, which can minimize the "silly window
+ * syndrome."
+ */
+ virtual int open (size_t hwm = ACE_Message_Queue_Base::DEFAULT_HWM,
+ size_t lwm = ACE_Message_Queue_Base::DEFAULT_LWM,
+ ACE_Notification_Strategy * = 0);
+
+ /// Close down the message queue and release all resources.
+ virtual int close (void);
+
+ /// Close down the message queue and release all resources.
+ virtual ~ACE_Message_Queue (void);
+
+ // = Enqueue and dequeue methods.
+
+ // For the following enqueue and dequeue methods if <timeout> == 0,
+ // the caller will block until action is possible, else will wait
+ // until the absolute time specified in *<timeout> elapses). These
+ // calls will return, however, when queue is closed, deactivated,
+ // when a signal occurs, or if the time specified in timeout
+ // elapses, (in which case errno = EWOULDBLOCK).
+
+ /**
+ * Retrieve the first <ACE_Message_Block> without removing it. Note
+ * that <timeout> uses <{absolute}> time rather than <{relative}>
+ * time. If the <timeout> elapses without receiving a message -1 is
+ * returned and <errno> is set to <EWOULDBLOCK>. If the queue is
+ * deactivated -1 is returned and <errno> is set to <ESHUTDOWN>.
+ * Otherwise, returns -1 on failure, else the number of items still
+ * on the queue.
+ */
+ virtual int peek_dequeue_head (ACE_Message_Block *&first_item,
+ ACE_Time_Value *timeout = 0);
+
+ /**
+ * Enqueue an <ACE_Message_Block *> into the <Message_Queue> in
+ * accordance with its <msg_priority> (0 is lowest priority). FIFO
+ * order is maintained when messages of the same priority are
+ * inserted consecutively. Note that <timeout> uses <{absolute}>
+ * time rather than <{relative}> time. If the <timeout> elapses
+ * without receiving a message -1 is returned and <errno> is set to
+ * <EWOULDBLOCK>. If the queue is deactivated -1 is returned and
+ * <errno> is set to <ESHUTDOWN>. Otherwise, returns -1 on failure,
+ * else the number of items still on the queue.
+ */
+ virtual int enqueue_prio (ACE_Message_Block *new_item,
+ ACE_Time_Value *timeout = 0);
+
+ /**
+ * This is an alias for <enqueue_prio>. It's only here for
+ * backwards compatibility and will go away in a subsequent release.
+ * Please use <enqueue_prio> instead. Note that <timeout> uses
+ * <{absolute}> time rather than <{relative}> time.
+ */
+ virtual int enqueue (ACE_Message_Block *new_item,
+ ACE_Time_Value *timeout = 0);
+
+ /**
+ * Enqueue an <ACE_Message_Block *> at the end of the queue. Note
+ * that <timeout> uses <{absolute}> time rather than <{relative}>
+ * time. If the <timeout> elapses without receiving a message -1 is
+ * returned and <errno> is set to <EWOULDBLOCK>. If the queue is
+ * deactivated -1 is returned and <errno> is set to <ESHUTDOWN>.
+ * Otherwise, returns -1 on failure, else the number of items still
+ * on the queue.
+ */
+ virtual int enqueue_tail (ACE_Message_Block *new_item,
+ ACE_Time_Value *timeout = 0);
+
+ /**
+ * Enqueue an <ACE_Message_Block *> at the head of the queue. Note
+ * that <timeout> uses <{absolute}> time rather than <{relative}>
+ * time. If the <timeout> elapses without receiving a message -1 is
+ * returned and <errno> is set to <EWOULDBLOCK>. If the queue is
+ * deactivated -1 is returned and <errno> is set to <ESHUTDOWN>.
+ * Otherwise, returns -1 on failure, else the number of items still
+ * on the queue.
+ */
+ virtual int enqueue_head (ACE_Message_Block *new_item,
+ ACE_Time_Value *timeout = 0);
+
+ /// This method is an alias for the following <dequeue_head> method.
+ virtual int dequeue (ACE_Message_Block *&first_item,
+ ACE_Time_Value *timeout = 0);
+
+ /**
+ * Dequeue and return the <ACE_Message_Block *> at the head of the
+ * queue. Note that <timeout> uses <{absolute}> time rather than
+ * <{relative}> time. If the <timeout> elapses without receiving a
+ * message -1 is returned and <errno> is set to <EWOULDBLOCK>. If
+ * the queue is deactivated -1 is returned and <errno> is set to
+ * <ESHUTDOWN>. Otherwise, returns -1 on failure, else the number
+ * of items still on the queue.
+ */
+ virtual int dequeue_head (ACE_Message_Block *&first_item,
+ ACE_Time_Value *timeout = 0);
+
+ // = Check if queue is full/empty.
+ /// True if queue is full, else false.
+ virtual int is_full (void);
+ /// True if queue is empty, else false.
+ virtual int is_empty (void);
+
+ // = Queue statistic methods.
+ /**
+ * Number of total bytes on the queue, i.e., sum of the message
+ * block sizes.
+ */
+ virtual size_t message_bytes (void);
+ /**
+ * Number of total length on the queue, i.e., sum of the message
+ * block lengths.
+ */
+ virtual size_t message_length (void);
+ /**
+ * Number of total messages on the queue.
+ */
+ virtual size_t message_count (void);
+
+ // = Manual changes to these stats (used when queued message blocks
+ // change size or lengths).
+ /**
+ * New value of the number of total bytes on the queue, i.e., sum of
+ * the message block sizes.
+ */
+ virtual void message_bytes (size_t new_size);
+ /**
+ * New value of the number of total length on the queue, i.e., sum
+ * of the message block lengths.
+ */
+ virtual void message_length (size_t new_length);
+
+ // = Flow control methods.
+
+ /**
+ * Get high watermark.
+ */
+ virtual size_t high_water_mark (void);
+ /**
+ * Set the high watermark, which determines how many bytes can be
+ * stored in a queue before it's considered "full."
+ */
+ virtual void high_water_mark (size_t hwm);
+
+ /**
+ * Get low watermark.
+ */
+ virtual size_t low_water_mark (void);
+ /**
+ * Set the low watermark, which determines how many bytes must be in
+ * the queue before supplier threads are allowed to enqueue
+ * additional <ACE_Message_Block>s.
+ */
+ virtual void low_water_mark (size_t lwm);
+
+ // = Activation control methods.
+
+ /**
+ * Deactivate the queue and wakeup all threads waiting on the queue
+ * so they can continue. No messages are removed from the queue,
+ * however. Any other operations called until the queue is
+ * activated again will immediately return -1 with <errno> ==
+ * ESHUTDOWN. Returns WAS_INACTIVE if queue was inactive before the
+ * call and WAS_ACTIVE if queue was active before the call.
+ */
+ virtual int deactivate (void);
+
+ /**
+ * Reactivate the queue so that threads can enqueue and dequeue
+ * messages again. Returns WAS_INACTIVE if queue was inactive
+ * before the call and WAS_ACTIVE if queue was active before the
+ * call.
+ */
+ virtual int activate (void);
+
+ /// Returns true if <deactivated_> is enabled.
+ virtual int deactivated (void);
+
+ // = Notification hook.
+
+ /**
+ * This hook is automatically invoked by <enqueue_head>,
+ * <enqueue_tail>, and <enqueue_prio> when a new item is inserted
+ * into the queue. Subclasses can override this method to perform
+ * specific notification strategies (e.g., signaling events for a
+ * <WFMO_Reactor>, notifying a <Reactor>, etc.). In a
+ * multi-threaded application with concurrent consumers, there is no
+ * guarantee that the queue will be still be non-empty by the time
+ * the notification occurs.
+ */
+ virtual int notify (void);
+
+ // = Get/set the notification strategy for the <Message_Queue>
+ virtual ACE_Notification_Strategy *notification_strategy (void);
+ virtual void notification_strategy (ACE_Notification_Strategy *s);
+
+ /// Returns a reference to the lock used by the <ACE_Message_Queue>.
+ virtual ACE_SYNCH_MUTEX_T &lock (void)
+ {
+ // The Sun Forte 6 (CC 5.1) compiler is only happy if this is in the
+ // header file (j.russell.noseworthy@objectsciences.com)
+ return this->lock_;
+ }
+
+ /// Dump the state of an object.
+ virtual void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+protected:
+ // = Routines that actually do the enqueueing and dequeueing.
+
+ // These routines assume that locks are held by the corresponding
+ // public methods. Since they are virtual, you can change the
+ // queueing mechanism by subclassing from <ACE_Message_Queue>.
+
+ /// Enqueue an <ACE_Message_Block *> in accordance with its priority.
+ virtual int enqueue_i (ACE_Message_Block *new_item);
+
+ /// Enqueue an <ACE_Message_Block *> at the end of the queue.
+ virtual int enqueue_tail_i (ACE_Message_Block *new_item);
+
+ /// Enqueue an <ACE_Message_Block *> at the head of the queue.
+ virtual int enqueue_head_i (ACE_Message_Block *new_item);
+
+ /// Dequeue and return the <ACE_Message_Block *> at the head of the
+ /// queue.
+ virtual int dequeue_head_i (ACE_Message_Block *&first_item);
+
+ // = Check the boundary conditions (assumes locks are held).
+
+ /// True if queue is full, else false.
+ virtual int is_full_i (void);
+
+ /// True if queue is empty, else false.
+ virtual int is_empty_i (void);
+
+ // = Implementation of the public <activate> and <deactivate> methods.
+
+ // These methods assume locks are held.
+
+ /// Deactivate the queue.
+ virtual int deactivate_i (void);
+
+ /// Activate the queue.
+ virtual int activate_i (void);
+
+ // = Helper methods to factor out common #ifdef code.
+
+ /// Wait for the queue to become non-full.
+ virtual int wait_not_full_cond (ACE_Guard<ACE_SYNCH_MUTEX_T> &mon,
+ ACE_Time_Value *timeout);
+
+ /// Wait for the queue to become non-empty.
+ virtual int wait_not_empty_cond (ACE_Guard<ACE_SYNCH_MUTEX_T> &mon,
+ ACE_Time_Value *timeout);
+
+ /// Inform any threads waiting to enqueue that they can procede.
+ virtual int signal_enqueue_waiters (void);
+
+ /// Inform any threads waiting to dequeue that they can procede.
+ virtual int signal_dequeue_waiters (void);
+
+ /// Pointer to head of ACE_Message_Block list.
+ ACE_Message_Block *head_;
+
+ /// Pointer to tail of ACE_Message_Block list.
+ ACE_Message_Block *tail_;
+
+ /// Lowest number before unblocking occurs.
+ size_t low_water_mark_;
+
+ /// Greatest number of bytes before blocking.
+ size_t high_water_mark_;
+
+ /// Current number of bytes in the queue.
+ size_t cur_bytes_;
+
+ /// Current length of messages in the queue.
+ size_t cur_length_;
+
+ /// Current number of messages in the queue.
+ size_t cur_count_;
+
+ /// Indicates that the queue is inactive.
+ int deactivated_;
+
+ /// The notification strategy used when a new message is enqueued.
+ ACE_Notification_Strategy *notification_strategy_;
+
+ // = Synchronization primitives for controlling concurrent access.
+ /// Protect queue from concurrent access.
+ ACE_SYNCH_MUTEX_T lock_;
+
+#if defined (ACE_HAS_OPTIMIZED_MESSAGE_QUEUE)
+ /// Used to make threads sleep until the queue is no longer empty.
+ ACE_SYNCH_SEMAPHORE_T not_empty_cond_;
+
+ /// Used to make threads sleep until the queue is no longer full.
+ ACE_SYNCH_SEMAPHORE_T not_full_cond_;
+
+ /// Number of threads waiting to dequeue a <Message_Block>.
+ size_t dequeue_waiters_;
+
+ /// Number of threads waiting to enqueue a <Message_Block>.
+ size_t enqueue_waiters_;
+#else
+ /// Used to make threads sleep until the queue is no longer empty.
+ ACE_SYNCH_CONDITION_T not_empty_cond_;
+
+ /// Used to make threads sleep until the queue is no longer full.
+ ACE_SYNCH_CONDITION_T not_full_cond_;
+#endif /* ACE_HAS_OPTIMIZED_MESSAGE_QUEUE */
+
+private:
+
+ // = Disallow these operations.
+ ACE_UNIMPLEMENTED_FUNC (void operator= (const ACE_Message_Queue<ACE_SYNCH_USE> &))
+ ACE_UNIMPLEMENTED_FUNC (ACE_Message_Queue (const ACE_Message_Queue<ACE_SYNCH_USE> &))
+};
+
+// This typedef is used to get around a compiler bug in g++/vxworks.
+typedef ACE_Message_Queue<ACE_SYNCH> ACE_DEFAULT_MESSAGE_QUEUE_TYPE;
+
+
+/**
+ * @class ACE_Message_Queue_Iterator
+ *
+ * @brief Iterator for the <ACE_Message_Queue>.
+ */
+template <ACE_SYNCH_DECL>
+class ACE_Message_Queue_Iterator
+{
+public:
+ // = Initialization method.
+ ACE_Message_Queue_Iterator (ACE_Message_Queue <ACE_SYNCH_USE> &queue);
+
+ // = Iteration methods.
+ /// Pass back the <entry> that hasn't been seen in the queue.
+ /// Returns 0 when all items have been seen, else 1.
+ int next (ACE_Message_Block *&entry);
+
+ /// Returns 1 when all items have been seen, else 0.
+ int done (void) const;
+
+ /// Move forward by one element in the queue. Returns 0 when all the
+ /// items in the set have been seen, else 1.
+ int advance (void);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+private:
+ /// Message_Queue we are iterating over.
+ ACE_Message_Queue <ACE_SYNCH_USE> &queue_;
+
+ /// Keeps track of how far we've advanced...
+ ACE_Message_Block *curr_;
+};
+
+/**
+ * @class ACE_Message_Queue_Reverse_Iterator
+ *
+ * @brief Reverse Iterator for the <ACE_Message_Queue>.
+ */
+template <ACE_SYNCH_DECL>
+class ACE_Message_Queue_Reverse_Iterator
+{
+public:
+ // = Initialization method.
+ ACE_Message_Queue_Reverse_Iterator (ACE_Message_Queue <ACE_SYNCH_USE> &queue);
+
+ // = Iteration methods.
+ /// Pass back the <entry> that hasn't been seen in the queue.
+ /// Returns 0 when all items have been seen, else 1.
+ int next (ACE_Message_Block *&entry);
+
+ /// Returns 1 when all items have been seen, else 0.
+ int done (void) const;
+
+ /// Move forward by one element in the queue. Returns 0 when all the
+ /// items in the set have been seen, else 1.
+ int advance (void);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+private:
+ /// Message_Queue we are iterating over.
+ ACE_Message_Queue <ACE_SYNCH_USE> &queue_;
+
+ /// Keeps track of how far we've advanced...
+ ACE_Message_Block *curr_;
+};
+
+/**
+ * @class ACE_Dynamic_Message_Queue
+ *
+ * @brief A derived class which adapts the <ACE_Message_Queue>
+ * class in order to maintain dynamic priorities for enqueued
+ * <ACE_Message_Blocks> and manage the queue order according
+ * to these dynamic priorities.
+ *
+ * The messages in the queue are managed so as to preserve
+ * a logical ordering with minimal overhead per enqueue and
+ * dequeue operation. For this reason, the actual order of
+ * messages in the linked list of the queue may differ from
+ * their priority order. As time passes, a message may change
+ * from pending status to late status, and eventually to beyond
+ * late status. To minimize reordering overhead under this
+ * design force, three separate boundaries are maintained
+ * within the linked list of messages. Messages are dequeued
+ * preferentially from the head of the pending portion, then
+ * the head of the late portion, and finally from the head
+ * of the beyond late portion. In this way, only the boundaries
+ * need to be maintained (which can be done efficiently, as
+ * aging messages maintain the same linked list order as they
+ * progress from one status to the next), with no reordering
+ * of the messages themselves, while providing correct priority
+ * ordered dequeueing semantics.
+ * Head and tail enqueue methods inherited from ACE_Message_Queue
+ * are made private to prevent out-of-order messages from confusing
+ * management of the various portions of the queue. Messages in
+ * the pending portion of the queue whose priority becomes late
+ * (according to the specific dynamic strategy) advance into
+ * the late portion of the queue. Messages in the late portion
+ * of the queue whose priority becomes later than can be represented
+ * advance to the beyond_late portion of the queue. These behaviors
+ * support a limited schedule overrun, with pending messages prioritized
+ * ahead of late messages, and late messages ahead of beyond late
+ * messages. These behaviors can be modified in derived classes by
+ * providing alternative definitions for the appropriate virtual methods.
+ * When filled with messages, the queue's linked list should look like:
+ * H T
+ * | |
+ * B - B - B - B - L - L - L - P - P - P - P - P
+ * | | | | | |
+ * BH BT LH LT PH PT
+ * Where the symbols are as follows:
+ * H = Head of the entire list
+ * T = Tail of the entire list
+ * B = Beyond late message
+ * BH = Beyond late messages Head
+ * BT = Beyond late messages Tail
+ * L = Late message
+ * LH = Late messages Head
+ * LT = Late messages Tail
+ * P = Pending message
+ * PH = Pending messages Head
+ * PT = Pending messages Tail
+ * Caveat: the virtual methods enqueue_tail, enqueue_head,
+ * and peek_dequeue_head have semantics for the static
+ * message queues that cannot be guaranteed for dynamic
+ * message queues. The peek_dequeue_head method just
+ * calls the base class method, while the two enqueue
+ * methods call the priority enqueue method. The
+ * order of messages in the dynamic queue is a function
+ * of message deadlines and how long they are in the
+ * queues. You can manipulate these in some cases to
+ * ensure the correct semantics, but that is not a
+ * very stable or portable approach (discouraged).
+ */
+template <ACE_SYNCH_DECL>
+class ACE_Dynamic_Message_Queue : public ACE_Message_Queue<ACE_SYNCH_USE>
+{
+public:
+ // = Initialization and termination methods.
+ ACE_Dynamic_Message_Queue (ACE_Dynamic_Message_Strategy & message_strategy,
+ size_t hwm = ACE_Message_Queue_Base::DEFAULT_HWM,
+ size_t lwm = ACE_Message_Queue_Base::DEFAULT_LWM,
+ ACE_Notification_Strategy * = 0);
+
+ /// Close down the message queue and release all resources.
+ virtual ~ACE_Dynamic_Message_Queue (void);
+
+ /**
+ * Detach all messages with status given in the passed flags from
+ * the queue and return them by setting passed head and tail pointers
+ * to the linked list they comprise. This method is intended primarily
+ * as a means of periodically harvesting messages that have missed
+ * their deadlines, but is available in its most general form. All
+ * messages are returned in priority order, from head to tail, as of
+ * the time this method was called.
+ */
+ virtual int remove_messages (ACE_Message_Block *&list_head,
+ ACE_Message_Block *&list_tail,
+ u_int status_flags);
+
+ /**
+ * Dequeue and return the <ACE_Message_Block *> at the head of the
+ * queue. Returns -1 on failure, else the number of items still on
+ * the queue.
+ */
+ virtual int dequeue_head (ACE_Message_Block *&first_item,
+ ACE_Time_Value *timeout = 0);
+
+ /// Dump the state of the queue.
+ virtual void dump (void) const;
+
+ /**
+ * just call priority enqueue method: tail enqueue semantics for dynamic
+ * message queues are unstable: the message may or may not be where
+ * it was placed after the queue is refreshed prior to the next
+ * enqueue or dequeue operation.
+ */
+ virtual int enqueue_tail (ACE_Message_Block *new_item,
+ ACE_Time_Value *timeout = 0);
+
+ /**
+ * just call priority enqueue method: head enqueue semantics for dynamic
+ * message queues are unstable: the message may or may not be where
+ * it was placed after the queue is refreshed prior to the next
+ * enqueue or dequeue operation.
+ */
+ virtual int enqueue_head (ACE_Message_Block *new_item,
+ ACE_Time_Value *timeout = 0);
+
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+protected:
+
+ /**
+ * Enqueue an <ACE_Message_Block *> in accordance with its priority.
+ * priority may be *dynamic* or *static* or a combination or *both*
+ * It calls the priority evaluation function passed into the Dynamic
+ * Message Queue constructor to update the priorities of all
+ * enqueued messages.
+ */
+ virtual int enqueue_i (ACE_Message_Block *new_item);
+
+ /// enqueue a message in priority order within a given priority status sublist
+ virtual int sublist_enqueue_i (ACE_Message_Block *new_item,
+ const ACE_Time_Value &current_time,
+ ACE_Message_Block *&sublist_head,
+ ACE_Message_Block *&sublist_tail,
+ ACE_Dynamic_Message_Strategy::Priority_Status status);
+
+ /**
+ * Dequeue and return the <ACE_Message_Block *> at the head of the
+ * logical queue. Attempts first to dequeue from the pending
+ * portion of the queue, or if that is empty from the late portion,
+ * or if that is empty from the beyond late portion, or if that is
+ * empty just sets the passed pointer to zero and returns -1.
+ */
+ virtual int dequeue_head_i (ACE_Message_Block *&first_item);
+
+ /// Refresh the queue using the strategy
+ /// specific priority status function.
+ virtual int refresh_queue (const ACE_Time_Value & current_time);
+
+ /// Refresh the pending queue using the strategy
+ /// specific priority status function.
+ virtual int refresh_pending_queue (const ACE_Time_Value & current_time);
+
+ /// Refresh the late queue using the strategy
+ /// specific priority status function.
+ virtual int refresh_late_queue (const ACE_Time_Value & current_time);
+
+ /// Pointer to head of the pending messages
+ ACE_Message_Block *pending_head_;
+
+ /// Pointer to tail of the pending messages
+ ACE_Message_Block *pending_tail_;
+
+ /// Pointer to head of the late messages
+ ACE_Message_Block *late_head_;
+
+ /// Pointer to tail of the late messages
+ ACE_Message_Block *late_tail_;
+
+ /// Pointer to head of the beyond late messages
+ ACE_Message_Block *beyond_late_head_;
+
+ /// Pointer to tail of the beyond late messages
+ ACE_Message_Block *beyond_late_tail_;
+
+ /// Pointer to a dynamic priority evaluation function.
+ ACE_Dynamic_Message_Strategy &message_strategy_;
+
+private:
+ // = Disallow public access to these operations.
+
+ ACE_UNIMPLEMENTED_FUNC (void operator= (const ACE_Dynamic_Message_Queue<ACE_SYNCH_USE> &))
+ ACE_UNIMPLEMENTED_FUNC (ACE_Dynamic_Message_Queue (const ACE_Dynamic_Message_Queue<ACE_SYNCH_USE> &))
+
+ // provide definitions for these (just call base class method),
+ // but make them private so they're not accessible outside the class
+
+ /// private method to hide public base class method: just calls base class method
+ virtual int peek_dequeue_head (ACE_Message_Block *&first_item,
+ ACE_Time_Value *timeout = 0);
+
+};
+
+/**
+ * @class ACE_Message_Queue_Factory
+ *
+ * @brief ACE_Message_Queue_Factory is a static factory class template which
+ * provides a separate factory method for each of the major kinds of
+ * priority based message dispatching: static, earliest deadline first
+ * (EDF), and minimum laxity first (MLF).
+ *
+ * The ACE_Dynamic_Message_Queue class assumes responsibility for
+ * releasing the resources of the strategy with which it was
+ * constructed: the user of a message queue constructed by
+ * any of these factory methods is only responsible for
+ * ensuring destruction of the message queue itself.
+ */
+template <ACE_SYNCH_DECL>
+class ACE_Message_Queue_Factory
+{
+public:
+ /// factory method for a statically prioritized ACE_Message_Queue
+ static ACE_Message_Queue<ACE_SYNCH_USE> *
+ create_static_message_queue (size_t hwm = ACE_Message_Queue_Base::DEFAULT_HWM,
+ size_t lwm = ACE_Message_Queue_Base::DEFAULT_LWM,
+ ACE_Notification_Strategy * = 0);
+
+ /// factory method for a dynamically prioritized (by time to deadline) ACE_Dynamic_Message_Queue
+ static ACE_Dynamic_Message_Queue<ACE_SYNCH_USE> *
+ create_deadline_message_queue (size_t hwm = ACE_Message_Queue_Base::DEFAULT_HWM,
+ size_t lwm = ACE_Message_Queue_Base::DEFAULT_LWM,
+ ACE_Notification_Strategy * = 0,
+ u_long static_bit_field_mask = 0x3FFUL, // 2^(10) - 1
+ u_long static_bit_field_shift = 10, // 10 low order bits
+ u_long dynamic_priority_max = 0x3FFFFFUL, // 2^(22)-1
+ u_long dynamic_priority_offset = 0x200000UL); // 2^(22-1)
+
+ /// factory method for a dynamically prioritized (by laxity) ACE_Dynamic_Message_Queue
+ static ACE_Dynamic_Message_Queue<ACE_SYNCH_USE> *
+ create_laxity_message_queue (size_t hwm = ACE_Message_Queue_Base::DEFAULT_HWM,
+ size_t lwm = ACE_Message_Queue_Base::DEFAULT_LWM,
+ ACE_Notification_Strategy * = 0,
+ u_long static_bit_field_mask = 0x3FFUL, // 2^(10) - 1
+ u_long static_bit_field_shift = 10, // 10 low order bits
+ u_long dynamic_priority_max = 0x3FFFFFUL, // 2^(22)-1
+ u_long dynamic_priority_offset = 0x200000UL); // 2^(22-1)
+
+
+#if defined (VXWORKS)
+
+ /// factory method for a wrapped VxWorks message queue
+ static ACE_Message_Queue_Vx *
+ create_Vx_message_queue (size_t max_messages, size_t max_message_length,
+ ACE_Notification_Strategy *ns = 0);
+
+#endif /* defined (VXWORKS) */
+
+#if defined (ACE_WIN32) && (ACE_HAS_WINNT4 != 0)
+
+ /// factory method for a NT message queue.
+ static ACE_Message_Queue_NT *
+ create_NT_message_queue (size_t max_threads);
+
+#endif /* ACE_WIN32 && ACE_HAS_WINNT4 != 0 */
+};
+
+/**
+ * @class ACE_Message_Queue_Ex
+ *
+ * @brief A threaded message queueing facility, modeled after the
+ * queueing facilities in System V STREAMs.
+ *
+ * An <ACE_Message_Queue_Ex> is a strongly-typed version of the
+ * <ACE_Message_Queue>. If
+ * <ACE_SYNCH_DECL> is <ACE_MT_SYNCH> then all operations are
+ * thread-safe. Otherwise, if it's <ACE_NULL_SYNCH> then there's no
+ * locking overhead.
+ */
+template <class ACE_MESSAGE_TYPE, ACE_SYNCH_DECL>
+class ACE_Message_Queue_Ex
+{
+public:
+
+ // = Default priority value.
+ enum
+ {
+ DEFAULT_PRIORITY = 0
+ };
+
+#if 0
+ // @@ Iterators are not implemented yet...
+
+ friend class ACE_Message_Queue_Iterator<ACE_SYNCH_USE>;
+ friend class ACE_Message_Queue_Reverse_Iterator<ACE_SYNCH_USE>;
+
+ // = Traits
+ typedef ACE_Message_Queue_Iterator<ACE_SYNCH_USE>
+ ITERATOR;
+ typedef ACE_Message_Queue_Reverse_Iterator<ACE_SYNCH_USE>
+ REVERSE_ITERATOR;
+#endif /* 0 */
+
+ // = Initialization and termination methods.
+
+ /**
+ * Initialize an <ACE_Message_Queue>. The <high_water_mark>
+ * determines how many bytes can be stored in a queue before it's
+ * considered "full." Supplier threads must block until the queue
+ * is no longer full. The <low_water_mark> determines how many
+ * bytes must be in the queue before supplier threads are allowed to
+ * enqueue additional <ACE_Message_Block>s. By default, the
+ * <high_water_mark> equals the <low_water_mark>, which means that
+ * suppliers will be able to enqueue new messages as soon as a
+ * consumer removes any message from the queue. Making the
+ * <low_water_mark> smaller than the <high_water_mark> forces
+ * consumers to drain more messages from the queue before suppliers
+ * can enqueue new messages, which can minimize the "silly window
+ * syndrome."
+ */
+ ACE_Message_Queue_Ex (size_t high_water_mark = ACE_Message_Queue_Base::DEFAULT_HWM,
+ size_t low_water_mark = ACE_Message_Queue_Base::DEFAULT_LWM,
+ ACE_Notification_Strategy * = 0);
+
+ /**
+ * Initialize an <ACE_Message_Queue>. The <high_water_mark>
+ * determines how many bytes can be stored in a queue before it's
+ * considered "full." Supplier threads must block until the queue
+ * is no longer full. The <low_water_mark> determines how many
+ * bytes must be in the queue before supplier threads are allowed to
+ * enqueue additional <ACE_Message_Block>s. By default, the
+ * <high_water_mark> equals the <low_water_mark>, which means that
+ * suppliers will be able to enqueue new messages as soon as a
+ * consumer removes any message from the queue. Making the
+ * <low_water_mark> smaller than the <high_water_mark> forces
+ * consumers to drain more messages from the queue before suppliers
+ * can enqueue new messages, which can minimize the "silly window
+ * syndrome."
+ */
+ virtual int open (size_t hwm = ACE_Message_Queue_Base::DEFAULT_HWM,
+ size_t lwm = ACE_Message_Queue_Base::DEFAULT_LWM,
+ ACE_Notification_Strategy * = 0);
+
+ /// Close down the message queue and release all resources.
+ virtual int close (void);
+
+ /// Close down the message queue and release all resources.
+ virtual ~ACE_Message_Queue_Ex (void);
+
+ // = Enqueue and dequeue methods.
+
+ // For the following enqueue and dequeue methods if <timeout> == 0,
+ // the caller will block until action is possible, else will wait
+ // until the absolute time specified in *<timeout> elapses). These
+ // calls will return, however, when queue is closed, deactivated,
+ // when a signal occurs, or if the time specified in timeout
+ // elapses, (in which case errno = EWOULDBLOCK).
+
+ /**
+ * Retrieve the first <ACE_Message_Block> without removing it. Note
+ * that <timeout> uses <{absolute}> time rather than <{relative}>
+ * time. If the <timeout> elapses without receiving a message -1 is
+ * returned and <errno> is set to <EWOULDBLOCK>. If the queue is
+ * deactivated -1 is returned and <errno> is set to <ESHUTDOWN>.
+ * Otherwise, returns -1 on failure, else the number of items still
+ * on the queue.
+ */
+ virtual int peek_dequeue_head (ACE_MESSAGE_TYPE *&first_item,
+ ACE_Time_Value *timeout = 0);
+
+ /**
+ * Enqueue an <ACE_Message_Block *> into the <Message_Queue> in
+ * accordance with its <msg_priority> (0 is lowest priority). FIFO
+ * order is maintained when messages of the same priority are
+ * inserted consecutively. Note that <timeout> uses <{absolute}>
+ * time rather than <{relative}> time. If the <timeout> elapses
+ * without receiving a message -1 is returned and <errno> is set to
+ * <EWOULDBLOCK>. If the queue is deactivated -1 is returned and
+ * <errno> is set to <ESHUTDOWN>. Otherwise, returns -1 on failure,
+ * else the number of items still on the queue.
+ */
+ virtual int enqueue_prio (ACE_MESSAGE_TYPE *new_item,
+ ACE_Time_Value *timeout = 0);
+
+ /**
+ * This is an alias for <enqueue_prio>. It's only here for
+ * backwards compatibility and will go away in a subsequent release.
+ * Please use <enqueue_prio> instead. Note that <timeout> uses
+ * <{absolute}> time rather than <{relative}> time.
+ */
+ virtual int enqueue (ACE_MESSAGE_TYPE *new_item,
+ ACE_Time_Value *timeout = 0);
+
+ /**
+ * Enqueue an <ACE_Message_Block *> at the end of the queue. Note
+ * that <timeout> uses <{absolute}> time rather than <{relative}>
+ * time. If the <timeout> elapses without receiving a message -1 is
+ * returned and <errno> is set to <EWOULDBLOCK>. If the queue is
+ * deactivated -1 is returned and <errno> is set to <ESHUTDOWN>.
+ * Otherwise, returns -1 on failure, else the number of items still
+ * on the queue.
+ */
+ virtual int enqueue_tail (ACE_MESSAGE_TYPE *new_item,
+ ACE_Time_Value *timeout = 0);
+
+ /**
+ * Enqueue an <ACE_Message_Block *> at the head of the queue. Note
+ * that <timeout> uses <{absolute}> time rather than <{relative}>
+ * time. If the <timeout> elapses without receiving a message -1 is
+ * returned and <errno> is set to <EWOULDBLOCK>. If the queue is
+ * deactivated -1 is returned and <errno> is set to <ESHUTDOWN>.
+ * Otherwise, returns -1 on failure, else the number of items still
+ * on the queue.
+ */
+ virtual int enqueue_head (ACE_MESSAGE_TYPE *new_item,
+ ACE_Time_Value *timeout = 0);
+
+ /// This method is an alias for the following <dequeue_head> method.
+ virtual int dequeue (ACE_MESSAGE_TYPE *&first_item,
+ ACE_Time_Value *timeout = 0);
+ // This method is an alias for the following <dequeue_head> method.
+
+ /**
+ * Dequeue and return the <ACE_Message_Block *> at the head of the
+ * queue. Note that <timeout> uses <{absolute}> time rather than
+ * <{relative}> time. If the <timeout> elapses without receiving a
+ * message -1 is returned and <errno> is set to <EWOULDBLOCK>. If
+ * the queue is deactivated -1 is returned and <errno> is set to
+ * <ESHUTDOWN>. Otherwise, returns -1 on failure, else the number
+ * of items still on the queue.
+ */
+ virtual int dequeue_head (ACE_MESSAGE_TYPE *&first_item,
+ ACE_Time_Value *timeout = 0);
+
+ // = Check if queue is full/empty.
+ /// True if queue is full, else false.
+ virtual int is_full (void);
+ /// True if queue is empty, else false.
+ virtual int is_empty (void);
+
+
+ // = Queue statistic methods.
+ /**
+ * Number of total bytes on the queue, i.e., sum of the message
+ * block sizes.
+ */
+ virtual size_t message_bytes (void);
+ /**
+ * Number of total length on the queue, i.e., sum of the message
+ * block lengths.
+ */
+ virtual size_t message_length (void);
+ /**
+ * Number of total messages on the queue.
+ */
+ virtual size_t message_count (void);
+
+ // = Manual changes to these stats (used when queued message blocks
+ // change size or lengths).
+ /**
+ * New value of the number of total bytes on the queue, i.e., sum of
+ * the message block sizes.
+ */
+ virtual void message_bytes (size_t new_size);
+ /**
+ * New value of the number of total length on the queue, i.e., sum
+ * of the message block lengths.
+ */
+ virtual void message_length (size_t new_length);
+
+ // = Flow control methods.
+ /**
+ * Get high watermark.
+ */
+ virtual size_t high_water_mark (void);
+ /**
+ * Set the high watermark, which determines how many bytes can be
+ * stored in a queue before it's considered "full."
+ */
+ virtual void high_water_mark (size_t hwm);
+
+ /**
+ * Get low watermark.
+ */
+ virtual size_t low_water_mark (void);
+ /**
+ * Set the low watermark, which determines how many bytes must be in
+ * the queue before supplier threads are allowed to enqueue
+ * additional <ACE_Message_Block>s.
+ */
+ virtual void low_water_mark (size_t lwm);
+
+ // = Activation control methods.
+
+ /**
+ * Deactivate the queue and wakeup all threads waiting on the queue
+ * so they can continue. No messages are removed from the queue,
+ * however. Any other operations called until the queue is
+ * activated again will immediately return -1 with <errno> ==
+ * ESHUTDOWN. Returns WAS_INACTIVE if queue was inactive before the
+ * call and WAS_ACTIVE if queue was active before the call.
+ */
+ virtual int deactivate (void);
+
+ /**
+ * Reactivate the queue so that threads can enqueue and dequeue
+ * messages again. Returns WAS_INACTIVE if queue was inactive
+ * before the call and WAS_ACTIVE if queue was active before the
+ * call.
+ */
+ virtual int activate (void);
+
+ /// Returns true if <deactivated_> is enabled.
+ virtual int deactivated (void);
+
+ // = Notification hook.
+
+ /**
+ * This hook is automatically invoked by <enqueue_head>,
+ * <enqueue_tail>, and <enqueue_prio> when a new item is inserted
+ * into the queue. Subclasses can override this method to perform
+ * specific notification strategies (e.g., signaling events for a
+ * <WFMO_Reactor>, notifying a <Reactor>, etc.). In a
+ * multi-threaded application with concurrent consumers, there is no
+ * guarantee that the queue will be still be non-empty by the time
+ * the notification occurs.
+ */
+ virtual int notify (void);
+
+ /// Get/set the notification strategy for the <Message_Queue>
+ virtual ACE_Notification_Strategy *notification_strategy (void);
+ virtual void notification_strategy (ACE_Notification_Strategy *s);
+
+ /// Returns a reference to the lock used by the <ACE_Message_Queue_Ex>.
+ virtual ACE_SYNCH_MUTEX_T &lock (void)
+ {
+ // The Sun Forte 6 (CC 5.1) compiler is only happy if this is in the
+ // header file (j.russell.noseworthy@objectsciences.com)
+ return this->queue_.lock ();
+ }
+
+ /// Dump the state of an object.
+ virtual void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+private:
+ /// Implement this via an <ACE_Message_Queue>.
+ ACE_Message_Queue<ACE_SYNCH_USE> queue_;
+};
+
+#if defined (__ACE_INLINE__)
+#include "ace/Message_Queue_T.i"
+#endif /* __ACE_INLINE__ */
+
+#if defined (ACE_TEMPLATES_REQUIRE_SOURCE)
+#include "ace/Message_Queue_T.cpp"
+#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */
+
+#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA)
+#pragma implementation ("Message_Queue_T.cpp")
+#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */
+
+#include "ace/post.h"
+#endif /* ACE_MESSAGE_QUEUE_T_H */
diff --git a/ace/Streams/Message_Queue_T.i b/ace/Streams/Message_Queue_T.i
new file mode 100644
index 00000000000..297cd12830e
--- /dev/null
+++ b/ace/Streams/Message_Queue_T.i
@@ -0,0 +1,303 @@
+/* -*- C++ -*- */
+// $Id$
+
+template <ACE_SYNCH_DECL> ACE_INLINE int
+ACE_Message_Queue<ACE_SYNCH_USE>::dequeue (ACE_Message_Block *&first_item,
+ ACE_Time_Value *timeout)
+{
+ ACE_TRACE ("ACE_Message_Queue<ACE_SYNCH_USE>::dequeue");
+ return this->dequeue_head (first_item, timeout);
+}
+
+template <ACE_SYNCH_DECL> ACE_INLINE ACE_Notification_Strategy *
+ACE_Message_Queue<ACE_SYNCH_USE>::notification_strategy (void)
+{
+ ACE_TRACE ("ACE_Message_Queue<ACE_SYNCH_USE>::notification_strategy");
+
+ return this->notification_strategy_;
+}
+
+template <ACE_SYNCH_DECL> ACE_INLINE void
+ACE_Message_Queue<ACE_SYNCH_USE>::notification_strategy (ACE_Notification_Strategy *s)
+{
+ ACE_TRACE ("ACE_Message_Queue<ACE_SYNCH_USE>::notification_strategy");
+
+ this->notification_strategy_ = s;
+}
+
+// Check if queue is empty (does not hold locks).
+
+template <ACE_SYNCH_DECL> ACE_INLINE int
+ACE_Message_Queue<ACE_SYNCH_USE>::is_empty_i (void)
+{
+ ACE_TRACE ("ACE_Message_Queue<ACE_SYNCH_USE>::is_empty_i");
+ return this->tail_ == 0;
+}
+
+// Check if queue is full (does not hold locks).
+
+template <ACE_SYNCH_DECL> ACE_INLINE int
+ACE_Message_Queue<ACE_SYNCH_USE>::is_full_i (void)
+{
+ ACE_TRACE ("ACE_Message_Queue<ACE_SYNCH_USE>::is_full_i");
+ return this->cur_bytes_ > this->high_water_mark_;
+}
+
+// Check if queue is empty (holds locks).
+
+template <ACE_SYNCH_DECL> ACE_INLINE int
+ACE_Message_Queue<ACE_SYNCH_USE>::is_empty (void)
+{
+ ACE_TRACE ("ACE_Message_Queue<ACE_SYNCH_USE>::is_empty");
+ ACE_GUARD_RETURN (ACE_SYNCH_MUTEX_T, ace_mon, this->lock_, -1);
+
+ return this->is_empty_i ();
+}
+
+// Check if queue is full (holds locks).
+
+template <ACE_SYNCH_DECL> ACE_INLINE int
+ACE_Message_Queue<ACE_SYNCH_USE>::is_full (void)
+{
+ ACE_TRACE ("ACE_Message_Queue<ACE_SYNCH_USE>::is_full");
+ ACE_GUARD_RETURN (ACE_SYNCH_MUTEX_T, ace_mon, this->lock_, -1);
+
+ return this->is_full_i ();
+}
+
+template <ACE_SYNCH_DECL> ACE_INLINE size_t
+ACE_Message_Queue<ACE_SYNCH_USE>::high_water_mark (void)
+{
+ ACE_TRACE ("ACE_Message_Queue<ACE_SYNCH_USE>::high_water_mark");
+ ACE_GUARD_RETURN (ACE_SYNCH_MUTEX_T, ace_mon, this->lock_, 0);
+
+ return this->high_water_mark_;
+}
+
+template <ACE_SYNCH_DECL> ACE_INLINE void
+ACE_Message_Queue<ACE_SYNCH_USE>::high_water_mark (size_t hwm)
+{
+ ACE_TRACE ("ACE_Message_Queue<ACE_SYNCH_USE>::high_water_mark");
+ ACE_GUARD (ACE_SYNCH_MUTEX_T, ace_mon, this->lock_);
+
+ this->high_water_mark_ = hwm;
+}
+
+template <ACE_SYNCH_DECL> ACE_INLINE size_t
+ACE_Message_Queue<ACE_SYNCH_USE>::low_water_mark (void)
+{
+ ACE_TRACE ("ACE_Message_Queue<ACE_SYNCH_USE>::low_water_mark");
+ ACE_GUARD_RETURN (ACE_SYNCH_MUTEX_T, ace_mon, this->lock_, 0);
+
+ return this->low_water_mark_;
+}
+
+template <ACE_SYNCH_DECL> ACE_INLINE void
+ACE_Message_Queue<ACE_SYNCH_USE>::low_water_mark (size_t lwm)
+{
+ ACE_TRACE ("ACE_Message_Queue<ACE_SYNCH_USE>::low_water_mark");
+ ACE_GUARD (ACE_SYNCH_MUTEX_T, ace_mon, this->lock_);
+
+ this->low_water_mark_ = lwm;
+}
+
+template <ACE_SYNCH_DECL> ACE_INLINE size_t
+ACE_Message_Queue<ACE_SYNCH_USE>::message_bytes (void)
+{
+ ACE_TRACE ("ACE_Message_Queue<ACE_SYNCH_USE>::message_bytes");
+ ACE_GUARD_RETURN (ACE_SYNCH_MUTEX_T, ace_mon, this->lock_, 0);
+
+ return this->cur_bytes_;
+}
+
+template <ACE_SYNCH_DECL> ACE_INLINE size_t
+ACE_Message_Queue<ACE_SYNCH_USE>::message_length (void)
+{
+ ACE_TRACE ("ACE_Message_Queue<ACE_SYNCH_USE>::message_length");
+ ACE_GUARD_RETURN (ACE_SYNCH_MUTEX_T, ace_mon, this->lock_, 0);
+
+ return this->cur_length_;
+}
+
+template <ACE_SYNCH_DECL> ACE_INLINE size_t
+ACE_Message_Queue<ACE_SYNCH_USE>::message_count (void)
+{
+ ACE_TRACE ("ACE_Message_Queue<ACE_SYNCH_USE>::message_count");
+ ACE_GUARD_RETURN (ACE_SYNCH_MUTEX_T, ace_mon, this->lock_, 0);
+
+ return this->cur_count_;
+}
+
+template <ACE_SYNCH_DECL> ACE_INLINE int
+ACE_Message_Queue<ACE_SYNCH_USE>::activate (void)
+{
+ ACE_TRACE ("ACE_Message_Queue<ACE_SYNCH_USE>::activate");
+ ACE_GUARD_RETURN (ACE_SYNCH_MUTEX_T, ace_mon, this->lock_, -1);
+
+ return this->activate_i ();
+}
+
+template <ACE_SYNCH_DECL> ACE_INLINE int
+ACE_Message_Queue<ACE_SYNCH_USE>::deactivate (void)
+{
+ ACE_TRACE ("ACE_Message_Queue<ACE_SYNCH_USE>::deactivate");
+ ACE_GUARD_RETURN (ACE_SYNCH_MUTEX_T, ace_mon, this->lock_, -1);
+
+ return this->deactivate_i ();
+}
+
+template <ACE_SYNCH_DECL> ACE_INLINE int
+ACE_Message_Queue<ACE_SYNCH_USE>::deactivated (void)
+{
+ ACE_TRACE ("ACE_Message_Queue<ACE_SYNCH_USE>::deactivated");
+
+ return this->deactivated_;
+}
+
+#if 0
+// The Sun Forte 6 (CC 5.1) compiler is only happy if this is in the
+// header file (j.russell.noseworthy@objectsciences.com)
+
+template <ACE_SYNCH_DECL> ACE_INLINE ACE_SYNCH_MUTEX_T &
+ACE_Message_Queue<ACE_SYNCH_USE>::lock (void)
+{
+ return this->lock_;
+}
+#endif /* 0 */
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Message_Queue_Reverse_Iterator)
+
+template <class ACE_MESSAGE_TYPE, ACE_SYNCH_DECL> ACE_INLINE int
+ACE_Message_Queue_Ex<ACE_MESSAGE_TYPE, ACE_SYNCH_USE>::dequeue (ACE_MESSAGE_TYPE *&first_item,
+ ACE_Time_Value *timeout)
+{
+ ACE_TRACE ("ACE_Message_Queue_Ex<ACE_MESSAGE_TYPE, ACE_SYNCH_USE>::dequeue");
+
+ return this->dequeue_head (first_item, timeout);
+}
+
+template <class ACE_MESSAGE_TYPE, ACE_SYNCH_DECL> ACE_INLINE ACE_Notification_Strategy *
+ACE_Message_Queue_Ex<ACE_MESSAGE_TYPE, ACE_SYNCH_USE>::notification_strategy (void)
+{
+ ACE_TRACE ("ACE_Message_Queue_Ex<ACE_MESSAGE_TYPE, ACE_SYNCH_USE>::notification_strategy");
+
+ return this->queue_.notification_strategy ();
+}
+
+template <class ACE_MESSAGE_TYPE, ACE_SYNCH_DECL> ACE_INLINE void
+ACE_Message_Queue_Ex<ACE_MESSAGE_TYPE, ACE_SYNCH_USE>::notification_strategy (ACE_Notification_Strategy *s)
+{
+ ACE_TRACE ("ACE_Message_Queue_Ex<ACE_MESSAGE_TYPE, ACE_SYNCH_USE>::notification_strategy");
+
+ this->queue_.notification_strategy (s);
+}
+
+// Check if queue is empty (holds locks).
+
+template <class ACE_MESSAGE_TYPE, ACE_SYNCH_DECL> ACE_INLINE int
+ACE_Message_Queue_Ex<ACE_MESSAGE_TYPE, ACE_SYNCH_USE>::is_empty (void)
+{
+ ACE_TRACE ("ACE_Message_Queue_Ex<ACE_MESSAGE_TYPE, ACE_SYNCH_USE>::is_empty");
+
+ return this->queue_.is_empty ();
+}
+
+// Check if queue is full (holds locks).
+
+template <class ACE_MESSAGE_TYPE, ACE_SYNCH_DECL> ACE_INLINE int
+ACE_Message_Queue_Ex<ACE_MESSAGE_TYPE, ACE_SYNCH_USE>::is_full (void)
+{
+ ACE_TRACE ("ACE_Message_Queue_Ex<ACE_MESSAGE_TYPE, ACE_SYNCH_USE>::is_full");
+
+ return this->queue_.is_full ();
+}
+
+template <class ACE_MESSAGE_TYPE, ACE_SYNCH_DECL> ACE_INLINE size_t
+ACE_Message_Queue_Ex<ACE_MESSAGE_TYPE, ACE_SYNCH_USE>::high_water_mark (void)
+{
+ ACE_TRACE ("ACE_Message_Queue_Ex<ACE_MESSAGE_TYPE, ACE_SYNCH_USE>::high_water_mark");
+
+ return this->queue_.high_water_mark ();
+}
+
+template <class ACE_MESSAGE_TYPE, ACE_SYNCH_DECL> ACE_INLINE void
+ACE_Message_Queue_Ex<ACE_MESSAGE_TYPE, ACE_SYNCH_USE>::high_water_mark (size_t hwm)
+{
+ ACE_TRACE ("ACE_Message_Queue_Ex<ACE_MESSAGE_TYPE, ACE_SYNCH_USE>::high_water_mark");
+
+ this->queue_.high_water_mark (hwm);
+}
+
+template <class ACE_MESSAGE_TYPE, ACE_SYNCH_DECL> ACE_INLINE size_t
+ACE_Message_Queue_Ex<ACE_MESSAGE_TYPE, ACE_SYNCH_USE>::low_water_mark (void)
+{
+ ACE_TRACE ("ACE_Message_Queue_Ex<ACE_MESSAGE_TYPE, ACE_SYNCH_USE>::low_water_mark");
+
+ return this->queue_.low_water_mark ();
+}
+
+template <class ACE_MESSAGE_TYPE, ACE_SYNCH_DECL> ACE_INLINE void
+ACE_Message_Queue_Ex<ACE_MESSAGE_TYPE, ACE_SYNCH_USE>::low_water_mark (size_t lwm)
+{
+ ACE_TRACE ("ACE_Message_Queue_Ex<ACE_MESSAGE_TYPE, ACE_SYNCH_USE>::low_water_mark");
+
+ this->queue_.low_water_mark (lwm);
+}
+
+template <class ACE_MESSAGE_TYPE, ACE_SYNCH_DECL> ACE_INLINE size_t
+ACE_Message_Queue_Ex<ACE_MESSAGE_TYPE, ACE_SYNCH_USE>::message_bytes (void)
+{
+ ACE_TRACE ("ACE_Message_Queue_Ex<ACE_MESSAGE_TYPE, ACE_SYNCH_USE>::message_bytes");
+
+ return this->queue_.message_bytes ();
+}
+
+template <class ACE_MESSAGE_TYPE, ACE_SYNCH_DECL> ACE_INLINE size_t
+ACE_Message_Queue_Ex<ACE_MESSAGE_TYPE, ACE_SYNCH_USE>::message_length (void)
+{
+ ACE_TRACE ("ACE_Message_Queue_Ex<ACE_MESSAGE_TYPE, ACE_SYNCH_USE>::message_length");
+
+ return this->queue_.message_length ();
+}
+
+template <class ACE_MESSAGE_TYPE, ACE_SYNCH_DECL> ACE_INLINE size_t
+ACE_Message_Queue_Ex<ACE_MESSAGE_TYPE, ACE_SYNCH_USE>::message_count (void)
+{
+ ACE_TRACE ("ACE_Message_Queue_Ex<ACE_MESSAGE_TYPE, ACE_SYNCH_USE>::message_count");
+
+ return this->queue_.message_count ();
+}
+
+template <class ACE_MESSAGE_TYPE, ACE_SYNCH_DECL> ACE_INLINE int
+ACE_Message_Queue_Ex<ACE_MESSAGE_TYPE, ACE_SYNCH_USE>::activate (void)
+{
+ ACE_TRACE ("ACE_Message_Queue_Ex<ACE_MESSAGE_TYPE, ACE_SYNCH_USE>::activate");
+
+ return this->queue_.activate ();
+}
+
+template <class ACE_MESSAGE_TYPE, ACE_SYNCH_DECL> ACE_INLINE int
+ACE_Message_Queue_Ex<ACE_MESSAGE_TYPE, ACE_SYNCH_USE>::deactivate (void)
+{
+ ACE_TRACE ("ACE_Message_Queue_Ex<ACE_MESSAGE_TYPE, ACE_SYNCH_USE>::deactivate");
+
+ return this->queue_.deactivate ();
+}
+
+template <class ACE_MESSAGE_TYPE, ACE_SYNCH_DECL> ACE_INLINE int
+ACE_Message_Queue_Ex<ACE_MESSAGE_TYPE, ACE_SYNCH_USE>::deactivated (void)
+{
+ ACE_TRACE ("ACE_Message_Queue_Ex<ACE_MESSAGE_TYPE, ACE_SYNCH_USE>::deactivated");
+
+ return this->queue_.deactivated ();
+}
+
+#if 0
+// The Sun Forte 6 (CC 5.1) compiler is only happy if this is in the
+// header file (j.russell.noseworthy@objectsciences.com)
+template <class ACE_MESSAGE_TYPE, ACE_SYNCH_DECL> ACE_INLINE ACE_SYNCH_MUTEX_T &
+ACE_Message_Queue_Ex<ACE_MESSAGE_TYPE, ACE_SYNCH_USE>::lock (void)
+{
+ return this->queue_.lock ();
+}
+#endif /* 0 */
diff --git a/ace/Streams/Module.cpp b/ace/Streams/Module.cpp
new file mode 100644
index 00000000000..e21b2cc49a6
--- /dev/null
+++ b/ace/Streams/Module.cpp
@@ -0,0 +1,266 @@
+// Module.cpp
+// $Id$
+
+#ifndef ACE_MODULE_C
+#define ACE_MODULE_C
+
+#include "ace/Module.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "ace/Stream_Modules.h"
+
+#if !defined (__ACE_INLINE__)
+#include "ace/Module.i"
+#endif /* __ACE_INLINE__ */
+
+ACE_RCSID(ace, Module, "$Id$")
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Module)
+
+template <ACE_SYNCH_DECL> void
+ACE_Module<ACE_SYNCH_USE>::dump (void) const
+{
+ ACE_TRACE ("ACE_Module<ACE_SYNCH_USE>::dump");
+}
+
+template <ACE_SYNCH_DECL> void
+ACE_Module<ACE_SYNCH_USE>::writer (ACE_Task<ACE_SYNCH_USE> *q,
+ int flags /* = M_DELETE_WRITER */)
+{
+ ACE_TRACE ("ACE_Module<ACE_SYNCH_USE>::writer");
+
+ // Close and maybe delete old writer
+ this->close_i (1, flags);
+
+ this->q_pair_[1] = q;
+
+ if (q != 0)
+ {
+ ACE_CLR_BITS (q->flags_, ACE_Task_Flags::ACE_READER);
+ // Set the q's module pointer to point to us.
+ q->mod_ = this;
+ }
+
+ // Don't allow the caller to change the reader status.
+ ACE_SET_BITS (flags_, (flags & M_DELETE_WRITER));
+}
+
+template <ACE_SYNCH_DECL> void
+ACE_Module<ACE_SYNCH_USE>::reader (ACE_Task<ACE_SYNCH_USE> *q,
+ int flags /* = M_DELETE_READER */)
+{
+ ACE_TRACE ("ACE_Module<ACE_SYNCH_USE>::reader");
+
+ // Close and maybe delete old writer
+ this->close_i (0, flags);
+
+ this->q_pair_[0] = q;
+
+ if (q != 0)
+ {
+ ACE_SET_BITS (q->flags_, ACE_Task_Flags::ACE_READER);
+ // Set the q's module pointer to point to us.
+ q->mod_ = this;
+ }
+
+ // don't allow the caller to change the reader status
+ ACE_SET_BITS (flags_, (flags & M_DELETE_READER));
+}
+
+// Link this ACE_Module on top of ACE_Module M.
+
+template <ACE_SYNCH_DECL> void
+ACE_Module<ACE_SYNCH_USE>::link (ACE_Module<ACE_SYNCH_USE> *m)
+{
+ ACE_TRACE ("ACE_Module<ACE_SYNCH_USE>::link");
+ this->next (m);
+ this->writer ()->next (m->writer ());
+ m->reader ()->next (this->reader ());
+}
+
+template <ACE_SYNCH_DECL> int
+ACE_Module<ACE_SYNCH_USE>::open (const ACE_TCHAR *mod_name,
+ ACE_Task<ACE_SYNCH_USE> *writer_q,
+ ACE_Task<ACE_SYNCH_USE> *reader_q,
+ void *arg,
+ int flags /* = M_DELETE */)
+{
+ ACE_TRACE ("ACE_Module<ACE_SYNCH_USE>::open");
+ this->name (mod_name);
+ this->arg_ = arg;
+
+ // We may already have readers and/or writers.
+ if (this->reader ())
+ this->close_i (0, M_DELETE_READER);
+
+ if (this->writer ())
+ this->close_i (1, M_DELETE_WRITER);
+
+ if (writer_q == 0)
+ {
+ ACE_NEW_RETURN (writer_q,
+ ACE_Thru_Task<ACE_SYNCH_USE>,
+ -1);
+ ACE_SET_BITS (flags, M_DELETE_WRITER);
+ }
+
+ if (reader_q == 0)
+ {
+ ACE_NEW_RETURN (reader_q,
+ ACE_Thru_Task<ACE_SYNCH_USE>,
+ -1);
+ ACE_SET_BITS (flags, M_DELETE_READER);
+ }
+
+ this->reader (reader_q);
+ this->writer (writer_q);
+
+ // Save the flags
+ this->flags_ = flags;
+
+ // Make sure that the memory is allocated before proceding.
+ if (writer_q == 0 || reader_q == 0)
+ {
+ // These calls will delete writer_q and/or reader_q, if
+ // necessary.
+ this->close_i (0, M_DELETE_READER);
+ this->close_i (1, M_DELETE_WRITER);
+
+ errno = ENOMEM;
+ return -1;
+ }
+
+ // Setup back pointers (this must come last, after we've made sure
+ // there's memory allocated here.
+ reader_q->mod_ = this;
+ writer_q->mod_ = this;
+
+ return 0;
+}
+
+// Set and get pointer to sibling ACE_Task in ACE_Module.
+
+template <ACE_SYNCH_DECL> ACE_Task<ACE_SYNCH_USE> *
+ACE_Module<ACE_SYNCH_USE>::sibling (ACE_Task<ACE_SYNCH_USE> *orig)
+{
+ ACE_TRACE ("ACE_Module<ACE_SYNCH_USE>::sibling");
+ if (this->q_pair_[0] == orig)
+ return this->q_pair_[1];
+ else if (this->q_pair_[1] == orig)
+ return this->q_pair_[0];
+ else
+ return 0;
+}
+
+template <ACE_SYNCH_DECL>
+ACE_Module<ACE_SYNCH_USE>::ACE_Module (void)
+ : flags_ (0)
+{
+ ACE_TRACE ("ACE_Module<ACE_SYNCH_USE>::ACE_Module");
+ this->name (ACE_LIB_TEXT ("<unknown>"));
+ // Do nothing...
+ this->q_pair_[0] = 0;
+ this->q_pair_[1] = 0;
+}
+
+template <ACE_SYNCH_DECL>
+ACE_Module<ACE_SYNCH_USE>::~ACE_Module (void)
+{
+ ACE_TRACE ("ACE_Module<ACE_SYNCH_USE>::~ACE_Module");
+
+ // Only close down if we haven't already done so.
+ if (this->reader () || this->writer ())
+ this->close ();
+}
+
+template <ACE_SYNCH_DECL>
+ACE_Module<ACE_SYNCH_USE>::ACE_Module (const ACE_TCHAR *mod_name,
+ ACE_Task<ACE_SYNCH_USE> *writer_q,
+ ACE_Task<ACE_SYNCH_USE> *reader_q,
+ void *args,
+ int flags /* = M_DELETE */)
+ : flags_ (0)
+{
+ ACE_TRACE ("ACE_Module<ACE_SYNCH_USE>::ACE_Module");
+
+ this->q_pair_[0] = 0;
+ this->q_pair_[1] = 0;
+
+ if (this->open (mod_name, writer_q, reader_q, args, flags) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("%p\n"),
+ ACE_LIB_TEXT ("ACE_Module")));
+}
+
+template <ACE_SYNCH_DECL> int
+ACE_Module<ACE_SYNCH_USE>::close (int flags /* = M_DELETE_NONE */)
+{
+ ACE_TRACE ("ACE_Module<ACE_SYNCH_USE>::close");
+
+ int result = 0;
+
+ ACE_SET_BITS (flags_, flags);
+
+ if (this->close_i (0, flags) == -1)
+ result = -1;
+
+ if (this->close_i (1, flags) == -1)
+ result = -1;
+
+ return result;
+}
+
+template <ACE_SYNCH_DECL> int
+ACE_Module<ACE_SYNCH_USE>::close_i (int which,
+ int flags)
+{
+ ACE_TRACE ("ACE_Module<ACE_SYNCH_USE>::close_i");
+
+ if (this->q_pair_[which] == 0)
+ return 0;
+
+ // Copy task pointer to prevent problems when ACE_Task::close
+ // changes the task pointer
+ ACE_Task<ACE_SYNCH_USE> *task = this->q_pair_[which];
+
+ // Change so that close doesn't get called again from the task base.
+
+ // Now close the task.
+ int result = 0;
+
+ if (task->module_closed () == -1)
+ result = -1;
+
+ task->flush ();
+ task->next (0);
+
+ // Should we also delete it ?
+ if (flags != M_DELETE_NONE
+ && ACE_BIT_ENABLED (flags_, which + 1))
+ {
+ // Only delete the Tasks if there aren't any more threads
+ // running in them.
+ task->wait ();
+
+ // If this assert happens it is likely because the task was
+ // activated with the THR_DETACHED flag, which means that we
+ // can't join() with the thread. Not using THR_DETACHED should
+ // solve this problem.
+ ACE_ASSERT (task->thr_count () == 0);
+
+ delete task;
+ }
+
+ // Set the tasks pointer to 0 so that we don't try to close()
+ // this object again if the destructor gets called.
+ this->q_pair_[which] = 0;
+
+ // Finally remove the delete bit.
+ ACE_CLR_BITS (flags_, which + 1);
+
+ return result;
+}
+#endif /* ACE_MODULE_C */
diff --git a/ace/Streams/Module.h b/ace/Streams/Module.h
new file mode 100644
index 00000000000..735220a55ba
--- /dev/null
+++ b/ace/Streams/Module.h
@@ -0,0 +1,207 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Module.h
+ *
+ * $Id$
+ *
+ * @author Doug Schmidt
+ */
+//=============================================================================
+
+
+#ifndef ACE_MODULE_H
+#define ACE_MODULE_H
+#include "ace/pre.h"
+
+#include "ace/ACE.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "ace/Task_T.h"
+
+/**
+ * @class ACE_Module_Base
+ *
+ * @brief Workaround HP/C++ compiler bug with enums in templates.
+ *
+ * Certain C++ compilers, e.g., the HP/UX 10.x and 9.x compilers,
+ * seem to fail if enums are defined inside a template, hence we
+ * have to move them into a base class.
+ */
+class ACE_Export ACE_Module_Base
+{
+public:
+ enum
+ {
+ /// Indicates that <close> should not delete any Tasks.
+ M_DELETE_NONE = 0,
+
+ /// Indicates that <close> should delete the writer Task.
+ M_DELETE_READER = 1,
+
+ /// Indicates that <close> should delete the reader Task.
+ M_DELETE_WRITER = 2,
+
+ /// Indicates that <close> deletes the Tasks.
+ /**
+ * Don't change this value without updating the same enum in class
+ * ACE_Stream...
+ * The <M_DELETE_READER> and <M_DELETE_WRITER> flags may be or'ed
+ * together.
+ */
+ M_DELETE = 3
+ };
+};
+
+/**
+ * @class ACE_Module
+ *
+ * @brief An abstraction for managing a bi-directional flow of messages.
+ *
+ * This is based on the Module concept in System V Streams,
+ * which contains a pair of Tasks, one for handling upstream
+ * processing, one for handling downstream processing. In
+ * general, you shouldn't subclass from this class, but instead
+ * subclass from the <ACE_Task>.
+ */
+template <ACE_SYNCH_DECL>
+class ACE_Module : public ACE_Module_Base
+{
+public:
+ friend class ACE_Shutup_GPlusPlus; // Turn off g++ warning
+
+ // = Initialization and termination methods.
+ /// Create an empty Module.
+ ACE_Module (void);
+
+ /// Shutdown the Module.
+ ~ACE_Module (void);
+
+ /// Create an initialized module with <module_name> as its identity
+ /// and <reader> and <writer> as its tasks.
+ ACE_Module (const ACE_TCHAR *module_name,
+ ACE_Task<ACE_SYNCH_USE> *writer = 0,
+ ACE_Task<ACE_SYNCH_USE> *reader = 0,
+ void *args = 0,
+ int flags = M_DELETE);
+
+ /**
+ * Create an initialized module with <module_name> as its identity
+ * and <reader> and <writer> as its tasks. Previously register
+ * reader or writers or closed down and deleted according to the
+ * value of flags_. Should not be called from within
+ * <ACE_Task::module_closed>.
+ */
+ int open (const ACE_TCHAR *module_name,
+ ACE_Task<ACE_SYNCH_USE> *writer = 0,
+ ACE_Task<ACE_SYNCH_USE> *reader = 0,
+ void *a = 0,
+ int flags = M_DELETE);
+
+ /**
+ * Close down the Module and its Tasks. The flags argument can be
+ * used to override the default behaviour, which depends on previous
+ * <flags> values in calls to c'tor, <open>, <reader>, and <writer>.
+ * A previous value M_DELETE[_XXX] can not be overridden. Should
+ * not be called from within <ACE_Task::module_closed>.
+ */
+ int close (int flags = M_DELETE_NONE);
+
+ // = ACE_Task manipulation routines
+ /// Get the writer task.
+ ACE_Task<ACE_SYNCH_USE> *writer (void);
+
+ /**
+ * Set the writer task. <flags> can be used to indicate that the
+ * module should delete the writer during a call to close or to the
+ * destructor. If a previous writer exists, it is closed. It may
+ * also be deleted, depending on the old flags_ value. Should not
+ * be called from within <ACE_Task::module_closed>.
+ */
+ void writer (ACE_Task<ACE_SYNCH_USE> *q, int flags = M_DELETE_WRITER);
+
+ /// Get the reader task.
+ ACE_Task<ACE_SYNCH_USE> *reader (void);
+
+ /**
+ * Set the reader task. <flags> can be used to indicate that the
+ * module should delete the reader during a call to close or to the
+ * destructor. If a previous reader exists, it is closed. It may
+ * also be deleted, depending on the old flags_ value. Should not
+ * be called from within <ACE_Task::module_closed>.
+ */
+ void reader (ACE_Task<ACE_SYNCH_USE> *q, int flags = M_DELETE_READER);
+
+ /// Set and get pointer to sibling <ACE_Task> in an <ACE_Module>
+ ACE_Task<ACE_SYNCH_USE> *sibling (ACE_Task<ACE_SYNCH_USE> *orig);
+
+ // = Identify the module
+ /// Get the module name.
+ /// Set the module name.
+ const ACE_TCHAR *name (void) const;
+ void name (const ACE_TCHAR *);
+
+ // = Argument to the Tasks.
+ /// Get the argument passed to the tasks.
+ void *arg (void) const;
+
+ /// Set the argument passed to the tasks.
+ void arg (void *);
+
+ /// Link to other modules in the ustream stack
+ void link (ACE_Module<ACE_SYNCH_USE> *m);
+
+ /// Get the next pointer to the module above in the stream.
+ ACE_Module<ACE_SYNCH_USE> *next (void);
+
+ /// Set the next pointer to the module above in the stream.
+ void next (ACE_Module<ACE_SYNCH_USE> *m);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+private:
+ /// Implements the close operation for either the reader or the
+ /// writer task (depending on <which>).
+ int close_i (int which, int flags);
+
+ /// Pair of Tasks that form the "read-side" and "write-side" of the
+ /// ACE_Module partitioning.
+ ACE_Task<ACE_SYNCH_USE> *q_pair_[2];
+
+ /// Name of the ACE_Module.
+ ACE_TCHAR name_[MAXNAMLEN + 1];
+
+ /// Next ACE_Module in the stack.
+ ACE_Module<ACE_SYNCH_USE> *next_;
+
+ /// Argument passed through to the reader and writer task when they
+ /// are opened.
+ void *arg_;
+
+ /// Holds flags which are used to determine if the reader and writer
+ /// task have to be deleted on exit
+ int flags_;
+};
+
+#if defined (__ACE_INLINE__)
+#include "ace/Module.i"
+#endif /* __ACE_INLINE__ */
+
+#if defined (ACE_TEMPLATES_REQUIRE_SOURCE)
+#include "ace/Module.cpp"
+#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */
+
+#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA)
+#pragma implementation ("Module.cpp")
+#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */
+
+#include "ace/post.h"
+#endif /* ACE_MODULE_H */
diff --git a/ace/Streams/Module.i b/ace/Streams/Module.i
new file mode 100644
index 00000000000..f0ecad5881c
--- /dev/null
+++ b/ace/Streams/Module.i
@@ -0,0 +1,62 @@
+/* -*- C++ -*- */
+// $Id$
+
+// Module.i
+
+template <ACE_SYNCH_DECL> ACE_INLINE void *
+ACE_Module<ACE_SYNCH_USE>::arg (void) const
+{
+ ACE_TRACE ("ACE_Module<ACE_SYNCH_USE>::arg");
+ return this->arg_;
+}
+
+template <ACE_SYNCH_DECL> ACE_INLINE void
+ACE_Module<ACE_SYNCH_USE>::arg (void *a)
+{
+ ACE_TRACE ("ACE_Module<ACE_SYNCH_USE>::arg");
+ this->arg_ = a;
+}
+
+template <ACE_SYNCH_DECL> ACE_INLINE const ACE_TCHAR *
+ACE_Module<ACE_SYNCH_USE>::name (void) const
+{
+ ACE_TRACE ("ACE_Module<ACE_SYNCH_USE>::name");
+ return this->name_;
+}
+
+template <ACE_SYNCH_DECL> ACE_INLINE void
+ACE_Module<ACE_SYNCH_USE>::name (const ACE_TCHAR *n)
+{
+ ACE_TRACE ("ACE_Module<ACE_SYNCH_USE>::name");
+ ACE_OS::strsncpy (this->name_, n, MAXNAMLEN);
+}
+
+template <ACE_SYNCH_DECL> ACE_INLINE ACE_Task<ACE_SYNCH_USE> *
+ACE_Module<ACE_SYNCH_USE>::writer (void)
+{
+ ACE_TRACE ("ACE_Module<ACE_SYNCH_USE>::writer");
+ return this->q_pair_[1];
+}
+
+template <ACE_SYNCH_DECL> ACE_INLINE ACE_Task<ACE_SYNCH_USE> *
+ACE_Module<ACE_SYNCH_USE>::reader (void)
+{
+ ACE_TRACE ("ACE_Module<ACE_SYNCH_USE>::reader");
+ return this->q_pair_[0];
+}
+
+template <ACE_SYNCH_DECL> ACE_INLINE ACE_Module<ACE_SYNCH_USE> *
+ACE_Module<ACE_SYNCH_USE>::next (void)
+{
+ ACE_TRACE ("ACE_Module<ACE_SYNCH_USE>::next");
+ return this->next_;
+}
+
+template <ACE_SYNCH_DECL> ACE_INLINE void
+ACE_Module<ACE_SYNCH_USE>::next (ACE_Module<ACE_SYNCH_USE> *m)
+{
+ ACE_TRACE ("ACE_Module<ACE_SYNCH_USE>::next");
+ this->next_ = m;
+}
+
+
diff --git a/ace/Streams/Notification_Strategy.cpp b/ace/Streams/Notification_Strategy.cpp
new file mode 100644
index 00000000000..77d5dc235b0
--- /dev/null
+++ b/ace/Streams/Notification_Strategy.cpp
@@ -0,0 +1,18 @@
+#include "ace/Notification_Strategy.h"
+
+#if !defined (__ACE_INLINE__)
+#include "ace/Notification_Strategy.inl"
+#endif /* __ACE_INLINE __ */
+
+ACE_RCSID(ace, Strategies, "$Id$")
+
+ACE_Notification_Strategy::ACE_Notification_Strategy (ACE_Event_Handler *eh,
+ ACE_Reactor_Mask mask)
+ : eh_ (eh),
+ mask_ (mask)
+{
+}
+
+ACE_Notification_Strategy::~ACE_Notification_Strategy (void)
+{
+}
diff --git a/ace/Streams/Notification_Strategy.h b/ace/Streams/Notification_Strategy.h
new file mode 100644
index 00000000000..e1ec8b3f034
--- /dev/null
+++ b/ace/Streams/Notification_Strategy.h
@@ -0,0 +1,63 @@
+/* -*- C++ -*- */
+//=============================================================================
+/**
+ * @file Notification_Strategy.h
+ *
+ * $Id$
+ *
+ * @author Doug Schmidt
+ */
+//=============================================================================
+#ifndef ACE_NOTIFICATION_STRATEGY_H
+#define ACE_NOTIFICATION_STRATEGY_H
+#include "ace/pre.h"
+
+#include "ace/Event_Handler.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+// Forward decls.
+class ACE_Reactor;
+
+/**
+ * @class ACE_Notification_Strategy
+ *
+ * @brief Abstract class used for notifying an interested party
+ *
+ * A vehicle for extending the behavior of ACE_Message_Queue wrt
+ * notification *without subclassing*. Thus, it's an example of
+ * the Bridge/Strategy patterns.
+ */
+class ACE_Export ACE_Notification_Strategy
+{
+public:
+ ACE_Notification_Strategy (ACE_Event_Handler *eh,
+ ACE_Reactor_Mask mask);
+ virtual ~ACE_Notification_Strategy (void);
+
+ virtual int notify (void) = 0;
+ virtual int notify (ACE_Event_Handler *,
+ ACE_Reactor_Mask mask) = 0;
+
+ // Get/Set the event handler
+ ACE_Event_Handler *event_handler (void);
+ void event_handler (ACE_Event_Handler *eh);
+
+ // Get/Set the reactor mask
+ ACE_Reactor_Mask mask (void);
+ void mask (ACE_Reactor_Mask m);
+
+protected:
+ ACE_Event_Handler *eh_;
+ ACE_Reactor_Mask mask_;
+};
+
+
+#if defined (__ACE_INLINE__)
+#include "ace/Notification_Strategy.inl"
+#endif /* __ACE_INLINE __ */
+
+#include "ace/post.h"
+#endif /*ACE_NOTIFICATION_STRATEGY_H */
diff --git a/ace/Streams/Notification_Strategy.inl b/ace/Streams/Notification_Strategy.inl
new file mode 100644
index 00000000000..aa89acddcbb
--- /dev/null
+++ b/ace/Streams/Notification_Strategy.inl
@@ -0,0 +1,26 @@
+/* -*- C++ -*- */
+//$Id$
+
+ACE_INLINE ACE_Event_Handler *
+ACE_Notification_Strategy::event_handler (void)
+{
+ return eh_;
+}
+
+ACE_INLINE void
+ACE_Notification_Strategy::event_handler (ACE_Event_Handler *eh)
+{
+ this->eh_ = eh;
+}
+
+ACE_INLINE ACE_Reactor_Mask
+ACE_Notification_Strategy::mask (void)
+{
+ return mask_;
+}
+
+ACE_INLINE void
+ACE_Notification_Strategy::mask (ACE_Reactor_Mask m)
+{
+ this->mask_ = m;
+}
diff --git a/ace/Streams/Read_Buffer.cpp b/ace/Streams/Read_Buffer.cpp
new file mode 100644
index 00000000000..2b88461446e
--- /dev/null
+++ b/ace/Streams/Read_Buffer.cpp
@@ -0,0 +1,162 @@
+// $Id$
+
+#include "ace/Read_Buffer.h"
+#include "ace/Service_Config.h"
+
+#if !defined (__ACE_INLINE__)
+#include "ace/Read_Buffer.i"
+#endif /* __ACE_INLINE__ */
+
+ACE_RCSID(ace, Read_Buffer, "$Id$")
+
+void
+ACE_Read_Buffer::dump (void) const
+{
+ ACE_TRACE ("ACE_Read_Buffer::dump");
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("size_ = %d"), this->size_));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\noccurrences_ = %d"), this->occurrences_));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\nstream_ = %x"), this->stream_));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\nallocator_ = %x"), this->allocator_));
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+ACE_Read_Buffer::ACE_Read_Buffer (FILE *fp,
+ int close_on_delete,
+ ACE_Allocator *alloc)
+ : stream_ (fp),
+ close_on_delete_ (close_on_delete),
+ allocator_ (alloc)
+{
+ ACE_TRACE ("ACE_Read_Buffer::ACE_Read_Buffer");
+ if (this->allocator_ == 0)
+ this->allocator_ = ACE_Allocator::instance ();
+}
+
+ACE_Read_Buffer::ACE_Read_Buffer (ACE_HANDLE handle,
+ int close_on_delete,
+ ACE_Allocator *alloc)
+ : stream_ (ACE_OS::fdopen (handle, ACE_LIB_TEXT ("r"))),
+ close_on_delete_ (close_on_delete),
+ allocator_ (alloc)
+{
+ ACE_TRACE ("ACE_Read_Buffer::ACE_Read_Buffer");
+
+ if (this->allocator_ == 0)
+ this->allocator_ = ACE_Allocator::instance ();
+}
+
+ACE_Read_Buffer::~ACE_Read_Buffer (void)
+{
+ ACE_TRACE ("ACE_Read_Buffer::~ACE_Read_Buffer");
+
+ if (this->close_on_delete_)
+ ACE_OS::fclose (this->stream_);
+}
+
+// Input: term the character to terminate on
+// search the character to search for
+// replace the character with which to replace search
+// Output: a buffer containing the contents of stream
+// Method: call the recursive helper function read_helper
+
+char *
+ACE_Read_Buffer::read (int term, int search, int replace)
+{
+ ACE_TRACE ("ACE_Read_Buffer::read");
+ this->occurrences_ = 0;
+ this->size_ = 0;
+ return this->rec_read (term, search, replace);
+}
+
+// Input: term the termination character
+// search the character to search for
+// replace the character with which to replace search
+// Purpose: read in a file to a buffer using only a single dynamic
+// allocation.
+// Method: read until the local buffer is full and then recurse.
+// Must continue until the termination character is reached.
+// Allocate the final buffer based on the number of local
+// buffers read and as the recursive calls bottom out,
+// copy them in reverse order into the allocated buffer.
+
+char *
+ACE_Read_Buffer::rec_read (int term, int search, int replace)
+{
+ ACE_TRACE ("ACE_Read_Buffer::rec_read");
+ // This is our temporary workspace.
+ char buf[BUFSIZ];
+
+ int c = EOF;
+ size_t slot = 0;
+ int done = 0;
+
+ // Read in the file char by char
+ while (slot < BUFSIZ)
+ {
+ c = getc (this->stream_);
+
+ // Don't insert EOF into the buffer...
+ if (c == EOF)
+ {
+ ungetc (c, this->stream_);
+ break;
+ }
+ else if (c == term)
+ done = 1;
+
+ // Check for possible substitutions.
+ if (c == search)
+ {
+ this->occurrences_++;
+
+ if (replace >= 0)
+ c = replace;
+ }
+
+ buf[slot++] = (char) c;
+
+ // Substitutions must be made before checking for termination.
+ if (done)
+ break;
+ }
+
+ // Increment the number of bytes.
+ this->size_ += slot;
+
+ // Don't bother going any farther if the total size is 0.
+ if (this->size_ == 0)
+ return 0;
+
+ char *result;
+
+ // Recurse, when the recursion bottoms out, allocate the result
+ // buffer.
+ if (done || c == EOF)
+ {
+ // Use the allocator to acquire the memory. The + 1 allows
+ // space for the null terminator.
+ result = (char *) this->allocator_->malloc (this->size_ + 1);
+
+ if (result == 0)
+ {
+ errno = ENOMEM;
+ return 0;
+ }
+ result += this->size_;
+
+ // Null terminate the buffer.
+ *result = '\0';
+ }
+ else if ((result = this->rec_read (term, search, replace)) == 0)
+ return 0;
+
+
+ // Copy buf into the appropriate location starting from end of
+ // buffer. Peter says this is confusing and that we should use
+ // memcpy() ;-)
+ for (size_t j = slot; j > 0; j--)
+ *--result = buf[j - 1];
+
+ return result;
+}
diff --git a/ace/Streams/Read_Buffer.h b/ace/Streams/Read_Buffer.h
new file mode 100644
index 00000000000..ad1bef9fa32
--- /dev/null
+++ b/ace/Streams/Read_Buffer.h
@@ -0,0 +1,114 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Read_Buffer.h
+ *
+ * $Id$
+ *
+ * @author Doug Schmidt and Seth Widoff
+ */
+//=============================================================================
+
+
+#ifndef ACE_READ_BUFFER_H
+#define ACE_READ_BUFFER_H
+#include "ace/pre.h"
+
+#include "ace/ACE.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "ace/Malloc.h"
+
+/**
+ * @class ACE_Read_Buffer
+ *
+ * @brief Efficiently reads an artibrarily large buffer from an input
+ * stream up to and including a termination character. Also
+ * performs search/replace on single occurrences a character in
+ * the buffer using the principles of Integrated Layer
+ * Processing.
+ *
+ * This implementation is optimized to do a single dynamic
+ * allocation and make only one copy of the data. It uses
+ * recursion and the run-time stack to accomplish this
+ * efficiently.
+ */
+class ACE_Export ACE_Read_Buffer
+{
+public:
+ // = Initialization and termination methods.
+ /// Read from a FILE *.
+ ACE_Read_Buffer (FILE *fp,
+ int close_on_delete = 0,
+ ACE_Allocator * = 0);
+
+ /// Read from an open HANDLE.
+ ACE_Read_Buffer (ACE_HANDLE handle,
+ int close_on_delete = 0,
+ ACE_Allocator * = 0);
+
+ /// Closes the FILE *.
+ ~ACE_Read_Buffer (void);
+
+ /**
+ * Returns a pointer dynamically allocated with
+ * <ACE_Allocator::malloc> to data from the input stream up to (and
+ * including) the <terminator>. If <search> is >= 0 then all
+ * occurrences of the <search> value are substituted with the
+ * <replace> value. The last of the byte of data is a 0, so that
+ * <strlen> can be used on it. The caller is responsible for
+ * freeing the pointer returned from this method using the
+ * <ACE_Allocator::free>.
+ */
+ char *read (int terminator = EOF,
+ int search = '\n',
+ int replace = '\0');
+
+ /// Returns the number of characters replaced during a <read>.
+ size_t replaced (void) const;
+
+ /// Returns the size of the allocated buffer obtained during a
+ /// <read>, not including the null terminator.
+ size_t size (void) const;
+
+ /// Returns a pointer to its allocator.
+ ACE_Allocator *alloc (void) const;
+
+ /// Dump the state of the object.
+ void dump (void) const;
+
+private:
+ /// Recursive helper method that does the work...
+ char *rec_read (int term, int search, int replace);
+
+ /// The total number of characters in the buffer.
+ size_t size_;
+
+ /// The total number of characters replaced.
+ size_t occurrences_;
+
+ /// The stream we are reading from.
+ FILE *stream_;
+
+ /// Keeps track of whether we should close the FILE in the
+ /// destructor.
+ int close_on_delete_;
+
+ /// Pointer to the allocator.
+ ACE_Allocator *allocator_;
+
+ // = Disallow copying and assignment...
+ ACE_UNIMPLEMENTED_FUNC (void operator= (const ACE_Read_Buffer &))
+ ACE_UNIMPLEMENTED_FUNC (ACE_Read_Buffer (const ACE_Read_Buffer &))
+};
+
+#if defined (__ACE_INLINE__)
+# include "ace/Read_Buffer.i"
+#endif /* __ACE_INLINE__ */
+
+#include "ace/post.h"
+#endif /* ACE_READ_BUFFER_H */
diff --git a/ace/Streams/Read_Buffer.i b/ace/Streams/Read_Buffer.i
new file mode 100644
index 00000000000..3534c62db2e
--- /dev/null
+++ b/ace/Streams/Read_Buffer.i
@@ -0,0 +1,28 @@
+/* -*- C++ -*- */
+// $Id$
+
+// Accessor to the number of bytes in the buffer.
+
+ACE_INLINE size_t
+ACE_Read_Buffer::size (void) const
+{
+ ACE_TRACE ("ACE_Read_Buffer::size");
+ return this->size_;
+}
+
+// The total number of characters replaced.
+
+ACE_INLINE size_t
+ACE_Read_Buffer::replaced (void) const
+{
+ ACE_TRACE ("ACE_Read_Buffer::replaced");
+ return this->occurrences_;
+}
+
+ACE_INLINE ACE_Allocator *
+ACE_Read_Buffer::alloc (void) const
+{
+ ACE_TRACE ("ACE_Read_Buffer::alloc");
+ return this->allocator_;
+}
+
diff --git a/ace/Streams/Stream.cpp b/ace/Streams/Stream.cpp
new file mode 100644
index 00000000000..f72ebd4acfb
--- /dev/null
+++ b/ace/Streams/Stream.cpp
@@ -0,0 +1,614 @@
+// Stream.cpp
+// $Id$
+
+#ifndef ACE_STREAM_C
+#define ACE_STREAM_C
+
+//#include "ace/Module.h"
+#include "ace/Stream.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "ace/Stream_Modules.h"
+
+#if !defined (__ACE_INLINE__)
+#include "ace/Stream.i"
+#endif /* __ACE_INLINE__ */
+
+ACE_RCSID(ace, Stream, "$Id$")
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Stream)
+
+// Give some idea of what the heck is going on in a stream!
+
+template <ACE_SYNCH_DECL> void
+ACE_Stream<ACE_SYNCH_USE>::dump (void) const
+{
+ ACE_TRACE ("ACE_Stream<ACE_SYNCH_USE>::dump");
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("-------- module links --------\n")));
+
+ for (ACE_Module<ACE_SYNCH_USE> *mp = this->stream_head_;
+ ;
+ mp = mp->next ())
+ {
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("module name = %s\n"), mp->name ()));
+ if (mp == this->stream_tail_)
+ break;
+ }
+
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("-------- writer links --------\n")));
+
+ ACE_Task<ACE_SYNCH_USE> *tp;
+
+ for (tp = this->stream_head_->writer ();
+ ;
+ tp = tp->next ())
+ {
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("writer queue name = %s\n"), tp->name ()));
+ tp->dump ();
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("-------\n")));
+ if (tp == this->stream_tail_->writer ()
+ || (this->linked_us_
+ && tp == this->linked_us_->stream_head_->reader ()))
+ break;
+ }
+
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("-------- reader links --------\n")));
+ for (tp = this->stream_tail_->reader (); ; tp = tp->next ())
+ {
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("reader queue name = %s\n"), tp->name ()));
+ tp->dump ();
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("-------\n")));
+ if (tp == this->stream_head_->reader ()
+ || (this->linked_us_
+ && tp == this->linked_us_->stream_head_->writer ()))
+ break;
+ }
+}
+
+template <ACE_SYNCH_DECL> int
+ACE_Stream<ACE_SYNCH_USE>::push (ACE_Module<ACE_SYNCH_USE> *new_top)
+{
+ ACE_TRACE ("ACE_Stream<ACE_SYNCH_USE>::push");
+ if (this->push_module (new_top,
+ this->stream_head_->next (),
+ this->stream_head_) == -1)
+ return -1;
+ else
+ return 0;
+}
+
+template <ACE_SYNCH_DECL> int
+ACE_Stream<ACE_SYNCH_USE>::put (ACE_Message_Block *mb, ACE_Time_Value *tv)
+{
+ ACE_TRACE ("ACE_Stream<ACE_SYNCH_USE>::put");
+ return this->stream_head_->writer ()->put (mb, tv);
+}
+
+template <ACE_SYNCH_DECL> int
+ACE_Stream<ACE_SYNCH_USE>::get (ACE_Message_Block *&mb, ACE_Time_Value *tv)
+{
+ ACE_TRACE ("ACE_Stream<ACE_SYNCH_USE>::get");
+ return this->stream_head_->reader ()->getq (mb, tv);
+}
+
+// Return the "top" ACE_Module in a ACE_Stream, skipping over the
+// stream_head.
+
+template <ACE_SYNCH_DECL> int
+ACE_Stream<ACE_SYNCH_USE>::top (ACE_Module<ACE_SYNCH_USE> *&m)
+{
+ ACE_TRACE ("ACE_Stream<ACE_SYNCH_USE>::top");
+ if (this->stream_head_->next () == this->stream_tail_)
+ return -1;
+ else
+ {
+ m = this->stream_head_->next ();
+ return 0;
+ }
+}
+
+template <ACE_SYNCH_DECL> int
+ACE_Stream<ACE_SYNCH_USE>::insert (const ACE_TCHAR *prev_name,
+ ACE_Module<ACE_SYNCH_USE> *mod)
+{
+ ACE_TRACE ("ACE_Stream<ACE_SYNCH_USE>::insert");
+
+ for (ACE_Module<ACE_SYNCH_USE> *prev_mod = this->stream_head_;
+ prev_mod != 0;
+ prev_mod = prev_mod->next ())
+ if (ACE_OS::strcmp (prev_mod->name (), prev_name) == 0)
+ {
+ ACE_Module<ACE_SYNCH_USE> *next_mod = prev_mod->next ();
+
+ // We can't insert a module below <stream_tail_>.
+ if (next_mod == 0)
+ return -1;
+
+ mod->link (next_mod);
+ prev_mod->link (mod);
+
+ if (mod->reader ()->open (mod->arg ()) == -1)
+ return -1;
+
+ if (mod->writer ()->open (mod->arg ()) == -1)
+ return -1;
+
+ return 0;
+ }
+
+ return -1;
+}
+
+template <ACE_SYNCH_DECL> int
+ACE_Stream<ACE_SYNCH_USE>::replace (const ACE_TCHAR *replace_name,
+ ACE_Module<ACE_SYNCH_USE> *mod,
+ int flags)
+{
+ ACE_TRACE ("ACE_Stream<ACE_SYNCH_USE>::replace");
+ ACE_Module<ACE_SYNCH_USE> *prev_mod = 0;
+
+ for (ACE_Module<ACE_SYNCH_USE> *rep_mod = this->stream_head_;
+ rep_mod != 0;
+ rep_mod = rep_mod->next ())
+ if (ACE_OS::strcmp (rep_mod->name (), replace_name) == 0)
+ {
+ ACE_Module<ACE_SYNCH_USE> *next_mod = rep_mod->next ();
+
+ if (next_mod)
+ mod->link (next_mod);
+ else // In case the <next_mod> is <stream_tail_>.
+ {
+ mod->writer ()->next (0);
+ mod->next (0);
+ this->stream_tail_ = mod;
+ }
+
+ if (prev_mod)
+ prev_mod->link (mod);
+ else // In case the <rep_mod> is <stream_head_>.
+ {
+ mod->reader ()->next (0);
+ this->stream_head_ = mod;
+ }
+
+ if (mod->reader ()->open (mod->arg ()) == -1)
+ return -1;
+
+ if (mod->writer ()->open (mod->arg ()) == -1)
+ return -1;
+
+ if (flags != ACE_Module<ACE_SYNCH_USE>::M_DELETE_NONE)
+ {
+ rep_mod->close (flags);
+ delete rep_mod;
+ }
+
+ return 0;
+ }
+ else
+ prev_mod = rep_mod;
+
+ return -1;
+}
+
+// Remove the "top" ACE_Module in a ACE_Stream, skipping over the
+// stream_head.
+
+template <ACE_SYNCH_DECL> int
+ACE_Stream<ACE_SYNCH_USE>::pop (int flags)
+{
+ ACE_TRACE ("ACE_Stream<ACE_SYNCH_USE>::pop");
+ if (this->stream_head_->next () == this->stream_tail_)
+ return -1;
+ else
+ {
+ // Skip over the ACE_Stream head.
+ ACE_Module<ACE_SYNCH_USE> *top_mod = this->stream_head_->next ();
+ ACE_Module<ACE_SYNCH_USE> *new_top = top_mod->next ();
+
+ this->stream_head_->next (new_top);
+
+ // Close the top ACE_Module.
+
+ top_mod->close (flags);
+
+ // Don't delete the Module unless the flags request this.
+ if (flags != ACE_Module<ACE_SYNCH_USE>::M_DELETE_NONE)
+ delete top_mod;
+
+ this->stream_head_->writer ()->next (new_top->writer ());
+ new_top->reader ()->next (this->stream_head_->reader ());
+ return 0;
+ }
+}
+
+// Remove a named ACE_Module from an arbitrary place in the
+// ACE_Stream.
+
+template <ACE_SYNCH_DECL> int
+ACE_Stream<ACE_SYNCH_USE>::remove (const ACE_TCHAR *name,
+ int flags)
+{
+ ACE_TRACE ("ACE_Stream<ACE_SYNCH_USE>::remove");
+ ACE_Module<ACE_SYNCH_USE> *prev = 0;
+
+ for (ACE_Module<ACE_SYNCH_USE> *mod = this->stream_head_;
+ mod != 0;
+ mod = mod->next ())
+ if (ACE_OS::strcmp (mod->name (), name) == 0)
+ {
+ if (prev == 0) // Deleting ACE_Stream Head
+ this->stream_head_->link (mod->next ());
+ else
+ prev->link (mod->next ());
+
+ // Don't delete the Module unless the flags request this.
+ if (flags != ACE_Module<ACE_SYNCH_USE>::M_DELETE_NONE)
+ {
+ // Close down the module and release the memory.
+ mod->close (flags);
+ delete mod;
+ }
+
+ return 0;
+ }
+ else
+ prev = mod;
+
+ return -1;
+}
+
+template <ACE_SYNCH_DECL> ACE_Module<ACE_SYNCH_USE> *
+ACE_Stream<ACE_SYNCH_USE>::find (const ACE_TCHAR *name)
+{
+ ACE_TRACE ("ACE_Stream<ACE_SYNCH_USE>::find");
+ for (ACE_Module<ACE_SYNCH_USE> *mod = this->stream_head_;
+ mod != 0;
+ mod = mod->next ())
+ if (ACE_OS::strcmp (mod->name (), name) == 0)
+ return mod;
+
+ return 0;
+}
+
+// Actually push a module onto the stack...
+
+template <ACE_SYNCH_DECL> int
+ACE_Stream<ACE_SYNCH_USE>::push_module (ACE_Module<ACE_SYNCH_USE> *new_top,
+ ACE_Module<ACE_SYNCH_USE> *current_top,
+ ACE_Module<ACE_SYNCH_USE> *head)
+{
+ ACE_TRACE ("ACE_Stream<ACE_SYNCH_USE>::push_module");
+ ACE_Task<ACE_SYNCH_USE> *nt_reader = new_top->reader ();
+ ACE_Task<ACE_SYNCH_USE> *nt_writer = new_top->writer ();
+ ACE_Task<ACE_SYNCH_USE> *ct_reader = 0;
+ ACE_Task<ACE_SYNCH_USE> *ct_writer = 0;
+
+ if (current_top)
+ {
+ ct_reader = current_top->reader ();
+ ct_writer = current_top->writer ();
+ ct_reader->next (nt_reader);
+ }
+
+ nt_writer->next (ct_writer);
+
+ if (head)
+ {
+ if (head != new_top)
+ head->link (new_top);
+ }
+ else
+ nt_reader->next (0);
+
+ new_top->next (current_top);
+
+ if (nt_reader->open (new_top->arg ()) == -1)
+ return -1;
+
+ if (nt_writer->open (new_top->arg ()) == -1)
+ return -1;
+ return 0;
+}
+
+template <ACE_SYNCH_DECL> int
+ACE_Stream<ACE_SYNCH_USE>::open (void *a,
+ ACE_Module<ACE_SYNCH_USE> *head,
+ ACE_Module<ACE_SYNCH_USE> *tail)
+{
+ ACE_TRACE ("ACE_Stream<ACE_SYNCH_USE>::open");
+ ACE_GUARD_RETURN (ACE_SYNCH_MUTEX_T, ace_mon, this->lock_, -1);
+
+ ACE_Task<ACE_SYNCH_USE> *h1 = 0, *h2 = 0;
+ ACE_Task<ACE_SYNCH_USE> *t1 = 0, *t2 = 0;
+
+ if (head == 0)
+ {
+ ACE_NEW_RETURN (h1,
+ ACE_Stream_Head<ACE_SYNCH_USE>,
+ -1);
+ ACE_NEW_RETURN (h2,
+ ACE_Stream_Head<ACE_SYNCH_USE>,
+ -1);
+ ACE_NEW_RETURN (head,
+ ACE_Module<ACE_SYNCH_USE> (ACE_LIB_TEXT ("ACE_Stream_Head"),
+ h1, h2,
+ a,
+ M_DELETE),
+ -1);
+ }
+
+ if (tail == 0)
+ {
+ ACE_NEW_RETURN (t1,
+ ACE_Stream_Tail<ACE_SYNCH_USE>,
+ -1);
+ ACE_NEW_RETURN (t2,
+ ACE_Stream_Tail<ACE_SYNCH_USE>,
+ -1);
+ ACE_NEW_RETURN (tail,
+ ACE_Module<ACE_SYNCH_USE> (ACE_LIB_TEXT ("ACE_Stream_Tail"),
+ t1, t2,
+ a,
+ M_DELETE),
+ -1);
+ }
+
+ // Make sure *all* the allocation succeeded!
+ if (head == 0 && (h1 == 0 || h2 == 0)
+ || tail == 0 && (t1 == 0 || t2 == 0))
+ {
+ delete h1;
+ delete h2;
+ delete t1;
+ delete t2;
+ delete head;
+ delete tail;
+ errno = ENOMEM;
+ return -1;
+ }
+
+ this->stream_head_ = head;
+ this->stream_tail_ = tail;
+
+ if (this->push_module (this->stream_tail_) == -1)
+ return -1;
+ else if (this->push_module (this->stream_head_,
+ this->stream_tail_,
+ this->stream_head_) == -1)
+ return -1;
+
+ return 0;
+}
+
+template <ACE_SYNCH_DECL> int
+ACE_Stream<ACE_SYNCH_USE>::close (int flags)
+{
+ ACE_TRACE ("ACE_Stream<ACE_SYNCH_USE>::close");
+ ACE_GUARD_RETURN (ACE_SYNCH_MUTEX_T, ace_mon, this->lock_, -1);
+
+ if (this->stream_head_ != 0
+ && this->stream_tail_ != 0)
+ {
+ // Don't bother checking return value here.
+ this->unlink_i ();
+
+ int result = 0;
+
+ // Remove and cleanup all the intermediate modules.
+
+ while (this->stream_head_->next () != this->stream_tail_)
+ if (this->pop (flags) == -1)
+ result = -1;
+
+ // Clean up the head and tail of the stream.
+ if (this->stream_head_->close (flags) == -1)
+ result = -1;
+ if (this->stream_tail_->close (flags) == -1)
+ result = -1;
+
+ // Cleanup the memory.
+ delete this->stream_head_;
+ delete this->stream_tail_;
+
+ this->stream_head_ = 0;
+ this->stream_tail_ = 0;
+
+ // Tell all threads waiting on the close that we are done.
+ this->final_close_.broadcast ();
+ return result;
+ }
+ return 0;
+}
+
+template <ACE_SYNCH_DECL> int
+ACE_Stream<ACE_SYNCH_USE>::control (ACE_IO_Cntl_Msg::ACE_IO_Cntl_Cmds cmd,
+ void *a)
+{
+ ACE_TRACE ("ACE_Stream<ACE_SYNCH_USE>::control");
+ ACE_IO_Cntl_Msg ioc (cmd);
+
+ ACE_Message_Block *db;
+
+ // Try to create a data block that contains the user-supplied data.
+ ACE_NEW_RETURN (db,
+ ACE_Message_Block (sizeof (int),
+ ACE_Message_Block::MB_IOCTL,
+ 0,
+ (char *) a),
+ -1);
+ // Try to create a control block <cb> that contains the control
+ // field and a pointer to the data block <db> in <cb>'s continuation
+ // field.
+ ACE_Message_Block *cb = 0;
+
+ ACE_NEW_RETURN (cb,
+ ACE_Message_Block (sizeof ioc,
+ ACE_Message_Block::MB_IOCTL,
+ db,
+ (char *) &ioc),
+ -1);
+ // @@ Michael: The old semantic assumed that cb returns == 0
+ // if no memory was available. We will now return immediately
+ // without release (errno is set to ENOMEM by the macro).
+
+ // If we can't allocate <cb> then we need to delete db and return
+ // -1.
+ if (cb == 0)
+ {
+ db->release ();
+ errno = ENOMEM;
+ return -1;
+ }
+
+ int result;
+
+ if (this->stream_head_->writer ()->put (cb) == -1)
+ result = -1;
+ else if (this->stream_head_->reader ()->getq (cb) == -1)
+ result = -1;
+ else
+ result = ((ACE_IO_Cntl_Msg *) cb->rd_ptr ())->rval ();
+
+ // This will also release db if it's reference count == 0.
+ cb->release ();
+
+ return result;
+}
+
+// Link two streams together at their bottom-most Modules (i.e., the
+// one just above the Stream tail). Note that all of this is premised
+// on the fact that the Stream head and Stream tail are non-NULL...
+// This must be called with locks held.
+
+template <ACE_SYNCH_DECL> int
+ACE_Stream<ACE_SYNCH_USE>::link_i (ACE_Stream<ACE_SYNCH_USE> &us)
+{
+ ACE_TRACE ("ACE_Stream<ACE_SYNCH_USE>::link_i");
+ this->linked_us_ = &us;
+ // Make sure the other side is also linked to us!
+ us.linked_us_ = this;
+
+ ACE_Module<ACE_SYNCH_USE> *my_tail = this->stream_head_;
+
+ if (my_tail == 0)
+ return -1;
+
+ // Locate the module just above our Stream tail.
+ while (my_tail->next () != this->stream_tail_)
+ my_tail = my_tail->next ();
+
+ ACE_Module<ACE_SYNCH_USE> *other_tail = us.stream_head_;
+
+ if (other_tail == 0)
+ return -1;
+
+ // Locate the module just above the other Stream's tail.
+ while (other_tail->next () != us.stream_tail_)
+ other_tail = other_tail->next ();
+
+ // Reattach the pointers so that the two streams are linked!
+ my_tail->writer ()->next (other_tail->reader ());
+ other_tail->writer ()->next (my_tail->reader ());
+ return 0;
+}
+
+template <ACE_SYNCH_DECL> int
+ACE_Stream<ACE_SYNCH_USE>::link (ACE_Stream<ACE_SYNCH_USE> &us)
+{
+ ACE_TRACE ("ACE_Stream<ACE_SYNCH_USE>::link");
+
+ ACE_GUARD_RETURN (ACE_SYNCH_MUTEX_T, ace_mon, this->lock_, -1);
+
+ return this->link_i (us);
+}
+
+// Must be called with locks held...
+
+template <ACE_SYNCH_DECL> int
+ACE_Stream<ACE_SYNCH_USE>::unlink_i (void)
+{
+ ACE_TRACE ("ACE_Stream<ACE_SYNCH_USE>::unlink_i");
+
+ // Only try to unlink if we are in fact still linked!
+
+ if (this->linked_us_ != 0)
+ {
+ ACE_Module<ACE_SYNCH_USE> *my_tail = this->stream_head_;
+
+ // Only relink if we still exist!
+ if (my_tail)
+ {
+ // Find the module that's just before our stream tail.
+ while (my_tail->next () != this->stream_tail_)
+ my_tail = my_tail->next ();
+
+ // Restore the writer's next() link to our tail.
+ my_tail->writer ()->next (this->stream_tail_->writer ());
+ }
+
+ ACE_Module<ACE_SYNCH_USE> *other_tail =
+ this->linked_us_->stream_head_;
+
+ // Only fiddle with the other side if it in fact still remains.
+ if (other_tail != 0)
+ {
+ while (other_tail->next () != this->linked_us_->stream_tail_)
+ other_tail = other_tail->next ();
+
+ other_tail->writer ()->next (this->linked_us_->stream_tail_->writer ());
+
+ }
+
+ // Make sure the other side is also aware that it's been unlinked!
+ this->linked_us_->linked_us_ = 0;
+
+ this->linked_us_ = 0;
+ return 0;
+ }
+ else
+ return -1;
+}
+
+template <ACE_SYNCH_DECL> int
+ACE_Stream<ACE_SYNCH_USE>::unlink (void)
+{
+ ACE_TRACE ("ACE_Stream<ACE_SYNCH_USE>::unlink");
+ ACE_GUARD_RETURN (ACE_SYNCH_MUTEX_T, ace_mon, this->lock_, -1);
+ return this->unlink_i ();
+}
+
+template <ACE_SYNCH_DECL>
+ACE_Stream<ACE_SYNCH_USE>::ACE_Stream (void * a,
+ ACE_Module<ACE_SYNCH_USE> *head,
+ ACE_Module<ACE_SYNCH_USE> *tail)
+ : linked_us_ (0),
+ final_close_ (this->lock_)
+{
+ ACE_TRACE ("ACE_Stream<ACE_SYNCH_USE>::ACE_Stream");
+ if (this->open (a, head, tail) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("ACE_Stream<ACE_SYNCH_USE>::open (%s, %s)\n"),
+ head->name (), tail->name ()));
+}
+
+template <ACE_SYNCH_DECL>
+ACE_Stream<ACE_SYNCH_USE>::~ACE_Stream (void)
+{
+ ACE_TRACE ("ACE_Stream<ACE_SYNCH_USE>::~ACE_Stream");
+
+ if (this->stream_head_ != 0)
+ this->close ();
+}
+
+template <ACE_SYNCH_DECL>
+ACE_Stream_Iterator<ACE_SYNCH_USE>::ACE_Stream_Iterator (const ACE_Stream<ACE_SYNCH_USE> &sr)
+ : next_ (sr.stream_head_)
+{
+ ACE_TRACE ("ACE_Stream_Iterator<ACE_SYNCH_USE>::ACE_Stream_Iterator");
+}
+
+#endif /* ACE_STREAM_C */
diff --git a/ace/Streams/Stream.h b/ace/Streams/Stream.h
new file mode 100644
index 00000000000..f4f432e10f3
--- /dev/null
+++ b/ace/Streams/Stream.h
@@ -0,0 +1,232 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Stream.h
+ *
+ * $Id$
+ *
+ * @author Doug Schmidt <schmidt@uci.edu>
+ */
+//=============================================================================
+
+
+#ifndef ACE_STREAM_H
+#define ACE_STREAM_H
+#include "ace/pre.h"
+
+#include "ace/ACE.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "ace/IO_Cntl_Msg.h"
+#include "ace/Message_Block.h"
+#include "ace/Time_Value.h"
+#include "ace/Module.h"
+
+// Forward decls.
+template<ACE_SYNCH_DECL> class ACE_Stream_Iterator;
+
+/**
+ * @class ACE_Stream
+ *
+ * @brief This class is the primary abstraction for the ASX framework.
+ * It is moduled after System V Stream.
+ *
+ * A Stream consists of a stack of <ACE_Modules>, each of which
+ * contains two <ACE_Tasks>. Even though the methods in this
+ * class are virtual, this class isn't really intended for
+ * subclassing unless you know what you are doing. In
+ * particular, the <ACE_Stream> destructor calls <close>, which
+ * won't be overridden properly unless you call it in a subclass
+ * destructor.
+ */
+template <ACE_SYNCH_DECL>
+class ACE_Stream
+{
+public:
+ friend class ACE_Stream_Iterator<ACE_SYNCH_USE>;
+
+ enum
+ {
+ /// Indicates that <close> deletes the Tasks. Don't change this
+ /// value without updating the same enum in class ACE_Module...
+ M_DELETE = 3
+ };
+
+ // = Initializatation and termination methods.
+ /**
+ * Create a Stream consisting of <head> and <tail> as the Stream
+ * head and Stream tail, respectively. If these are 0 then the
+ * <ACE_Stream_Head> and <ACE_Stream_Tail> are used, respectively.
+ * <arg> is the value past in to the <open> methods of the tasks.
+ */
+ ACE_Stream (void *arg = 0,
+ ACE_Module<ACE_SYNCH_USE> *head = 0,
+ ACE_Module<ACE_SYNCH_USE> *tail = 0);
+
+ /**
+ * Create a Stream consisting of <head> and <tail> as the Stream
+ * head and Stream tail, respectively. If these are 0 then the
+ * <ACE_Stream_Head> and <ACE_Stream_Tail> are used, respectively.
+ * <arg> is the value past in to the <open> methods of the tasks.
+ */
+ virtual int open (void *arg,
+ ACE_Module<ACE_SYNCH_USE> *head = 0,
+ ACE_Module<ACE_SYNCH_USE> *tail = 0);
+
+ /// Close down the stream and release all the resources.
+ virtual int close (int flags = M_DELETE);
+
+ /// Close down the stream and release all the resources.
+ virtual ~ACE_Stream (void);
+
+ // = ACE_Stream plumbing operations
+
+ /// Add a new module <mod> right below the Stream head.
+ virtual int push (ACE_Module<ACE_SYNCH_USE> *mod);
+
+ /// Remove the <mod> right below the Stream head and close it down.
+ virtual int pop (int flags = M_DELETE);
+
+ /// Return the top module on the stream (right below the stream
+ /// head).
+ virtual int top (ACE_Module<ACE_SYNCH_USE> *&mod);
+
+ /// Insert a new module <mod> below the named module <prev_name>.
+ virtual int insert (const ACE_TCHAR *prev_name,
+ ACE_Module<ACE_SYNCH_USE> *mod);
+
+ /// Replace the named module <replace_name> with a new module <mod>.
+ virtual int replace (const ACE_TCHAR *replace_name,
+ ACE_Module<ACE_SYNCH_USE> *mod,
+ int flags = M_DELETE);
+
+ /// Remove the named module <mod> from the stream. This bypasses the
+ /// strict LIFO ordering of <push> and <pop>.
+ virtual int remove (const ACE_TCHAR *mod,
+ int flags = M_DELETE);
+
+ /// Return current stream head.
+ virtual ACE_Module<ACE_SYNCH_USE> *head (void);
+
+ /// Return current stream tail.
+ virtual ACE_Module<ACE_SYNCH_USE> *tail (void);
+
+ /// Find a particular ACE_Module.
+ virtual ACE_Module<ACE_SYNCH_USE> *find (const ACE_TCHAR *mod);
+
+ /// Create a pipe between two Streams.
+ virtual int link (ACE_Stream<ACE_SYNCH_USE> &);
+
+ /// Remove a pipe formed between two Streams.
+ virtual int unlink (void);
+
+ // = Blocking data transfer operations
+ /**
+ * Send the message <mb> down the stream, starting at the Module
+ * below the Stream head. Wait for upto <timeout> amount of
+ * absolute time for the operation to complete (or block forever if
+ * <timeout> == 0).
+ */
+ virtual int put (ACE_Message_Block *mb,
+ ACE_Time_Value *timeout = 0);
+
+ /**
+ * Read the message <mb> that is stored in the the stream head.
+ * Wait for upto <timeout> amount of absolute time for the operation
+ * to complete (or block forever if <timeout> == 0).
+ */
+ virtual int get (ACE_Message_Block *&mb,
+ ACE_Time_Value *timeout = 0);
+
+ /// Send control message down the stream.
+ virtual int control (ACE_IO_Cntl_Msg::ACE_IO_Cntl_Cmds cmd,
+ void *args);
+
+ /// Synchronize with the final close of the stream.
+ virtual int wait (void);
+
+ /// Dump the state of an object.
+ virtual void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+private:
+ /// Actually perform the unlinking of two Streams (must be called
+ /// with locks held).
+ int unlink_i (void);
+
+ /// Actually perform the linking of two Streams (must be called with
+ /// locks held).
+ int link_i (ACE_Stream<ACE_SYNCH_USE> &);
+
+ /// Must a new module onto the Stream.
+ int push_module (ACE_Module<ACE_SYNCH_USE> *,
+ ACE_Module<ACE_SYNCH_USE> * = 0,
+ ACE_Module<ACE_SYNCH_USE> * = 0);
+
+ /// Pointer to the head of the stream.
+ ACE_Module<ACE_SYNCH_USE> *stream_head_;
+
+ /// Pointer to the tail of the stream.
+ ACE_Module<ACE_SYNCH_USE> *stream_tail_;
+
+ /// Pointer to an adjoining linked stream.
+ ACE_Stream<ACE_SYNCH_USE> *linked_us_;
+
+ // = Synchronization objects used for thread-safe streams.
+ /// Protect the stream against race conditions.
+ ACE_SYNCH_MUTEX_T lock_;
+
+ /// Use to tell all threads waiting on the close that we are done.
+ ACE_SYNCH_CONDITION_T final_close_;
+};
+
+/**
+ * @class ACE_Stream_Iterator
+ *
+ * @brief Iterate through an <ACE_Stream>.
+ */
+template <ACE_SYNCH_DECL>
+class ACE_Stream_Iterator
+{
+public:
+ // = Initialization method.
+ ACE_Stream_Iterator (const ACE_Stream<ACE_SYNCH_USE> &sr);
+
+ // = Iteration methods.
+
+ /// Pass back the <next_item> that hasn't been seen in the set.
+ /// Returns 0 when all items have been seen, else 1.
+ int next (const ACE_Module<ACE_SYNCH_USE> *&next_item);
+
+ /// Returns 1 when all items have been seen, else 0.
+ int done (void) const;
+
+ /// Move forward by one element in the set. Returns 0 when all the
+ /// items in the set have been seen, else 1.
+ int advance (void);
+
+private:
+ /// Next <Module> that we haven't yet seen.
+ ACE_Module<ACE_SYNCH_USE> *next_;
+};
+
+#if defined (__ACE_INLINE__)
+#include "ace/Stream.i"
+#endif /* __ACE_INLINE__ */
+
+#if defined (ACE_TEMPLATES_REQUIRE_SOURCE)
+#include "ace/Stream.cpp"
+#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */
+
+#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA)
+#pragma implementation ("Stream.cpp")
+#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */
+
+#include "ace/post.h"
+#endif /* ACE_STREAM_H */
diff --git a/ace/Streams/Stream.i b/ace/Streams/Stream.i
new file mode 100644
index 00000000000..42a4989eff0
--- /dev/null
+++ b/ace/Streams/Stream.i
@@ -0,0 +1,49 @@
+/* -*- C++ -*- */
+// $Id$
+
+// Stream.i
+
+template <ACE_SYNCH_DECL> ACE_INLINE ACE_Module<ACE_SYNCH_USE> *
+ACE_Stream<ACE_SYNCH_USE>::head (void)
+{
+ ACE_TRACE ("ACE_Stream<ACE_SYNCH_USE>::head");
+ return this->stream_head_;
+}
+
+template <ACE_SYNCH_DECL> ACE_INLINE ACE_Module<ACE_SYNCH_USE> *
+ACE_Stream<ACE_SYNCH_USE>::tail (void)
+{
+ ACE_TRACE ("ACE_Stream<ACE_SYNCH_USE>::tail");
+ return this->stream_tail_;
+}
+
+template <ACE_SYNCH_DECL> ACE_INLINE int
+ACE_Stream<ACE_SYNCH_USE>::wait (void)
+{
+ ACE_TRACE ("ACE_Stream<ACE_SYNCH_USE>::wait");
+ return this->final_close_.wait ();
+}
+
+template <ACE_SYNCH_DECL> ACE_INLINE int
+ACE_Stream_Iterator<ACE_SYNCH_USE>::next (const ACE_Module<ACE_SYNCH_USE> *&mod)
+{
+ ACE_TRACE ("ACE_Stream_Iterator<ACE_SYNCH_USE>::next");
+ mod = this->next_;
+ return this->next_ != 0;
+}
+
+template <ACE_SYNCH_DECL> ACE_INLINE int
+ACE_Stream_Iterator<ACE_SYNCH_USE>::done (void) const
+{
+ ACE_TRACE ("ACE_Stream_Iterator<ACE_SYNCH_USE>::done");
+ return this->next_ == 0;
+}
+
+template <ACE_SYNCH_DECL> int
+ACE_Stream_Iterator<ACE_SYNCH_USE>::advance (void)
+{
+ ACE_TRACE ("ACE_Stream_Iterator<ACE_SYNCH_USE>::advance");
+ this->next_ = this->next_->next ();
+ return this->next_ != 0;
+}
+
diff --git a/ace/Streams/Stream_Modules.cpp b/ace/Streams/Stream_Modules.cpp
new file mode 100644
index 00000000000..859e2369839
--- /dev/null
+++ b/ace/Streams/Stream_Modules.cpp
@@ -0,0 +1,369 @@
+// Stream_Modules.cpp
+// $Id$
+
+#ifndef ACE_STREAM_MODULES_C
+#define ACE_STREAM_MODULES_C
+
+#include "ace/Stream_Modules.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+ACE_RCSID(ace, Stream_Modules, "$Id$")
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Stream_Head)
+
+template <ACE_SYNCH_DECL>
+ACE_Stream_Head<ACE_SYNCH_USE>::ACE_Stream_Head (void)
+{
+ ACE_TRACE ("ACE_Stream_Head<ACE_SYNCH_USE>::ACE_Stream_Head");
+}
+
+template <ACE_SYNCH_DECL>
+ACE_Stream_Head<ACE_SYNCH_USE>::~ACE_Stream_Head (void)
+{
+ ACE_TRACE ("ACE_Stream_Head<ACE_SYNCH_USE>::~ACE_Stream_Head");
+}
+
+template <ACE_SYNCH_DECL> void
+ACE_Stream_Head<ACE_SYNCH_USE>::dump (void) const
+{
+ ACE_TRACE ("ACE_Stream_Head<ACE_SYNCH_USE>::dump");
+}
+
+// ACE_Module that act as the head and tail of a Stream.
+
+template <ACE_SYNCH_DECL> int
+ACE_Stream_Head<ACE_SYNCH_USE>::open (void *)
+{
+ ACE_TRACE ("ACE_Stream_Head<ACE_SYNCH_USE>::open");
+ return 0;
+}
+
+template <ACE_SYNCH_DECL> int
+ACE_Stream_Head<ACE_SYNCH_USE>::close (u_long)
+{
+ ACE_TRACE ("ACE_Stream_Head<ACE_SYNCH_USE>::close");
+ return 0;
+}
+
+template <ACE_SYNCH_DECL> int
+ACE_Stream_Head<ACE_SYNCH_USE>::svc (void)
+{
+ ACE_TRACE ("ACE_Stream_Head<ACE_SYNCH_USE>::svc");
+ return -1;
+}
+
+template <ACE_SYNCH_DECL> int
+ACE_Stream_Head<ACE_SYNCH_USE>::control (ACE_Message_Block *mb)
+{
+ ACE_TRACE ("ACE_Stream_Head<ACE_SYNCH_USE>::control");
+ ACE_IO_Cntl_Msg *ioc = (ACE_IO_Cntl_Msg *) mb->rd_ptr ();
+ ACE_IO_Cntl_Msg::ACE_IO_Cntl_Cmds cmd;
+
+ switch (cmd = ioc->cmd ())
+ {
+ case ACE_IO_Cntl_Msg::SET_LWM:
+ case ACE_IO_Cntl_Msg::SET_HWM:
+ this->water_marks (cmd, *(size_t *) mb->cont ()->rd_ptr ());
+ ioc->rval (0);
+ break;
+ default:
+ return 0;
+ }
+ return ioc->rval ();
+}
+
+// Performs canonical flushing at the ACE_Stream Head.
+
+template <ACE_SYNCH_DECL> int
+ACE_Stream_Head<ACE_SYNCH_USE>::canonical_flush (ACE_Message_Block *mb)
+{
+ ACE_TRACE ("ACE_Stream_Head<ACE_SYNCH_USE>::canonical_flush");
+ char *cp = mb->rd_ptr ();
+
+ if (ACE_BIT_ENABLED (*cp, ACE_Task_Flags::ACE_FLUSHR))
+ {
+ this->flush (ACE_Task_Flags::ACE_FLUSHALL);
+ ACE_CLR_BITS (*cp, ACE_Task_Flags::ACE_FLUSHR);
+ }
+
+ if (ACE_BIT_ENABLED (*cp, ACE_Task_Flags::ACE_FLUSHW))
+ return this->reply (mb);
+ else
+ mb->release ();
+ return 0;
+}
+
+template <ACE_SYNCH_DECL> int
+ACE_Stream_Head<ACE_SYNCH_USE>::put (ACE_Message_Block *mb,
+ ACE_Time_Value *tv)
+{
+ ACE_TRACE ("ACE_Stream_Head<ACE_SYNCH_USE>::put");
+ int res = 0;
+
+ if (mb->msg_type () == ACE_Message_Block::MB_IOCTL
+ && (res = this->control (mb)) == -1)
+ return res;
+
+ if (this->is_writer ())
+ return this->put_next (mb, tv);
+ else // this->is_reader ()
+ {
+ switch (mb->msg_type ())
+ {
+ case ACE_Message_Block::MB_FLUSH:
+ return this->canonical_flush (mb);
+ default:
+ break;
+ }
+
+ return this->putq (mb, tv);
+ }
+}
+
+template <ACE_SYNCH_DECL> int
+ACE_Stream_Head<ACE_SYNCH_USE>::init (int, ACE_TCHAR *[])
+{
+ ACE_TRACE ("ACE_Stream_Head<ACE_SYNCH_USE>::init");
+ return 0;
+}
+
+template <ACE_SYNCH_DECL> int
+ACE_Stream_Head<ACE_SYNCH_USE>::info (ACE_TCHAR **strp, size_t length) const
+{
+ ACE_TRACE ("ACE_Stream_Head<ACE_SYNCH_USE>::info");
+ const ACE_TCHAR *name = this->name ();
+
+ if (*strp == 0 && (*strp = ACE_OS::strdup (name)) == 0)
+ return -1;
+ else
+ ACE_OS::strsncpy (*strp, name, length);
+ return ACE_OS::strlen (name);
+}
+
+template <ACE_SYNCH_DECL> int
+ACE_Stream_Head<ACE_SYNCH_USE>::fini (void)
+{
+ ACE_TRACE ("ACE_Stream_Head<ACE_SYNCH_USE>::fini");
+ return 0;
+}
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Stream_Tail)
+
+template <ACE_SYNCH_DECL>
+ACE_Stream_Tail<ACE_SYNCH_USE>::ACE_Stream_Tail (void)
+{
+ ACE_TRACE ("ACE_Stream_Tail<ACE_SYNCH_USE>::ACE_Stream_Tail");
+}
+
+template <ACE_SYNCH_DECL>
+ACE_Stream_Tail<ACE_SYNCH_USE>::~ACE_Stream_Tail (void)
+{
+ ACE_TRACE ("ACE_Stream_Tail<ACE_SYNCH_USE>::~ACE_Stream_Tail");
+}
+
+template <ACE_SYNCH_DECL> void
+ACE_Stream_Tail<ACE_SYNCH_USE>::dump (void) const
+{
+ ACE_TRACE ("ACE_Stream_Tail<ACE_SYNCH_USE>::dump");
+}
+
+template <ACE_SYNCH_DECL> int
+ACE_Stream_Tail<ACE_SYNCH_USE>::open (void *)
+{
+ ACE_TRACE ("ACE_Stream_Tail<ACE_SYNCH_USE>::open");
+ return 0;
+}
+
+template <ACE_SYNCH_DECL> int
+ACE_Stream_Tail<ACE_SYNCH_USE>::close (u_long)
+{
+ ACE_TRACE ("ACE_Stream_Tail<ACE_SYNCH_USE>::close");
+ return 0;
+}
+
+template <ACE_SYNCH_DECL> int
+ACE_Stream_Tail<ACE_SYNCH_USE>::svc (void)
+{
+ ACE_TRACE ("ACE_Stream_Tail<ACE_SYNCH_USE>::svc");
+ return -1;
+}
+
+template <ACE_SYNCH_DECL> int
+ACE_Stream_Tail<ACE_SYNCH_USE>::control (ACE_Message_Block *mb)
+{
+ ACE_TRACE ("ACE_Stream_Tail<ACE_SYNCH_USE>::control");
+ ACE_IO_Cntl_Msg *ioc = (ACE_IO_Cntl_Msg *) mb->rd_ptr ();
+ ACE_IO_Cntl_Msg::ACE_IO_Cntl_Cmds cmd;
+
+ switch (cmd = ioc->cmd ())
+ {
+ case ACE_IO_Cntl_Msg::SET_LWM:
+ case ACE_IO_Cntl_Msg::SET_HWM:
+ {
+ size_t wm_size = *(size_t *) mb->cont ()->rd_ptr ();
+
+ this->water_marks (cmd, wm_size);
+ this->sibling ()->water_marks (cmd, wm_size);
+ ioc->rval (0);
+ break;
+ }
+ default:
+ mb->msg_type (ACE_Message_Block::MB_IOCNAK);
+ }
+ return this->reply (mb);
+}
+
+// Perform flush algorithm as though we were the driver.
+
+template <ACE_SYNCH_DECL> int
+ACE_Stream_Tail<ACE_SYNCH_USE>::canonical_flush (ACE_Message_Block *mb)
+{
+ ACE_TRACE ("ACE_Stream_Tail<ACE_SYNCH_USE>::canonical_flush");
+ char *cp = mb->rd_ptr ();
+
+ if (ACE_BIT_ENABLED (*cp, ACE_Task_Flags::ACE_FLUSHW))
+ {
+ this->flush (ACE_Task_Flags::ACE_FLUSHALL);
+ ACE_CLR_BITS (*cp, ACE_Task_Flags::ACE_FLUSHW);
+ }
+
+ if (ACE_BIT_ENABLED (*cp, ACE_Task_Flags::ACE_FLUSHR))
+ {
+ this->sibling ()->flush (ACE_Task_Flags::ACE_FLUSHALL);
+ return this->reply (mb);
+ }
+ else
+ mb->release ();
+
+ return 0;
+}
+
+template <ACE_SYNCH_DECL> int
+ACE_Stream_Tail<ACE_SYNCH_USE>::put (ACE_Message_Block *mb,
+ ACE_Time_Value *)
+{
+ ACE_TRACE ("ACE_Stream_Tail<ACE_SYNCH_USE>::put");
+
+ if (this->is_writer ())
+ {
+ switch (mb->msg_type ())
+ {
+ case ACE_Message_Block::MB_IOCTL:
+ return this->control (mb);
+ /* NOTREACHED */
+ default:
+ mb->release ();
+ }
+ }
+
+ return -1;
+}
+
+template <ACE_SYNCH_DECL> int
+ACE_Stream_Tail<ACE_SYNCH_USE>::init (int, ACE_TCHAR *[])
+{
+ ACE_TRACE ("ACE_Stream_Tail<ACE_SYNCH_USE>::init");
+ return 0;
+}
+
+template <ACE_SYNCH_DECL> int
+ACE_Stream_Tail<ACE_SYNCH_USE>::info (ACE_TCHAR **strp, size_t length) const
+{
+ ACE_TRACE ("ACE_Stream_Tail<ACE_SYNCH_USE>::info");
+ const ACE_TCHAR *name = this->name ();
+
+ if (*strp == 0 && (*strp = ACE_OS::strdup (name)) == 0)
+ return -1;
+ else
+ ACE_OS::strsncpy (*strp, name, length);
+ return ACE_OS::strlen (name);
+}
+
+template <ACE_SYNCH_DECL> int
+ACE_Stream_Tail<ACE_SYNCH_USE>::fini (void)
+{
+ ACE_TRACE ("ACE_Stream_Tail<ACE_SYNCH_USE>::fini");
+ return 0;
+}
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Thru_Task)
+
+template <ACE_SYNCH_DECL>
+ACE_Thru_Task<ACE_SYNCH_USE>::ACE_Thru_Task (void)
+{
+ ACE_TRACE ("ACE_Thru_Task<ACE_SYNCH_USE>::ACE_Thru_Task");
+}
+
+template <ACE_SYNCH_DECL>
+ACE_Thru_Task<ACE_SYNCH_USE>::~ACE_Thru_Task (void)
+{
+ ACE_TRACE ("ACE_Thru_Task<ACE_SYNCH_USE>::~ACE_Thru_Task");
+}
+
+template <ACE_SYNCH_DECL> void
+ACE_Thru_Task<ACE_SYNCH_USE>::dump (void) const
+{
+ ACE_TRACE ("ACE_Thru_Task<ACE_SYNCH_USE>::dump");
+}
+
+template <ACE_SYNCH_DECL> int
+ACE_Thru_Task<ACE_SYNCH_USE>::open (void *)
+{
+ ACE_TRACE ("ACE_Thru_Task<ACE_SYNCH_USE>::open");
+ return 0;
+}
+
+template <ACE_SYNCH_DECL> int
+ACE_Thru_Task<ACE_SYNCH_USE>::close (u_long)
+{
+ ACE_TRACE ("ACE_Thru_Task<ACE_SYNCH_USE>::close");
+ return 0;
+}
+
+template <ACE_SYNCH_DECL> int
+ACE_Thru_Task<ACE_SYNCH_USE>::svc (void)
+{
+ ACE_TRACE ("ACE_Thru_Task<ACE_SYNCH_USE>::svc");
+ return -1;
+}
+
+template <ACE_SYNCH_DECL> int
+ACE_Thru_Task<ACE_SYNCH_USE>::put (ACE_Message_Block *msg,
+ ACE_Time_Value *tv)
+{
+ ACE_TRACE ("ACE_Thru_Task<ACE_SYNCH_USE>::put");
+ return this->put_next (msg, tv);
+}
+
+template <ACE_SYNCH_DECL> int
+ACE_Thru_Task<ACE_SYNCH_USE>::init (int, ACE_TCHAR *[])
+{
+ ACE_TRACE ("ACE_Thru_Task<ACE_SYNCH_USE>::init");
+ return 0;
+}
+
+template <ACE_SYNCH_DECL> int
+ACE_Thru_Task<ACE_SYNCH_USE>::info (ACE_TCHAR **strp,
+ size_t length) const
+{
+ ACE_TRACE ("ACE_Thru_Task<ACE_SYNCH_USE>::info");
+ const ACE_TCHAR *name = this->name ();
+
+ if (*strp == 0 && (*strp = ACE_OS::strdup (name)) == 0)
+ return -1;
+ else
+ ACE_OS::strsncpy (*strp, name, length);
+ return ACE_OS::strlen (name);
+}
+
+template <ACE_SYNCH_DECL> int
+ACE_Thru_Task<ACE_SYNCH_USE>::fini (void)
+{
+ ACE_TRACE ("ACE_Thru_Task<ACE_SYNCH_USE>::fini");
+ return 0;
+}
+
+#endif /* ACE_STREAM_MODULES_C */
diff --git a/ace/Streams/Stream_Modules.h b/ace/Streams/Stream_Modules.h
new file mode 100644
index 00000000000..1cf2ef4e6ad
--- /dev/null
+++ b/ace/Streams/Stream_Modules.h
@@ -0,0 +1,144 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Stream_Modules.h
+ *
+ * $Id$
+ *
+ * @author Doug Schmidt
+ */
+//=============================================================================
+
+
+// This needs to go outside of the #if !defined() block. Don't ask...
+#include "ace/Task.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#ifndef ACE_STREAM_MODULES
+#define ACE_STREAM_MODULES
+#include "ace/pre.h"
+
+/**
+ * @class ACE_Stream_Head
+ *
+ * @brief Standard module that acts as the head of a ustream.
+ */
+template <ACE_SYNCH_DECL>
+class ACE_Stream_Head : public ACE_Task<ACE_SYNCH_USE>
+{
+public:
+ /// Construction
+ ACE_Stream_Head (void);
+
+ /// Destruction
+ ~ACE_Stream_Head (void);
+
+ // = ACE_Task hooks
+ virtual int open (void *a = 0);
+ virtual int close (u_long flags = 0);
+ virtual int put (ACE_Message_Block *msg, ACE_Time_Value * = 0);
+ virtual int svc (void);
+
+ // = Dynamic linking hooks
+ virtual int init (int argc, ACE_TCHAR *argv[]);
+ virtual int info (ACE_TCHAR **info_string, size_t length) const;
+ virtual int fini (void);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+private:
+ /// Performs canonical flushing at the ACE_Stream Head.
+ int control (ACE_Message_Block *);
+ int canonical_flush (ACE_Message_Block *);
+};
+
+/**
+ * @class ACE_Stream_Tail
+ *
+ * @brief Standard module that acts as the head of a ustream.
+ */
+template <ACE_SYNCH_DECL>
+class ACE_Stream_Tail : public ACE_Task<ACE_SYNCH_USE>
+{
+public:
+ /// Construction
+ ACE_Stream_Tail (void);
+
+ /// Destruction
+ ~ACE_Stream_Tail (void);
+
+ // = ACE_Task hooks
+ virtual int open (void *a = 0);
+ virtual int close (u_long flags = 0);
+ virtual int put (ACE_Message_Block *msg, ACE_Time_Value * = 0);
+ virtual int svc (void);
+
+ // = Dynamic linking hooks
+ virtual int init (int argc, ACE_TCHAR *argv[]);
+ virtual int info (ACE_TCHAR **info_string, size_t length) const;
+ virtual int fini (void);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+private:
+ /// Performs canonical flushing at the ACE_Stream tail.
+ int control (ACE_Message_Block *);
+ int canonical_flush (ACE_Message_Block *);
+};
+
+/**
+ * @class ACE_Thru_Task
+ *
+ * @brief Standard module that acts as a "no op", simply passing on all
+ * data to its adjacent neighbor.
+ */
+template <ACE_SYNCH_DECL>
+class ACE_Thru_Task : public ACE_Task<ACE_SYNCH_USE>
+{
+public:
+ /// Construction
+ ACE_Thru_Task (void);
+
+ /// Destruction
+ ~ACE_Thru_Task (void);
+
+ // = ACE_Task hooks
+ virtual int open (void *a = 0);
+ virtual int close (u_long flags = 0);
+ virtual int put (ACE_Message_Block *msg, ACE_Time_Value * = 0);
+ virtual int svc (void);
+
+ // = Dynamic linking hooks
+ virtual int init (int argc, ACE_TCHAR *argv[]);
+ virtual int info (ACE_TCHAR **info_string, size_t length) const;
+ virtual int fini (void);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+};
+
+#if defined (ACE_TEMPLATES_REQUIRE_SOURCE)
+#include "ace/Stream_Modules.cpp"
+#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */
+
+#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA)
+#pragma implementation ("Stream_Modules.cpp")
+#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */
+
+#include "ace/post.h"
+#endif /* ACE_STREAM_MODULES */
diff --git a/ace/Streams/Task.cpp b/ace/Streams/Task.cpp
new file mode 100644
index 00000000000..b073c27eaed
--- /dev/null
+++ b/ace/Streams/Task.cpp
@@ -0,0 +1,227 @@
+// $Id$
+
+#include "ace/Task.h"
+#include "ace/Module.h"
+
+#if !defined (__ACE_INLINE__)
+#include "ace/Task.i"
+#endif /* __ACE_INLINE__ */
+
+ACE_RCSID(ace, Task, "$Id$")
+
+ACE_Task_Base::~ACE_Task_Base (void)
+{
+}
+
+ACE_Task_Base::ACE_Task_Base (ACE_Thread_Manager *thr_man)
+ : thr_count_ (0),
+ thr_mgr_ (thr_man),
+ flags_ (0),
+ grp_id_ (-1)
+{
+}
+
+// Wait for all threads running in a task to exit.
+
+int
+ACE_Task_Base::wait (void)
+{
+ ACE_TRACE ("ACE_Task_Base::wait");
+
+ // If we don't have a thread manager, we probably were never
+ // activated.
+ if (this->thr_mgr () != 0)
+ return this->thr_mgr ()->wait_task (this);
+ else
+ return 0;
+}
+
+// Suspend a task.
+int
+ACE_Task_Base::suspend (void)
+{
+ ACE_TRACE ("ACE_Task_Base::suspend");
+ ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1));
+ if (this->thr_count_ > 0)
+ return this->thr_mgr_->suspend_task (this);
+
+ return 0;
+}
+
+// Resume a suspended task.
+int
+ACE_Task_Base::resume (void)
+{
+ ACE_TRACE ("ACE_Task_Base::resume");
+ ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1));
+ if (this->thr_count_ > 0)
+ return this->thr_mgr_->resume_task (this);
+
+ return 0;
+}
+
+int
+ACE_Task_Base::activate (long flags,
+ int n_threads,
+ int force_active,
+ long priority,
+ int grp_id,
+ ACE_Task_Base *task,
+ ACE_hthread_t thread_handles[],
+ void *stack[],
+ size_t stack_size[],
+ ACE_thread_t thread_ids[])
+{
+ ACE_TRACE ("ACE_Task_Base::activate");
+
+#if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0)
+ ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1);
+
+ // If the task passed in is zero, we will use <this>
+ if (task == 0)
+ task = this;
+
+ if (this->thr_count_ > 0 && force_active == 0)
+ return 1; // Already active.
+ else
+ {
+ if (this->thr_count_ > 0 && grp_id != -1)
+ // If we're joining an existing group of threads then make
+ // sure to use its group id.
+ grp_id = this->grp_id_;
+ this->thr_count_ += n_threads;
+ }
+
+ // Use the ACE_Thread_Manager singleton if we're running as an
+ // active object and the caller didn't supply us with a
+ // Thread_Manager.
+ if (this->thr_mgr_ == 0)
+# if defined (ACE_THREAD_MANAGER_LACKS_STATICS)
+ this->thr_mgr_ = ACE_THREAD_MANAGER_SINGLETON::instance ();
+# else /* ! ACE_THREAD_MANAGER_LACKS_STATICS */
+ this->thr_mgr_ = ACE_Thread_Manager::instance ();
+# endif /* ACE_THREAD_MANAGER_LACKS_STATICS */
+
+ int grp_spawned = -1;
+ if (thread_ids == 0)
+ // Thread Ids were not specified
+ grp_spawned =
+ this->thr_mgr_->spawn_n (n_threads,
+ ACE_THR_FUNC (&ACE_Task_Base::svc_run),
+ (void *) this,
+ flags,
+ priority,
+ grp_id,
+ task,
+ thread_handles,
+ stack,
+ stack_size);
+ else
+ // thread names were specified
+ grp_spawned =
+ this->thr_mgr_->spawn_n (thread_ids,
+ n_threads,
+ ACE_THR_FUNC (&ACE_Task_Base::svc_run),
+ (void *) this,
+ flags,
+ priority,
+ grp_id,
+ stack,
+ stack_size,
+ thread_handles,
+ task);
+ if (grp_spawned == -1)
+ {
+ // If spawn_n fails, restore original thread count.
+ this->thr_count_ -= n_threads;
+ return -1;
+ }
+
+ if (this->grp_id_ == -1)
+ this->grp_id_ = grp_spawned;
+
+ return 0;
+
+#else
+ {
+ // Keep the compiler from complaining.
+ ACE_UNUSED_ARG (flags);
+ ACE_UNUSED_ARG (n_threads);
+ ACE_UNUSED_ARG (force_active);
+ ACE_UNUSED_ARG (priority);
+ ACE_UNUSED_ARG (grp_id);
+ ACE_UNUSED_ARG (task);
+ ACE_UNUSED_ARG (thread_handles);
+ ACE_UNUSED_ARG (stack);
+ ACE_UNUSED_ARG (stack_size);
+ ACE_UNUSED_ARG (thread_ids);
+ ACE_NOTSUP_RETURN (-1);
+ }
+#endif /* ACE_MT_SAFE */
+}
+
+void
+ACE_Task_Base::cleanup (void *object, void *)
+{
+ ACE_Task_Base *t = (ACE_Task_Base *) object;
+
+ // The thread count must be decremented first in case the <close>
+ // hook does something crazy like "delete this".
+ t->thr_count_dec ();
+
+ // @@ Is it possible to pass in the exit status somehow?
+ t->close ();
+}
+
+
+#if defined (ACE_HAS_SIG_C_FUNC)
+extern "C" void
+ACE_Task_Base_cleanup (void *object, void *)
+{
+ ACE_Task_Base::cleanup (object, 0);
+}
+#endif /* ACE_HAS_SIG_C_FUNC */
+
+void *
+ACE_Task_Base::svc_run (void *args)
+{
+ ACE_TRACE ("ACE_Task_Base::svc_run");
+
+ ACE_Task_Base *t = (ACE_Task_Base *) args;
+
+ // Register ourself with our <Thread_Manager>'s thread exit hook
+ // mechanism so that our close() hook will be sure to get invoked
+ // when this thread exits.
+
+#if defined ACE_HAS_SIG_C_FUNC
+ t->thr_mgr ()->at_exit (t, ACE_Task_Base_cleanup, 0);
+#else
+ t->thr_mgr ()->at_exit (t, ACE_Task_Base::cleanup, 0);
+#endif /* ACE_HAS_SIG_C_FUNC */
+
+ // Call the Task's svc() hook method.
+ void * status = ACE_reinterpret_cast(void *, t->svc ());
+
+// If we changed this zero change the other if in OS.cpp Thread_Adapter::invoke
+#if 1
+ // Call the <Task->close> hook.
+ ACE_Thread_Manager *thr_mgr_ptr = t->thr_mgr ();
+
+ // This calls the Task->close () hook.
+ t->cleanup (t, 0);
+
+ // This prevents a second invocation of the cleanup code
+ // (called later by <ACE_Thread_Manager::exit>.
+ thr_mgr_ptr->at_exit (t, 0, 0);
+#endif
+ return status;
+}
+
+// Forward the call to close() so that existing applications don't
+// break.
+
+int
+ACE_Task_Base::module_closed (void)
+{
+ return this->close (1);
+}
diff --git a/ace/Streams/Task.h b/ace/Streams/Task.h
new file mode 100644
index 00000000000..28e02dc6bb9
--- /dev/null
+++ b/ace/Streams/Task.h
@@ -0,0 +1,265 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Task.h
+ *
+ * $Id$
+ *
+ * @author Douglas C. Schmidt <schmidt@cs.wustl.edu>
+ */
+//=============================================================================
+
+#ifndef ACE_TASK_H
+#define ACE_TASK_H
+#include "ace/pre.h"
+
+#include "ace/Service_Object.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "ace/Thread_Manager.h"
+
+/**
+ * @class ACE_Task_Flags
+ *
+ * @brief These flags are used within the ACE_Task.
+ *
+ * These flags should be hidden within ACE_Task. Unfortunately, the
+ * HP/UX C++ compiler can't grok this... Fortunately, there's no
+ * code defined here, so we don't have to worry about multiple
+ * definitions.
+ */
+class ACE_Export ACE_Task_Flags
+{
+public:
+ enum
+ {
+ /// Identifies a Task as being the "reader" in a Module.
+ ACE_READER = 01,
+ /// Just flush data messages in the queue.
+ ACE_FLUSHDATA = 02,
+ /// Flush all messages in the Queue.
+ ACE_FLUSHALL = 04,
+ /// flush read queue
+ ACE_FLUSHR = 010,
+ /// flush write queue
+ ACE_FLUSHW = 020,
+ /// flush both queues
+ ACE_FLUSHRW = 030
+ };
+};
+
+/**
+ * @class ACE_Task_Base
+ *
+ * @brief Direct base class for the ACE_Task template.
+ *
+ * This class factors out the non-template code in order to
+ * reduce template bloat, as well as to make it possible for the
+ * <ACE_Thread_Manager> to store <ACE_Task_Base> *'s
+ * polymorphically.
+ */
+class ACE_Export ACE_Task_Base : public ACE_Service_Object
+{
+public:
+ // = Initialization and termination methods.
+ /// Constructor.
+ ACE_Task_Base (ACE_Thread_Manager * = 0);
+
+ /// Destructor.
+ virtual ~ACE_Task_Base (void);
+
+ // = Initialization and termination hooks.
+
+ // These methods should be overridden by subclasses if you'd like to
+ // provide <Task>-specific initialization and termination behavior.
+
+ /// Hook called to open a Task. <args> can be used to pass arbitrary
+ /// information into <open>.
+ virtual int open (void *args = 0);
+
+ /**
+ * Hook called from <ACE_Thread_Exit> when during thread exit and from
+ * the default implemenation of <module_closed>. In general, this
+ * method shouldn't be called directly by an application,
+ * particularly if the <Task> is running as an Active Object.
+ * Instead, a special message should be passed into the <Task> via
+ * the <put> method defined below, and the <svc> method should
+ * interpret this as a flag to shut down the <Task>.
+ */
+ virtual int close (u_long flags = 0);
+
+ /**
+ * Hook called during <ACE_Module::close>. The default
+ * implementation calls forwards the call to close(1). Please
+ * notice the changed value of the default argument of <close>.
+ * This allows tasks to differ between the call has been originated
+ * from <ACE_Thread_Exit> or from <module_closed>. Be aware that
+ * close(0) will be also called when a thread associated with the
+ * ACE_Task instance exits.
+ */
+ virtual int module_closed (void);
+
+ // = Immediate and deferred processing methods, respectively.
+
+ // These methods should be overridden by subclasses if you'd like to
+ // provide <Task>-specific message processing behavior.
+
+ /// A hook method that can be used to pass a message to a
+ /// task, where it can be processed immediately or queued for subsequent
+ /// processing in the <svc> hook method.
+ virtual int put (ACE_Message_Block *, ACE_Time_Value * = 0);
+
+ /// Run by a daemon thread to handle deferred processing.
+ virtual int svc (void);
+
+ // = Active object activation method.
+ /**
+ * Turn the task into an active object, i.e., having <n_threads> of
+ * control, all running at the <priority> level (see below) with the
+ * same <grp_id>, all of which invoke <Task::svc>. Returns -1 if
+ * failure occurs, returns 1 if Task is already an active object and
+ * <force_active> is false (i.e., do *not* create a new thread in
+ * this case), and returns 0 if Task was not already an active
+ * object and a thread is created successfully or thread is an
+ * active object and <force_active> is true. Note that if
+ * <force_active> is true and there are already threads spawned in
+ * this <Task>, the <grp_id> parameter is ignored and the <grp_id>
+ * of any newly activated thread(s) will inherit the existing
+ * <grp_id> of the existing thread(s) in the <Task>.
+ *
+ * The <{flags}> are a bitwise-OR of the following:
+ * = BEGIN<INDENT>
+ * THR_CANCEL_DISABLE, THR_CANCEL_ENABLE, THR_CANCEL_DEFERRED,
+ * THR_CANCEL_ASYNCHRONOUS, THR_BOUND, THR_NEW_LWP, THR_DETACHED,
+ * THR_SUSPENDED, THR_DAEMON, THR_JOINABLE, THR_SCHED_FIFO,
+ * THR_SCHED_RR, THR_SCHED_DEFAULT, THR_EXPLICIT_SCHED,
+ * THR_SCOPE_SYSTEM, THR_SCOPE_PROCESS
+ * = END<INDENT>
+ *
+ * By default, or if <{priority}> is set to
+ * ACE_DEFAULT_THREAD_PRIORITY, an "appropriate" priority value for
+ * the given scheduling policy (specified in <{flags}>, e.g.,
+ * <THR_SCHED_DEFAULT>) is used. This value is calculated
+ * dynamically, and is the median value between the minimum and
+ * maximum priority values for the given policy. If an explicit
+ * value is given, it is used. Note that actual priority values are
+ * EXTREMEMLY implementation-dependent, and are probably best
+ * avoided.
+ *
+ * If <thread_handles> != 0 it is assumed to be an array of <n>
+ * thread_handles that will be assigned the values of the thread
+ * handles being spawned. Returns -1 on failure (<errno> will
+ * explain...), otherwise returns the group id of the threads.
+ *
+ * If <stack> != 0 it is assumed to be an array of <n> pointers to
+ * the base of the stacks to use for the threads being spawned.
+ * Likewise, if <stack_size> != 0 it is assumed to be an array of
+ * <n> values indicating how big each of the corresponding <stack>s
+ * are.
+ */
+ virtual int activate (long flags = THR_NEW_LWP | THR_JOINABLE,
+ int n_threads = 1,
+ int force_active = 0,
+ long priority = ACE_DEFAULT_THREAD_PRIORITY,
+ int grp_id = -1,
+ ACE_Task_Base *task = 0,
+ ACE_hthread_t thread_handles[] = 0,
+ void *stack[] = 0,
+ size_t stack_size[] = 0,
+ ACE_thread_t thread_ids[] = 0);
+
+ /// Wait for all threads running in this task to exit.
+ virtual int wait (void);
+
+ // = Suspend/resume a Task.
+
+ // Note that these methods are not portable and should be avoided
+ // since they are inherently error-prone to use. They are only here
+ // for (the rare) applications that know how to use them correctly.
+ /// Suspend a task.
+ /// Resume a suspended task.
+ virtual int suspend (void);
+ virtual int resume (void);
+
+ /// Get the current group id.
+ int grp_id (void) const;
+
+ /// Set the current group id.
+ void grp_id (int);
+
+ /// Gets the thread manager associated with this Task.
+ ACE_Thread_Manager *thr_mgr (void) const;
+
+ /// Set the thread manager associated with this Task.
+ void thr_mgr (ACE_Thread_Manager *);
+
+ /// True if queue is a reader, else false.
+ int is_reader (void) const;
+
+ /// True if queue is a writer, else false.
+ int is_writer (void) const;
+
+ /**
+ * Returns the number of threads currently running within a task.
+ * If we're a passive object this value is 0, else it's greater than
+ * 0.
+ */
+ size_t thr_count (void) const;
+
+ /// Atomically decrement the thread count by 1. This should only be
+ /// called by the <ACE_Thread_Exit> class destructor.
+ void thr_count_dec (void);
+
+ /// Routine that runs the service routine as a daemon thread.
+ static void *svc_run (void *);
+
+ /// Cleanup hook that is called when a thread exits to gracefully
+ /// shutdown an <ACE_Task>.
+ static void cleanup (void *object, void *params);
+
+ // = Internal data (should be private...).
+// private:
+
+ /**
+ * Count of the number of threads running within the task. If this
+ * value is great than 0 then we're an active object and the value
+ * of <thr_count_> is the number of active threads at this instant.
+ * If the value == 0, then we're a passive object.
+ */
+ size_t thr_count_;
+
+ /// Multi-threading manager.
+ ACE_Thread_Manager *thr_mgr_;
+
+ /// ACE_Task flags.
+ u_long flags_;
+
+ /// This maintains the group id of the Task.
+ int grp_id_;
+
+#if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0)
+ /// Protect the state of a Task during concurrent operations, but
+ /// only if we're configured as MT safe...
+ ACE_Thread_Mutex lock_;
+#endif /* ACE_MT_SAFE */
+
+private:
+
+ // = Disallow these operations.
+ ACE_Task_Base &operator= (const ACE_Task_Base &);
+ ACE_Task_Base (const ACE_Task_Base &);
+};
+
+#if defined (__ACE_INLINE__)
+#include "ace/Task.i"
+#endif /* __ACE_INLINE__ */
+
+// Include the ACE_Task templates classes at this point.
+#include "ace/Task_T.h"
+
+#include "ace/post.h"
+#endif /* ACE_TASK_H */
diff --git a/ace/Streams/Task.i b/ace/Streams/Task.i
new file mode 100644
index 00000000000..fd9f992579b
--- /dev/null
+++ b/ace/Streams/Task.i
@@ -0,0 +1,114 @@
+/* -*- C++ -*- */
+// $Id$
+
+// Task.i
+
+ACE_INLINE ACE_Thread_Manager *
+ACE_Task_Base::thr_mgr (void) const
+{
+ ACE_TRACE ("ACE_Task_Base::thr_mgr");
+ return this->thr_mgr_;
+}
+
+ACE_INLINE void
+ACE_Task_Base::thr_mgr (ACE_Thread_Manager *thr_mgr)
+{
+ ACE_TRACE ("ACE_Task_Base::thr_mgr");
+ this->thr_mgr_ = thr_mgr;
+}
+
+// Return the count of the current number of threads.
+ACE_INLINE size_t
+ACE_Task_Base::thr_count (void) const
+{
+ ACE_TRACE ("ACE_Task_Base::thr_count");
+ ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, (ACE_Thread_Mutex &) this->lock_, 0));
+
+ return this->thr_count_;
+}
+
+// Decrement the count of the active threads by 1.
+
+ACE_INLINE void
+ACE_Task_Base::thr_count_dec (void)
+{
+ ACE_TRACE ("ACE_Task_Base::thr_count_dec");
+ ACE_MT (ACE_GUARD (ACE_Thread_Mutex, ace_mon, this->lock_));
+
+ this->thr_count_--;
+}
+
+ACE_INLINE int
+ACE_Task_Base::is_reader (void) const
+{
+ ACE_TRACE ("ACE_Task_Base::is_reader");
+ return (ACE_BIT_ENABLED (this->flags_, ACE_Task_Flags::ACE_READER));
+}
+
+ACE_INLINE int
+ACE_Task_Base::is_writer (void) const
+{
+ ACE_TRACE ("ACE_Task_Base::is_writer");
+ return (ACE_BIT_DISABLED (this->flags_, ACE_Task_Flags::ACE_READER));
+}
+
+// Default ACE_Task service routine
+
+ACE_INLINE int
+ACE_Task_Base::svc (void)
+{
+ ACE_TRACE ("ACE_Task_Base::svc");
+ return 0;
+}
+
+// Default ACE_Task open routine
+
+ACE_INLINE int
+ACE_Task_Base::open (void *)
+{
+ ACE_TRACE ("ACE_Task_Base::open");
+ return 0;
+}
+
+// Default ACE_Task close routine
+
+ACE_INLINE int
+ACE_Task_Base::close (u_long)
+{
+ ACE_TRACE ("ACE_Task_Base::close");
+ return 0;
+}
+
+// Default ACE_Task put routine.
+
+ACE_INLINE int
+ACE_Task_Base::put (ACE_Message_Block *, ACE_Time_Value *)
+{
+ ACE_TRACE ("ACE_Task_Base::put");
+ return 0;
+}
+
+// Get the current group id.
+ACE_INLINE int
+ACE_Task_Base::grp_id (void) const
+{
+ ACE_TRACE ("ACE_Task_Base::grp_id");
+ ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, (ACE_Thread_Mutex &) this->lock_, -1));
+ return this->grp_id_;
+}
+
+// Set the current group id.
+
+ACE_INLINE void
+ACE_Task_Base::grp_id (int id)
+{
+ ACE_TRACE ("ACE_Task_Base::grp_id");
+ ACE_MT (ACE_GUARD (ACE_Thread_Mutex, ace_mon, this->lock_));
+
+ // Cache the group id in the task and then set it in the
+ // Thread_Manager, if there is one.
+ this->grp_id_ = id;
+ if (this->thr_mgr ())
+ this->thr_mgr ()->set_grp (this, id);
+}
+
diff --git a/ace/Streams/Task_T.cpp b/ace/Streams/Task_T.cpp
new file mode 100644
index 00000000000..88bc3a2bfc5
--- /dev/null
+++ b/ace/Streams/Task_T.cpp
@@ -0,0 +1,105 @@
+// Task.cpp
+// $Id$
+
+#ifndef ACE_TASK_T_C
+#define ACE_TASK_T_C
+
+#include "ace/Task_T.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "ace/Module.h"
+//#include "ace/Service_Config.h"
+
+#if !defined (__ACE_INLINE__)
+#include "ace/Task_T.i"
+#endif /* __ACE_INLINE__ */
+
+ACE_RCSID(ace, Task_T, "$Id$")
+
+template <ACE_SYNCH_DECL> void
+ACE_Task<ACE_SYNCH_USE>::dump (void) const
+{
+ ACE_TRACE ("ACE_Task<ACE_SYNCH_USE>::dump");
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\nthr_mgr_ = %x"), this->thr_mgr_));
+ this->msg_queue_->dump ();
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("delete_msg_queue_ = %d\n"), this->delete_msg_queue_));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\nflags = %x"), this->flags_));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\nmod_ = %x"), this->mod_));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\nnext_ = %x"), this->next_));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\ngrp_id_ = %d"), this->grp_id_));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\nthr_count_ = %d"), this->thr_count_));
+#if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0)
+ this->lock_.dump ();
+#endif /* ACE_MT_SAFE */
+
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+// If the user doesn't supply a ACE_Message_Queue pointer then we'll
+// allocate one dynamically. Otherwise, we'll use the one they give.
+
+template<ACE_SYNCH_DECL>
+ACE_Task<ACE_SYNCH_USE>::ACE_Task (ACE_Thread_Manager *thr_man,
+ ACE_Message_Queue<ACE_SYNCH_USE> *mq)
+ : ACE_Task_Base (thr_man),
+ msg_queue_ (0),
+ delete_msg_queue_ (0),
+ mod_ (0),
+ next_ (0)
+{
+ ACE_TRACE ("ACE_Task<ACE_SYNCH_USE>::ACE_Task");
+
+ if (mq == 0)
+ {
+ ACE_NEW (mq,
+ ACE_Message_Queue<ACE_SYNCH_USE>);
+ this->delete_msg_queue_ = 1;
+ }
+
+ this->msg_queue_ = mq;
+}
+
+template<ACE_SYNCH_DECL>
+ACE_Task<ACE_SYNCH_USE>::~ACE_Task (void)
+{
+ ACE_TRACE ("ACE_Task<ACE_SYNCH_USE>::~ACE_Task");
+ if (this->delete_msg_queue_)
+ delete this->msg_queue_;
+
+ // These assignments aren't strickly necessary but they help guard
+ // against odd race conditions...
+ this->delete_msg_queue_ = 0;
+}
+
+template<ACE_SYNCH_DECL> ACE_Task<ACE_SYNCH_USE> *
+ACE_Task<ACE_SYNCH_USE>::sibling (void)
+{
+ ACE_TRACE ("ACE_Task<ACE_SYNCH_USE>::sibling");
+ if (this->mod_ == 0)
+ return 0;
+ else
+ return this->mod_->sibling (this);
+}
+
+template<ACE_SYNCH_DECL> const ACE_TCHAR *
+ACE_Task<ACE_SYNCH_USE>::name (void) const
+{
+ ACE_TRACE ("ACE_Task<ACE_SYNCH_USE>::name");
+ if (this->mod_ == 0)
+ return 0;
+ else
+ return this->mod_->name ();
+}
+
+template<ACE_SYNCH_DECL> ACE_Module<ACE_SYNCH_USE> *
+ACE_Task<ACE_SYNCH_USE>::module (void) const
+{
+ ACE_TRACE ("ACE_Task<ACE_SYNCH_USE>::module");
+ return this->mod_;
+}
+
+#endif /* ACE_TASK_T_C */
diff --git a/ace/Streams/Task_T.h b/ace/Streams/Task_T.h
new file mode 100644
index 00000000000..b7e5a14b7c2
--- /dev/null
+++ b/ace/Streams/Task_T.h
@@ -0,0 +1,174 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Task_T.h
+ *
+ * $Id$
+ *
+ * @author Douglas C. Schmidt <schmidt@cs.wustl.edu>
+ */
+//=============================================================================
+
+
+#ifndef ACE_TASK_T_H
+#define ACE_TASK_T_H
+#include "ace/pre.h"
+
+#include "ace/Message_Queue.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "ace/Synch_T.h"
+#include "ace/Task.h"
+
+// Forward decls...
+template <ACE_SYNCH_DECL> class ACE_Module;
+
+/**
+ * @class ACE_Task
+ *
+ * @brief Primary interface for application message processing, as well
+ * as input and output message queueing.
+ *
+ * This class serves as the basis for passive and active objects
+ * in ACE.
+ */
+template <ACE_SYNCH_DECL>
+class ACE_Export ACE_Task : public ACE_Task_Base
+{
+public:
+ friend class ACE_Module<ACE_SYNCH_USE>;
+ friend class ACE_Module_Type;
+
+ // = Initialization/termination methods.
+ /**
+ * Initialize a Task, supplying a thread manager and a message
+ * queue. If the user doesn't supply a ACE_Message_Queue pointer
+ * then we'll allocate one dynamically. Otherwise, we'll use the
+ * one passed as a parameter.
+ */
+ ACE_Task (ACE_Thread_Manager *thr_mgr = 0,
+ ACE_Message_Queue<ACE_SYNCH_USE> *mq = 0);
+
+ /// Destructor.
+ virtual ~ACE_Task (void);
+
+ /// Gets the message queue associated with this task.
+ ACE_Message_Queue<ACE_SYNCH_USE> *msg_queue (void);
+
+ /// Sets the message queue associated with this task.
+ void msg_queue (ACE_Message_Queue<ACE_SYNCH_USE> *);
+
+public: // Should be protected:
+ // = Message queue manipulation methods.
+
+ // = Enqueue and dequeue methods.
+
+ // For the following five method if <timeout> == 0, the caller will
+ // block until action is possible, else will wait until the
+ // <{absolute}> time specified in *<timeout> elapses). These calls
+ // will return, however, when queue is closed, deactivated, when a
+ // signal occurs, or if the time specified in timeout elapses, (in
+ // which case errno = EWOULDBLOCK).
+
+ /// Insert message into the message queue. Note that <timeout> uses
+ /// <{absolute}> time rather than <{relative}> time.
+ int putq (ACE_Message_Block *, ACE_Time_Value *timeout = 0);
+
+ /// Extract the first message from the queue (blocking). Note that
+ /// <timeout> uses <{absolute}> time rather than <{relative}> time.
+ int getq (ACE_Message_Block *&mb, ACE_Time_Value *timeout = 0);
+
+ /// Return a message to the queue. Note that <timeout> uses
+ /// <{absolute}> time rather than <{relative}> time.
+ int ungetq (ACE_Message_Block *, ACE_Time_Value *timeout = 0);
+
+ /**
+ * Turn the message around and send it back down the Stream. Note
+ * that <timeout> uses <{absolute}> time rather than <{relative}>
+ * time.
+ */
+ int reply (ACE_Message_Block *, ACE_Time_Value *timeout = 0);
+
+ /**
+ * Transfer message to the adjacent ACE_Task in a ACE_Stream. Note
+ * that <timeout> uses <{absolute}> time rather than <{relative}>
+ * time.
+ */
+ int put_next (ACE_Message_Block *msg, ACE_Time_Value *timeout = 0);
+
+ /// Tests whether we can enqueue a message without blocking.
+ int can_put (ACE_Message_Block *);
+
+ // = ACE_Task utility routines to identify names et al.
+ /// Return the name of the enclosing Module if there's one associated
+ /// with the Task, else returns 0.
+ const ACE_TCHAR *name (void) const;
+
+ // = Pointers to next ACE_Task_Base (if ACE is part of an ACE_Stream).
+ /// Get next Task pointer.
+ /// Set next Task pointer.
+ ACE_Task<ACE_SYNCH_USE> *next (void);
+ void next (ACE_Task<ACE_SYNCH_USE> *);
+
+ /// Return the Task's sibling if there's one associated with the
+ /// Task's Module, else returns 0.
+ ACE_Task<ACE_SYNCH_USE> *sibling (void);
+
+ /// Return the Task's Module if there is one, else returns 0.
+ ACE_Module<ACE_SYNCH_USE> *module (void) const;
+
+ /**
+ * Flush the queue. Note that if this conflicts with the C++
+ * iostream <flush> function, just rewrite the iostream function as
+ * ::<flush>.
+ */
+ int flush (u_long flag = ACE_Task_Flags::ACE_FLUSHALL);
+
+ // = Special routines corresponding to certain message types.
+
+ /// Manipulate watermarks.
+ void water_marks (ACE_IO_Cntl_Msg::ACE_IO_Cntl_Cmds, size_t);
+
+ /// Queue of messages on the ACE_Task..
+ ACE_Message_Queue<ACE_SYNCH_USE> *msg_queue_;
+
+ /// 1 if should delete Message_Queue, 0 otherwise.
+ int delete_msg_queue_;
+
+ /// Back-pointer to the enclosing module.
+ ACE_Module<ACE_SYNCH_USE> *mod_;
+
+ /// Pointer to adjacent ACE_Task.
+ ACE_Task<ACE_SYNCH_USE> *next_;
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+private:
+
+ // = Disallow these operations.
+ ACE_UNIMPLEMENTED_FUNC (void operator= (const ACE_Task<ACE_SYNCH_USE> &))
+ ACE_UNIMPLEMENTED_FUNC (ACE_Task (const ACE_Task<ACE_SYNCH_USE> &))
+};
+
+#if defined (__ACE_INLINE__)
+#include "ace/Task_T.i"
+#endif /* __ACE_INLINE__ */
+
+#if defined (ACE_TEMPLATES_REQUIRE_SOURCE)
+#include "ace/Task_T.cpp"
+#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */
+
+#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA)
+#pragma implementation ("Task_T.cpp")
+#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */
+
+#include "ace/post.h"
+#endif /* ACE_TASK_T_H */
diff --git a/ace/Streams/Task_T.i b/ace/Streams/Task_T.i
new file mode 100644
index 00000000000..1a78650279f
--- /dev/null
+++ b/ace/Streams/Task_T.i
@@ -0,0 +1,103 @@
+/* -*- C++ -*- */
+// $Id$
+
+// Task_T.i
+
+template <ACE_SYNCH_DECL> ACE_INLINE void
+ACE_Task<ACE_SYNCH_USE>::water_marks (ACE_IO_Cntl_Msg::ACE_IO_Cntl_Cmds cmd,
+ size_t wm_size)
+{
+ ACE_TRACE ("ACE_Task<ACE_SYNCH_USE>::water_marks");
+ if (cmd == ACE_IO_Cntl_Msg::SET_LWM)
+ this->msg_queue_->low_water_mark (wm_size);
+ else /* cmd == ACE_IO_Cntl_Msg::SET_HWM */
+ this->msg_queue_->high_water_mark (wm_size);
+}
+
+template <ACE_SYNCH_DECL> ACE_INLINE int
+ACE_Task<ACE_SYNCH_USE>::getq (ACE_Message_Block *&mb, ACE_Time_Value *tv)
+{
+ ACE_TRACE ("ACE_Task<ACE_SYNCH_USE>::getq");
+ return this->msg_queue_->dequeue_head (mb, tv);
+}
+
+template <ACE_SYNCH_DECL> ACE_INLINE int
+ACE_Task<ACE_SYNCH_USE>::can_put (ACE_Message_Block *)
+{
+ ACE_TRACE ("ACE_Task<ACE_SYNCH_USE>::can_put");
+ assert (!"not implemented");
+ return -1;
+}
+
+template <ACE_SYNCH_DECL> ACE_INLINE int
+ACE_Task<ACE_SYNCH_USE>::putq (ACE_Message_Block *mb, ACE_Time_Value *tv)
+{
+ ACE_TRACE ("ACE_Task<ACE_SYNCH_USE>::putq");
+ return this->msg_queue_->enqueue_tail (mb, tv);
+}
+
+template <ACE_SYNCH_DECL> ACE_INLINE int
+ACE_Task<ACE_SYNCH_USE>::ungetq (ACE_Message_Block *mb, ACE_Time_Value *tv)
+{
+ ACE_TRACE ("ACE_Task<ACE_SYNCH_USE>::ungetq");
+ return this->msg_queue_->enqueue_head (mb, tv);
+}
+
+template <ACE_SYNCH_DECL> ACE_INLINE int
+ACE_Task<ACE_SYNCH_USE>::flush (u_long flag)
+{
+ ACE_TRACE ("ACE_Task<ACE_SYNCH_USE>::flush");
+ if (ACE_BIT_ENABLED (flag, ACE_Task_Flags::ACE_FLUSHALL))
+ return this->msg_queue_ != 0 && this->msg_queue_->close ();
+ else
+ return -1; // Note, need to be more careful about what we free...
+}
+
+template <ACE_SYNCH_DECL> ACE_INLINE void
+ACE_Task<ACE_SYNCH_USE>::msg_queue (ACE_Message_Queue<ACE_SYNCH_USE> *mq)
+{
+ ACE_TRACE ("ACE_Task<ACE_SYNCH_USE>::msg_queue");
+ if (this->delete_msg_queue_)
+ {
+ delete this->msg_queue_;
+ this->delete_msg_queue_ = 0;
+ }
+ this->msg_queue_ = mq;
+}
+
+template <ACE_SYNCH_DECL> ACE_Message_Queue<ACE_SYNCH_USE> *
+ACE_Task<ACE_SYNCH_USE>::msg_queue (void)
+{
+ ACE_TRACE ("ACE_Task<ACE_SYNCH_USE>::msg_queue");
+ return this->msg_queue_;
+}
+
+template <ACE_SYNCH_DECL> ACE_INLINE int
+ACE_Task<ACE_SYNCH_USE>::reply (ACE_Message_Block *mb, ACE_Time_Value *tv)
+{
+ ACE_TRACE ("ACE_Task<ACE_SYNCH_USE>::reply");
+ return this->sibling ()->put_next (mb, tv);
+}
+
+template <ACE_SYNCH_DECL> ACE_INLINE ACE_Task<ACE_SYNCH_USE> *
+ACE_Task<ACE_SYNCH_USE>::next (void)
+{
+ ACE_TRACE ("ACE_Task<ACE_SYNCH_USE>::next");
+ return this->next_;
+}
+
+template <ACE_SYNCH_DECL> ACE_INLINE void
+ACE_Task<ACE_SYNCH_USE>::next (ACE_Task<ACE_SYNCH_USE> *q)
+{
+ ACE_TRACE ("ACE_Task<ACE_SYNCH_USE>::next");
+ this->next_ = q;
+}
+
+// Transfer msg to the next ACE_Task.
+
+template <ACE_SYNCH_DECL> ACE_INLINE int
+ACE_Task<ACE_SYNCH_USE>::put_next (ACE_Message_Block *msg, ACE_Time_Value *tv)
+{
+ ACE_TRACE ("ACE_Task<ACE_SYNCH_USE>::put_next");
+ return this->next_ == 0 ? -1 : this->next_->put (msg, tv);
+}
diff --git a/ace/Streams/Typed_SV_Message.cpp b/ace/Streams/Typed_SV_Message.cpp
new file mode 100644
index 00000000000..6b4ae9024b0
--- /dev/null
+++ b/ace/Streams/Typed_SV_Message.cpp
@@ -0,0 +1,26 @@
+// Typed_SV_Message.cpp
+// $Id$
+
+#ifndef ACE_TYPED_SV_MESSAGE_C
+#define ACE_TYPED_SV_MESSAGE_C
+#include "ace/Typed_SV_Message.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#if !defined (__ACE_INLINE__)
+#include "ace/Typed_SV_Message.i"
+#endif /* __ACE_INLINE__ */
+
+ACE_RCSID(ace, Typed_SV_Message, "$Id$")
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Typed_SV_Message)
+
+template <class T> void
+ACE_Typed_SV_Message<T>::dump (void) const
+{
+ ACE_TRACE ("ACE_Typed_SV_Message<T>::dump");
+}
+
+#endif /* ACE_TYPED_SV_MESSAGE_C */
diff --git a/ace/Streams/Typed_SV_Message.h b/ace/Streams/Typed_SV_Message.h
new file mode 100644
index 00000000000..36c5137b80e
--- /dev/null
+++ b/ace/Streams/Typed_SV_Message.h
@@ -0,0 +1,94 @@
+/* -*- C++ -*- */
+
+
+//=============================================================================
+/**
+ * @file Typed_SV_Message.h
+ *
+ * $Id$
+ *
+ * @author Doug Schmidt
+ */
+//=============================================================================
+
+
+#ifndef ACE_TYPED_SV_MESSAGE_H
+#define ACE_TYPED_SV_MESSAGE_H
+#include "ace/pre.h"
+
+#include "ace/ACE.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+/**
+ * @class ACE_Typed_SV_Message
+ *
+ * @brief Defines the header file for the C++ wrapper for System V
+ * message queues.
+ */
+template <class T>
+class ACE_Typed_SV_Message
+{
+public:
+ // = Initialization and termination methods.
+ ACE_Typed_SV_Message (long type = 0,
+ int length = sizeof (T),
+ int max_size = sizeof (T));
+ ACE_Typed_SV_Message (const T &data,
+ long type = 0,
+ int length = sizeof (T),
+ int max_size = sizeof (T));
+ ~ACE_Typed_SV_Message (void);
+
+ // = Get/set the type of the message.
+ long type (void) const;
+ void type (long type);
+
+ // = Get/set the length of the message.
+ int length (void) const;
+ void length (int l);
+
+ // = Get/set the maximum size of the message.
+ int max_size (void) const;
+ void max_size (int m);
+
+ // = Get/set a pointer to the data in the message.
+ T &data (void);
+ void data (const T &data);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+private:
+ /// Type of message.
+ long type_;
+
+ /// Length of this message.
+ int length_;
+
+ /// Maximum length of any message.
+ int max_;
+
+ /// Data stored in a message.
+ T data_;
+};
+
+#if defined (__ACE_INLINE__)
+#include "ace/Typed_SV_Message.i"
+#endif /* __ACE_INLINE__ */
+
+#if defined (ACE_TEMPLATES_REQUIRE_SOURCE)
+#include "ace/Typed_SV_Message.cpp"
+#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */
+
+#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA)
+#pragma implementation ("Typed_SV_Message.cpp")
+#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */
+
+#include "ace/post.h"
+#endif /* ACE_TYPED_SV_MESSAGE_H */
diff --git a/ace/Streams/Typed_SV_Message.i b/ace/Streams/Typed_SV_Message.i
new file mode 100644
index 00000000000..4d74a14f5dd
--- /dev/null
+++ b/ace/Streams/Typed_SV_Message.i
@@ -0,0 +1,91 @@
+/* -*- C++ -*- */
+// $Id$
+
+// Typed_SV_Message.i
+
+template <class T> ACE_INLINE
+ACE_Typed_SV_Message<T>::ACE_Typed_SV_Message (long t,
+ int l,
+ int m)
+ : type_ (t)
+{
+ ACE_TRACE ("ACE_Typed_SV_Message<T>::ACE_Typed_SV_Message");
+ this->length (l);
+ this->max_size (m);
+}
+
+template <class T> ACE_INLINE
+ACE_Typed_SV_Message<T>::ACE_Typed_SV_Message (const T &d,
+ long t,
+ int l,
+ int m)
+ : type_ (t),
+ data_ (d)
+{
+ ACE_TRACE ("ACE_Typed_SV_Message<T>::ACE_Typed_SV_Message");
+ this->length (l);
+ this->max_size (m);
+}
+
+template <class T> ACE_INLINE
+ACE_Typed_SV_Message<T>::~ACE_Typed_SV_Message (void)
+{
+ ACE_TRACE ("ACE_Typed_SV_Message<T>::~ACE_Typed_SV_Message");
+}
+
+template <class T> ACE_INLINE long
+ACE_Typed_SV_Message<T>::type (void) const
+{
+ ACE_TRACE ("ACE_Typed_SV_Message<T>::type");
+ return this->type_;
+}
+
+template <class T> ACE_INLINE void
+ACE_Typed_SV_Message<T>::type (long t)
+{
+ ACE_TRACE ("ACE_Typed_SV_Message<T>::type");
+ this->type_ = t;
+}
+
+template <class T> ACE_INLINE int
+ACE_Typed_SV_Message<T>::length (void) const
+{
+ ACE_TRACE ("ACE_Typed_SV_Message<T>::length");
+ return this->length_;
+}
+
+template <class T> ACE_INLINE void
+ACE_Typed_SV_Message<T>::length (int len)
+{
+ ACE_TRACE ("ACE_Typed_SV_Message<T>::length");
+ this->length_ = len + (sizeof *this - (sizeof this->type_ + sizeof this->data_));
+}
+
+template <class T> ACE_INLINE int
+ACE_Typed_SV_Message<T>::max_size (void) const
+{
+ ACE_TRACE ("ACE_Typed_SV_Message<T>::max_size");
+ return this->max_;
+}
+
+template <class T> ACE_INLINE void
+ACE_Typed_SV_Message<T>::max_size (int m)
+{
+ ACE_TRACE ("ACE_Typed_SV_Message<T>::max_size");
+ this->max_ = m + (sizeof *this - (sizeof this->type_ + sizeof this->data_));
+}
+
+template <class T> T &
+ACE_Typed_SV_Message<T>::data (void)
+{
+ ACE_TRACE ("ACE_Typed_SV_Message<T>::data");
+ return this->data_;
+}
+
+template <class T> void
+ACE_Typed_SV_Message<T>::data (const T &d)
+{
+ ACE_TRACE ("ACE_Typed_SV_Message<T>::data");
+ this->data_ = d;
+}
+
diff --git a/ace/Streams/Typed_SV_Message_Queue.cpp b/ace/Streams/Typed_SV_Message_Queue.cpp
new file mode 100644
index 00000000000..1a0a3b99943
--- /dev/null
+++ b/ace/Streams/Typed_SV_Message_Queue.cpp
@@ -0,0 +1,53 @@
+// Typed_SV_Message_Queue.cpp
+// $Id$
+
+#ifndef ACE_TYPED_SV_MESSAGE_QUEUE_C
+#define ACE_TYPED_SV_MESSAGE_QUEUE_C
+
+#include "ace/Typed_SV_Message.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "ace/Typed_SV_Message_Queue.h"
+#include "ace/Log_Msg.h"
+
+#if !defined (__ACE_INLINE__)
+#include "ace/Typed_SV_Message_Queue.i"
+#endif /* __ACE_INLINE__ */
+
+ACE_RCSID(ace, Typed_SV_Message_Queue, "$Id$")
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Typed_SV_Message_Queue)
+
+template <class T> void
+ACE_Typed_SV_Message_Queue<T>::dump (void) const
+{
+ ACE_TRACE ("ACE_Typed_SV_Message_Queue<T>::dump");
+}
+
+template <class T>
+ACE_Typed_SV_Message_Queue<T>::ACE_Typed_SV_Message_Queue (void)
+{
+ ACE_TRACE ("ACE_Typed_SV_Message_Queue<T>::ACE_Typed_SV_Message_Queue");
+}
+
+template <class T>
+ACE_Typed_SV_Message_Queue<T>::ACE_Typed_SV_Message_Queue (key_t external_id,
+ int create,
+ int perms)
+{
+ ACE_TRACE ("ACE_Typed_SV_Message_Queue<T>::ACE_Typed_SV_Message_Queue");
+ if (this->open (external_id, create, perms) == -1)
+ ACE_ERROR ((LM_ERROR,
+ "ACE_Typed_SV_Message_Queue::ACE_Typed_SV_Message_Queue"));
+}
+
+template <class T>
+ACE_Typed_SV_Message_Queue<T>::~ACE_Typed_SV_Message_Queue (void)
+{
+ ACE_TRACE ("ACE_Typed_SV_Message_Queue<T>::~ACE_Typed_SV_Message_Queue");
+}
+
+#endif /* ACE_TYPED_SV_MESSAGE_QUEUE_C */
diff --git a/ace/Streams/Typed_SV_Message_Queue.h b/ace/Streams/Typed_SV_Message_Queue.h
new file mode 100644
index 00000000000..20d2ec690c2
--- /dev/null
+++ b/ace/Streams/Typed_SV_Message_Queue.h
@@ -0,0 +1,86 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Typed_SV_Message_Queue.h
+ *
+ * $Id$
+ *
+ * @author Douglas C. Schmidt <schmidt@cs.wustl.edu>
+ */
+//=============================================================================
+
+#ifndef ACE_TYPED_MESSAGE_QUEUE_H
+#define ACE_TYPED_MESSAGE_QUEUE_H
+#include "ace/pre.h"
+
+#include "ace/SV_Message_Queue.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "ace/Typed_SV_Message.h"
+
+/**
+ * @class ACE_Typed_SV_Message_Queue
+ *
+ * @brief Defines the header file for the C++ wrapper facade for typed message queues.
+ */
+template <class T>
+class ACE_Typed_SV_Message_Queue
+{
+public:
+ enum
+ {
+ ACE_CREATE = IPC_CREAT,
+ ACE_OPEN = 0,
+ ACE_NOWAIT = IPC_NOWAIT
+ };
+
+ // = Initialization and termination operations.
+ ACE_Typed_SV_Message_Queue (void);
+ ACE_Typed_SV_Message_Queue (key_t external_id,
+ int create = ACE_OPEN,
+ int perms = ACE_DEFAULT_FILE_PERMS);
+ int open (key_t external_id,
+ int create = ACE_OPEN,
+ int perms = ACE_DEFAULT_FILE_PERMS);
+ int close (void);
+ int remove (void);
+ ~ACE_Typed_SV_Message_Queue (void);
+
+ // = Send and recv methods.
+ int send (const ACE_Typed_SV_Message<T> &mb, int mflags = 0);
+ int recv (ACE_Typed_SV_Message<T> &mb, int mflags = 0);
+
+ /// Return the id of the underlying <ACE_SV_Message_Queue>.
+ int get_id (void) const;
+
+ /// Control the underlying message queue.
+ int control (int option, void *arg = 0);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+private:
+ ACE_SV_Message_Queue message_queue_;
+};
+
+#if defined (__ACE_INLINE__)
+#include "ace/Typed_SV_Message_Queue.i"
+#endif /* __ACE_INLINE__ */
+
+#if defined (ACE_TEMPLATES_REQUIRE_SOURCE)
+#include "ace/Typed_SV_Message_Queue.cpp"
+#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */
+
+#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA)
+#pragma implementation ("Typed_SV_Message_Queue.cpp")
+#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */
+
+#include "ace/post.h"
+#endif /* ACE_TYPED_MESSAGE_QUEUE_H */
diff --git a/ace/Streams/Typed_SV_Message_Queue.i b/ace/Streams/Typed_SV_Message_Queue.i
new file mode 100644
index 00000000000..afbea9c455d
--- /dev/null
+++ b/ace/Streams/Typed_SV_Message_Queue.i
@@ -0,0 +1,77 @@
+/* -*- C++ -*- */
+// $Id$
+
+// Typed_SV_Message_Queue.i
+
+#include "ace/SV_Message_Queue.h"
+
+template <class T> ACE_INLINE int
+ACE_Typed_SV_Message_Queue<T>::open (key_t external_id,
+ int create,
+ int perms)
+{
+ ACE_TRACE ("ACE_Typed_SV_Message_Queue<T>::open");
+ return this->message_queue_.open (external_id, create, perms);
+}
+
+// What does it mean to close a message queue?!
+
+template <class T> ACE_INLINE int
+ACE_Typed_SV_Message_Queue<T>::close (void)
+{
+ ACE_TRACE ("ACE_Typed_SV_Message_Queue<T>::close");
+ return 1;
+}
+
+template <class T> ACE_INLINE int
+ACE_Typed_SV_Message_Queue<T>::recv (ACE_Typed_SV_Message<T> &mb,
+ int mflags)
+{
+ ACE_TRACE ("ACE_Typed_SV_Message_Queue<T>::recv");
+
+ int length = this->message_queue_.recv (ACE_reinterpret_cast (ACE_SV_Message &,
+ mb),
+ mb.max_size (),
+ mb.type (),
+ mflags);
+ if (length != -1)
+ mb.length (length);
+
+ return length;
+}
+
+template <class T> ACE_INLINE int
+ACE_Typed_SV_Message_Queue<T>::send (const ACE_Typed_SV_Message<T> &mb,
+ int mflags)
+{
+ ACE_TRACE ("ACE_Typed_SV_Message_Queue<T>::send");
+ return this->message_queue_.
+ send (ACE_reinterpret_cast (ACE_SV_Message &,
+ ACE_const_cast (ACE_Typed_SV_Message<T> &,
+ mb)),
+ mb.length (),
+ mflags);
+}
+
+template <class T> ACE_INLINE int
+ACE_Typed_SV_Message_Queue<T>::remove (void)
+{
+ ACE_TRACE ("ACE_Typed_SV_Message_Queue<T>::remove");
+
+ return this->message_queue_.remove ();
+}
+
+template <class T> ACE_INLINE int
+ACE_Typed_SV_Message_Queue<T>::control (int option,
+ void *arg)
+{
+ ACE_TRACE ("ACE_Typed_SV_Message_Queue<T>::control");
+
+ return this->message_queue_.control (option, arg);
+}
+
+template <class T> ACE_INLINE int
+ACE_Typed_SV_Message_Queue<T>::get_id (void) const
+{
+ return this->message_queue_.get_id ();
+}
diff --git a/ace/Streams/streams.h b/ace/Streams/streams.h
new file mode 100644
index 00000000000..5ac89a44bcf
--- /dev/null
+++ b/ace/Streams/streams.h
@@ -0,0 +1,149 @@
+// -*- C++ -*-
+
+//=============================================================================
+/**
+ * @file streams.h
+ *
+ * $Id$
+ *
+ * @author Irfan Pyarali
+ *
+ * This file contains the portability ugliness for the Standard C++
+ * Library. As implementations of the "standard" emerge, this file
+ * will need to be updated.
+ *
+ * This files deals with the streams includes.
+ *
+ *
+ */
+//=============================================================================
+
+
+#ifndef ACE_STREAMS_H
+#define ACE_STREAMS_H
+#include "ace/pre.h"
+
+#include "ace/config-all.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+// Do this so the #pragma warning in the MSVC headers do not
+// affect our #pragma warning settings
+#if (_MSC_VER >= 1200)
+#pragma warning(push)
+#endif /* _MSC_VER >= 1200 */
+
+
+#if !defined (ACE_LACKS_IOSTREAM_TOTALLY)
+
+# if defined (ACE_HAS_STANDARD_CPP_LIBRARY) && \
+ (ACE_HAS_STANDARD_CPP_LIBRARY != 0)
+
+# if defined (_MSC_VER)
+# pragma warning(disable: 4018 4114 4146 4245)
+# pragma warning(disable: 4663 4664 4665 4511 4512)
+# endif /* _MSC_VER */
+
+# if defined (ACE_USES_OLD_IOSTREAMS)
+# include /**/ <iostream.h>
+# include /**/ <fstream.h>
+ // This has been commented as it is not needed and causes problems with Qt.
+ // (brunsch) But has been uncommented since it should be included. Qt
+ // probably should have some sort of macro that will prevent including this
+ // when it is used.
+# include /**/ <iomanip.h>
+# if defined (_MSC_VER)
+# include /**/ <strstrea.h>
+# else
+# include /**/ <strstream.h>
+# endif /* _MSC_VER */
+# else
+# include /**/ <iostream>
+# include /**/ <fstream>
+# include /**/ <istream>
+# include /**/ <ostream>
+# include /**/ <streambuf>
+# include /**/ <iomanip>
+# include /**/ <ios>
+# include /**/ <strstream>
+# endif /* ACE_USES_OLD_IOSTREAMS */
+
+# if defined (ACE_USES_STD_NAMESPACE_FOR_STDCPP_LIB) && \
+ (ACE_USES_STD_NAMESPACE_FOR_STDCPP_LIB != 0)
+
+# if !defined (ACE_USES_OLD_IOSTREAMS)
+ // Make these available in the global name space
+ using std::ios;
+ using std::streambuf;
+ using std::istream;
+ using std::ostream;
+ using std::iostream;
+ using std::filebuf;
+ using std::ifstream;
+ using std::ofstream;
+ using std::fstream;
+
+ using std::istrstream;
+ using std::ostrstream;
+
+ using std::cin;
+ using std::cout;
+ using std::cerr;
+ using std::clog;
+
+ using std::endl;
+ using std::ends;
+ using std::flush;
+
+ using std::ws;
+
+ using std::resetiosflags;
+ using std::setfill;
+ using std::setiosflags;
+ using std::setprecision;
+ using std::setw;
+
+ using std::dec;
+ using std::hex;
+ using std::oct;
+# endif /* ! ACE_USES_OLD_IOSTREAMS */
+
+# endif /* ACE_USES_STD_NAMESPACE_FOR_STDCPP_LIB */
+
+# if defined (_MSC_VER)
+# pragma warning(4: 4018 4114 4146 4245)
+# pragma warning(4: 4663 4664 4665 4512 4511)
+# endif /* _MSC_VER */
+
+# else /* ! ACE_HAS_STANDARD_CPP_LIBRARY */
+
+# include /**/ <fstream.h>
+# include /**/ <iostream.h>
+# include /**/ <iomanip.h>
+
+# if defined (ACE_WIN32) && !defined(__MINGW32__)
+# if defined(_MSC_VER) // VSB
+# include /**/ <ios.h>
+# include /**/ <streamb.h>
+# include /**/ <istream.h>
+# include /**/ <ostream.h>
+# endif /* _MSC_VER */
+# include /**/ <strstrea.h> // VSB
+# else
+# include /**/ <strstream.h>
+# endif /* ACE_WIN32 && !__MINGW32__ */
+
+# endif /* ! ACE_HAS_STANDARD_CPP_LIBRARY */
+
+#endif /* ! ACE_LACKS_IOSTREAM_TOTALLY */
+
+// Do this so the #pragma warning in the MSVC headers do not
+// affect our #pragma warning settings
+#if (_MSC_VER >= 1200)
+#pragma warning(pop)
+#endif /* _MSC_VER >= 1200 */
+
+#include "ace/post.h"
+#endif /* ACE_STREAMS_H */
diff --git a/ace/Svcconf/DLL.cpp b/ace/Svcconf/DLL.cpp
new file mode 100644
index 00000000000..622cbe081ab
--- /dev/null
+++ b/ace/Svcconf/DLL.cpp
@@ -0,0 +1,188 @@
+// DLL.cpp
+// $Id$
+
+#include "ace/DLL.h"
+
+#include "ace/Log_Msg.h"
+#include "ace/ACE.h"
+
+ACE_RCSID(ace, DLL, "$Id$")
+
+// Default constructor. Also, by default, the object will be closed
+// before it is destroyed.
+
+ACE_DLL::ACE_DLL (int close_on_destruction)
+ : handle_ (ACE_SHLIB_INVALID_HANDLE),
+ close_on_destruction_ (close_on_destruction)
+{
+}
+
+// If the library name and the opening mode are specified than on
+// object creation the library is implicitly opened.
+
+ACE_DLL::ACE_DLL (const ACE_TCHAR *dll_name,
+ int open_mode,
+ int close_on_destruction)
+ : handle_ (ACE_OS::dlopen (dll_name,
+ open_mode)),
+ close_on_destruction_ (close_on_destruction)
+{
+ if (this->handle_ == ACE_SHLIB_INVALID_HANDLE)
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("%s\n"),
+ this->error ()));
+}
+
+// The library is closed before the class gets destroyed depending on
+// the close_on_destruction value specified which is stored in
+// close_on_destruction_.
+
+ACE_DLL::~ACE_DLL (void)
+{
+ // CLose the library only if it hasn't been already.
+ this->close ();
+}
+
+// This method opens the library based on the mode specified using the
+// ACE_SHLIB_HANDLE which is obtained on making the ACE_OS::dlopen call.
+// The default mode is:
+// RTLD_LAZY Only references to data symbols are relocate when the
+// object is first loaded.
+// The other modes include:
+// RTLD_NOW All necessary relocations are performed when the
+// object is first loaded.
+// RTLD_GLOBAL The object symbols are made available for the
+// relocation processing of any other object.
+
+int
+ACE_DLL::open (const ACE_TCHAR *dll_filename,
+ int open_mode,
+ int close_on_destruction)
+{
+ // This check is necessary as the library could be opened more than
+ // once without closing it which would cause handle memory leaks.
+ this->close ();
+
+ // Reset the flag
+ this->close_on_destruction_ = close_on_destruction;
+
+ // Find out where the library is
+ ACE_TCHAR dll_pathname[MAXPATHLEN + 1];
+
+ // Transform the pathname into the appropriate dynamic link library
+ // by searching the ACE_LD_SEARCH_PATH.
+ int result = ACE_Lib_Find::ldfind (dll_filename,
+ dll_pathname,
+ (sizeof dll_pathname / sizeof (ACE_TCHAR)));
+ // Check for errors
+ if (result != 0)
+ return result;
+
+ // The ACE_SHLIB_HANDLE object is obtained.
+ this->handle_ = ACE_OS::dlopen (dll_pathname,
+ open_mode);
+
+ if (this->handle_ == ACE_SHLIB_INVALID_HANDLE)
+ {
+#if defined (AIX)
+ do
+ {
+ // AIX often puts the shared library file (most often named shr.o)
+ // inside an archive library. If this is an archive library
+ // name, then try appending [shr.o] and retry.
+ if (0 != ACE_OS_String::strstr (dll_pathname, ACE_LIB_TEXT (".a")))
+ {
+ ACE_OS_String::strcat (dll_pathname, ACE_LIB_TEXT ("(shr.o)"));
+ open_mode |= RTLD_MEMBER;
+ this->handle_ = ACE_OS::dlopen (dll_pathname, open_mode);
+ if (this->handle_ != ACE_SHLIB_INVALID_HANDLE)
+ break; // end up returning 0
+ }
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_LIB_TEXT ("%s\n"), this->error ()),
+ -1);
+ }
+ while (0);
+#else
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_LIB_TEXT ("%s\n"), this->error ()),
+ -1);
+#endif /* AIX */
+ }
+
+ return 0;
+}
+
+// The symbol refernce of the name specified is obtained.
+
+void *
+ACE_DLL::symbol (const ACE_TCHAR *sym_name)
+{
+ return ACE_OS::dlsym (this->handle_, sym_name);
+}
+
+// The library is closed using the ACE_SHLIB_HANDLE obejct. i.e. The
+// shared object is now disassociated form the current process.
+
+int
+ACE_DLL::close (void)
+{
+ int retval = 0;
+
+ // The handle is checked to see whether the library is closed
+ // already and the <close_on_destruction_> flag is specified. If
+ // not, it is closed and the handle is made invalid to indicate that
+ // it's now closed.
+ if (this->close_on_destruction_ != 0 &&
+ this->handle_ != ACE_SHLIB_INVALID_HANDLE)
+ {
+ retval = ACE_OS::dlclose (this->handle_);
+ }
+
+ this->handle_ = ACE_SHLIB_INVALID_HANDLE;
+ return retval;
+}
+
+// This method is used on error in an library operation.
+
+ACE_TCHAR *
+ACE_DLL::error (void)
+{
+ return ACE_OS::dlerror ();
+}
+
+// Return the handle to the user either temporarily or forever, thus
+// orphaning it. If 0 means the user wants the handle forever and if 1
+// means the user temporarily wants to take the handle.
+
+ACE_SHLIB_HANDLE
+ACE_DLL::get_handle (int become_owner)
+{
+ // Since the caller is becoming the owner of the handle we lose
+ // rights to close it on destruction. The new controller has to do
+ // it explicitly.
+ if (become_owner)
+ this->close_on_destruction_ = 0;
+
+ // Return the handle requested by the user.
+ return this->handle_;
+}
+
+// Set the handle for the DLL. By default, the object will be closed
+// before it is destroyed.
+
+int
+ACE_DLL::set_handle (ACE_SHLIB_HANDLE handle,
+ int close_on_destruction)
+{
+ // Close the handle in use before accepting the next one.
+ if (this->close () == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_LIB_TEXT ("%s\n"), this->error ()),
+ -1);
+
+ this->handle_ = handle;
+ this->close_on_destruction_ = close_on_destruction;
+
+ return 0;
+}
diff --git a/ace/Svcconf/DLL.h b/ace/Svcconf/DLL.h
new file mode 100644
index 00000000000..2a870fa08c1
--- /dev/null
+++ b/ace/Svcconf/DLL.h
@@ -0,0 +1,115 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file DLL.h
+ *
+ * $Id$
+ *
+ * @author Kirthika Parameswaran <kirthika@cs.wustl.edu>
+ */
+//=============================================================================
+
+
+#ifndef ACE_DLL_H
+#define ACE_DLL_H
+#include "ace/pre.h"
+
+#include "ace/OS.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+/**
+ * @class ACE_DLL
+ *
+ * @brief Provides an abstract interface for handling various DLL
+ * operations.
+ *
+ * This class is an wrapper over the various methods for utilizing
+ * a dynamically linked library (DLL), which is called a shared
+ * library on some platforms. Operations <open>, <close>, and
+ * <symbol> have been implemented to help opening/closing and
+ * extracting symbol information from a DLL, respectively.
+ */
+class ACE_Export ACE_DLL
+{
+public:
+ // = Initialization and termination methods.
+
+ /// Default constructor. By default, the <close> operation on the
+ /// object will be invoked before it is destroyed.
+ ACE_DLL (int close_on_destruction = 1);
+
+ /**
+ * This constructor opens and dynamically links <dll_name>. The
+ * default mode is <RTLD_LAZY>, which loads identifier symbols but
+ * not the symbols for functions, which are loaded dynamically
+ * on-demand. Other supported modes include: <RTLD_NOW>, which
+ * performs all necessary relocations when <dll_name> is first
+ * loaded and <RTLD_GLOBAL>, which makes symbols available for
+ * relocation processing of any other DLLs.
+ */
+ ACE_DLL (const ACE_TCHAR *dll_name,
+ int open_mode = ACE_DEFAULT_SHLIB_MODE,
+ int close_on_destruction = 1);
+
+ /**
+ * This method opens and dynamically links <dll_name>. The default
+ * mode is <RTLD_LAZY>, which loads identifier symbols but not the
+ * symbols for functions, which are loaded dynamically on-demand.
+ * Other supported modes include: <RTLD_NOW>, which performs all
+ * necessary relocations when <dll_name> is first loaded and
+ * <RTLD_GLOBAL>, which makes symbols available for relocation
+ * processing of any other DLLs. Returns -1 on failure and 0 on
+ * success.
+ */
+ int open (const ACE_TCHAR *dll_name,
+ int open_mode = ACE_DEFAULT_SHLIB_MODE,
+ int close_on_destruction = 1);
+
+ /// Call to close the DLL object.
+ int close (void);
+
+ /**
+ * Called when the DLL object is destroyed -- invokes <close> if the
+ * <close_on_destruction> flag is set in the constructor or <open>
+ * method.
+ */
+ ~ACE_DLL (void);
+
+ /// If <symbol_name> is in the symbol table of the DLL a pointer to
+ /// the <symbol_name> is returned. Otherwise, returns 0.
+ void *symbol (const ACE_TCHAR *symbol_name);
+
+ /// Returns a pointer to a string explaining why <symbol> or <open>
+ /// failed.
+ ACE_TCHAR *error (void);
+
+ /**
+ * Return the handle to the caller. If <become_owner> is non-0 then
+ * caller assumes ownership of the handle and the <ACE_DLL> object
+ * won't call <close> when it goes out of scope, even if
+ * <close_on_destruction> is set.
+ */
+ ACE_SHLIB_HANDLE get_handle (int become_owner = 0);
+
+ /// Set the handle for the DLL object. By default, the <close> operation on the
+ /// object will be invoked before it is destroyed.
+ int set_handle (ACE_SHLIB_HANDLE handle, int close_on_destruction = 1);
+private:
+ /// This is a handle to the DLL.
+ ACE_SHLIB_HANDLE handle_;
+
+ /// This flag keeps track of whether we should close the handle
+ /// automatically when the destructor runs.
+ int close_on_destruction_;
+
+ // = Disallow copying and assignment since we don't handle these.
+ ACE_UNIMPLEMENTED_FUNC (ACE_DLL (const ACE_DLL &))
+ ACE_UNIMPLEMENTED_FUNC (void operator= (const ACE_DLL &))
+};
+
+#include "ace/post.h"
+#endif /* ACE_DLL_H */
diff --git a/ace/Svcconf/Dynamic_Service.cpp b/ace/Svcconf/Dynamic_Service.cpp
new file mode 100644
index 00000000000..ee40d45f112
--- /dev/null
+++ b/ace/Svcconf/Dynamic_Service.cpp
@@ -0,0 +1,19 @@
+// Dynamic_Service.cpp
+// $Id$
+
+#ifndef ACE_DYNAMIC_SERVICE_C
+#define ACE_DYNAMIC_SERVICE_C
+
+#include "ace/Dynamic_Service.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#if !defined (__ACE_INLINE__)
+#include "ace/Dynamic_Service.i"
+#endif /* __ACE_INLINE__ */
+
+ACE_RCSID(ace, Dynamic_Service, "$Id$")
+
+#endif /* ACE_DYNAMIC_SERVICE_C */
diff --git a/ace/Svcconf/Dynamic_Service.h b/ace/Svcconf/Dynamic_Service.h
new file mode 100644
index 00000000000..bd3a92c24af
--- /dev/null
+++ b/ace/Svcconf/Dynamic_Service.h
@@ -0,0 +1,52 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Dynamic_Service.h
+ *
+ * $Id$
+ *
+ * @author Prashant Jain <pjain@cs.wustl.edu>
+ * @author Douglas C. Schmidt <schmidt@cs.wustl.edu>
+ */
+//=============================================================================
+
+#ifndef ACE_DYNAMIC_SERVICE_H
+#define ACE_DYNAMIC_SERVICE_H
+#include "ace/pre.h"
+
+#include "ace/OS.h"
+
+#include "ace/Dynamic_Service_Base.h"
+
+/**
+ * @class ACE_Dynamic_Service
+ *
+ * @brief Provides a general interface to retrieve arbitrary objects
+ * from the ACE service repository.
+ *
+ * Uses "name" for lookup in the ACE service repository. Obtains
+ * the object and returns it as the appropriate type.
+ */
+template <class TYPE>
+class ACE_Dynamic_Service : public ACE_Dynamic_Service_Base
+{
+public:
+ /// Return instance using <name> to search the Service_Repository.
+ static TYPE*instance (const ACE_TCHAR *name);
+};
+
+#if defined (__ACE_INLINE__)
+#include "ace/Dynamic_Service.i"
+#endif /* __ACE_INLINE__ */
+
+#if defined (ACE_TEMPLATES_REQUIRE_SOURCE)
+# include "ace/Dynamic_Service.cpp"
+#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */
+
+#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA)
+# pragma implementation ("Dynamic_Service.cpp")
+#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */
+
+#include "ace/post.h"
+#endif /* ACE_DYNAMIC_SERVICE_H */
diff --git a/ace/Svcconf/Dynamic_Service.i b/ace/Svcconf/Dynamic_Service.i
new file mode 100644
index 00000000000..2d0b32b056c
--- /dev/null
+++ b/ace/Svcconf/Dynamic_Service.i
@@ -0,0 +1,8 @@
+/* -*- C++ -*- */
+// $Id$
+
+template <class TYPE> ACE_INLINE TYPE *
+ACE_Dynamic_Service<TYPE>::instance (const ACE_TCHAR *name)
+{
+ return ACE_reinterpret_cast(TYPE*,ACE_Dynamic_Service_Base::instance (name));
+}
diff --git a/ace/Svcconf/Dynamic_Service_Base.cpp b/ace/Svcconf/Dynamic_Service_Base.cpp
new file mode 100644
index 00000000000..6bcc87ad1ec
--- /dev/null
+++ b/ace/Svcconf/Dynamic_Service_Base.cpp
@@ -0,0 +1,39 @@
+// $Id$
+
+#include "ace/Dynamic_Service_Base.h"
+#include "ace/Service_Config.h"
+#include "ace/Service_Repository.h"
+#include "ace/Log_Msg.h"
+
+ACE_RCSID(ace, Dynamic_Service_Base, "$Id$")
+
+void
+ACE_Dynamic_Service_Base::dump (void) const
+{
+ ACE_TRACE ("ACE_Dynamic_Service_Base::dump");
+
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\n")));
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+// Get the instance using <name>.
+
+void *
+ACE_Dynamic_Service_Base::instance (const ACE_TCHAR *name)
+{
+ ACE_TRACE ("ACE_Dynamic_Service_Base::instance");
+ const ACE_Service_Type *svc_rec;
+
+ if (ACE_Service_Repository::instance ()->find (name,
+ &svc_rec) == -1)
+ return 0;
+
+ const ACE_Service_Type_Impl *type = svc_rec->type ();
+
+ if (type == 0)
+ return 0;
+
+ void *obj = type->object ();
+ return obj;
+}
diff --git a/ace/Svcconf/Dynamic_Service_Base.h b/ace/Svcconf/Dynamic_Service_Base.h
new file mode 100644
index 00000000000..15379c32e5b
--- /dev/null
+++ b/ace/Svcconf/Dynamic_Service_Base.h
@@ -0,0 +1,40 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Dynamic_Service_Base.h
+ *
+ * $Id$
+ *
+ * @author Prashant Jain <pjain@cs.wustl.edu>
+ * @author Douglas C. Schmidt <schmidt@cs.wustl.edu>
+ */
+//=============================================================================
+
+#ifndef ACE_DYNAMIC_SERVICE_BASE_H
+#define ACE_DYNAMIC_SERVICE_BASE_H
+#include "ace/pre.h"
+
+#include "ace/OS.h"
+
+/**
+ * @class ACE_Dynamic_Service_Base
+ *
+ * @brief Base class for all ACE_Dynamic_Service instantiations.
+ *
+ * Factors out common code shared by all ACE_Dynamic_Service
+ * instantiations, this avoid code bloat.
+ */
+class ACE_Export ACE_Dynamic_Service_Base
+{
+public:
+ /// Dump the current static of the object
+ void dump (void) const;
+
+protected:
+ /// Return instance using <name> to search the Service_Repository.
+ static void* instance (const ACE_TCHAR *name);
+};
+
+#include "ace/post.h"
+#endif /* ACE_DYNAMIC_SERVICE_BASE_H */
diff --git a/ace/Svcconf/Dynamic_Service_Base.i b/ace/Svcconf/Dynamic_Service_Base.i
new file mode 100644
index 00000000000..6318deb79a0
--- /dev/null
+++ b/ace/Svcconf/Dynamic_Service_Base.i
@@ -0,0 +1,2 @@
+/* -*- C++ -*- */
+// $Id$
diff --git a/ace/Svcconf/Parse_Node.cpp b/ace/Svcconf/Parse_Node.cpp
new file mode 100644
index 00000000000..899398bae90
--- /dev/null
+++ b/ace/Svcconf/Parse_Node.cpp
@@ -0,0 +1,652 @@
+// $Id$
+
+#include "ace/Service_Config.h"
+#include "ace/Service_Repository.h"
+#include "ace/Task.h"
+#include "ace/Parse_Node.h"
+
+// Provide the class hierarchy that defines the parse tree of Service
+// Nodes.
+
+#if !defined (__ACE_INLINE__)
+#include "ace/Parse_Node.i"
+#endif /* ____ */
+
+ACE_RCSID(ace, Parse_Node, "$Id$")
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Stream_Node)
+
+void
+ACE_Stream_Node::dump (void) const
+{
+ ACE_TRACE ("ACE_Stream_Node::dump");
+}
+
+void
+ACE_Stream_Node::apply (void)
+{
+ ACE_TRACE ("ACE_Stream_Node::apply");
+
+ if (ACE_Service_Config::initialize (this->node_->record (),
+ this->node_->parameters ()) == -1)
+ ace_yyerrno++;
+
+ if (ACE::debug ())
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_LIB_TEXT ("did stream on %s, error = %d\n"),
+ this->node_->name (),
+ ace_yyerrno));
+}
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Parse_Node)
+
+void
+ACE_Parse_Node::dump (void) const
+{
+ ACE_TRACE ("ACE_Parse_Node::dump");
+}
+
+const ACE_TCHAR *
+ACE_Parse_Node::name (void) const
+{
+ ACE_TRACE ("ACE_Parse_Node::name");
+ return this->name_;
+}
+
+ACE_Parse_Node *
+ACE_Parse_Node::link (void) const
+{
+ ACE_TRACE ("ACE_Parse_Node::link");
+ return this->next_;
+}
+
+void
+ACE_Parse_Node::link (ACE_Parse_Node *n)
+{
+ ACE_TRACE ("ACE_Parse_Node::link");
+ this->next_ = n;
+}
+
+ACE_Stream_Node::ACE_Stream_Node (const ACE_Static_Node *str_ops,
+ const ACE_Parse_Node *str_mods)
+#if defined (ACE_HAS_BROKEN_CONDITIONAL_STRING_CASTS)
+ : ACE_Parse_Node (str_ops == 0 ? ACE_static_cast (ACE_TCHAR *,
+ ACE_LIB_TEXT ("<unknown>"))
+ : ACE_static_cast (ACE_TCHAR *,
+ str_ops->name ())),
+#else
+ : ACE_Parse_Node ((str_ops == 0 ? ACE_LIB_TEXT ("<unknown>") : str_ops->name ())),
+#endif /* defined (ACE_HAS_BROKEN_CONDITIONAL_STRING_CASTS) */
+ node_ (str_ops),
+ mods_ (str_mods)
+{
+ ACE_TRACE ("ACE_Stream_Node::ACE_Stream_Node");
+}
+
+
+ACE_Stream_Node::~ACE_Stream_Node (void)
+{
+ ACE_TRACE ("ACE_Stream_Node::~ACE_Stream_Node");
+ ACE_Static_Node *n = ACE_const_cast (ACE_Static_Node *,
+ this->node_);
+ delete n;
+ ACE_Parse_Node *m = ACE_const_cast (ACE_Parse_Node *,
+ this->mods_);
+ delete m;
+}
+
+ACE_Parse_Node::ACE_Parse_Node (void)
+ : name_ (0),
+ next_ (0)
+{
+ ACE_TRACE ("ACE_Parse_Node::ACE_Parse_Node");
+}
+
+
+ACE_Parse_Node::ACE_Parse_Node (const ACE_TCHAR *nm)
+ : name_ (ACE::strnew (nm)),
+ next_ (0)
+{
+ ACE_TRACE ("ACE_Parse_Node::ACE_Parse_Node");
+}
+
+void
+ACE_Parse_Node::print (void) const
+{
+ ACE_TRACE ("ACE_Parse_Node::print");
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_LIB_TEXT ("svc = %s\n"),
+ this->name ()));
+
+ if (this->next_)
+ this->next_->print ();
+}
+
+
+ACE_Parse_Node::~ACE_Parse_Node (void)
+{
+ ACE_TRACE ("ACE_Parse_Node::~ACE_Parse_Node");
+ delete[] ACE_const_cast (ACE_TCHAR*, this->name_);
+ delete this->next_;
+}
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Suspend_Node)
+
+void
+ACE_Suspend_Node::dump (void) const
+{
+ ACE_TRACE ("ACE_Suspend_Node::dump");
+}
+
+ACE_Suspend_Node::ACE_Suspend_Node (const ACE_TCHAR *name)
+ : ACE_Parse_Node (name)
+{
+ ACE_TRACE ("ACE_Suspend_Node::ACE_Suspend_Node");
+}
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Resume_Node)
+
+void
+ACE_Resume_Node::dump (void) const
+{
+ ACE_TRACE ("ACE_Resume_Node::dump");
+}
+
+ACE_Resume_Node::ACE_Resume_Node (const ACE_TCHAR *name)
+ : ACE_Parse_Node (name)
+{
+ ACE_TRACE ("ACE_Resume_Node::ACE_Resume_Node");
+}
+
+void
+ACE_Suspend_Node::apply (void)
+{
+ ACE_TRACE ("ACE_Suspend_Node::apply");
+
+ if (ACE_Service_Config::suspend (this->name ()) == -1)
+ ace_yyerrno++;
+
+ if (ACE::debug ())
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_LIB_TEXT ("did suspend on %s, error = %d\n"),
+ this->name (),
+ ace_yyerrno));
+}
+
+void
+ACE_Resume_Node::apply (void)
+{
+ ACE_TRACE ("ACE_Resume_Node::apply");
+ if (ACE_Service_Config::resume (this->name ()) == -1)
+ ace_yyerrno++;
+
+ if (ACE::debug ())
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_LIB_TEXT ("did resume on %s, error = %d\n"),
+ this->name (),
+ ace_yyerrno));
+}
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Remove_Node)
+
+void
+ACE_Remove_Node::dump (void) const
+{
+ ACE_TRACE ("ACE_Remove_Node::dump");
+}
+
+ACE_Remove_Node::ACE_Remove_Node (const ACE_TCHAR *name)
+ : ACE_Parse_Node (name)
+{
+ ACE_TRACE ("ACE_Remove_Node::ACE_Remove_Node");
+}
+
+void
+ACE_Remove_Node::apply (void)
+{
+ ACE_TRACE ("ACE_Remove_Node::apply");
+ if (ACE_Service_Config::remove (this->name ()) == -1)
+ ace_yyerrno++;
+
+ if (ACE::debug ())
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_LIB_TEXT ("did remove on %s, error = %d\n"),
+ this->name (),
+ ace_yyerrno));
+}
+
+ACE_Dynamic_Node::ACE_Dynamic_Node (const ACE_Service_Type *sr,
+ ACE_TCHAR *parms)
+ : ACE_Static_Node (sr->name (), parms),
+ record_ (sr)
+{
+ ACE_TRACE ("ACE_Dynamic_Node::ACE_Dynamic_Node");
+}
+
+const ACE_Service_Type *
+ACE_Dynamic_Node::record (void) const
+{
+ ACE_TRACE ("ACE_Dynamic_Node::record");
+ return this->record_;
+}
+
+void
+ACE_Dynamic_Node::apply (void)
+{
+ ACE_TRACE ("ACE_Dynamic_Node::apply");
+
+ if (ACE_Service_Config::initialize (this->record (),
+ this->parameters ()) == -1)
+ ace_yyerrno++;
+
+ if (ACE::debug ())
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_LIB_TEXT ("did dynamic on %s, error = %d\n"),
+ this->name (),
+ ace_yyerrno));
+}
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Dynamic_Node)
+
+void
+ACE_Dynamic_Node::dump (void) const
+{
+ ACE_TRACE ("ACE_Dynamic_Node::dump");
+}
+
+ACE_Dynamic_Node::~ACE_Dynamic_Node (void)
+{
+ ACE_TRACE ("ACE_Dynamic_Node::~ACE_Dynamic_Node");
+}
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Static_Node)
+
+void
+ACE_Static_Node::dump (void) const
+{
+ ACE_TRACE ("ACE_Static_Node::dump");
+}
+
+ACE_Static_Node::ACE_Static_Node (const ACE_TCHAR *nm,
+ ACE_TCHAR *params)
+ : ACE_Parse_Node (nm),
+ parameters_ (ACE::strnew (params))
+{
+ ACE_TRACE ("ACE_Static_Node::ACE_Static_Node");
+}
+
+const ACE_Service_Type *
+ACE_Static_Node::record (void) const
+{
+ ACE_TRACE ("ACE_Static_Node::record");
+ ACE_Service_Type *sr;
+
+ if (ACE_Service_Repository::instance()->find
+ (this->name (),
+ (const ACE_Service_Type **) &sr) == -1)
+ return 0;
+ else
+ return sr;
+}
+
+ACE_TCHAR *
+ACE_Static_Node::parameters (void) const
+{
+ ACE_TRACE ("ACE_Static_Node::parameters");
+ return this->parameters_;
+}
+
+void
+ACE_Static_Node::apply (void)
+{
+ ACE_TRACE ("ACE_Static_Node::apply");
+ if (ACE_Service_Config::initialize (this->name (),
+ this->parameters ()) == -1)
+ ace_yyerrno++;
+
+ if (ACE::debug ())
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_LIB_TEXT ("did static on %s, error = %d\n"),
+ this->name (),
+ ace_yyerrno));
+}
+
+ACE_Static_Node::~ACE_Static_Node (void)
+{
+ ACE_TRACE ("ACE_Static_Node::~ACE_Static_Node");
+ delete[] this->parameters_;
+}
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Location_Node)
+
+void
+ACE_Location_Node::dump (void) const
+{
+ ACE_TRACE ("ACE_Location_Node::dump");
+}
+
+ACE_Location_Node::ACE_Location_Node (void)
+ : pathname_ (0),
+ symbol_ (0)
+{
+ ACE_TRACE ("ACE_Location_Node::ACE_Location_Node");
+}
+
+ACE_Location_Node::~ACE_Location_Node (void)
+{
+ ACE_TRACE ("ACE_Location_Node::~ACE_Location_Node");
+}
+
+ACE_SHLIB_HANDLE
+ACE_Location_Node::handle (void)
+{
+ ACE_TRACE ("ACE_Location_Node::handle");
+ return this->dll_.get_handle (1); // Caller now owns the handle
+}
+
+const ACE_TCHAR *
+ACE_Location_Node::pathname (void) const
+{
+ ACE_TRACE ("ACE_Location_Node::pathname");
+ return this->pathname_;
+}
+
+void
+ACE_Location_Node::pathname (const ACE_TCHAR *p)
+{
+ ACE_TRACE ("ACE_Location_Node::pathname");
+ this->pathname_ = p;
+}
+
+void
+ACE_Location_Node::set_symbol (void *s)
+{
+ ACE_TRACE ("ACE_Location_Node::set_symbol");
+ this->symbol_ = s;
+}
+
+int
+ACE_Location_Node::dispose (void) const
+{
+ ACE_TRACE ("ACE_Location_Node::dispose");
+ return this->must_delete_;
+}
+
+int
+ACE_Location_Node::open_dll (void)
+{
+ ACE_TRACE ("ACE_Location_Node::open_dll");
+
+ if (-1 == this->dll_.open (this->pathname ()))
+ {
+ ace_yyerrno++;
+
+ ACE_TCHAR *errmsg = this->dll_.error ();
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("ACE_DLL::open failed for %s: %s\n"),
+ this->pathname (),
+ errmsg ? errmsg : ACE_LIB_TEXT ("no error reported")));
+ return -1;
+ }
+
+ return 0;
+
+}
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Object_Node)
+
+void
+ACE_Object_Node::dump (void) const
+{
+ ACE_TRACE ("ACE_Object_Node::dump");
+}
+
+ACE_Object_Node::ACE_Object_Node (const ACE_TCHAR *path,
+ const ACE_TCHAR *obj_name)
+ : object_name_ (obj_name ? ACE_Lib_Find::ldname (obj_name) : 0)
+{
+ ACE_TRACE ("ACE_Object_Node::ACE_Object_Node");
+ this->pathname (ACE::strnew (path));
+ this->must_delete_ = 0;
+}
+
+void *
+ACE_Object_Node::symbol (ACE_Service_Object_Exterminator *)
+{
+ ACE_TRACE ("ACE_Object_Node::symbol");
+ if (this->open_dll () == 0)
+ {
+ ACE_TCHAR *object_name = ACE_const_cast (ACE_TCHAR *, this->object_name_);
+
+ this->symbol_ = this->dll_.symbol (object_name);
+ if (this->symbol_ == 0)
+ {
+ ace_yyerrno++;
+
+ ACE_TCHAR *errmsg = this->dll_.error ();
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("ACE_DLL::symbol failed for object %s: %s\n"),
+ object_name,
+ errmsg ? errmsg : ACE_LIB_TEXT ("no error reported")));
+ return 0;
+ }
+
+ return this->symbol_;
+ }
+
+ return 0;
+}
+
+ACE_Object_Node::~ACE_Object_Node (void)
+{
+ ACE_TRACE ("ACE_Object_Node::~ACE_Object_Node");
+ delete[] ACE_const_cast (ACE_TCHAR *, this->object_name_);
+}
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Function_Node)
+
+void
+ACE_Function_Node::dump (void) const
+{
+ ACE_TRACE ("ACE_Function_Node::dump");
+}
+
+ACE_Function_Node::ACE_Function_Node (const ACE_TCHAR *path,
+ const ACE_TCHAR *func_name)
+ : function_name_ (func_name ? ACE_Lib_Find::ldname (func_name) : 0)
+{
+ ACE_TRACE ("ACE_Function_Node::ACE_Function_Node");
+ this->pathname (ACE::strnew (path));
+ this->must_delete_ = 1;
+}
+
+void *
+ACE_Function_Node::symbol (ACE_Service_Object_Exterminator *gobbler)
+{
+ ACE_TRACE ("ACE_Function_Node::symbol");
+ if (this->open_dll () == 0)
+ {
+ void *(*func) (ACE_Service_Object_Exterminator *) = 0;
+ this->symbol_ = 0;
+
+ // Locate the factory function <function_name> in the shared
+ // object.
+
+ ACE_TCHAR *function_name = ACE_const_cast (ACE_TCHAR *,
+ this->function_name_);
+
+ // According to the new ANSI C++ specification, casting a void*
+ // pointer to a function pointer is not allowed. However,
+ // casting a void* pointer to an integer type that is large
+ // enough to hold the pointer value is legal. I (Nanbor) chose
+ // to cast the return value to long since it should be large
+ // enough to hold the void* pointer's value on most platforms.
+ // I am not sure if casting a long value to a function pointer
+ // is legal or not (can't find a good explanation in spec) but
+ // SunC++, egcs, and KAI compilers, all of which are pretty
+ // close to (or, at least claim to conform with) the standard
+ // did not complain about this as an illegal pointer conversion.
+ long temp_ptr =
+ ACE_reinterpret_cast(long, this->dll_.symbol (function_name));
+ func = ACE_reinterpret_cast(void *(*)(ACE_Service_Object_Exterminator *),
+ temp_ptr);
+
+ if (func == 0)
+ {
+ ace_yyerrno++;
+
+ if (this->symbol_ == 0)
+ {
+ ace_yyerrno++;
+
+ ACE_TCHAR *errmsg = this->dll_.error ();
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("ACE_DLL::symbol failed for function %s: %s\n"),
+ function_name,
+ errmsg ? errmsg :
+ ACE_LIB_TEXT ("no error reported")));
+ return 0;
+ }
+ }
+ // Invoke the factory function and record it's return value.
+ this->symbol_ = (*func) (gobbler);
+
+ if (this->symbol_ == 0)
+ {
+ ace_yyerrno++;
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_LIB_TEXT ("%p\n"),
+ this->function_name_),
+ 0);
+ }
+ }
+ return this->symbol_;
+}
+
+ACE_Function_Node::~ACE_Function_Node (void)
+{
+ ACE_TRACE ("ACE_Function_Node::~ACE_Function_Node");
+ delete[] ACE_const_cast (ACE_TCHAR *, function_name_);
+ delete[] ACE_const_cast (ACE_TCHAR *, pathname_);
+}
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Dummy_Node)
+
+void
+ACE_Dummy_Node::dump (void) const
+{
+ ACE_TRACE ("ACE_Dummy_Node::dump");
+}
+
+ACE_Dummy_Node::ACE_Dummy_Node (const ACE_Static_Node *static_node,
+ const ACE_Parse_Node *str_mods)
+ : ACE_Parse_Node (static_node->name ()),
+ node_ (static_node),
+ mods_ (str_mods)
+{
+ ACE_TRACE ("ACE_Dummy_Node::ACE_Dummy_Node");
+}
+
+void
+ACE_Dummy_Node::apply (void)
+{
+ ACE_TRACE ("ACE_Dummy_Node::apply");
+
+ if (ACE::debug ())
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_LIB_TEXT ("did operations on stream %s, error = %d\n"),
+ this->name (),
+ ace_yyerrno));
+}
+
+ACE_Dummy_Node::~ACE_Dummy_Node (void)
+{
+ ACE_TRACE ("ACE_Dummy_Node::~ACE_Dummy_Node");
+ ACE_Static_Node *n = ACE_const_cast (ACE_Static_Node *,
+ this->node_);
+ delete n;
+ ACE_Parse_Node *m = ACE_const_cast (ACE_Parse_Node *,
+ this->mods_);
+ delete m;
+}
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Static_Function_Node)
+
+void
+ACE_Static_Function_Node::dump (void) const
+{
+ ACE_TRACE ("ACE_Static_Function_Node::dump");
+}
+
+ACE_Static_Function_Node::ACE_Static_Function_Node (const ACE_TCHAR *func_name)
+ : function_name_ (ACE::strnew (func_name))
+{
+ ACE_TRACE ("ACE_Static_Function_Node::ACE_Static_Function_Node");
+ this->must_delete_ = 1;
+}
+
+void *
+ACE_Static_Function_Node::symbol (ACE_Service_Object_Exterminator *gobbler)
+{
+ ACE_TRACE ("ACE_Static_Function_Node::symbol");
+
+ void *(*func)(ACE_Service_Object_Exterminator *) = 0;
+ this->symbol_ = 0;
+
+ // Locate the factory function <function_name> in the statically
+ // linked svcs.
+
+ ACE_Static_Svc_Descriptor **ssdp = 0;
+ ACE_STATIC_SVCS &svcs = *ACE_Service_Config::static_svcs ();
+ ACE_TCHAR *function_name = ACE_const_cast (ACE_TCHAR *, this->function_name_);
+
+ for (ACE_STATIC_SVCS_ITERATOR iter (svcs);
+ iter.next (ssdp) != 0;
+ iter.advance ())
+ {
+ ACE_Static_Svc_Descriptor *ssd = *ssdp;
+ if (ACE_OS::strcmp (ssd->name_,
+ function_name) == 0)
+ func = (void *(*)(ACE_Service_Object_Exterminator*)) ssd->alloc_;
+ }
+
+ if (func == 0)
+ {
+ ace_yyerrno++;
+
+ if (this->symbol_ == 0)
+ {
+ ace_yyerrno++;
+
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_LIB_TEXT ("no static service registered for function %s\n"),
+ function_name),
+ 0);
+ }
+ }
+
+ // Invoke the factory function and record it's return value.
+ this->symbol_ = (*func) (gobbler);
+
+ if (this->symbol_ == 0)
+ {
+ ace_yyerrno++;
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_LIB_TEXT ("%p\n"),
+ this->function_name_),
+ 0);
+ }
+
+ return this->symbol_;
+}
+
+ACE_Static_Function_Node::~ACE_Static_Function_Node (void)
+{
+ ACE_TRACE ("ACE_Static_Function_Node::~ACE_Static_Function_Node");
+ delete[] ACE_const_cast (ACE_TCHAR *, this->function_name_);
+}
+
+#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION)
+#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA)
+#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */
diff --git a/ace/Svcconf/Parse_Node.h b/ace/Svcconf/Parse_Node.h
new file mode 100644
index 00000000000..6df9def1915
--- /dev/null
+++ b/ace/Svcconf/Parse_Node.h
@@ -0,0 +1,343 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Parse_Node.h
+ *
+ * $Id$
+ *
+ * @author Doug Schmidt
+ */
+//=============================================================================
+
+
+#ifndef ACE_PARSE_NODE_H
+#define ACE_PARSE_NODE_H
+#include "ace/pre.h"
+
+#include "ace/Service_Types.h"
+#include "ace/DLL.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+/**
+ * @class ACE_Parse_Node
+ *
+ * @brief Provide the base of the object hierarchy that defines the parse
+ * tree of Service Nodes.
+ */
+class ACE_Export ACE_Parse_Node
+{
+public:
+ ACE_Parse_Node (void);
+ ACE_EXPLICIT ACE_Parse_Node (const ACE_TCHAR *name);
+ virtual ~ACE_Parse_Node (void);
+
+ ACE_Parse_Node *link (void) const;
+ void link (ACE_Parse_Node *);
+ virtual void apply (void) = 0;
+
+ const ACE_TCHAR *name (void) const;
+ void print (void) const;
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+private:
+ const ACE_TCHAR *name_;
+ ACE_Parse_Node *next_;
+};
+
+/**
+ * @class ACE_Suspend_Node
+ *
+ * @brief Suspend a Service Node.
+ */
+class ACE_Export ACE_Suspend_Node : public ACE_Parse_Node
+{
+public:
+ ACE_Suspend_Node (const ACE_TCHAR *name);
+ ~ACE_Suspend_Node (void);
+
+ virtual void apply (void);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+};
+
+/**
+ * @class ACE_Resume_Node
+ *
+ * @brief Resume a Service Node.
+ */
+class ACE_Export ACE_Resume_Node : public ACE_Parse_Node
+{
+public:
+ ACE_Resume_Node (const ACE_TCHAR *name);
+ ~ACE_Resume_Node (void);
+
+ virtual void apply (void);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+};
+
+/**
+ * @class ACE_Remove_Node
+ *
+ * @brief Remove a Service Node.
+ */
+class ACE_Export ACE_Remove_Node : public ACE_Parse_Node
+{
+public:
+ ACE_Remove_Node (const ACE_TCHAR *name);
+ ~ACE_Remove_Node (void);
+
+ virtual void apply (void);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+};
+
+/**
+ * @class ACE_Static_Node
+ *
+ * @brief Handle a statically linked node.
+ */
+class ACE_Export ACE_Static_Node : public ACE_Parse_Node
+{
+public:
+ ACE_Static_Node (const ACE_TCHAR *name, ACE_TCHAR *params = 0);
+ virtual ~ACE_Static_Node (void);
+
+ virtual void apply (void);
+ virtual const ACE_Service_Type *record (void) const;
+ ACE_TCHAR *parameters (void) const;
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+private:
+ /// "Command-line" parameters.
+ ACE_TCHAR *parameters_;
+};
+
+/**
+ * @class ACE_Dynamic_Node
+ *
+ * @brief Handle a dynamically linked node.
+ */
+class ACE_Export ACE_Dynamic_Node : public ACE_Static_Node
+{
+public:
+ ACE_Dynamic_Node (const ACE_Service_Type *, ACE_TCHAR *params);
+ virtual ~ACE_Dynamic_Node (void);
+
+ virtual const ACE_Service_Type *record (void) const;
+ virtual void apply (void);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+private:
+ /// Pointer to a descriptor that describes this node.
+ const ACE_Service_Type *record_;
+};
+
+/**
+ * @class ACE_Stream_Node
+ *
+ * @brief Handle a Stream.
+ */
+class ACE_Export ACE_Stream_Node : public ACE_Parse_Node
+{
+public:
+ ACE_Stream_Node (const ACE_Static_Node *, const ACE_Parse_Node *);
+ virtual ~ACE_Stream_Node (void);
+
+ virtual void apply (void);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+private:
+ /// Linked list of modules that are part of the stream.
+ const ACE_Static_Node *node_;
+ const ACE_Parse_Node *mods_;
+};
+
+/**
+ * @class ACE_Location_Node
+ *
+ * @brief Keep track of where a shared library is located.
+ */
+class ACE_Export ACE_Location_Node
+{
+public:
+ ACE_Location_Node (void);
+ virtual void *symbol (ACE_Service_Object_Exterminator * = 0) = 0;
+ virtual void set_symbol (void *h);
+ ACE_SHLIB_HANDLE handle (void);
+ const ACE_TCHAR *pathname (void) const;
+ void pathname (const ACE_TCHAR *h);
+ int dispose (void) const;
+
+ virtual ~ACE_Location_Node (void);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+protected:
+ int open_dll (void);
+
+ /// Pathname to the shared library we are working on.
+ const ACE_TCHAR *pathname_;
+
+ /**
+ * Flag indicating whether the Service_Object generated by this
+ * Location Node should be deleted or not
+ * (ACE_Service_Type::DELETE_OBJ.)
+ */
+ int must_delete_;
+
+ /// The open shared library.
+ ACE_DLL dll_;
+
+ /// Symbol that we've obtained from the shared library.
+ void *symbol_;
+};
+
+/**
+ * @class ACE_Object_Node
+ *
+ * @brief Keeps track of the symbol name for a shared object.
+ */
+class ACE_Export ACE_Object_Node : public ACE_Location_Node
+{
+public:
+ ACE_Object_Node (const ACE_TCHAR *pathname, const ACE_TCHAR *obj_name);
+ virtual void *symbol (ACE_Service_Object_Exterminator * = 0);
+ virtual ~ACE_Object_Node (void);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+private:
+ /// Name of the object that we're parsing.
+ const ACE_TCHAR *object_name_;
+};
+
+/**
+ * @class ACE_Function_Node
+ *
+ * @brief Keeps track of the symbol name of for a shared function.
+ */
+class ACE_Export ACE_Function_Node : public ACE_Location_Node
+{
+public:
+ ACE_Function_Node (const ACE_TCHAR *pathname, const ACE_TCHAR *func_name);
+ virtual void *symbol (ACE_Service_Object_Exterminator *gobbler = 0);
+ virtual ~ACE_Function_Node (void);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+private:
+ /// Name of the function that we're parsing.
+ const ACE_TCHAR *function_name_;
+};
+
+/**
+ * @class ACE_Dummy_Node
+ *
+ * @brief I forget why this is here... ;-)
+ */
+class ACE_Export ACE_Dummy_Node : public ACE_Parse_Node
+{
+public:
+ ACE_Dummy_Node (const ACE_Static_Node *, const ACE_Parse_Node *);
+ ~ACE_Dummy_Node (void);
+ virtual void apply (void);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+private:
+ /// Linked list of modules that we're dealing with.
+ const ACE_Static_Node *node_;
+ const ACE_Parse_Node *mods_;
+};
+
+/**
+ * @class ACE_Static_Function_Node
+ *
+ * @brief Keeps track of the symbol name for a function that is not
+ * linked in from a DLL, but is statically linked with the
+ * application.
+ */
+class ACE_Export ACE_Static_Function_Node : public ACE_Location_Node
+{
+public:
+ ACE_EXPLICIT ACE_Static_Function_Node (const ACE_TCHAR *func_name);
+ virtual void *symbol (ACE_Service_Object_Exterminator * = 0);
+ virtual ~ACE_Static_Function_Node (void);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+private:
+ /// Name of the function that we're parsing.
+ const ACE_TCHAR *function_name_;
+};
+
+#if defined (__ACE_INLINE__)
+#include "ace/Parse_Node.i"
+#endif /* __ACE_INLINE__ */
+
+// Keeps track of the number of errors encountered so far.
+extern int ace_yyerrno;
+
+// Global variable used to communicate between the parser and the main
+// program.
+extern ACE_Service_Config *ace_this_svc;
+
+#include "ace/post.h"
+#endif /* ACE_PARSE_NODE_H */
diff --git a/ace/Svcconf/Parse_Node.i b/ace/Svcconf/Parse_Node.i
new file mode 100644
index 00000000000..0728118ea80
--- /dev/null
+++ b/ace/Svcconf/Parse_Node.i
@@ -0,0 +1,19 @@
+/* -*- C++ -*- */
+// $Id$
+
+// Parse_Node.i
+
+ACE_INLINE
+ACE_Suspend_Node::~ACE_Suspend_Node (void)
+{
+}
+
+ACE_INLINE
+ACE_Resume_Node::~ACE_Resume_Node (void)
+{
+}
+
+ACE_INLINE
+ACE_Remove_Node::~ACE_Remove_Node (void)
+{
+}
diff --git a/ace/Svcconf/Service_Config.cpp b/ace/Svcconf/Service_Config.cpp
new file mode 100644
index 00000000000..05768a716ef
--- /dev/null
+++ b/ace/Svcconf/Service_Config.cpp
@@ -0,0 +1,884 @@
+// $Id$
+
+#include "ace/Svc_Conf.h"
+#include "ace/Get_Opt.h"
+#include "ace/ARGV.h"
+#include "ace/Malloc.h"
+#include "ace/Service_Manager.h"
+#include "ace/Service_Repository.h"
+#include "ace/Service_Types.h"
+#include "ace/Containers.h"
+#include "ace/Auto_Ptr.h"
+#include "ace/Reactor.h"
+#include "ace/Proactor.h"
+#include "ace/Thread_Manager.h"
+
+#include "ace/Service_Config.h"
+
+#if !defined (__ACE_INLINE__)
+#include "ace/Service_Config.i"
+#endif /* __ACE_INLINE__ */
+
+ACE_RCSID (ace,
+ Service_Config,
+ "$Id$")
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Service_Config)
+
+void
+ACE_Service_Config::dump (void) const
+{
+ ACE_TRACE ("ACE_Service_Config::dump");
+}
+
+// All the factory functions that allocate default statically linked
+// services should be placed below.
+
+// Allocate a Service Manager.
+
+ACE_FACTORY_DEFINE (ACE, ACE_Service_Manager)
+
+// ----------------------------------------
+
+// Set the signal handler to point to the handle_signal() function.
+ACE_Sig_Adapter *ACE_Service_Config::signal_handler_ = 0;
+
+// Trigger a reconfiguration.
+sig_atomic_t ACE_Service_Config::reconfig_occurred_ = 0;
+
+ // = Set by command-line options.
+int ACE_Service_Config::be_a_daemon_ = 0;
+int ACE_Service_Config::no_static_svcs_ = 1;
+
+// Number of the signal used to trigger reconfiguration.
+int ACE_Service_Config::signum_ = SIGHUP;
+
+// Indicates where to write the logging output. This is typically
+// either a STREAM pipe or a socket address.
+const ACE_TCHAR *ACE_Service_Config::logger_key_ = ACE_DEFAULT_LOGGER_KEY;
+
+// The ACE_Service_Manager static service object is now defined by the
+// ACE_Object_Manager, in Object_Manager.cpp.
+
+// Are we initialized already?
+int ACE_Service_Config::is_initialized_ = 0;
+
+// List of statically configured services.
+
+ACE_STATIC_SVCS *ACE_Service_Config::static_svcs_ = 0;
+ACE_SVC_QUEUE *ACE_Service_Config::svc_queue_ = 0;
+ACE_SVC_QUEUE *ACE_Service_Config::svc_conf_file_queue_ = 0;
+
+ACE_STATIC_SVCS *
+ACE_Service_Config::static_svcs (void)
+{
+ if (ACE_Service_Config::static_svcs_ == 0)
+ ACE_NEW_RETURN (ACE_Service_Config::static_svcs_,
+ ACE_STATIC_SVCS,
+ 0);
+ return ACE_Service_Config::static_svcs_;
+}
+
+ACE_Allocator *
+ACE_Service_Config::alloc (void)
+{
+ ACE_TRACE ("ACE_Service_Config::allocator");
+ return ACE_Allocator::instance ();
+}
+
+ACE_Allocator *
+ACE_Service_Config::alloc (ACE_Allocator *r)
+{
+ ACE_TRACE ("ACE_Service_Config::allocator");
+ return ACE_Allocator::instance (r);
+}
+
+ACE_Reactor *
+ACE_Service_Config::reactor (void)
+{
+ ACE_TRACE ("ACE_Service_Config::reactor");
+ return ACE_Reactor::instance ();
+}
+
+ACE_Reactor *
+ACE_Service_Config::reactor (ACE_Reactor *r)
+{
+ ACE_TRACE ("ACE_Service_Config::reactor");
+ return ACE_Reactor::instance (r);
+}
+
+ACE_Service_Repository *
+ACE_Service_Config::svc_rep ()
+{
+ ACE_TRACE ("ACE_Service_Config::svc_rep");
+ return ACE_Service_Repository::instance ();
+}
+
+ACE_Service_Repository *
+ACE_Service_Config::svc_rep (ACE_Service_Repository *s)
+{
+ ACE_TRACE ("ACE_Service_Config::svc_rep");
+ return ACE_Service_Repository::instance (s);
+}
+
+ACE_Thread_Manager *
+ACE_Service_Config::thr_mgr (void)
+{
+ ACE_TRACE ("ACE_Service_Config::thr_mgr");
+
+#if defined (ACE_THREAD_MANAGER_LACKS_STATICS)
+ return ACE_THREAD_MANAGER_SINGLETON::instance ();
+#else /* ! ACE_THREAD_MANAGER_LACKS_STATICS */
+ return ACE_Thread_Manager::instance ();
+#endif /* ACE_THREAD_MANAGER_LACKS_STATICS */
+}
+
+#if ! defined (ACE_THREAD_MANAGER_LACKS_STATICS)
+ACE_Thread_Manager *
+ACE_Service_Config::thr_mgr (ACE_Thread_Manager *tm)
+{
+ ACE_TRACE ("ACE_Service_Config::thr_mgr");
+ return ACE_Thread_Manager::instance (tm);
+}
+#endif /* ! ACE_THREAD_MANAGER_LACKS_STATICS */
+
+// Totally remove <svc_name> from the daemon by removing it from the
+// ACE_Reactor, and unlinking it if necessary.
+
+int
+ACE_Service_Config::remove (const ACE_TCHAR svc_name[])
+{
+ ACE_TRACE ("ACE_Service_Config::remove");
+ return ACE_Service_Repository::instance ()->remove (svc_name);
+}
+
+// Suspend <svc_name>. Note that this will not unlink the service
+// from the daemon if it was dynamically linked, it will mark it as
+// being suspended in the Service Repository and call the <suspend>
+// member function on the appropriate <ACE_Service_Object>. A service
+// can be resumed later on by calling the <resume> method...
+
+int
+ACE_Service_Config::suspend (const ACE_TCHAR svc_name[])
+{
+ ACE_TRACE ("ACE_Service_Config::suspend");
+ return ACE_Service_Repository::instance ()->suspend (svc_name);
+}
+
+// Resume a SVC_NAME that was previously suspended or has not yet
+// been resumed (e.g., a static service).
+
+int
+ACE_Service_Config::resume (const ACE_TCHAR svc_name[])
+{
+ ACE_TRACE ("ACE_Service_Config::resume");
+ return ACE_Service_Repository::instance ()->resume (svc_name);
+}
+
+// Initialize the Service Repository. Note that this *must* be
+// performed in the constructor (rather than <open>) since otherwise
+// the repository will not be properly initialized to allow static
+// configuration of services...
+
+ACE_Service_Config::ACE_Service_Config (int ignore_static_svcs,
+ size_t size,
+ int signum)
+{
+ ACE_TRACE ("ACE_Service_Config::ACE_Service_Config");
+ ACE_Service_Config::no_static_svcs_ = ignore_static_svcs;
+ ACE_Service_Config::signum_ = signum;
+
+ // Initialize the Service Repository.
+ ACE_Service_Repository::instance (size);
+
+ // Initialize the ACE_Reactor (the ACE_Reactor should be the same
+ // size as the ACE_Service_Repository).
+ ACE_Reactor::instance ();
+}
+
+int
+ACE_Service_Config::init_svc_conf_file_queue (void)
+{
+ if (ACE_Service_Config::svc_conf_file_queue_ == 0)
+ ACE_NEW_RETURN (ACE_Service_Config::svc_conf_file_queue_,
+ ACE_SVC_QUEUE,
+ -1);
+ return 0;
+}
+
+// Handle the command-line options intended for the
+// ACE_Service_Config.
+
+int
+ACE_Service_Config::parse_args (int argc, ACE_TCHAR *argv[])
+{
+ ACE_TRACE ("ACE_Service_Config::parse_args");
+ ACE_Get_Opt getopt (argc,
+ argv,
+ ACE_LIB_TEXT ("bdf:k:nys:S:"),
+ 1); // Start at argv[1].
+
+ if (ACE_Service_Config::init_svc_conf_file_queue () == -1)
+ return -1;
+
+ for (int c; (c = getopt ()) != -1; )
+ switch (c)
+ {
+ case 'b':
+ ACE_Service_Config::be_a_daemon_ = 1;
+ break;
+ case 'd':
+ ACE::debug (1);
+ break;
+ case 'f':
+ if (ACE_Service_Config::svc_conf_file_queue_->enqueue_tail
+ (ACE_TString (getopt.opt_arg ())) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_LIB_TEXT ("%p\n"),
+ "enqueue_tail"),
+ -1);
+ break;
+ case 'k':
+ ACE_Service_Config::logger_key_ = getopt.opt_arg ();
+ break;
+ case 'n':
+ ACE_Service_Config::no_static_svcs_ = 1;
+ break;
+ case 'y':
+ ACE_Service_Config::no_static_svcs_ = 0;
+ break;
+ case 's':
+ {
+ // There's no point in dealing with this on NT since it
+ // doesn't really support signals very well...
+#if !defined (ACE_LACKS_UNIX_SIGNALS)
+ ACE_Service_Config::signum_ =
+ ACE_OS::atoi (getopt.opt_arg ());
+
+ if (ACE_Reactor::instance ()->register_handler
+ (ACE_Service_Config::signum_,
+ ACE_Service_Config::signal_handler_) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_LIB_TEXT ("cannot obtain signal handler\n")),
+ -1);
+#endif /* ACE_LACKS_UNIX_SIGNALS */
+ break;
+ }
+ case 'S':
+ if (ACE_Service_Config::svc_queue_ == 0)
+ ACE_NEW_RETURN (ACE_Service_Config::svc_queue_,
+ ACE_SVC_QUEUE,
+ -1);
+ if (ACE_Service_Config::svc_queue_->enqueue_tail
+ (ACE_TString (getopt.opt_arg ())) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_LIB_TEXT ("%p\n"),
+ "enqueue_tail"),
+ -1);
+ break;
+ default:
+ if (ACE::debug () > 0)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_LIB_TEXT ("%c is not a ACE_Service_Config option\n"),
+ c));
+ }
+
+ return 0;
+}
+
+// Initialize and activate a statically linked service.
+
+int
+ACE_Service_Config::initialize (const ACE_TCHAR svc_name[],
+ ACE_TCHAR *parameters)
+{
+ ACE_TRACE ("ACE_Service_Config::initialize");
+ ACE_ARGV args (parameters);
+ ACE_Service_Type *srp = 0;
+
+ if (ACE::debug ())
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_LIB_TEXT ("opening static service %s\n"),
+ svc_name));
+
+ if (ACE_Service_Repository::instance ()->find
+ (svc_name,
+ (const ACE_Service_Type **) &srp) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_LIB_TEXT ("%s not found\n"),
+ svc_name),
+ -1);
+ else if (srp->type ()->init (args.argc (),
+ args.argv ()) == -1)
+ {
+ // Remove this entry.
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("static initialization failed, %p\n"),
+ svc_name));
+ ACE_Service_Repository::instance ()->remove (svc_name);
+ return -1;
+ }
+ else
+ {
+ srp->active (1);
+ return 0;
+ }
+}
+
+// Dynamically link the shared object file and retrieve a pointer to
+// the designated shared object in this file.
+
+int
+ACE_Service_Config::initialize (const ACE_Service_Type *sr,
+ ACE_TCHAR parameters[])
+{
+ ACE_TRACE ("ACE_Service_Config::initialize");
+ ACE_ARGV args (parameters);
+
+ if (ACE::debug ())
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_LIB_TEXT ("opening dynamic service %s\n"),
+ sr->name ()));
+
+ if (sr->type ()->init (args.argc (),
+ args.argv ()) == -1)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("dynamic initialization failed for %s\n"),
+ sr->name ()));
+ return -1;
+ }
+ else
+ {
+ if (ACE_Service_Repository::instance ()->insert (sr) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_LIB_TEXT ("insertion failed, %p\n"),
+ sr->name ()),
+ -1);
+ return 0;
+ }
+}
+
+int
+ACE_Service_Config::process_directives_i (ACE_Svc_Conf_Param *param)
+{
+ // AC 970827 Skip the heap check because yacc allocates a buffer
+ // here which will be reported as a memory leak for some reason.
+ ACE_NO_HEAP_CHECK
+
+ // The fact that these are global variables means that we really
+ // can't track the number of errors in multiple threads
+ // simultaneously.
+ ace_yyerrno = 0;
+ ace_yylineno = 1;
+
+ ace_yyparse (param);
+
+ if (param->yyerrno > 0)
+ {
+ // This is a hack, better errors should be provided...
+ errno = EINVAL;
+ return param->yyerrno;
+ }
+ else
+ return 0;
+}
+
+int
+ACE_Service_Config::process_directive (const ACE_TCHAR directive[])
+{
+ ACE_TRACE ("ACE_Service_Config::process_directive");
+
+ if (ACE::debug ())
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_LIB_TEXT ("Service_Config::process_directive - %s\n"),
+ directive));
+
+ ACE_UNUSED_ARG (directive);
+
+ ACE_Svc_Conf_Param d (directive);
+
+ int result = ACE_Service_Config::process_directives_i (&d);
+
+ return result;
+}
+
+// Process service configuration requests as indicated in the queue of
+// svc.conf files.
+
+int
+ACE_Service_Config::process_directives (void)
+{
+ ACE_TRACE ("ACE_Service_Config::process_directives");
+
+ int result = 0;
+
+ if (ACE_Service_Config::svc_conf_file_queue_ != 0)
+ {
+ ACE_TString *sptr = 0;
+ ACE_SVC_QUEUE &queue = *ACE_Service_Config::svc_conf_file_queue_;
+
+ // Iterate through all the svc.conf files.
+ for (ACE_SVC_QUEUE_ITERATOR iter (queue);
+ iter.next (sptr) != 0;
+ iter.advance ())
+ {
+ FILE *fp = ACE_OS::fopen (sptr->fast_rep (),
+ ACE_LIB_TEXT ("r"));
+ if (fp == 0)
+ {
+ // Invalid svc.conf file. We'll report it here and
+ // break out of the method.
+ if (ACE::debug ())
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_LIB_TEXT ("%p\n"),
+ sptr->fast_rep ()));
+ errno = ENOENT;
+ result = -1;
+ break;
+ }
+ else
+ {
+ ACE_Svc_Conf_Param f (fp);
+
+ // Keep track of the number of errors.
+ result += ACE_Service_Config::process_directives_i (&f);
+ }
+ ACE_OS::fclose (fp);
+ }
+ }
+
+ return result;
+}
+
+int
+ACE_Service_Config::process_commandline_directives (void)
+{
+ int result = 0;
+
+ if (ACE_Service_Config::svc_queue_ != 0)
+ {
+ ACE_TString *sptr = 0;
+ ACE_SVC_QUEUE &queue = *ACE_Service_Config::svc_queue_;
+
+ for (ACE_SVC_QUEUE_ITERATOR iter (queue);
+ iter.next (sptr) != 0;
+ iter.advance ())
+ {
+ // Process just a single directive.
+ if (ACE_Service_Config::process_directive (sptr->fast_rep ()) != 0)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("%p\n"),
+ ACE_LIB_TEXT ("process_directive")));
+ result = -1;
+ }
+ }
+
+ delete ACE_Service_Config::svc_queue_;
+ ACE_Service_Config::svc_queue_ = 0;
+ }
+
+ return result;
+}
+
+int
+ACE_Service_Config::process_directive (const ACE_Static_Svc_Descriptor &ssd,
+ int force_replace)
+{
+ if (!force_replace)
+ {
+ if (ACE_Service_Repository::instance ()->find (ssd.name_,
+ 0, 0) >= 0)
+ {
+ // The service is already there, just return
+ return 0;
+ }
+ }
+
+ ACE_Service_Object_Exterminator gobbler;
+ void *sym = (ssd.alloc_)(&gobbler);
+
+ ACE_Service_Type_Impl *stp =
+ ace_create_service_type (ssd.name_,
+ ssd.type_,
+ sym,
+ ssd.flags_,
+ gobbler);
+ if (stp == 0)
+ return 0;
+
+
+ ACE_Service_Type *service_type;
+ ACE_NEW_RETURN (service_type,
+ ACE_Service_Type (ssd.name_,
+ stp,
+ 0,
+ ssd.active_),
+ -1);
+
+ return ACE_Service_Repository::instance ()->insert (service_type);
+}
+
+// Add the default statically-linked services to the Service
+// Repository.
+
+int
+ACE_Service_Config::load_static_svcs (void)
+{
+ ACE_TRACE ("ACE_Service_Config::load_static_svcs");
+
+ ACE_Static_Svc_Descriptor **ssdp = 0;
+ ACE_STATIC_SVCS &svcs = *ACE_Service_Config::static_svcs ();
+
+ for (ACE_STATIC_SVCS_ITERATOR iter (svcs);
+ iter.next (ssdp) != 0;
+ iter.advance ())
+ {
+ ACE_Static_Svc_Descriptor *ssd = *ssdp;
+
+ if (ACE_Service_Config::process_directive (*ssd, 1) == -1)
+ return -1;
+ }
+ return 0;
+}
+
+// Performs an open without parsing command-line arguments.
+
+int
+ACE_Service_Config::open_i (const ACE_TCHAR program_name[],
+ const ACE_TCHAR *logger_key,
+ int ignore_default_svc_conf_file,
+ int ignore_debug_flag)
+{
+ int result = 0;
+ ACE_TRACE ("ACE_Service_Config::open_i");
+ ACE_Log_Msg *log_msg = ACE_LOG_MSG;
+
+ // Record the current log setting upon entering this thread.
+ u_long old_process_mask = log_msg->priority_mask
+ (ACE_Log_Msg::PROCESS);
+ u_long old_thread_mask = log_msg->priority_mask
+ (ACE_Log_Msg::THREAD);
+
+ if (ACE_Service_Config::is_initialized_ != 0)
+ // Guard against reentrant processing!
+ return 0;
+ else
+ ACE_Service_Config::is_initialized_++;
+
+ if (ACE_Service_Config::init_svc_conf_file_queue () == -1)
+ return -1;
+ else if (!ignore_default_svc_conf_file
+ && ACE_Service_Config::svc_conf_file_queue_->is_empty ()
+ // Load the default "svc.conf" entry here if there weren't
+ // overriding -f arguments in <parse_args>.
+ && ACE_Service_Config::svc_conf_file_queue_->enqueue_tail
+ (ACE_TString (ACE_DEFAULT_SVC_CONF)) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_LIB_TEXT ("%p\n"),
+ "enqueue_tail"),
+ -1);
+
+ if (ignore_debug_flag == 0)
+ {
+ // If -d was included as a startup parameter, the user wants debug
+ // information printed during service initialization.
+ if (ACE::debug ())
+ ACE_Log_Msg::enable_debug_messages ();
+ else
+ // The user has requested no debugging info.
+ ACE_Log_Msg::disable_debug_messages ();
+ }
+
+ // Become a daemon before doing anything else.
+ if (ACE_Service_Config::be_a_daemon_)
+ ACE_Service_Config::start_daemon ();
+
+ u_long flags = log_msg->flags ();
+
+ if (flags == 0)
+ // Only use STDERR if the caller hasn't already set the flags.
+ flags = (u_long) ACE_Log_Msg::STDERR;
+
+ const ACE_TCHAR *key = logger_key;
+
+ if (key == 0 || ACE_OS::strcmp (key, ACE_DEFAULT_LOGGER_KEY) == 0)
+ // Only use the static <logger_key_> if the caller doesn't
+ // override it in the parameter list or if the key supplied is
+ // equal to the default static logger key.
+ key = ACE_Service_Config::logger_key_;
+ else
+ ACE_SET_BITS (flags, ACE_Log_Msg::LOGGER);
+
+ if (log_msg->open (program_name,
+ flags,
+ key) == -1)
+ result = -1;
+ else
+ {
+ if (ACE::debug ())
+ ACE_DEBUG ((LM_STARTUP,
+ ACE_LIB_TEXT ("starting up daemon %n\n")));
+
+ // Initialize the Service Repository (this will still work if
+ // user forgets to define an object of type ACE_Service_Config).
+ ACE_Service_Repository::instance (ACE_Service_Config::MAX_SERVICES);
+
+ // Initialize the ACE_Reactor (the ACE_Reactor should be the
+ // same size as the ACE_Service_Repository).
+ ACE_Reactor::instance ();
+
+ // There's no point in dealing with this on NT since it doesn't
+ // really support signals very well...
+#if !defined (ACE_LACKS_UNIX_SIGNALS)
+ // @@ This really ought to be a Singleton.
+ if (ACE_Reactor::instance ()->register_handler
+ (ACE_Service_Config::signum_,
+ ACE_Service_Config::signal_handler_) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("can't register signal handler\n")));
+#endif /* ACE_LACKS_UNIX_SIGNALS */
+
+ // See if we need to load the static services.
+ if (ACE_Service_Config::no_static_svcs_ == 0
+ && ACE_Service_Config::load_static_svcs () == -1)
+ result = -1;
+ else
+ {
+ if (ACE_Service_Config::process_commandline_directives () == -1)
+ result = -1;
+ else
+ result = ACE_Service_Config::process_directives ();
+ }
+ }
+
+ {
+ // Make sure to save/restore errno properly.
+ ACE_Errno_Guard error (errno);
+
+ if (ignore_debug_flag == 0)
+ {
+ // Reset debugging back to the way it was when we came into
+ // into <open_i>.
+ log_msg->priority_mask (old_process_mask, ACE_Log_Msg::PROCESS);
+ log_msg->priority_mask (old_thread_mask, ACE_Log_Msg::THREAD);
+ }
+ }
+
+ return result;
+}
+
+ACE_Service_Config::ACE_Service_Config (const ACE_TCHAR program_name[],
+ const ACE_TCHAR *logger_key)
+{
+ ACE_TRACE ("ACE_Service_Config::ACE_Service_Config");
+
+ if (this->open (program_name,
+ logger_key) == -1
+ && errno != ENOENT)
+ // Only print out an error if it wasn't the svc.conf file that was
+ // missing.
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("%p\n"),
+ program_name));
+}
+
+// Signal handling API to trigger dynamic reconfiguration.
+
+void
+ACE_Service_Config::handle_signal (int sig,
+ siginfo_t *,
+ ucontext_t *)
+{
+#if defined (ACE_NDEBUG)
+ ACE_UNUSED_ARG (sig);
+#else /* ! ACE_NDEBUG */
+ ACE_ASSERT (ACE_Service_Config::signum_ == sig);
+#endif /* ! ACE_NDEBUG */
+
+ ACE_Service_Config::reconfig_occurred_ = 1;
+}
+
+// Trigger the reconfiguration process.
+
+void
+ACE_Service_Config::reconfigure (void)
+{
+ ACE_TRACE ("ACE_Service_Config::reconfigure");
+
+ ACE_Service_Config::reconfig_occurred_ = 0;
+
+ if (ACE::debug ())
+ {
+#if !defined (ACE_NLOGGING)
+ time_t t = ACE_OS::time (0);
+#endif /* ! ACE_NLOGGING */
+ if (ACE::debug ())
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_LIB_TEXT ("beginning reconfiguration at %s"),
+ ACE_OS::ctime (&t)));
+ }
+ if (ACE_Service_Config::process_directives () == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("%p\n"),
+ ACE_LIB_TEXT ("process_directives")));
+}
+
+// Run the event loop until the <ACE_Reactor::handle_events>
+// method returns -1 or the <end_reactor_event_loop> method
+// is invoked.
+
+int
+ACE_Service_Config::run_reactor_event_loop (void)
+{
+ ACE_TRACE ("ACE_Service_Config::run_reactor_event_loop");
+
+ return ACE_Reactor::run_event_loop ();
+}
+
+// Run the event loop until the <ACE_Reactor::handle_events> method
+// returns -1, the <end_reactor_event_loop> method is invoked, or the
+// <ACE_Time_Value> expires.
+
+int
+ACE_Service_Config::run_reactor_event_loop (ACE_Time_Value &tv)
+{
+ ACE_TRACE ("ACE_Service_Config::run_reactor_event_loop");
+
+ return ACE_Reactor::run_event_loop (tv);
+}
+
+/* static */
+int
+ACE_Service_Config::end_reactor_event_loop (void)
+{
+ ACE_TRACE ("ACE_Service_Config::end_reactor_event_loop");
+ return ACE_Reactor::end_event_loop ();
+}
+
+/* static */
+int
+ACE_Service_Config::reactor_event_loop_done (void)
+{
+ ACE_TRACE ("ACE_Service_Config::reactor_event_loop_done");
+ return ACE_Reactor::event_loop_done ();
+}
+
+// Tidy up and perform last rites on a terminating ACE_Service_Config.
+int
+ACE_Service_Config::close (void)
+{
+ ACE_TRACE ("ACE_Service_Config::close");
+
+ ACE_Service_Config::is_initialized_--;
+ if (ACE_Service_Config::is_initialized_ > 0)
+ return 0;
+
+ // Delete the service repository. All the objects inside the
+ // service repository should already have been finalized.
+ ACE_Service_Config::close_svcs ();
+
+ // Delete the list fo svc.conf files
+ delete ACE_Service_Config::svc_conf_file_queue_;
+ ACE_Service_Config::svc_conf_file_queue_ = 0;
+
+ // Delete the dynamically allocated static_svcs instance.
+ delete ACE_Service_Config::static_svcs_;
+ ACE_Service_Config::static_svcs_ = 0;
+
+ return 0;
+}
+
+int
+ACE_Service_Config::close_svcs (void)
+{
+ ACE_TRACE ("ACE_Service_Config::close_svcs");
+
+ ACE_Service_Repository::close_singleton ();
+
+ return 0;
+}
+
+int
+ACE_Service_Config::fini_svcs (void)
+{
+ ACE_TRACE ("ACE_Service_Config::fini_svcs");
+
+ // Clear the LM_DEBUG bit from log messages if appropriate
+ if (ACE::debug ())
+ ACE_Log_Msg::disable_debug_messages ();
+
+ int result = 0;
+ if (ACE_Service_Repository::instance () != 0)
+ result = ACE_Service_Repository::instance ()->fini ();
+
+ // Since the fini() method of the objects inside the service
+ // repository may reference the ACE singletons, they must be
+ // destroyed after the objects have been finalized.
+ ACE_Service_Config::close_singletons ();
+
+ if (ACE::debug ())
+ ACE_Log_Msg::enable_debug_messages ();
+
+ return result;
+}
+
+int
+ACE_Service_Config::close_singletons (void)
+{
+ ACE_TRACE ("ACE_Service_Config::close_singletons");
+
+ ACE_Reactor::close_singleton ();
+
+#if (((defined (ACE_HAS_WINNT)) && (ACE_HAS_WINNT == 1)) || (defined (ACE_HAS_AIO_CALLS)))
+ ACE_Proactor::close_singleton ();
+#endif /* !ACE_HAS_WINCE */
+
+#if ! defined (ACE_THREAD_MANAGER_LACKS_STATICS)
+ ACE_Thread_Manager::close_singleton ();
+#endif /* ! ACE_THREAD_MANAGER_LACKS_STATICS */
+
+ return 0;
+}
+
+// Perform user-specified close activities and remove dynamic memory.
+
+ACE_Service_Config::~ACE_Service_Config (void)
+{
+ ACE_TRACE ("ACE_Service_Config::~ACE_Service_Config");
+}
+
+// ************************************************************
+
+/* static */
+int
+ACE_Service_Config::reconfig_occurred (void)
+{
+ ACE_TRACE ("ACE_Service_Config::reconfig_occurred");
+ return ACE_Service_Config::reconfig_occurred_ != 0;
+}
+
+void
+ACE_Service_Config::reconfig_occurred (int config_occurred)
+{
+ ACE_TRACE ("ACE_Service_Config::reconfig_occurred");
+ ACE_Service_Config::reconfig_occurred_ = config_occurred;
+}
+
+// Become a daemon (i.e., run as a "background" process).
+
+int
+ACE_Service_Config::start_daemon (void)
+{
+ ACE_TRACE ("ACE_Service_Config::start_daemon");
+ return ACE::daemonize ();
+}
+
+#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION)
+template class ACE_Array<ACE_Get_Opt::ACE_Get_Opt_Long_Option *>;
+template class ACE_Array_Base<ACE_Get_Opt::ACE_Get_Opt_Long_Option *>;
+#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA)
+#pragma instantiate ACE_Array<ACE_Get_Opt::ACE_Get_Opt_Long_Option *>
+#pragma instantiate ACE_Array_Base<ACE_Get_Opt::ACE_Get_Opt_Long_Option *>
+#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */
diff --git a/ace/Svcconf/Service_Config.h b/ace/Svcconf/Service_Config.h
new file mode 100644
index 00000000000..ffe4c4fd85e
--- /dev/null
+++ b/ace/Svcconf/Service_Config.h
@@ -0,0 +1,516 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Service_Config.h
+ *
+ * $Id$
+ *
+ * @author Douglas C. Schmidt <schmidt@cs.wustl.edu>
+ */
+//=============================================================================
+
+#ifndef ACE_SERVICE_CONFIG_H
+#define ACE_SERVICE_CONFIG_H
+#include "ace/pre.h"
+
+#include "ace/Svcconf/Service_Object.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "ace/IPC/Signal.h"
+#include "ace/Utils/Unbounded_Queue.h"
+#include "ace/Utils/Unbounded_Set.h"
+#include "ace/Utils/SString.h"
+
+// Forward decl.
+class ACE_Service_Repository;
+class ACE_Service_Type;
+class ACE_Allocator;
+class ACE_Reactor;
+class ACE_Thread_Manager;
+class ACE_Svc_Conf_Param;
+
+extern "C"
+{
+ typedef ACE_Service_Object *(*ACE_SERVICE_ALLOCATOR) (ACE_Service_Object_Exterminator *);
+}
+
+/**
+ * @class ACE_Static_Svc_Descriptor
+ *
+ * @brief Holds the information necessary to describe a statically linked
+ * Svc.
+ */
+class ACE_Static_Svc_Descriptor
+{
+public:
+ /// Name of the service.
+ const ACE_TCHAR *name_;
+
+ /// Type of service.
+ int type_;
+
+ /// Factory function that allocates the service.
+ ACE_SERVICE_ALLOCATOR alloc_;
+
+ /// Bitmask flags indicating how the framework should delete memory.
+ u_int flags_;
+
+ /// Flag indicating whether the service starts out active.
+ int active_;
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+public:
+ /// Compare two service descriptors for equality.
+ int operator== (ACE_Static_Svc_Descriptor &) const;
+
+ /// Compare two service descriptors for inequality.
+ int operator!= (ACE_Static_Svc_Descriptor &) const;
+};
+
+// Maintain a set of the statically linked service descriptors.
+typedef ACE_Unbounded_Set<ACE_Static_Svc_Descriptor *>
+ ACE_STATIC_SVCS;
+typedef ACE_Unbounded_Set_Iterator<ACE_Static_Svc_Descriptor *>
+ ACE_STATIC_SVCS_ITERATOR;
+
+// Maintain a queue of services to be configured from the
+// command-line.
+typedef ACE_Unbounded_Queue<ACE_TString>
+ ACE_SVC_QUEUE;
+typedef ACE_Unbounded_Queue_Iterator<ACE_TString>
+ ACE_SVC_QUEUE_ITERATOR;
+
+#define ACE_Component_Config ACE_Service_Config
+/**
+ * @class ACE_Service_Config
+ *
+ * @brief Supplies common server operations for dynamic and static
+ * configuration of services.
+ *
+ * The <ACE_Service_Config> uses the Monostate pattern. Therefore,
+ * you can only have one of these instantiated per-process.
+ * NOTE: the signal_handler_ static member is allocated by the
+ * <ACE_Object_Manager>. The <ACE_Service_Config> constructor
+ * uses signal_handler_. Therefore, if the program has any
+ * static <ACE_Service_Config> objects, there might be
+ * initialization order problems. They can be minimized, but
+ * not eliminated, by _not_ #defining
+ * <ACE_HAS_NONSTATIC_OBJECT_MANAGER>.
+ */
+class ACE_Export ACE_Service_Config
+{
+public:
+ enum
+ {
+ MAX_SERVICES = ACE_DEFAULT_SERVICE_REPOSITORY_SIZE
+ };
+
+ // = Initialization and termination methods.
+
+ /// Initialize the Service Repository.
+ ACE_Service_Config (int ignore_static_svcs = 1,
+ size_t size = ACE_Service_Config::MAX_SERVICES,
+ int signum = SIGHUP);
+
+ /**
+ * Performs an open without parsing command-line arguments. The
+ * <logger_key> indicates where to write the logging output, which
+ * is typically either a STREAM pipe or a socket address.
+ */
+ ACE_Service_Config (const ACE_TCHAR program_name[],
+ const ACE_TCHAR *logger_key = ACE_DEFAULT_LOGGER_KEY);
+
+ /**
+ * Performs an open without parsing command-line arguments. The
+ * <logger_key> indicates where to write the logging output, which
+ * is typically either a STREAM pipe or a socket address. If
+ * <ignore_default_svc_conf_file> is non-0 then the "svc.conf" file
+ * will be ignored. If <ignore_debug_flag> is non-0 then the
+ * application is responsible for setting the
+ * <ACE_Log_Msg::priority_mask> appropriately. Returns number of
+ * errors that occurred on failure and 0 otherwise.
+ */
+ static int open_i (const ACE_TCHAR program_name[],
+ const ACE_TCHAR *logger_key = ACE_DEFAULT_LOGGER_KEY,
+ int ignore_default_svc_conf_file = 0,
+ int ignore_debug_flag = 0);
+
+ /**
+ * Performs an open without parsing command-line arguments. The
+ * <logger_key> indicates where to write the logging output, which
+ * is typically either a STREAM pipe or a socket address. If
+ * <ignore_static_svcs> is 1 then static services are not loaded,
+ * otherwise, they are loaded. If <ignore_default_svc_conf_file> is
+ * non-0 then the <svc.conf> configuration file will be ignored.
+ * Returns zero upon success, -1 if the file is not found or cannot
+ * be opened (errno is set accordingly), otherwise returns the
+ * number of errors encountered loading the services in the
+ * specified svc.conf configuration file. If <ignore_debug_flag> is
+ * non-0 then the application is responsible for setting the
+ * <ACE_Log_Msg::priority_mask> appropriately.
+ */
+ static int open (const ACE_TCHAR program_name[],
+ const ACE_TCHAR *logger_key = ACE_DEFAULT_LOGGER_KEY,
+ int ignore_static_svcs = 1,
+ int ignore_default_svc_conf_file = 0,
+ int ignore_debug_flag = 0);
+
+ /**
+ * This is the primary entry point into the ACE_Service_Config (the
+ * constructor just handles simple initializations). It parses
+ * arguments passed in from <argc> and <argv> parameters. The
+ * arguments that are valid in a call to this method include:
+ *
+ * - '-b' Option to indicate that we should be a daemon
+ * - '-d' Turn on debugging mode
+ * - '-f' Option to read in the list of svc.conf file names
+ * - '-k' Option to read a wide string where in the logger output can
+ * be written
+ * - '-y' Option required to use statically linked services.
+ * A static service repostory will be constructed if the flag
+ * is used. Use this flag to override the default
+ * <ignore_static_svcs> flag at run-time.
+ * - '-n' Option to avoid using any statically linked services, which
+ * eliminates the need to construct the static service repository.
+ * - '-S' Option to read in the list of services on the command-line
+ * Please observe the difference between options '-f' that looks
+ * for a list of files and here a list of services.
+ *
+ * Returns number of errors that occurred on failure and 0
+ * otherwise.
+ *
+ * The <logger_key> indicates where to write the logging output,
+ * which is typically either a STREAM pipe or a socket address. If
+ * <ignore_static_svcs> is 1 then static services are not loaded,
+ * otherwise, they are loaded. If <ignore_default_svc_conf_file> is
+ * non-0 then the <svc.conf> configuration file will be ignored.
+ * Returns zero upon success, -1 if the file is not found or cannot
+ * be opened (errno is set accordingly), otherwise returns the
+ * number of errors encountered loading the services in the
+ * specified svc.conf configuration file. If <ignore_debug_flag> is
+ * non-0 then the application is responsible for setting the
+ * <ACE_Log_Msg::priority_mask> appropriately.
+ */
+ static int open (int argc,
+ ACE_TCHAR *argv[],
+ const ACE_TCHAR *logger_key = ACE_DEFAULT_LOGGER_KEY,
+ int ignore_static_svcs = 1,
+ int ignore_default_svc_conf = 0,
+ int ignore_debug_flag = 0);
+
+ /// Perform user-specified close activities and remove dynamic
+ /// memory.
+ virtual ~ACE_Service_Config (void);
+
+ /// Tidy up and perform last rites when ACE_Service_Config is shut
+ /// down. This method calls <close_svcs>. Returns 0.
+ static int close (void);
+
+ /// Perform user-specified close hooks and possibly delete all of the
+ /// configured services in the <Service_Repository>.
+ static int fini_svcs (void);
+
+ /**
+ * Perform user-specified close hooks on all of the configured
+ * services in the <Service_Repository>, then delete the
+ * <Service_Repository> itself. Returns 0.
+ */
+ static int close_svcs (void);
+
+ /**
+ * Delete the dynamically allocated Singletons (i.e., the <Reactor>,
+ * <Proactor>, <ReactorEx>, and <Thread_Manager>.
+ * Returns 0.
+ */
+ static int close_singletons (void);
+
+ // = Reactor event loop management methods.
+ /**
+ * Run the event loop until the <ACE_Reactor::handle_events> method
+ * returns -1 or the <end_reactor_event_loop> method is invoked.
+ * DO NOT USE THIS METHOD. It may be unsupported in future releases.
+ * Use <ACE_Reactor::run_event_loop> instead.
+ */
+ static int run_reactor_event_loop (void);
+
+ /**
+ * Run the event loop until the <ACE_Reactor::handle_events> method
+ * returns -1, the <end_reactor_event_loop> method is invoked, or the
+ * <ACE_Time_Value> expires.
+ * DO NOT USE THIS METHOD. It may be unsupported in future releases.
+ * <Use ACE_Reactor::run_event_loop> instead.
+ */
+ static int run_reactor_event_loop (ACE_Time_Value &tv);
+
+ /**
+ * Instruct the <ACE_Service_Config> to terminate its event loop and
+ * notifies the <ACE_Reactor::instance> so that it can wake up
+ * and close down gracefully.
+ * DO NOT USE THIS METHOD. It may be unsupported in future releases.
+ * Use <ACE_Reactor::end_event_loop> instead.
+ */
+ static int end_reactor_event_loop (void);
+
+ /**
+ * Report if the Reactor's event loop is finished.
+ * DO NOT USE THIS METHOD. It may be unsupported in future releases.
+ * Use <ACE_Reactor::event_loop_done> instead.
+ */
+ static int reactor_event_loop_done (void);
+
+ /// True if reconfiguration occurred.
+ static int reconfig_occurred (void);
+
+ /// Indicate that reconfiguration occurred.
+ static void reconfig_occurred (int);
+
+ /// Perform the reconfiguration process.
+ static void reconfigure (void);
+
+ // = The following methods are static in order to enforce Singleton
+ // semantics for the Reactor, Service_Repository, Thread_Manager,
+ // and Acceptor/Connector Strategy factory. Other portions of the
+ // system may need to access them at some point or another...
+
+ // = Accessors and mutators for process-wide Singletons.
+
+ /// Returns a pointer to the list of statically linked services.
+ static ACE_STATIC_SVCS *static_svcs (void);
+
+ /**
+ * Get pointer to a process-wide <ACE_Reactor>.
+ * DO NOT USE THIS METHOD. It may be unsupported in future releases.
+ * Use <ACE_Reactor::instance> instead.
+ */
+ static ACE_Reactor *reactor (void);
+
+ /**
+ * Set pointer to a process-wide <ACE_Reactor> and return existing
+ * pointer.
+ * DO NOT USE THIS METHOD. It may be unsupported in future releases.
+ * Use <ACE_Reactor::instance> instead.
+ */
+ static ACE_Reactor *reactor (ACE_Reactor *);
+
+ /**
+ * Get pointer to a process-wide <ACE_Service_Repository>.
+ * DO NOT USE THIS METHOD. It may be unsupported in future releases.
+ * Use <ACE_Service_Repository::instance> instead.
+ */
+ static ACE_Service_Repository *svc_rep (void);
+
+ /**
+ * Set pointer to a process-wide <ACE_Service_Repository> and return
+ * existing pointer.
+ * DO NOT USE THIS METHOD. It may be unsupported in future releases.
+ * Use <ACE_Service_Repository::instance> instead.
+ */
+ static ACE_Service_Repository *svc_rep (ACE_Service_Repository *);
+
+ /**
+ * Get pointer to a process-wide <ACE_Thread_Manager>.
+ * DO NOT USE THIS METHOD. It may be unsupported in future releases.
+ * Use <ACE_Thread_Manager::instance> instead.
+ */
+ static ACE_Thread_Manager *thr_mgr (void);
+
+#if ! defined (ACE_THREAD_MANAGER_LACKS_STATICS)
+ /**
+ * Set pointer to a process-wide <ACE_Thread_Manager> and return
+ * existing pointer.
+ * DO NOT USE THIS METHOD. It may be unsupported in future releases.
+ * Use ACE_Thread_Manager::instance() instead.
+ */
+ static ACE_Thread_Manager *thr_mgr (ACE_Thread_Manager *);
+#endif /* ! defined (ACE_THREAD_MANAGER_LACKS_STATICS) */
+
+ /**
+ * Get pointer to a default <ACE_Allocator>.
+ * DO NOT USE THIS METHOD. It may be unsupported in future releases.
+ * Use <ACE_Allocator::instance> instead.
+ */
+ static ACE_Allocator *alloc (void);
+
+ /**
+ * Set pointer to a process-wide <ACE_Allocator> and return existing
+ * pointer.
+ * DO NOT USE THIS METHOD. It may be unsupported in future releases.
+ * Use <ACE_Allocator::instance> instead.
+ */
+ static ACE_Allocator *alloc (ACE_Allocator *);
+
+ // = Utility methods.
+ /// Dynamically link the shared object file and retrieve a pointer to
+ /// the designated shared object in this file.
+ static int initialize (const ACE_Service_Type *,
+ ACE_TCHAR parameters[]);
+
+ /// Initialize and activate a statically <svc_name> service.
+ static int initialize (const ACE_TCHAR svc_name[],
+ ACE_TCHAR parameters[]);
+
+ /// Resume a <svc_name> that was previously suspended or has not yet
+ /// been resumed (e.g., a static service).
+ static int resume (const ACE_TCHAR svc_name[]);
+
+ /**
+ * Suspend <svc_name>. Note that this will not unlink the service
+ * from the daemon if it was dynamically linked, it will mark it as
+ * being suspended in the Service Repository and call the <suspend>
+ * member function on the appropriate <ACE_Service_Object>. A
+ * service can be resumed later on by calling the <RESUME> member
+ * function...
+ */
+ static int suspend (const ACE_TCHAR svc_name[]);
+
+ /// Totally remove <svc_name> from the daemon by removing it
+ /// from the ACE_Reactor, and unlinking it if necessary.
+ static int remove (const ACE_TCHAR svc_name[]);
+
+#if defined (ACE_HAS_WINCE)
+ // We must provide these function to bridge the Svc_Conf parser
+ // with ACE.
+ static int initialize (const ACE_Service_Type *, char parameters[]);
+ static int initialize (const char svc_name[], char parameters[]);
+ static int resume (const char svc_name[]);
+ static int suspend (const char svc_name[]);
+ static int remove (const char svc_name[]);
+#endif /* ACE_HAS_WINCE */
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Set the signal_handler;for internal use by ACE_Object_Manager only.
+ static ACE_INLINE void signal_handler (ACE_Sig_Adapter *);
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+ /// Process one service configuration <directive>, which is passed as
+ /// a string. Returns the number of errors that occurred.
+ static int process_directive (const ACE_TCHAR directive[]);
+
+ /// Process one static service definition.
+ /**
+ * Load a new static service into the ACE_Service_Repository.
+ *
+ * @param ssd Service descriptor, see the document of
+ * ACE_Static_Svc_Descriptor for more details.
+ *
+ * @param force_replace If set the new service descriptor replaces
+ * any previous instance in the ACE_Service_Repository.
+ *
+ * @return Returns -1 if the service cannot be 'loaded'.
+ */
+ static int process_directive (const ACE_Static_Svc_Descriptor &ssd,
+ int force_replace = 0);
+
+ /**
+ * Process (or re-process) service configuration requests that are
+ * provided in the svc.conf file(s). Returns the number of errors
+ * that occurred.
+ */
+ static int process_directives (void);
+
+ /// Handles signals to trigger reconfigurations.
+ static void handle_signal (int sig, siginfo_t *, ucontext_t *);
+
+ /**
+ * Handle the command-line options intended for the
+ * <ACE_Service_Config>. Note that <argv[0]> is assumed to be the
+ * program name.
+ * The arguments that are valid in a call to this method are
+ * - '-b' Option to indicate that we should be a daemon
+ * - '-d' Turn on debugging mode
+ * - '-f' Option to read in the list of svc.conf file names
+ * - '-k' Option to read a wide string where in the logger output can
+ * be written
+ * - '-y' Turn on the flag for a repository of statically
+ * linked services
+ * - '-n' Need not have a repository of statically linked services
+ * - '-S' Option to read in the list of services on the command-line
+ * Please observe the difference between options '-f' that looks
+ * for a list of files and here a list of services.
+ */
+ static int parse_args (int, ACE_TCHAR *argv[]);
+protected:
+ /// Process service configuration requests that were provided on the
+ /// command-line. Returns the number of errors that occurred.
+ static int process_commandline_directives (void);
+
+ /// This is the implementation function that process_directives()
+ /// and process_directive() both call. Returns the number of errors
+ /// that occurred.
+ static int process_directives_i (ACE_Svc_Conf_Param *param);
+
+ /// Become a daemon.
+ static int start_daemon (void);
+
+ /// Add the default statically-linked services to the
+ /// <ACE_Service_Repository>.
+ static int load_static_svcs (void);
+
+private:
+ /// Indicates where to write the logging output. This is typically
+ /// either a STREAM pipe or a socket address.
+ static const ACE_TCHAR *logger_key_;
+
+ /// Singleton repository of statically linked services.
+ static ACE_STATIC_SVCS *static_svcs_;
+
+ /// Queue of services specified on the command-line.
+ static ACE_SVC_QUEUE *svc_queue_;
+
+ /// Queue of svc.conf files specified on the command-line.
+ /// @@ This should probably be made to handle unicode filenames...
+ static ACE_SVC_QUEUE *svc_conf_file_queue_;
+
+ /// Initialize the <svc_conf_file_queue_> if necessary.
+ static int init_svc_conf_file_queue (void);
+
+ /// True if reconfiguration occurred.
+ static sig_atomic_t reconfig_occurred_;
+
+ // = Set by command-line options.
+ /// Shall we become a daemon process?
+ static int be_a_daemon_;
+
+ /// Should we avoid loading the static services?
+ static int no_static_svcs_;
+
+ /// Number of the signal used to trigger reconfiguration.
+ static int signum_;
+
+ /// Handles the reconfiguration signals.
+ static ACE_Sig_Adapter *signal_handler_;
+
+ /**
+ * Keep track of whether the <ACE_Service_Config> is already
+ * initialized. If so, we can't allow <yyparse> to be called since
+ * it's not reentrant. This variable is incremented by the
+ * <ACE_Service_Config::open> method and decremented by the
+ * <ACE_Service_Config::close> method.
+ */
+ static int is_initialized_;
+};
+
+#if defined (__ACE_INLINE__)
+#include "ace/Svcconf/Service_Config.i"
+#endif /* __ACE_INLINE__ */
+
+// These must go here to avoid circular includes... (only left here
+// for to not break applications which rely on this - no real need any
+// longer)
+#include "ace/Demux/Reactor.h"
+#include "ace/Svcconf/Svc_Conf_Tokens.h"
+#include "ace/post.h"
+#endif /* ACE_SERVICE_CONFIG_H */
diff --git a/ace/Svcconf/Service_Config.i b/ace/Svcconf/Service_Config.i
new file mode 100644
index 00000000000..42577cb1e04
--- /dev/null
+++ b/ace/Svcconf/Service_Config.i
@@ -0,0 +1,101 @@
+// -*- C++ -*-
+//
+// $Id$
+
+
+// This is the primary entry point into the ACE_Service_Config (the
+// constructor just handles simple initializations).
+
+ACE_INLINE int
+ACE_Service_Config::open (const ACE_TCHAR program_name[],
+ const ACE_TCHAR *logger_key,
+ int ignore_static_svcs,
+ int ignore_default_svc_conf,
+ int ignore_debug_flag)
+{
+ ACE_TRACE ("ACE_Service_Config::open");
+ ACE_Service_Config::no_static_svcs_ = ignore_static_svcs;
+
+ return ACE_Service_Config::open_i (program_name,
+ logger_key,
+ ignore_default_svc_conf,
+ ignore_debug_flag);
+}
+
+ACE_INLINE int
+ACE_Service_Config::open (int argc,
+ ACE_TCHAR *argv[],
+ const ACE_TCHAR *logger_key,
+ int ignore_static_svcs,
+ int ignore_default_svc_conf,
+ int ignore_debug_flag)
+{
+ ACE_TRACE ("ACE_Service_Config::open");
+ ACE_Service_Config::no_static_svcs_ = ignore_static_svcs;
+
+ if (ACE_Service_Config::parse_args (argc,
+ argv) == -1)
+ return -1;
+ else
+ return ACE_Service_Config::open_i (argv[0],
+ logger_key,
+ ignore_default_svc_conf,
+ ignore_debug_flag);
+}
+
+// Compare two service descriptors for equality.
+
+ACE_INLINE int
+ACE_Static_Svc_Descriptor::operator== (ACE_Static_Svc_Descriptor &d) const
+{
+ return ACE_OS::strcmp (name_, d.name_) == 0;
+}
+
+// Compare two service descriptors for inequality.
+
+ACE_INLINE int
+ACE_Static_Svc_Descriptor::operator!= (ACE_Static_Svc_Descriptor &d) const
+{
+ return !(*this == d);
+}
+
+ACE_INLINE void
+ACE_Service_Config::signal_handler (ACE_Sig_Adapter *signal_handler)
+{
+ signal_handler_ = signal_handler;
+}
+
+#if defined (ACE_HAS_WINCE) && !defined (ACE_USES_WCHAR)
+ // We must provide these function to bridge Svc_Conf parser with ACE.
+
+ACE_INLINE int
+ACE_Service_Config::initialize (const ACE_Service_Type *sp, char parameters[])
+{
+ return ACE_Service_Config::initialize (sp, ACE_TEXT_CHAR_TO_TCHAR (parameters));
+}
+
+ACE_INLINE int
+ACE_Service_Config::initialize (const char svc_name[], char parameters[])
+{
+ return ACE_Service_Config::initialize (ACE_TEXT_CHAR_TO_TCHAR (svc_name),
+ ACE_TEXT_CHAR_TO_TCHAR (parameters));
+}
+
+ACE_INLINE int
+ACE_Service_Config::resume (const char svc_name[])
+{
+ return ACE_Service_Config::resume (ACE_TEXT_CHAR_TO_TCHAR (svc_name));
+}
+
+ACE_INLINE int
+ACE_Service_Config::suspend (const char svc_name[])
+{
+ return ACE_Service_Config::suspend (ACE_TEXT_CHAR_TO_TCHAR (svc_name));
+}
+
+ACE_INLINE int
+ACE_Service_Config::remove (const char svc_name[])
+{
+ return ACE_Service_Config::remove (ACE_TEXT_CHAR_TO_TCHAR (svc_name));
+}
+#endif /* ACE_HAS_WINCE && !ACE_USES_WCHAR */
diff --git a/ace/Svcconf/Service_Manager.cpp b/ace/Svcconf/Service_Manager.cpp
new file mode 100644
index 00000000000..8d94f95bb70
--- /dev/null
+++ b/ace/Svcconf/Service_Manager.cpp
@@ -0,0 +1,367 @@
+// $Id$
+
+#include "ace/Get_Opt.h"
+#include "ace/Service_Repository.h"
+#include "ace/Service_Config.h"
+#include "ace/Service_Manager.h"
+#include "ace/Reactor.h"
+#include "ace/WFMO_Reactor.h"
+
+#if !defined (__ACE_INLINE__)
+#include "ace/Service_Manager.i"
+#endif /* __ACE_INLINE__ */
+
+ACE_RCSID(ace, Service_Manager, "$Id$")
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Service_Manager)
+
+void
+ACE_Service_Manager::dump (void) const
+{
+ ACE_TRACE ("ACE_Service_Manager::dump");
+}
+
+// Static variables.
+
+u_short ACE_Service_Manager::DEFAULT_PORT_ = 10000;
+
+ACE_Service_Manager::ACE_Service_Manager (void)
+ : debug_ (0),
+ signum_ (SIGHUP)
+{
+ ACE_TRACE ("ACE_Service_Manager::ACE_Service_Manager");
+}
+
+int
+ACE_Service_Manager::suspend (void)
+{
+ ACE_TRACE ("ACE_Service_Manager::suspend");
+ return ACE_Reactor::instance ()->suspend_handler (this);
+}
+
+int
+ACE_Service_Manager::resume (void)
+{
+ ACE_TRACE ("ACE_Service_Manager::resume");
+ return ACE_Reactor::instance ()->resume_handler (this);
+}
+
+int
+ACE_Service_Manager::open (const ACE_INET_Addr &sia)
+{
+ ACE_TRACE ("ACE_Service_Manager::open");
+
+ // Reuse the listening address, even if it's already in use!
+ if (this->acceptor_.open (sia, 1) == -1)
+ return -1;
+ return 0;
+}
+
+int
+ACE_Service_Manager::info (ACE_TCHAR **strp, size_t length) const
+{
+ ACE_TRACE ("ACE_Service_Manager::info");
+ ACE_INET_Addr sa;
+ ACE_TCHAR buf[BUFSIZ];
+
+ if (this->acceptor_.get_local_addr (sa) == -1)
+ return -1;
+
+ ACE_OS::sprintf (buf,
+ ACE_LIB_TEXT ("%d/%s %s"),
+ sa.get_port_number (),
+ ACE_LIB_TEXT ("tcp"),
+ ACE_LIB_TEXT ("# lists all services in the daemon\n"));
+ if (*strp == 0 && (*strp = ACE_OS::strdup (buf)) == 0)
+ return -1;
+ else
+ ACE_OS::strsncpy (*strp, buf, length);
+ return ACE_OS::strlen (buf);
+}
+
+int
+ACE_Service_Manager::init (int argc, ACE_TCHAR *argv[])
+{
+ ACE_TRACE ("ACE_Service_Manager::init");
+ ACE_INET_Addr local_addr (ACE_Service_Manager::DEFAULT_PORT_);
+ ACE_Get_Opt getopt (argc, argv, ACE_LIB_TEXT ("dp:s:"), 0); // Start at argv[0]
+
+ for (int c; (c = getopt ()) != -1; )
+ switch (c)
+ {
+ case 'd':
+ this->debug_ = 1;
+ break;
+ case 'p':
+ local_addr.set ((u_short) ACE_OS::atoi (getopt.opt_arg ()));
+ break;
+ case 's':
+ this->signum_ = ACE_OS::atoi (getopt.opt_arg ());
+ break;
+ default:
+ break;
+ }
+
+ if (this->get_handle () == ACE_INVALID_HANDLE &&
+ this->open (local_addr) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_LIB_TEXT ("%p\n"),
+ ACE_LIB_TEXT ("open")), -1);
+ else if (ACE_Reactor::instance ()->register_handler
+ (this,
+ ACE_Event_Handler::ACCEPT_MASK) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_LIB_TEXT ("registering service with ACE_Reactor\n")),
+ -1);
+ return 0;
+}
+
+int
+ACE_Service_Manager::handle_close (ACE_HANDLE, ACE_Reactor_Mask)
+{
+ ACE_TRACE ("ACE_Service_Manager::handle_close");
+ return this->acceptor_.close ();
+}
+
+int
+ACE_Service_Manager::fini (void)
+{
+ ACE_TRACE ("ACE_Service_Manager::fini");
+
+ int retv = 0;
+ if (this->get_handle () != ACE_INVALID_HANDLE)
+ {
+ retv = ACE_Reactor::instance ()->remove_handler
+ (this,
+ ACE_Event_Handler::ACCEPT_MASK |
+ ACE_Event_Handler::DONT_CALL);
+ this->handle_close (ACE_INVALID_HANDLE,
+ ACE_Event_Handler::NULL_MASK);
+ }
+ return retv;
+}
+
+ACE_HANDLE
+ACE_Service_Manager::get_handle (void) const
+{
+ ACE_TRACE ("ACE_Service_Manager::get_handle");
+ return this->acceptor_.get_handle ();
+}
+
+int
+ACE_Service_Manager::handle_signal (int, siginfo_t *, ucontext_t *)
+{
+ return 0;
+}
+
+// Determine all the services offered by this daemon and return the
+// information back to the client.
+
+int
+ACE_Service_Manager::list_services (void)
+{
+ ACE_TRACE ("ACE_Service_Manager::list_services");
+ ACE_Service_Repository_Iterator sri (*ACE_Service_Repository::instance (), 0);
+
+ for (const ACE_Service_Type *sr;
+ sri.next (sr) != 0;
+ sri.advance ())
+ {
+ int len = ACE_OS::strlen (sr->name ()) + 11;
+ ACE_TCHAR buf[BUFSIZ];
+ ACE_TCHAR *p = buf + len;
+
+ ACE_OS::strcpy (buf, sr->name ());
+ ACE_OS::strcat (buf, (sr->active ()) ?
+ ACE_LIB_TEXT (" (active) ") :
+ ACE_LIB_TEXT (" (paused) "));
+
+ p[-1] = ' ';
+ p[0] = '\0';
+
+ len += sr->type ()->info (&p, sizeof buf - len);
+
+ if (this->debug_)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_LIB_TEXT ("len = %d, info = %s%s"),
+ len,
+ buf,
+ buf[len - 1] == '\n' ? ACE_LIB_TEXT ("") : ACE_LIB_TEXT ("\n")));
+
+ if (len > 0)
+ {
+ ssize_t n = this->client_stream_.send_n (buf,
+ len);
+
+ if (n != len || (n == -1 && errno != EPIPE))
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("%p\n"),
+ ACE_LIB_TEXT ("send_n")));
+ }
+ }
+
+ return 0;
+}
+
+// Trigger a reconfiguration of the Service Configurator via its
+// svc.conf file.
+
+int
+ACE_Service_Manager::reconfigure_services (void)
+{
+ ACE_TRACE ("ACE_Service_Manager::reconfigure_services");
+
+#if 0
+// Send ourselves a signal! ACE_OS::kill (ACE_OS::getpid (),
+// this->signum_);
+#endif /* 0 */
+
+ // Flag the main event loop that a reconfiguration should occur.
+ // The next trip through the <ACE_Reactor::run_event_loop> should
+ // pick this up and cause a reconfiguration. Note that we can't
+ // trigger the reconfiguration automatically since that might "pull
+ // the rug" out from underneath the existing services in a
+ // problematic way.
+ ACE_Service_Config::reconfig_occurred ((sig_atomic_t) 1);
+ return this->client_stream_.send_n ("done\n",
+ sizeof ("done\n"));
+}
+
+// isolate the request-processing code
+void
+ACE_Service_Manager::process_request (ACE_TCHAR *request)
+{
+ ACE_TRACE("ACE_Service_Manager::process_request");
+ ACE_TCHAR *p;
+
+ // Kill trailing newlines.
+ for (p = request;
+ (*p != '\0') && (*p != '\r') && (*p != '\n');
+ p++)
+ continue;
+
+ *p = '\0';
+
+ if (ACE_OS::strcmp (request, ACE_LIB_TEXT ("help")) == 0)
+ // Return a list of the configured services.
+ this->list_services ();
+ else if (ACE_OS::strcmp (request, ACE_LIB_TEXT ("reconfigure") )== 0)
+ // Trigger a reconfiguration by re-reading the local <svc.conf> file.
+ this->reconfigure_services ();
+ else
+ // Just process a single request passed in via the socket
+ // remotely.
+ ACE_Service_Config::process_directive (request);
+
+ // Additional management services may be handled here...
+}
+
+// Accept new connection from client and carry out the service they
+// request.
+
+int
+ACE_Service_Manager::handle_input (ACE_HANDLE)
+{
+ ACE_TRACE ("ACE_Service_Manager::handle_input");
+
+ // Try to find out if the implementation of the reactor that we are
+ // using requires us to reset the event association for the newly
+ // created handle. This is because the newly created handle will
+ // inherit the properties of the listen handle, including its event
+ // associations.
+ int reset_new_handle =
+ ACE_Reactor::instance ()->uses_event_associations ();
+
+ if (this->acceptor_.accept (this->client_stream_, // stream
+ 0, // remote address
+ 0, // timeout
+ 1, // restart
+ reset_new_handle // reset new handler
+ ) == -1)
+ return -1;
+
+ if (this->debug_)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_LIB_TEXT ("client_stream fd = %d\n"),
+ this->client_stream_.get_handle ()));
+ ACE_INET_Addr sa;
+ if (this->client_stream_.get_remote_addr (sa) == -1)
+ return -1;
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_LIB_TEXT ("accepted from host %s at port %d\n"),
+ sa.get_host_name (),
+ sa.get_port_number ()));
+ }
+
+ ACE_TCHAR request[BUFSIZ];
+ ACE_TCHAR* offset = request;
+ ssize_t remaining = sizeof (request);
+
+ // Read service request from client.
+
+ ssize_t result;
+
+ // Keep looping until we actually get the request. Note that Win32
+ // sets the socket into non-blocking mode, so we may need to loop if
+ // the system is heavily loaded. Read bytes into the buffer until a
+ // '\n' or '\r' is found in the buffer, otherwise the buffer
+ // contains an incomplete string.
+ do
+ {
+ result = client_stream_.recv (offset, remaining);
+
+ if (result >= 0)
+ {
+ if ((remaining -= result) <= 0)
+ {
+ ACE_DEBUG ((LM_ERROR,
+ ACE_LIB_TEXT ("Request buffer overflow.\n")));
+ result = 0;
+ break;
+ }
+
+ offset += result;
+ *offset = 0;
+
+ if (ACE_OS::strchr (request, '\r') != 0
+ || ACE_OS::strchr (request, '\n') != 0)
+ remaining = 0;
+ }
+ }
+ while (result == -1 && errno == EWOULDBLOCK || remaining > 0);
+
+ switch (result)
+ {
+ case -1:
+ if (this->debug_)
+ ACE_DEBUG ((LM_ERROR,
+ ACE_LIB_TEXT ("%p\n"),
+ ACE_LIB_TEXT ("recv")));
+ break;
+ case 0:
+ return 0;
+ /* NOTREACHED */
+ default:
+ {
+ ACE_Event_Handler *old_signal_handler = 0;
+ ACE_Reactor::instance ()->register_handler (SIGPIPE,
+ this,
+ 0,
+ &old_signal_handler);
+
+ this->process_request (request);
+
+ // Restore existing SIGPIPE handler
+ ACE_Reactor::instance ()->register_handler (SIGPIPE,
+ old_signal_handler);
+ }
+ }
+
+ if (this->client_stream_.close () == -1 && this->debug_)
+ ACE_DEBUG ((LM_ERROR,
+ ACE_LIB_TEXT ("%p\n"),
+ ACE_LIB_TEXT ("close")));
+ return 0;
+}
diff --git a/ace/Svcconf/Service_Manager.h b/ace/Svcconf/Service_Manager.h
new file mode 100644
index 00000000000..2dbb4e5068b
--- /dev/null
+++ b/ace/Svcconf/Service_Manager.h
@@ -0,0 +1,120 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Service_Manager.h
+ *
+ * $Id$
+ *
+ * @author Douglas C. Schmidt <schmidt@cs.wustl.edu>
+ */
+//=============================================================================
+
+#ifndef ACE_SERVICE_MANAGER_H
+#define ACE_SERVICE_MANAGER_H
+#include "ace/pre.h"
+
+#include "ace/SOCK_Stream.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "ace/SOCK_Acceptor.h"
+#include "ace/INET_Addr.h"
+#include "ace/Service_Object.h"
+
+/**
+ * @class ACE_Service_Manager
+ *
+ * @brief Provide a standard ACE service for managing all the services
+ * configured in an <ACE_Service_Repository>.
+ *
+ * This implementation is simple and just handles each client
+ * request one at a time. There are currently 3 types of requests:
+ * + List services: If the string "help" is sent, return a list of all
+ * the services supported by the Service Configurator.
+ * + Reconfigure: If the string "reconfigure" is sent trigger a
+ * reconfiguration, which will re-read the local <svc.conf> file.
+ * + Process directive: If neither "help" nor "reconfigure" is sent,
+ * simply treat the incoming string as a process directive and pass
+ * it along to <ACE_Service_Config::process_directive>. This allows
+ * remote configuration via command-line instructions like
+ * % echo suspend My_Remote_Service | telnet hostname 3911
+ *
+ * Each request is associated with a new connection, which is closed
+ * when the request is processed. In addition, you must be using the
+ * singleton <ACE_Reactor::instance> in order to trigger
+ * reconfigurations.
+ */
+class ACE_Export ACE_Service_Manager : public ACE_Service_Object
+{
+public:
+ // = Initialization and termination hooks.
+ /// Constructor.
+ ACE_Service_Manager (void);
+
+ /// Destructor.
+ ~ACE_Service_Manager (void);
+
+protected:
+ // = Perform the various meta-services.
+
+ /// Trigger a reconfiguration of the Service Configurator by
+ //re-reading its local <svc.conf> file.
+ virtual int reconfigure_services (void);
+
+ /// Determine all the services offered by this daemon and return the
+ /// information back to the client.
+ virtual int list_services (void);
+
+ // = Dynamic linking hooks.
+ virtual int init (int argc, ACE_TCHAR *argv[]);
+ virtual int info (ACE_TCHAR **info_string, size_t length) const;
+ virtual int fini (void);
+
+ // = Scheduling hooks.
+ virtual int suspend (void);
+ virtual int resume (void);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+private:
+ int open (const ACE_INET_Addr &sia);
+
+ // = Demultiplexing hooks.
+ virtual ACE_HANDLE get_handle (void) const;
+ virtual int handle_input (ACE_HANDLE fd);
+ virtual int handle_close (ACE_HANDLE fd, ACE_Reactor_Mask);
+ virtual int handle_signal (int signum, siginfo_t *, ucontext_t *);
+
+ /// Handle one request.
+ virtual void process_request (ACE_TCHAR *request);
+
+ /// Connection to the client (we only support one client connection
+ /// at a time).
+ ACE_SOCK_Stream client_stream_;
+
+ /// Acceptor instance.
+ ACE_SOCK_Acceptor acceptor_;
+
+ /// Keep track of the debugging level.
+ int debug_;
+
+ /// The signal used to trigger reconfiguration.
+ int signum_;
+
+ /// Default port for the Acceptor to listen on.
+ static u_short DEFAULT_PORT_;
+};
+
+#if defined (__ACE_INLINE__)
+#include "ace/Service_Manager.i"
+#endif /* __ACE_INLINE__ */
+
+#include "ace/post.h"
+#endif /* _SERVICE_MANAGER_H */
diff --git a/ace/Svcconf/Service_Manager.i b/ace/Svcconf/Service_Manager.i
new file mode 100644
index 00000000000..a040265d05f
--- /dev/null
+++ b/ace/Svcconf/Service_Manager.i
@@ -0,0 +1,10 @@
+/* -*- C++ -*- */
+// $Id$
+
+// Service_Manager.i
+
+ACE_INLINE
+ACE_Service_Manager::~ACE_Service_Manager (void)
+{
+ ACE_TRACE ("ACE_Service_Manager::~ACE_Service_Manager");
+}
diff --git a/ace/Svcconf/Service_Object.cpp b/ace/Svcconf/Service_Object.cpp
new file mode 100644
index 00000000000..c5dfa7ce240
--- /dev/null
+++ b/ace/Svcconf/Service_Object.cpp
@@ -0,0 +1,96 @@
+// $Id$
+
+#include "ace/Service_Types.h"
+#include "ace/Service_Object.h"
+
+#if !defined (__ACE_INLINE__)
+#include "ace/Service_Object.i"
+#endif /* __ACE_INLINE__ */
+
+ACE_RCSID(ace, Service_Object, "$Id$")
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Service_Object)
+ACE_ALLOC_HOOK_DEFINE(ACE_Service_Type)
+
+void
+ACE_Service_Type::dump (void) const
+{
+ ACE_TRACE ("ACE_Service_Type::dump");
+}
+
+ACE_Service_Type::ACE_Service_Type (const ACE_TCHAR *n,
+ ACE_Service_Type_Impl *t,
+ const ACE_SHLIB_HANDLE h,
+ int active)
+ : name_ (0),
+ type_ (t),
+ handle_ (h),
+ active_ (active),
+ fini_already_called_ (0)
+{
+ ACE_TRACE ("ACE_Service_Type::ACE_Service_Type");
+ this->name (n);
+}
+
+ACE_Service_Type::~ACE_Service_Type (void)
+{
+ ACE_TRACE ("ACE_Service_Type::~ACE_Service_Type");
+
+ this->fini ();
+
+ if (this->handle_ != 0)
+ ACE_OS::dlclose ((ACE_SHLIB_HANDLE) this->handle_);
+
+ delete [] (ACE_TCHAR *) this->name_;
+}
+
+void
+ACE_Service_Type::fini (void)
+{
+ if (!this->fini_already_called_)
+ {
+ this->type_->fini ();
+ this->fini_already_called_ = 1;
+ }
+}
+
+void
+ACE_Service_Type::suspend (void) const
+{
+ ACE_TRACE ("ACE_Service_Type::suspend");
+ ((ACE_Service_Type *) this)->active_ = 0;
+ this->type_->suspend ();
+}
+
+void
+ACE_Service_Type::resume (void) const
+{
+ ACE_TRACE ("ACE_Service_Type::resume");
+ ((ACE_Service_Type *) this)->active_ = 1;
+ this->type_->resume ();
+}
+
+ACE_Service_Object::ACE_Service_Object (ACE_Reactor *r)
+ : ACE_Event_Handler (r)
+{
+ ACE_TRACE ("ACE_Service_Object::ACE_Service_Object");
+}
+
+ACE_Service_Object::~ACE_Service_Object (void)
+{
+ ACE_TRACE ("ACE_Service_Object::~ACE_Service_Object");
+}
+
+int
+ACE_Service_Object::suspend (void)
+{
+ ACE_TRACE ("ACE_Service_Object::suspend");
+ return 0;
+}
+
+int
+ACE_Service_Object::resume (void)
+{
+ ACE_TRACE ("ACE_Service_Object::resume");
+ return 0;
+}
diff --git a/ace/Svcconf/Service_Object.h b/ace/Svcconf/Service_Object.h
new file mode 100644
index 00000000000..2801a8be3c4
--- /dev/null
+++ b/ace/Svcconf/Service_Object.h
@@ -0,0 +1,164 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Service_Object.h
+ *
+ * $Id$
+ *
+ * @author Douglas C. Schmidt <schmidt@cs.wustl.edu>
+ */
+//=============================================================================
+
+#ifndef ACE_SERVICE_OBJECT_H
+#define ACE_SERVICE_OBJECT_H
+#include "ace/pre.h"
+
+#include "ace/Shared_Object.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "ace/Event_Handler.h"
+
+#define ACE_Component ACE_Service_Object
+/**
+ * @class ACE_Service_Object
+ *
+ * @brief Provide the abstract base class common to all service
+ * implementations.
+ *
+ * Classes that inherit from <ACE_Service_Objects> are capable
+ * of being registered with the <ACE_Reactor> (due to the
+ * <ACE_Event_Handler>, as well as being dynamically linked by
+ * the <ACE_Service_Config> (due to the <ACE_Shared_Object>).
+ */
+class ACE_Export ACE_Service_Object : public ACE_Event_Handler, public ACE_Shared_Object
+{
+public:
+ // = Initialization and termination methods.
+ /// Constructor.
+ ACE_Service_Object (ACE_Reactor * = 0);
+
+ /// Destructor.
+ virtual ~ACE_Service_Object (void);
+
+ /// Temporarily disable a service without removing it completely.
+ virtual int suspend (void);
+
+ /// Re-enable a previously suspended service.
+ virtual int resume (void);
+};
+
+// Forward decl.
+class ACE_Service_Type_Impl;
+
+/**
+ * @class ACE_Service_Type
+ *
+ * @brief Keeps track of information related to the various
+ * <ACE_Service_Type_Impl> subclasses.
+ *
+ * This class acts as the interface of the "Bridge" pattern.
+ */
+class ACE_Export ACE_Service_Type
+{
+public:
+ enum
+ {
+ /// Delete the payload object.
+ DELETE_OBJ = 1,
+
+ /// Delete the enclosing object.
+ DELETE_THIS = 2
+ };
+
+ // = Initialization and termination methods.
+ ACE_Service_Type (const ACE_TCHAR *n,
+ ACE_Service_Type_Impl *o,
+ const ACE_SHLIB_HANDLE handle,
+ int active);
+ ~ACE_Service_Type (void);
+
+ const ACE_TCHAR *name (void) const;
+ void name (const ACE_TCHAR *);
+
+ const ACE_Service_Type_Impl *type (void) const;
+ void type (const ACE_Service_Type_Impl *,
+ int active = 1);
+
+ ACE_SHLIB_HANDLE handle (void) const;
+ void handle (const ACE_SHLIB_HANDLE);
+
+ void suspend (void) const;
+ void resume (void) const;
+ int active (void) const;
+ void active (int);
+
+ /// Calls <fini> on <type_>
+ void fini (void);
+
+ /// Check if the service has been fini'ed.
+ int fini_called (void) const;
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+private:
+ /// Humanly readible name of svc.
+ const ACE_TCHAR *name_;
+
+ /// Pointer to C++ object that implements the svc.
+ const ACE_Service_Type_Impl *type_;
+
+ /// Handle to shared object file (non-zero if dynamically linked).
+ ACE_SHLIB_HANDLE handle_;
+
+ /// 1 if svc is currently active, otherwise 0.
+ int active_;
+
+ /// 1 if <fini> on <type_> has already been called, otherwise 0.
+ int fini_already_called_;
+};
+
+/**
+ * @class ACE_Service_Object_Ptr
+ *
+ * @brief This is a smart pointer that holds onto the associated
+ * <ACE_Service_Object> * until the current scope is left, at
+ * which point the object's <fini> hook is called and the
+ * service_object_ gets deleted.
+ *
+ * This class is similar to the Standard C++ Library class
+ * <auto_ptr>. It is used in conjunction with statically linked
+ * <ACE_Service_Objects>, as shown in the
+ * ./netsvcs/server/main.cpp example.
+ */
+class ACE_Export ACE_Service_Object_Ptr
+{
+public:
+ // = Initialization and termination methods.
+ /// Acquire ownership of the <so>.
+ ACE_Service_Object_Ptr (ACE_Service_Object *so);
+
+ /// Release the held <ACE_Service_Object> by calling its <fini> hook.
+ ~ACE_Service_Object_Ptr (void);
+
+ /// Smart pointer to access the underlying <ACE_Service_Object>.
+ ACE_Service_Object *operator-> ();
+
+private:
+ /// Holds the service object until we're done.
+ ACE_Service_Object *service_object_;
+};
+
+#if defined (__ACE_INLINE__)
+#include "ace/Service_Object.i"
+#endif /* __ACE_INLINE__ */
+
+#include "ace/post.h"
+#endif /* ACE_SERVICE_OBJECT_H */
diff --git a/ace/Svcconf/Service_Object.i b/ace/Svcconf/Service_Object.i
new file mode 100644
index 00000000000..7b735cf6c1f
--- /dev/null
+++ b/ace/Svcconf/Service_Object.i
@@ -0,0 +1,87 @@
+/* -*- C++ -*- */
+// $Id$
+
+// Service_Object.i
+
+ACE_INLINE ACE_Service_Object_Ptr::ACE_Service_Object_Ptr (ACE_Service_Object *so)
+ : service_object_ (so)
+{
+}
+
+ACE_INLINE ACE_Service_Object_Ptr::~ACE_Service_Object_Ptr (void)
+{
+ this->service_object_->fini ();
+ delete this->service_object_;
+}
+
+ACE_INLINE ACE_Service_Object *
+ACE_Service_Object_Ptr::operator-> ()
+{
+ return this->service_object_;
+}
+
+ACE_INLINE const ACE_TCHAR *
+ACE_Service_Type::name (void) const
+{
+ ACE_TRACE ("ACE_Service_Type::name");
+ return this->name_;
+}
+
+ACE_INLINE const ACE_Service_Type_Impl *
+ACE_Service_Type::type (void) const
+{
+ ACE_TRACE ("ACE_Service_Type::type");
+ return this->type_;
+}
+
+ACE_INLINE ACE_SHLIB_HANDLE
+ACE_Service_Type::handle (void) const
+{
+ ACE_TRACE ("ACE_Service_Type::handle");
+ return this->handle_;
+}
+
+ACE_INLINE void
+ACE_Service_Type::name (const ACE_TCHAR *n)
+{
+ ACE_TRACE ("ACE_Service_Type::name");
+
+ delete [] (ACE_TCHAR *) this->name_;
+ this->name_ = ACE::strnew (n);
+}
+
+ACE_INLINE void
+ACE_Service_Type::type (const ACE_Service_Type_Impl *o, int enabled)
+{
+ ACE_TRACE ("ACE_Service_Type::type");
+ this->type_ = o;
+ ((ACE_Service_Type *) this)->active_ = enabled;
+}
+
+ACE_INLINE void
+ACE_Service_Type::handle (const ACE_SHLIB_HANDLE h)
+{
+ ACE_TRACE ("ACE_Service_Type::handle");
+ this->handle_ = h;
+}
+
+ACE_INLINE int
+ACE_Service_Type::active (void) const
+{
+ ACE_TRACE ("ACE_Service_Type::active");
+ return this->active_ != 0;
+}
+
+ACE_INLINE void
+ACE_Service_Type::active (int turnon)
+{
+ ACE_TRACE ("ACE_Service_Type::active");
+ this->active_ = turnon;
+}
+
+ACE_INLINE int
+ACE_Service_Type::fini_called (void) const
+{
+ ACE_TRACE ("ACE_Service_Type::fini_called");
+ return this->fini_already_called_;
+}
diff --git a/ace/Svcconf/Service_Repository.cpp b/ace/Svcconf/Service_Repository.cpp
new file mode 100644
index 00000000000..21e7c47c6e6
--- /dev/null
+++ b/ace/Svcconf/Service_Repository.cpp
@@ -0,0 +1,416 @@
+// Service_Repository.cpp
+// $Id$
+
+#include "ace/Service_Repository.h"
+#include "ace/Object_Manager.h"
+#include "ace/Log_Msg.h"
+
+#if !defined (__ACE_INLINE__)
+#include "ace/Service_Repository.i"
+#endif /* __ACE_INLINE__ */
+
+ACE_RCSID(ace, Service_Repository, "$Id$")
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Service_Repository)
+
+// Process-wide Service Repository.
+ACE_Service_Repository *ACE_Service_Repository::svc_rep_ = 0;
+
+// Controls whether the Service_Repository is deleted when we shut
+// down (we can only delete it safely if we created it)!
+int ACE_Service_Repository::delete_svc_rep_ = 0;
+
+void
+ACE_Service_Repository::dump (void) const
+{
+ ACE_TRACE ("ACE_Service_Repository::dump");
+}
+
+ACE_Service_Repository::ACE_Service_Repository (void)
+ : service_vector_ (0),
+ current_size_ (0),
+ total_size_ (0)
+{
+ ACE_TRACE ("ACE_Service_Repository::ACE_Service_Repository");
+}
+
+ACE_Service_Repository *
+ACE_Service_Repository::instance (int size /* = ACE_Service_Repository::DEFAULT_SIZE */)
+{
+ ACE_TRACE ("ACE_Service_Repository::instance");
+
+ if (ACE_Service_Repository::svc_rep_ == 0)
+ {
+ // Perform Double-Checked Locking Optimization.
+ ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon,
+ *ACE_Static_Object_Lock::instance (), 0));
+ if (ACE_Service_Repository::svc_rep_ == 0)
+ {
+ if (ACE_Object_Manager::starting_up () ||
+ !ACE_Object_Manager::shutting_down ())
+ {
+ ACE_NEW_RETURN (ACE_Service_Repository::svc_rep_,
+ ACE_Service_Repository (size),
+ 0);
+ ACE_Service_Repository::delete_svc_rep_ = 1;
+ }
+ }
+ }
+
+ return ACE_Service_Repository::svc_rep_;
+}
+
+ACE_Service_Repository *
+ACE_Service_Repository::instance (ACE_Service_Repository *s)
+{
+ ACE_TRACE ("ACE_Service_Repository::instance");
+ ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon,
+ *ACE_Static_Object_Lock::instance (), 0));
+
+ ACE_Service_Repository *t = ACE_Service_Repository::svc_rep_;
+ // We can't safely delete it since we don't know who created it!
+ ACE_Service_Repository::delete_svc_rep_ = 0;
+
+ ACE_Service_Repository::svc_rep_ = s;
+ return t;
+}
+
+void
+ACE_Service_Repository::close_singleton (void)
+{
+ ACE_TRACE ("ACE_Service_Repository::close_singleton");
+
+ ACE_MT (ACE_GUARD (ACE_Recursive_Thread_Mutex, ace_mon,
+ *ACE_Static_Object_Lock::instance ()));
+
+ if (ACE_Service_Repository::delete_svc_rep_)
+ {
+ delete ACE_Service_Repository::svc_rep_;
+ ACE_Service_Repository::svc_rep_ = 0;
+ ACE_Service_Repository::delete_svc_rep_ = 0;
+ }
+}
+
+// Initialize the Repository to a clean slate.
+
+int
+ACE_Service_Repository::open (int size)
+{
+ ACE_TRACE ("ACE_Service_Repository::open");
+
+ ACE_Service_Type **temp;
+
+ ACE_NEW_RETURN (temp,
+ ACE_Service_Type *[size],
+ -1);
+
+ this->service_vector_ = ACE_const_cast (const ACE_Service_Type **,
+ temp);
+ this->total_size_ = size;
+ return 0;
+}
+
+ACE_Service_Repository::ACE_Service_Repository (int size)
+ : current_size_ (0)
+{
+ ACE_TRACE ("ACE_Service_Repository::ACE_Service_Repository");
+
+ if (this->open (size) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("%p\n"),
+ ACE_LIB_TEXT ("ACE_Service_Repository")));
+}
+
+// Finalize (call <fini> and possibly delete) all the services.
+
+int
+ACE_Service_Repository::fini (void)
+{
+ ACE_TRACE ("ACE_Service_Repository::fini");
+ ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1));
+
+ if (this->service_vector_ != 0)
+ {
+ // <fini> the services in reverse order. Note that if services
+ // were removed from the middle of the repository the order
+ // won't necessarily be maintained since the <remove> method
+ // performs compaction. However, the common case is not to
+ // remove services, so typically they are deleted in reverse
+ // order.
+
+ for (int i = this->current_size_ - 1; i >= 0; i--)
+ {
+ if (ACE::debug ())
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_LIB_TEXT ("finalizing %s\n"),
+ this->service_vector_[i]->name ()));
+ ACE_Service_Type *s =
+ ACE_const_cast (ACE_Service_Type *,
+ this->service_vector_[i]);
+ s->fini ();
+ }
+ }
+
+ return 0;
+}
+
+// Close down all the services.
+
+int
+ACE_Service_Repository::close (void)
+{
+ ACE_TRACE ("ACE_Service_Repository::close");
+ ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1));
+
+ if (this->service_vector_ != 0)
+ {
+ // Delete services in reverse order. Note that if services were
+ // removed from the middle of the repository the order won't
+ // necessarily be maintained since the <remove> method performs
+ // compaction. However, the common case is not to remove
+ // services, so typically they are deleted in reverse order.
+
+ for (int i = this->current_size_ - 1; i >= 0; i--)
+ {
+ ACE_Service_Type *s = ACE_const_cast (ACE_Service_Type *,
+ this->service_vector_[i]);
+ --this->current_size_;
+ delete s;
+ }
+
+ delete [] this->service_vector_;
+ this->service_vector_ = 0;
+ this->current_size_ = 0;
+ }
+
+ return 0;
+}
+
+ACE_Service_Repository::~ACE_Service_Repository (void)
+{
+ ACE_TRACE ("ACE_Service_Repository::~ACE_Service_Repository");
+ this->close ();
+}
+
+// Locate an entry with <name> in the table. If <ignore_suspended> is
+// set then only consider services marked as resumed. If the caller
+// wants the located entry, pass back a pointer to the located entry
+// via <srp>. If <name> is not found -1 is returned. If <name> is
+// found, but it is suspended and the caller wants to ignore suspended
+// services a -2 is returned. Must be called with locks held.
+
+int
+ACE_Service_Repository::find_i (const ACE_TCHAR name[],
+ const ACE_Service_Type **srp,
+ int ignore_suspended)
+{
+ ACE_TRACE ("ACE_Service_Repository::find_i");
+ int i;
+
+ for (i = 0; i < this->current_size_; i++)
+ if (ACE_OS::strcmp (name,
+ this->service_vector_[i]->name ()) == 0)
+ break;
+
+ if (i < this->current_size_)
+ {
+ if (this->service_vector_[i]->fini_called ())
+ {
+ if (srp != 0)
+ *srp = 0;
+ return -1;
+ }
+
+ if (srp != 0)
+ *srp = this->service_vector_[i];
+ if (ignore_suspended
+ && this->service_vector_[i]->active () == 0)
+ return -2;
+ return i;
+ }
+ else
+ return -1;
+}
+
+int
+ACE_Service_Repository::find (const ACE_TCHAR name[],
+ const ACE_Service_Type **srp,
+ int ignore_suspended)
+{
+ ACE_TRACE ("ACE_Service_Repository::find");
+ ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1));
+
+ return this->find_i (name, srp, ignore_suspended);
+}
+
+
+// Insert the ACE_Service_Type SR into the repository. Note that
+// services may be inserted either resumed or suspended.
+
+int
+ACE_Service_Repository::insert (const ACE_Service_Type *sr)
+{
+ ACE_TRACE ("ACE_Service_Repository::insert");
+ ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1));
+ int i;
+
+ // Check to see if this is a duplicate.
+ for (i = 0; i < this->current_size_; i++)
+ if (ACE_OS::strcmp (sr->name (),
+ this->service_vector_[i]->name ()) == 0)
+ break;
+
+ // Replacing an existing entry
+ if (i < this->current_size_)
+ {
+ // Check for self-assignment...
+ if (sr == this->service_vector_[i])
+ return 0;
+ ACE_Service_Type *s = ACE_const_cast (ACE_Service_Type *,
+ this->service_vector_[i]);
+ delete s;
+ this->service_vector_[i] = sr;
+ return 0;
+ }
+ // Adding a new entry.
+ else if (i < this->total_size_)
+ {
+ this->service_vector_[i] = sr;
+ this->current_size_++;
+ return 0;
+ }
+
+ return -1;
+}
+
+// Re-resume a service that was previously suspended.
+
+int
+ACE_Service_Repository::resume (const ACE_TCHAR name[],
+ const ACE_Service_Type **srp)
+{
+ ACE_TRACE ("ACE_Service_Repository::resume");
+ ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1));
+
+ int i = this->find_i (name, srp, 0);
+
+ if (i == -1)
+ return -1;
+
+ this->service_vector_[i]->resume ();
+ return 0;
+}
+
+// Suspend a service so that it will not be considered active under
+// most circumstances by other portions of the ACE_Service_Repository.
+
+int
+ACE_Service_Repository::suspend (const ACE_TCHAR name[],
+ const ACE_Service_Type **srp)
+{
+ ACE_TRACE ("ACE_Service_Repository::suspend");
+ ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1));
+ int i = this->find_i (name, srp, 0);
+
+ if (i == -1)
+ return -1;
+
+ this->service_vector_[i]->suspend ();
+ return 0;
+}
+
+// Completely remove a <name> entry from the Repository and
+// dynamically unlink it if it was originally dynamically linked.
+// Since the order of services in the Respository does not matter, we
+// simply overwrite the entry being deleted with the final entry in
+// the array and decrement the <current_size> by 1.
+
+int
+ACE_Service_Repository::remove (const ACE_TCHAR name[])
+{
+ ACE_TRACE ("ACE_Service_Repository::remove");
+ ACE_Service_Type *s = 0;
+ {
+ ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1));
+ int i = this->find_i (name, 0, 0);
+
+ if (i == -1)
+ return -1;
+
+ s = ACE_const_cast (ACE_Service_Type *,
+ this->service_vector_[i]);
+ --this->current_size_;
+
+ if (this->current_size_ >= 1)
+ this->service_vector_[i]
+ = this->service_vector_[this->current_size_];
+ }
+ delete s;
+ return 0;
+}
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Service_Repository_Iterator)
+
+void
+ACE_Service_Repository_Iterator::dump (void) const
+{
+ ACE_TRACE ("ACE_Service_Repository_Iterator::dump");
+}
+
+// Initializes the iterator and skips over any suspended entries at
+// the beginning of the table, if necessary. Note, you must not
+// perform destructive operations on elements during this iteration...
+
+ACE_Service_Repository_Iterator::ACE_Service_Repository_Iterator
+ (ACE_Service_Repository &sr,
+ int ignr_suspended)
+ : svc_rep_ (sr),
+ next_ (-1),
+ ignore_suspended_ (ignr_suspended)
+{
+ this->advance ();
+}
+
+// Obtains a pointer to the next valid service in the table. If there
+// are no more entries, returns 0, else 1.
+
+int
+ACE_Service_Repository_Iterator::next (const ACE_Service_Type *&sr)
+{
+ ACE_TRACE ("ACE_Service_Repository_Iterator::next");
+ if (this->next_ < this->svc_rep_.current_size_)
+ {
+ sr = this->svc_rep_.service_vector_[this->next_];
+ return 1;
+ }
+ else
+ return 0;
+}
+
+int
+ACE_Service_Repository_Iterator::done (void) const
+{
+ ACE_TRACE ("ACE_Service_Repository_Iterator::done");
+
+ return this->next_ >= this->svc_rep_.current_size_;
+}
+
+// Advance the iterator by the proper amount. If we are ignoring
+// suspended entries and the current entry is suspended, then we must
+// skip over this entry. Otherwise, we must advance the NEXT index to
+// reference the next valid service entry.
+
+int
+ACE_Service_Repository_Iterator::advance (void)
+{
+ ACE_TRACE ("ACE_Service_Repository_Iterator::advance");
+
+ for (++this->next_;
+ this->next_ < this->svc_rep_.current_size_
+ && this->ignore_suspended_
+ && this->svc_rep_.service_vector_[this->next_]->active () == 0;
+ this->next_++)
+ continue;
+
+ return this->next_ < this->svc_rep_.current_size_;
+}
diff --git a/ace/Svcconf/Service_Repository.h b/ace/Svcconf/Service_Repository.h
new file mode 100644
index 00000000000..46685807437
--- /dev/null
+++ b/ace/Svcconf/Service_Repository.h
@@ -0,0 +1,203 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Service_Repository.h
+ *
+ * $Id$
+ *
+ * @author Douglas C. Schmidt <schmidt@cs.wustl.edu>
+ */
+//=============================================================================
+
+#ifndef ACE_SERVICE_REPOSITORY_H
+#define ACE_SERVICE_REPOSITORY_H
+#include "ace/pre.h"
+
+#include "ace/Service_Types.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#define ACE_Component_Repository ACE_Service_Repository
+/**
+ * @class ACE_Service_Repository
+ *
+ * @brief Contains all the services offered by a Service
+ * Configurator-based application.
+ *
+ * This class contains a vector of <ACE_Service_Types> *'s and
+ * allows an administrative entity to centrally manage and
+ * control the behavior of application services. Note that if
+ * services are removed from the middle of the repository the
+ * order won't necessarily be maintained since the <remove>
+ * method performs compaction. However, the common case is not
+ * to remove services, so typically they are deleted in the
+ * reverse order that they were added originally.
+ */
+class ACE_Export ACE_Service_Repository
+{
+public:
+ friend class ACE_Service_Repository_Iterator;
+
+ enum
+ {
+ DEFAULT_SIZE = ACE_DEFAULT_SERVICE_REPOSITORY_SIZE
+ };
+
+ // = Initialization and termination methods.
+ /// Initialize the repository.
+ ACE_Service_Repository (void);
+
+ /// Initialize the repository.
+ ACE_Service_Repository (int size);
+
+ /// Initialize the repository.
+ int open (int size = DEFAULT_SIZE);
+
+ /// Close down the repository and free up dynamically allocated
+ /// resources.
+ ~ACE_Service_Repository (void);
+
+ /// Close down the repository and free up dynamically allocated
+ /// resources.
+ int close (void);
+
+ /// Finalize all the services by calling <fini> and deleting
+ /// dynamically allocated services.
+ int fini (void);
+
+ /// Get pointer to a process-wide <ACE_Service_Repository>.
+ static ACE_Service_Repository *instance (int size = ACE_Service_Repository::DEFAULT_SIZE);
+
+ /// Set pointer to a process-wide <ACE_Service_Repository> and return
+ /// existing pointer.
+ static ACE_Service_Repository *instance (ACE_Service_Repository *);
+
+ /// Delete the dynamically allocated Singleton.
+ static void close_singleton (void);
+
+ // = Search structure operations (all acquire locks as necessary).
+
+ /// Insert a new service record. Returns -1 when the service repository is full
+ /// and 0 on success.
+ int insert (const ACE_Service_Type *);
+
+ /**
+ * Locate an entry with <name> in the table. If <ignore_suspended>
+ * is set then only consider services marked as resumed. If the
+ * caller wants the located entry, pass back a pointer to the
+ * located entry via <srp>. If <name> is not found, -1 is returned.
+ * If <name> is found, but it is suspended and the caller wants to
+ * ignore suspended services a -2 is returned.
+ */
+ int find (const ACE_TCHAR name[],
+ const ACE_Service_Type **srp = 0,
+ int ignore_suspended = 1);
+
+ /// Remove an existing service record.
+ int remove (const ACE_TCHAR[]);
+
+ // = Liveness control
+ /// Resume a service record.
+ int resume (const ACE_TCHAR[], const ACE_Service_Type ** = 0);
+
+ /// Suspend a service record.
+ int suspend (const ACE_TCHAR[], const ACE_Service_Type ** = 0);
+
+ /// Return the current size of the repository.
+ int current_size (void) const;
+
+ /// Return the total size of the repository.
+ int total_size (void) const;
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+private:
+ /// Locates <service_name>. Must be called without locks being
+ /// held...
+ int find_i (const ACE_TCHAR service_name[],
+ const ACE_Service_Type ** = 0,
+ int ignore_suspended = 1);
+
+ /// Contains all the configured services.
+ const ACE_Service_Type **service_vector_;
+
+ /// Current number of services.
+ int current_size_;
+
+ /// Maximum number of services.
+ int total_size_;
+
+ /// Pointer to a process-wide <ACE_Service_Repository>.
+ static ACE_Service_Repository *svc_rep_;
+
+ /// Must delete the <svc_rep_> if non-0.
+ static int delete_svc_rep_;
+
+#if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0)
+ /// Synchronization variable for the MT_SAFE Repository
+ ACE_Thread_Mutex lock_;
+#endif /* ACE_MT_SAFE */
+};
+
+/**
+ * @class ACE_Service_Repository_Iterator
+ *
+ * @brief Iterate through the <ACE_Service_Repository>.
+ *
+ * Make sure not to delete entries as the iteration is going on
+ * since this class is not designed as a robust iterator.
+ */
+class ACE_Export ACE_Service_Repository_Iterator
+{
+public:
+ // = Initialization and termination methods.
+ /// Constructor initializes the iterator.
+ ACE_Service_Repository_Iterator (ACE_Service_Repository &sr,
+ int ignored_suspended = 1);
+
+ /// Destructor.
+ ~ACE_Service_Repository_Iterator (void);
+
+ // = Iteration methods.
+
+ /// Pass back the <next_item> that hasn't been seen in the repository.
+ /// Returns 0 when all items have been seen, else 1.
+ int next (const ACE_Service_Type *&next_item);
+
+ /// Returns 1 when all items have been seen, else 0.
+ int done (void) const;
+
+ /// Move forward by one element in the repository. Returns 0 when all the
+ /// items in the set have been seen, else 1.
+ int advance (void);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+private:
+ /// Reference to the Service Repository we are iterating over.
+ ACE_Service_Repository &svc_rep_;
+
+ /// Next index location that we haven't yet seen.
+ int next_;
+
+ /// Are we ignoring suspended services?
+ int ignore_suspended_;
+};
+
+#if defined (__ACE_INLINE__)
+#include "ace/Service_Repository.i"
+#endif /* __ACE_INLINE__ */
+
+#include "ace/post.h"
+#endif /* _SERVICE_REPOSITORY_H */
diff --git a/ace/Svcconf/Service_Repository.i b/ace/Svcconf/Service_Repository.i
new file mode 100644
index 00000000000..053ff2673a8
--- /dev/null
+++ b/ace/Svcconf/Service_Repository.i
@@ -0,0 +1,31 @@
+/* -*- C++ -*- */
+// $Id$
+
+// Service_Repository.i
+
+// Returns a count of the number of currently valid entries (counting
+// both resumed and suspended entries).
+
+ACE_INLINE int
+ACE_Service_Repository::current_size (void) const
+{
+ ACE_TRACE ("ACE_Service_Repository::current_size");
+ ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, (ACE_Thread_Mutex &) this->lock_, -1));
+ return this->current_size_;
+}
+
+// Returns a count of the total number of possible entries in the
+// table.
+
+ACE_INLINE int
+ACE_Service_Repository::total_size (void) const
+{
+ ACE_TRACE ("ACE_Service_Repository::total_size");
+ ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, (ACE_Thread_Mutex &) this->lock_, -1));
+ return this->total_size_;
+}
+
+ACE_INLINE
+ACE_Service_Repository_Iterator::~ACE_Service_Repository_Iterator (void)
+{
+}
diff --git a/ace/Svcconf/Service_Templates.cpp b/ace/Svcconf/Service_Templates.cpp
new file mode 100644
index 00000000000..a4f073d3272
--- /dev/null
+++ b/ace/Svcconf/Service_Templates.cpp
@@ -0,0 +1,74 @@
+// $Id$
+
+#include "ace/Service_Templates.h"
+
+#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION)
+template class ACE_Node<ACE_Static_Svc_Descriptor *>;
+template class ACE_Unbounded_Set<ACE_Static_Svc_Descriptor *>;
+template class ACE_Unbounded_Set_Iterator<ACE_Static_Svc_Descriptor *>;
+template class ACE_Node<ACE_TString>;
+template class ACE_Unbounded_Queue<ACE_TString>;
+template class ACE_Unbounded_Queue_Iterator<ACE_TString>;
+template class ACE_Unbounded_Set<ACE_TString>;
+template class ACE_Unbounded_Set_Iterator<ACE_TString>;
+template class auto_ptr<ACE_Obstack>;
+template class ACE_Auto_Basic_Ptr<ACE_Obstack>;
+
+template class ACE_Message_Queue<ACE_SYNCH>;
+template class ACE_Message_Queue_Iterator<ACE_SYNCH>;
+template class ACE_Message_Queue_Reverse_Iterator<ACE_SYNCH>;
+template class ACE_Message_Queue_Factory<ACE_SYNCH>;
+template class ACE_Dynamic_Message_Queue<ACE_SYNCH>;
+template class ACE_Module<ACE_SYNCH>;
+template class ACE_Stream<ACE_SYNCH>;
+template class ACE_Stream_Head<ACE_SYNCH>;
+template class ACE_Stream_Tail<ACE_SYNCH>;
+template class ACE_Task<ACE_SYNCH>;
+template class ACE_Thru_Task<ACE_SYNCH>;
+
+// Even with threads, these ACE_NULL_SYNCH specializations are necessary.
+#if defined (ACE_HAS_THREADS)
+ template class ACE_Message_Queue<ACE_NULL_SYNCH>;
+ template class ACE_Message_Queue_Iterator<ACE_NULL_SYNCH>;
+ template class ACE_Message_Queue_Reverse_Iterator<ACE_NULL_SYNCH>;
+ template class ACE_Message_Queue_Factory<ACE_NULL_SYNCH>;
+ template class ACE_Dynamic_Message_Queue<ACE_NULL_SYNCH>;
+ template class ACE_Module<ACE_NULL_SYNCH>;
+ template class ACE_Task<ACE_NULL_SYNCH>;
+ template class ACE_Thru_Task<ACE_NULL_SYNCH>;
+#endif /* ACE_HAS_THREADS */
+#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA)
+#pragma instantiate ACE_Node<ACE_Static_Svc_Descriptor *>
+#pragma instantiate ACE_Unbounded_Set<ACE_Static_Svc_Descriptor *>
+#pragma instantiate ACE_Unbounded_Set_Iterator<ACE_Static_Svc_Descriptor *>
+#pragma instantiate ACE_Node<ACE_TString>
+#pragma instantiate ACE_Unbounded_Queue<ACE_TString>
+#pragma instantiate ACE_Unbounded_Queue_Iterator<ACE_TString>
+#pragma instantiate ACE_Unbounded_Set<ACE_TString>
+#pragma instantiate ACE_Unbounded_Set_Iterator<ACE_TString>
+#pragma instantiate auto_ptr<ACE_Obstack>
+#pragma instantiate ACE_Auto_Basic_Ptr<ACE_Obstack>
+
+#pragma instantiate ACE_Message_Queue<ACE_SYNCH>
+#pragma instantiate ACE_Message_Queue_Iterator<ACE_SYNCH>
+#pragma instantiate ACE_Message_Queue_Reverse_Iterator<ACE_SYNCH>
+#pragma instantiate ACE_Message_Queue_Factory<ACE_SYNCH>
+#pragma instantiate ACE_Dynamic_Message_Queue<ACE_SYNCH>
+#pragma instantiate ACE_Module<ACE_SYNCH>
+#pragma instantiate ACE_Stream<ACE_SYNCH>
+#pragma instantiate ACE_Stream_Head<ACE_SYNCH>
+#pragma instantiate ACE_Stream_Tail<ACE_SYNCH>
+#pragma instantiate ACE_Task<ACE_SYNCH>
+#pragma instantiate ACE_Thru_Task<ACE_SYNCH>
+// Even with threads, these ACE_NULL_SYNCH specializations are necessary.
+#if defined (ACE_HAS_THREADS)
+ #pragma instantiate ACE_Message_Queue<ACE_NULL_SYNCH>
+ #pragma instantiate ACE_Message_Queue_Iterator<ACE_NULL_SYNCH>
+ #pragma instantiate ACE_Message_Queue_Reverse_Iterator<ACE_NULL_SYNCH>
+ #pragma instantiate ACE_Message_Queue_Factory<ACE_NULL_SYNCH>
+ #pragma instantiate ACE_Dynamic_Message_Queue<ACE_NULL_SYNCH>
+ #pragma instantiate ACE_Module<ACE_NULL_SYNCH>
+ #pragma instantiate ACE_Task<ACE_NULL_SYNCH>
+ #pragma instantiate ACE_Thru_Task<ACE_NULL_SYNCH>
+#endif /* ACE_HAS_THREADS */
+#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */
diff --git a/ace/Svcconf/Service_Templates.h b/ace/Svcconf/Service_Templates.h
new file mode 100644
index 00000000000..939081f7813
--- /dev/null
+++ b/ace/Svcconf/Service_Templates.h
@@ -0,0 +1,29 @@
+
+//=============================================================================
+/**
+ * @file Service_Templates.h
+ *
+ * $Id$
+ *
+ * @author Priyanka Gontla <pgontla@ece.uci.edu>
+ */
+//=============================================================================
+
+
+#ifndef ACE_SERVICE_TEMPLATES_H
+#define ACE_SERVICE_TEMPLATES_H
+#include "ace/pre.h"
+
+#include "ace/Svc_Conf.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "ace/Auto_Ptr.h"
+#include "ace/Thread_Manager.h"
+#include "ace/Stream_Modules.h"
+#include "ace/Stream.h"
+
+#include "ace/post.h"
+#endif /* ACE_SERVICE_TEMPLATES_H */
diff --git a/ace/Svcconf/Service_Types.cpp b/ace/Svcconf/Service_Types.cpp
new file mode 100644
index 00000000000..4b66a1cb0d8
--- /dev/null
+++ b/ace/Svcconf/Service_Types.cpp
@@ -0,0 +1,454 @@
+// $Id$
+
+#include "ace/Service_Types.h"
+#include "ace/Stream_Modules.h"
+#include "ace/Stream.h"
+
+ACE_RCSID(ace, Service_Types, "$Id$")
+
+typedef ACE_Stream<ACE_SYNCH> MT_Stream;
+typedef ACE_Module<ACE_SYNCH> MT_Module;
+typedef ACE_Task<ACE_SYNCH> MT_Task;
+
+#if !defined (__ACE_INLINE__)
+#include "ace/Service_Types.i"
+#endif /* __ACE_INLINE__ */
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Service_Type_Impl)
+
+void
+ACE_Service_Type_Impl::dump (void) const
+{
+ ACE_TRACE ("ACE_Service_Type_Impl::dump");
+}
+
+ACE_Service_Type_Impl::ACE_Service_Type_Impl (void *so,
+ const ACE_TCHAR *s_name,
+ u_int f,
+ ACE_Service_Object_Exterminator gobbler)
+ : name_ (0),
+ obj_ (so),
+ gobbler_ (gobbler),
+ flags_ (f)
+{
+ ACE_TRACE ("ACE_Service_Type_Impl::ACE_Service_Type_Impl");
+ this->name (s_name);
+}
+
+ACE_Service_Type_Impl::~ACE_Service_Type_Impl (void)
+{
+ ACE_TRACE ("ACE_Service_Type_Impl::~ACE_Service_Type_Impl");
+
+ // It's ok to call this, even though we may have already deleted it
+ // in the fini() method since it would then be NULL.
+ delete [] (ACE_TCHAR *) this->name_;
+}
+
+int
+ACE_Service_Type_Impl::fini (void) const
+{
+ ACE_TRACE ("ACE_Service_Type_Impl::fini");
+ if (ACE::debug ())
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_LIB_TEXT ("destroying %s, flags = %d\n"),
+ this->name_,
+ this->flags_));
+
+ delete [] (ACE_TCHAR *) this->name_;
+ ((ACE_Service_Type_Impl *) this)->name_ = 0;
+
+ if (ACE_BIT_ENABLED (this->flags_,
+ ACE_Service_Type::DELETE_OBJ))
+ {
+ if (gobbler_ != 0)
+ gobbler_ (this->object ());
+ else
+ // Cast to remove const-ness.
+ operator delete ((void *) this->object ());
+ }
+
+ if (ACE_BIT_ENABLED (this->flags_,
+ ACE_Service_Type::DELETE_THIS))
+ delete (ACE_Service_Type_Impl *) this;
+
+ return 0;
+}
+
+ACE_Service_Object_Type::ACE_Service_Object_Type (void *so,
+ const ACE_TCHAR *s_name,
+ u_int f,
+ ACE_Service_Object_Exterminator gobbler)
+ : ACE_Service_Type_Impl (so, s_name, f, gobbler)
+{
+ ACE_TRACE ("ACE_Service_Object_Type::ACE_Service_Object_Type");
+}
+
+int
+ACE_Service_Object_Type::init (int argc, ACE_TCHAR *argv[]) const
+{
+ ACE_TRACE ("ACE_Service_Object_Type::init");
+
+ void *obj = this->object ();
+ ACE_Service_Object *so = (ACE_Service_Object *) obj;
+
+ if (so == 0)
+ return -1;
+ else
+ return so->init (argc, argv);
+}
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Module_Type)
+
+void
+ACE_Module_Type::dump (void) const
+{
+ ACE_TRACE ("ACE_Module_Type::dump");
+}
+
+ACE_Module_Type::ACE_Module_Type (void *m,
+ const ACE_TCHAR *m_name,
+ u_int f)
+ : ACE_Service_Type_Impl (m, m_name, f)
+{
+ ACE_TRACE ("ACE_Module_Type::ACE_Module_Type");
+}
+
+int
+ACE_Module_Type::init (int argc, ACE_TCHAR *argv[]) const
+{
+ ACE_TRACE ("ACE_Module_Type::init");
+ void *obj = this->object ();
+ MT_Module *mod = (MT_Module *) obj;
+ MT_Task *reader = mod->reader ();
+ MT_Task *writer = mod->writer ();
+
+ if (reader->init (argc, argv) == -1
+ || writer->init (argc, argv) == -1)
+ return -1;
+ else
+ return 0;
+}
+
+int
+ACE_Module_Type::suspend (void) const
+{
+ ACE_TRACE ("ACE_Module_Type::suspend");
+ void *obj = this->object ();
+ MT_Module *mod = (MT_Module *) obj;
+ MT_Task *reader = mod->reader ();
+ MT_Task *writer = mod->writer ();
+
+ if (reader->suspend () == -1
+ || writer->suspend () == -1)
+ return -1;
+ else
+ return 0;
+}
+
+int
+ACE_Module_Type::resume (void) const
+{
+ ACE_TRACE ("ACE_Module_Type::resume");
+ void *obj = this->object ();
+ MT_Module *mod = (MT_Module *) obj;
+ MT_Task *reader = mod->reader ();
+ MT_Task *writer = mod->writer ();
+
+ if (reader->resume () == -1
+ || writer->resume () == -1)
+ return -1;
+ else
+ return 0;
+}
+
+// Note, these operations are somewhat too familiar with the
+// implementation of ACE_Module and ACE_Module::close...
+
+int
+ACE_Module_Type::fini (void) const
+{
+ ACE_TRACE ("ACE_Module_Type::fini");
+
+ void *obj = this->object ();
+ MT_Module *mod = (MT_Module *) obj;
+ MT_Task *reader = mod->reader ();
+ MT_Task *writer = mod->writer ();
+
+ if (reader != 0)
+ reader->fini ();
+
+ if (writer != 0)
+ writer->fini ();
+
+ // Close the module and delete the memory.
+ mod->close (MT_Module::M_DELETE);
+ return ACE_Service_Type_Impl::fini ();
+}
+
+int
+ACE_Module_Type::info (ACE_TCHAR **str, size_t len) const
+{
+ ACE_TRACE ("ACE_Module_Type::info");
+ ACE_TCHAR buf[BUFSIZ];
+
+ ACE_OS::sprintf (buf,
+ ACE_LIB_TEXT ("%s\t %s"),
+ this->name (),
+ ACE_LIB_TEXT ("# ACE_Module\n"));
+
+ if (*str == 0 && (*str = ACE_OS::strdup (buf)) == 0)
+ return -1;
+ else
+ ACE_OS::strsncpy (*str, buf, len);
+ return ACE_OS::strlen (buf);
+}
+
+void
+ACE_Module_Type::link (ACE_Module_Type *n)
+{
+ ACE_TRACE ("ACE_Module_Type::link");
+ this->link_ = n;
+}
+
+ACE_Module_Type *
+ACE_Module_Type::link (void) const
+{
+ ACE_TRACE ("ACE_Module_Type::link");
+ return this->link_;
+}
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Stream_Type)
+
+void
+ACE_Stream_Type::dump (void) const
+{
+ ACE_TRACE ("ACE_Stream_Type::dump");
+}
+
+int
+ACE_Stream_Type::init (int, ACE_TCHAR *[]) const
+{
+ ACE_TRACE ("ACE_Stream_Type::init");
+ return 0;
+}
+
+int
+ACE_Stream_Type::suspend (void) const
+{
+ ACE_TRACE ("ACE_Stream_Type::suspend");
+
+ for (ACE_Module_Type *m = this->head_;
+ m != 0;
+ m = m->link ())
+ m->suspend ();
+
+ return 0;
+}
+
+int
+ACE_Stream_Type::resume (void) const
+{
+ ACE_TRACE ("ACE_Stream_Type::resume");
+
+ for (ACE_Module_Type *m = this->head_;
+ m != 0;
+ m = m->link ())
+ m->resume ();
+
+ return 0;
+}
+
+ACE_Stream_Type::ACE_Stream_Type (void *s,
+ const ACE_TCHAR *s_name,
+ u_int f)
+ : ACE_Service_Type_Impl (s, s_name, f),
+ head_ (0)
+{
+ ACE_TRACE ("ACE_Stream_Type::ACE_Stream_Type");
+}
+
+int
+ACE_Stream_Type::info (ACE_TCHAR **str, size_t len) const
+{
+ ACE_TRACE ("ACE_Stream_Type::info");
+ ACE_TCHAR buf[BUFSIZ];
+
+ ACE_OS::sprintf (buf,
+ ACE_LIB_TEXT ("%s\t %s"),
+ this->name (),
+ ACE_LIB_TEXT ("# STREAM\n"));
+
+ if (*str == 0 && (*str = ACE_OS::strdup (buf)) == 0)
+ return -1;
+ else
+ ACE_OS::strsncpy (*str, buf, len);
+ return ACE_OS::strlen (buf);
+}
+
+int
+ACE_Stream_Type::fini (void) const
+{
+ ACE_TRACE ("ACE_Stream_Type::fini");
+ void *obj = this->object ();
+ MT_Stream *str = (MT_Stream *) obj;
+
+ for (ACE_Module_Type *m = this->head_; m != 0; )
+ {
+ ACE_Module_Type *t = m->link ();
+
+ // Final arg is an indication to *not* delete the Module.
+ str->remove (m->name (),
+ MT_Module::M_DELETE_NONE);
+
+ // Finalize the Module (this may delete it, but we don't really
+ // care since we don't access it again).
+ m->fini ();
+ m = t;
+ }
+
+ str->close ();
+ return ACE_Service_Type_Impl::fini ();
+}
+
+// Locate and remove <mod_name> from the ACE_Stream.
+
+int
+ACE_Stream_Type::remove (ACE_Module_Type *mod)
+{
+ ACE_TRACE ("ACE_Stream_Type::remove");
+
+ ACE_Module_Type *prev = 0;
+ void *obj = this->object ();
+ MT_Stream *str = (MT_Stream *) obj;
+ int result = 0;
+
+ for (ACE_Module_Type *m = this->head_; m != 0; )
+ {
+ // We need to do this first so we don't bomb out if we delete m!
+ ACE_Module_Type *link = m->link ();
+
+ if (m == mod)
+ {
+ if (prev == 0)
+ this->head_ = link;
+ else
+ prev->link (link);
+
+ // Final arg is an indication to *not* delete the Module.
+ if (str->remove (m->name (),
+ MT_Module::M_DELETE_NONE) == -1)
+ result = -1;
+
+ // This call may end up deleting m, which is ok since we
+ // don't access it again!
+ m->fini ();
+ }
+ else
+ prev = m;
+
+ m = link;
+ }
+
+ return result;
+}
+
+int
+ACE_Stream_Type::push (ACE_Module_Type *new_module)
+{
+ ACE_TRACE ("ACE_Stream_Type::push");
+ void *obj = this->object ();
+ MT_Stream *str = (MT_Stream *) obj;
+
+ new_module->link (this->head_);
+ this->head_ = new_module;
+ obj = new_module->object ();
+ return str->push ((MT_Module *) obj);
+}
+
+ACE_Module_Type *
+ACE_Stream_Type::find (const ACE_TCHAR *mod_name) const
+{
+ ACE_TRACE ("ACE_Stream_Type::find");
+
+ for (ACE_Module_Type *m = this->head_;
+ m != 0;
+ m = m->link ())
+ if (ACE_OS::strcmp (m->name (), mod_name) == 0)
+ return m;
+
+ return 0;
+}
+
+int
+ACE_Service_Object_Type::fini (void) const
+{
+ ACE_TRACE ("ACE_Service_Object_Type::fini");
+
+ void *obj = this->object ();
+
+ ACE_Service_Object *so = (ACE_Service_Object *) obj;
+
+ if (so)
+ {
+ so->fini ();
+
+#if 0
+ if (ACE_BIT_ENABLED (this->flags_,
+ ACE_Service_Type::DELETE_OBJ))
+ delete so;
+#endif /* 1 */
+ }
+
+ return ACE_Service_Type_Impl::fini ();
+}
+/*
+#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION)
+template class ACE_Message_Queue<ACE_SYNCH>;
+template class ACE_Message_Queue_Iterator<ACE_SYNCH>;
+template class ACE_Message_Queue_Reverse_Iterator<ACE_SYNCH>;
+template class ACE_Message_Queue_Factory<ACE_SYNCH>;
+template class ACE_Dynamic_Message_Queue<ACE_SYNCH>;
+template class ACE_Module<ACE_SYNCH>;
+template class ACE_Stream<ACE_SYNCH>;
+template class ACE_Stream_Head<ACE_SYNCH>;
+template class ACE_Stream_Tail<ACE_SYNCH>;
+template class ACE_Task<ACE_SYNCH>;
+template class ACE_Thru_Task<ACE_SYNCH>;
+
+// Even with threads, these ACE_NULL_SYNCH specializations are necessary.
+#if defined (ACE_HAS_THREADS)
+ template class ACE_Message_Queue<ACE_NULL_SYNCH>;
+ template class ACE_Message_Queue_Iterator<ACE_NULL_SYNCH>;
+ template class ACE_Message_Queue_Reverse_Iterator<ACE_NULL_SYNCH>;
+ template class ACE_Message_Queue_Factory<ACE_NULL_SYNCH>;
+ template class ACE_Dynamic_Message_Queue<ACE_NULL_SYNCH>;
+ template class ACE_Module<ACE_NULL_SYNCH>;
+ template class ACE_Task<ACE_NULL_SYNCH>;
+ template class ACE_Thru_Task<ACE_NULL_SYNCH>;
+ #endif *//* ACE_HAS_THREADS */
+/*
+#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA)
+#pragma instantiate ACE_Message_Queue<ACE_SYNCH>
+#pragma instantiate ACE_Message_Queue_Iterator<ACE_SYNCH>
+#pragma instantiate ACE_Message_Queue_Reverse_Iterator<ACE_SYNCH>
+#pragma instantiate ACE_Message_Queue_Factory<ACE_SYNCH>
+#pragma instantiate ACE_Dynamic_Message_Queue<ACE_SYNCH>
+#pragma instantiate ACE_Module<ACE_SYNCH>
+#pragma instantiate ACE_Stream<ACE_SYNCH>
+#pragma instantiate ACE_Stream_Head<ACE_SYNCH>
+#pragma instantiate ACE_Stream_Tail<ACE_SYNCH>
+#pragma instantiate ACE_Task<ACE_SYNCH>
+#pragma instantiate ACE_Thru_Task<ACE_SYNCH>
+// Even with threads, these ACE_NULL_SYNCH specializations are necessary.
+#if defined (ACE_HAS_THREADS)
+ #pragma instantiate ACE_Message_Queue<ACE_NULL_SYNCH>
+ #pragma instantiate ACE_Message_Queue_Iterator<ACE_NULL_SYNCH>
+ #pragma instantiate ACE_Message_Queue_Reverse_Iterator<ACE_NULL_SYNCH>
+ #pragma instantiate ACE_Message_Queue_Factory<ACE_NULL_SYNCH>
+ #pragma instantiate ACE_Dynamic_Message_Queue<ACE_NULL_SYNCH>
+ #pragma instantiate ACE_Module<ACE_NULL_SYNCH>
+ #pragma instantiate ACE_Task<ACE_NULL_SYNCH>
+ #pragma instantiate ACE_Thru_Task<ACE_NULL_SYNCH>
+ #endif *//* ACE_HAS_THREADS */
+//#else
+//#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */
diff --git a/ace/Svcconf/Service_Types.h b/ace/Svcconf/Service_Types.h
new file mode 100644
index 00000000000..54cac6e4604
--- /dev/null
+++ b/ace/Svcconf/Service_Types.h
@@ -0,0 +1,196 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Service_Types.h
+ *
+ * $Id$
+ *
+ * @author Douglas C. Schmidt <schmidt@cs.wustl.edu>
+ */
+//=============================================================================
+
+#ifndef ACE_SERVICE_TYPE_H
+#define ACE_SERVICE_TYPE_H
+#include "ace/pre.h"
+
+#include "ace/Service_Object.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "ace/Synch.h"
+
+/**
+ * @class ACE_Service_Type_Impl
+ *
+ * @brief The abstract base class of the hierarchy that defines the
+ * contents of the <ACE_Service_Repository>. The subclasses of
+ * this class allow the configuration of <ACE_Service_Objects>,
+ * <ACE_Modules>, and <ACE_Streams>.
+ *
+ * This class provides the root of the implementation hierarchy
+ * of the "Bridge" pattern. It maintains a pointer to the
+ * appropriate type of service implementation, i.e.,
+ * <ACE_Service_Object>, <ACE_Module>, or <ACE_Stream>.
+ */
+class ACE_Export ACE_Service_Type_Impl
+{
+public:
+ // = Initialization and termination methods.
+ ACE_Service_Type_Impl (void *object,
+ const ACE_TCHAR *s_name,
+ u_int flags = 0,
+ ACE_Service_Object_Exterminator gobbler = 0);
+ virtual ~ACE_Service_Type_Impl (void);
+
+ // = Pure virtual interface (must be defined by the subclass).
+ virtual int suspend (void) const = 0;
+ virtual int resume (void) const = 0;
+ virtual int init (int argc, ACE_TCHAR *argv[]) const = 0;
+ virtual int fini (void) const;
+ virtual int info (ACE_TCHAR **str, size_t len) const = 0;
+
+ /// The pointer to the service.
+ void *object (void) const;
+
+ /// Get the name of the service.
+ const ACE_TCHAR *name (void) const;
+
+ /// Set the name of the service.
+ void name (const ACE_TCHAR *);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+protected:
+ /// Name of the service.
+ const ACE_TCHAR *name_;
+
+ /// Pointer to object that implements the service. This actually
+ /// points to an <ACE_Service_Object>, <ACE_Module>, or <ACE_Stream>.
+ void *obj_;
+
+ /// Destroy function to deallocate obj_.
+ ACE_Service_Object_Exterminator gobbler_;
+
+ /// Flags that control serivce behavior (particularly deletion).
+ u_int flags_;
+};
+
+/**
+ * @class ACE_Service_Object_Type
+ *
+ * @brief Define the methods for handling the configuration of
+ * <ACE_Service_Objects>.
+ */
+class ACE_Export ACE_Service_Object_Type : public ACE_Service_Type_Impl
+{
+public:
+ // = Initialization method.
+ ACE_Service_Object_Type (void *so,
+ const ACE_TCHAR *name,
+ u_int flags = 0,
+ ACE_Service_Object_Exterminator gobbler = 0);
+
+ ~ACE_Service_Object_Type (void);
+
+ // = Implement the hooks for <ACE_Service_Objects>.
+ virtual int suspend (void) const;
+ virtual int resume (void) const;
+ virtual int init (int argc, ACE_TCHAR *argv[]) const;
+ virtual int fini (void) const;
+ virtual int info (ACE_TCHAR **str, size_t len) const;
+};
+
+/**
+ * @class ACE_Module_Type
+ *
+ * @brief Define the methods for handling the configuration of
+ * <ACE_Modules>.
+ */
+class ACE_Export ACE_Module_Type : public ACE_Service_Type_Impl
+{
+public:
+ // = Initialization method.
+ ACE_Module_Type (void *m, // Really an <ACE_Module> *.
+ const ACE_TCHAR *identifier,
+ u_int flags = 0);
+
+ ~ACE_Module_Type (void);
+
+ // = Implement the hooks for <ACE_Modules>.
+ virtual int suspend (void) const;
+ virtual int resume (void) const;
+ virtual int init (int argc, ACE_TCHAR *argv[]) const;
+ virtual int fini (void) const;
+ virtual int info (ACE_TCHAR **str, size_t len) const;
+
+ // Get/set the link pointer.
+ ACE_Module_Type *link (void) const;
+ void link (ACE_Module_Type *);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+private:
+ /// Pointer to the next <ACE_Module_Type> in an <ACE_Stream_Type>.
+ ACE_Module_Type *link_;
+};
+
+/**
+ * @class ACE_Stream_Type
+ *
+ * @brief Define the methods for handling the configuration of
+ * <ACE_Streams>.
+ */
+class ACE_Export ACE_Stream_Type : public ACE_Service_Type_Impl
+{
+public:
+ // = Initialization method.
+ ACE_Stream_Type (void *s, // Really an <ACE_Stream> *.
+ const ACE_TCHAR *identifier,
+ u_int flags = 0);
+
+ ~ACE_Stream_Type (void);
+
+ // = Implement the hooks for <ACE_Streams>.
+ virtual int suspend (void) const;
+ virtual int resume (void) const;
+ virtual int init (int argc, ACE_TCHAR *argv[]) const;
+ virtual int fini (void) const;
+ virtual int info (ACE_TCHAR **str, size_t len) const;
+
+ /// Add a new <ACE_Module> to the top of the <ACE_Stream>.
+ int push (ACE_Module_Type *new_module);
+
+ /// Search for <module> and remove it from the <ACE_Stream>.
+ int remove (ACE_Module_Type *module);
+
+ /// Locate the <ACE_Module> with <mod_name>.
+ ACE_Module_Type *find (const ACE_TCHAR *mod_name) const;
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+private:
+ /// Pointer to the head of the <ACE_Module> list.
+ ACE_Module_Type *head_;
+};
+
+#if defined (__ACE_INLINE__)
+#include "ace/Service_Types.i"
+#endif /* __ACE_INLINE__ */
+
+#include "ace/post.h"
+#endif /* _SERVICE_TYPE_H */
diff --git a/ace/Svcconf/Service_Types.i b/ace/Svcconf/Service_Types.i
new file mode 100644
index 00000000000..78eb127cbfc
--- /dev/null
+++ b/ace/Svcconf/Service_Types.i
@@ -0,0 +1,64 @@
+/* -*- C++ -*- */
+// $Id$
+
+ACE_INLINE void *
+ACE_Service_Type_Impl::object (void) const
+{
+ ACE_TRACE ("ACE_Service_Type_Impl::object");
+ return this->obj_;
+}
+
+ACE_INLINE const ACE_TCHAR *
+ACE_Service_Type_Impl::name (void) const
+{
+ ACE_TRACE ("ACE_Service_Type_Impl::name");
+ return this->name_;
+}
+
+ACE_INLINE void
+ACE_Service_Type_Impl::name (const ACE_TCHAR *n)
+{
+ ACE_TRACE ("ACE_Service_Type_Impl::name");
+
+ delete [] (ACE_TCHAR *) this->name_;
+ this->name_ = ACE::strnew (n);
+}
+
+ACE_INLINE
+ACE_Service_Object_Type::~ACE_Service_Object_Type (void)
+{
+ ACE_TRACE ("ACE_Service_Object_Type::~ACE_Service_Object_Type");
+}
+
+ACE_INLINE int
+ACE_Service_Object_Type::suspend (void) const
+{
+ ACE_TRACE ("ACE_Service_Object_Type::suspend");
+ return ((ACE_Service_Object *) this->object ())->suspend ();
+}
+
+ACE_INLINE int
+ACE_Service_Object_Type::resume (void) const
+{
+ ACE_TRACE ("ACE_Service_Object_Type::resume");
+ return ((ACE_Service_Object *) this->object ())->resume ();
+}
+
+ACE_INLINE int
+ACE_Service_Object_Type::info (ACE_TCHAR **str, size_t len) const
+{
+ ACE_TRACE ("ACE_Service_Object_Type::info");
+ return ((ACE_Service_Object *) this->object ())->info (str, len);
+}
+
+ACE_INLINE
+ACE_Module_Type::~ACE_Module_Type (void)
+{
+ ACE_TRACE ("ACE_Module_Type::~ACE_Module_Type");
+}
+
+ACE_INLINE
+ACE_Stream_Type::~ACE_Stream_Type (void)
+{
+ ACE_TRACE ("ACE_Stream_Type::~ACE_Stream_Type");
+}
diff --git a/ace/Svcconf/Shared_Object.cpp b/ace/Svcconf/Shared_Object.cpp
new file mode 100644
index 00000000000..b7237bfb1a3
--- /dev/null
+++ b/ace/Svcconf/Shared_Object.cpp
@@ -0,0 +1,46 @@
+// Shared_Object.cpp
+// $Id$
+
+#include "ace/Shared_Object.h"
+/* Provide the abstract base class used to access dynamic linking
+ facilities */
+
+#if !defined (__ACE_INLINE__)
+#include "ace/Shared_Object.i"
+#endif /* __ACE_INLINE__ */
+
+ACE_RCSID(ace, Shared_Object, "$Id$")
+
+// Initializes object when dynamic linking occurs.
+
+int
+ACE_Shared_Object::init (int, ACE_TCHAR *[])
+{
+ ACE_TRACE ("ACE_Shared_Object::init");
+ return 0;
+}
+
+// Terminates object when dynamic unlinking occurs.
+
+int
+ACE_Shared_Object::fini (void)
+{
+ ACE_TRACE ("ACE_Shared_Object::fini");
+ return 0;
+}
+
+// Returns information on active object.
+
+int
+ACE_Shared_Object::info (ACE_TCHAR **, size_t) const
+{
+ ACE_TRACE ("ACE_Shared_Object::info");
+ return 0;
+}
+
+// Need to give a default implementation.
+
+ACE_Shared_Object::~ACE_Shared_Object (void)
+{
+ ACE_TRACE ("ACE_Shared_Object::~ACE_Shared_Object");
+}
diff --git a/ace/Svcconf/Shared_Object.h b/ace/Svcconf/Shared_Object.h
new file mode 100644
index 00000000000..dc6d1ed7480
--- /dev/null
+++ b/ace/Svcconf/Shared_Object.h
@@ -0,0 +1,51 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Shared_Object.h
+ *
+ * $Id$
+ *
+ * @author Douglas C. Schmidt <schmidt@cs.wustl.edu>
+ */
+//=============================================================================
+
+#ifndef ACE_SHARED_OBJECT_H
+#define ACE_SHARED_OBJECT_H
+#include "ace/pre.h"
+
+#include "ace/ACE.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+/**
+ * @class ACE_Shared_Object
+ *
+ * @brief Provide the abstract base class used to access dynamic
+ * linking facilities.
+ */
+class ACE_Export ACE_Shared_Object
+{
+public:
+ ACE_Shared_Object (void);
+
+ /// Initializes object when dynamic linking occurs.
+ virtual int init (int argc, ACE_TCHAR *argv[]);
+
+ /// Terminates object when dynamic unlinking occurs.
+ virtual int fini (void);
+
+ /// Returns information on a service object.
+ virtual int info (ACE_TCHAR **info_string, size_t length = 0) const;
+
+ virtual ~ACE_Shared_Object (void);
+};
+
+#if defined (__ACE_INLINE__)
+#include "ace/Shared_Object.i"
+#endif /* __ACE_INLINE__ */
+
+#include "ace/post.h"
+#endif /* ACE_SHARED_OBJECT_H */
diff --git a/ace/Svcconf/Shared_Object.i b/ace/Svcconf/Shared_Object.i
new file mode 100644
index 00000000000..97ca0090c6d
--- /dev/null
+++ b/ace/Svcconf/Shared_Object.i
@@ -0,0 +1,9 @@
+/* -*- C++ -*- */
+// $Id$
+
+// Shared_Object.i
+
+ACE_INLINE
+ACE_Shared_Object::ACE_Shared_Object (void)
+{
+}
diff --git a/ace/Svcconf/Svc_Conf.h b/ace/Svcconf/Svc_Conf.h
new file mode 100644
index 00000000000..ecf285baebf
--- /dev/null
+++ b/ace/Svcconf/Svc_Conf.h
@@ -0,0 +1,208 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Svc_Conf.h
+ *
+ * $Id$
+ *
+ * @author Doug Schmidt
+ */
+//=============================================================================
+
+
+#ifndef ACE_SVC_CONF_H
+#define ACE_SVC_CONF_H
+
+#include "ace/pre.h"
+
+// Globally visible macros, type decls, and extern var decls for
+// Service Configurator utility.
+
+#include "ace/Obstack.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "ace/Service_Config.h"
+#include "ace/Parse_Node.h"
+
+// Forward declarations.
+struct ace_yy_buffer_state;
+
+// The following yylex() declarations require support for reentrant
+// parser generation (e.g. from GNU Bison).
+#if defined (DEBUGGING)
+#if defined (ACE_YY_DECL)
+#undef ACE_YY_DECL
+#endif /* ACE_YY_DECL */
+#define ACE_YY_DECL extern "C" char *ace_yylex (ACE_YYSTYPE *ace_yylval, void *ACE_YYLEX_PARAM)
+#else
+#define ACE_YY_DECL extern "C" int ace_yylex (ACE_YYSTYPE *ace_yylval, void *ACE_YYLEX_PARAM)
+#endif /* DEBUGGING */
+
+extern void ace_yy_delete_buffer (ace_yy_buffer_state *buffer);
+
+/**
+ * @class ACE_Svc_Conf_Param
+ *
+ * @brief An instance of this object will be passed down to the
+ * yyparse() and yylex() functions.
+ *
+ * This class retains the state for a given parse/scan. It primarily
+ * makes it possible to hold the static object lock in the scanner
+ * for as short a period of time as possible. The resulting finer
+ * grained locking prevents deadlocks from occuring when scanning a
+ * `svc.conf' file and activating an ACE_Task, for example, as a
+ * result of processing the directives in that file.
+ */
+class ACE_Svc_Conf_Param
+{
+public:
+
+ enum SVC_CONF_PARAM_TYPE
+ {
+ /// The lexer will scan a file containing one or more directives.
+ SVC_CONF_FILE,
+
+ /// The lexer will scan a string containing a directive.
+ SVC_CONF_DIRECTIVE
+ };
+
+ /// Constructor
+ ACE_Svc_Conf_Param (FILE *file)
+ : type (SVC_CONF_FILE),
+ yyerrno (0),
+ yylineno (1),
+ buffer (0),
+ obstack ()
+ {
+ source.file = file;
+ }
+
+ /// Constructor
+ ACE_Svc_Conf_Param (const ACE_TCHAR *directive)
+ : type (SVC_CONF_DIRECTIVE),
+ yyerrno (0),
+ yylineno (1),
+ buffer (0),
+ obstack ()
+ {
+ source.directive = directive;
+ }
+
+ ~ACE_Svc_Conf_Param (void)
+ {
+ ace_yy_delete_buffer (this->buffer);
+ }
+
+public:
+
+ union
+ {
+
+ /// FILE stream from which directives will be scanned and parsed.
+ FILE *file;
+
+ /// String containing directive that will be scanned and parsed.
+ const ACE_TCHAR *directive;
+
+ } source;
+
+ // Discriminant use to determine which union member to use.
+ SVC_CONF_PARAM_TYPE type;
+
+ /// Keeps track of the number of errors encountered so far.
+ int yyerrno;
+
+ /// Keeps track of the current line number for error-handling routine.
+ int yylineno;
+
+ /// Lexer buffer that corresponds to the current Service
+ /// Configurator file/direct scan.
+ ace_yy_buffer_state *buffer;
+
+ /// Obstack used for efficient memory allocation when
+ /// parsing/scanning a service configurator directive.
+ ACE_Obstack_T<ACE_TCHAR> obstack;
+
+};
+
+// Parameter that is passed down to the yyparse() function, and
+// eventually to yylex().
+#define ACE_YYPARSE_PARAM ace_svc_conf_parameter
+#define ACE_YYLEX_PARAM ACE_YYPARSE_PARAM
+
+#define ACE_SVC_CONF_PARAM (ACE_static_cast (ACE_Svc_Conf_Param *, ACE_YYLEX_PARAM))
+
+// The following definition for the ACE_YYSTYPE must occur before
+// ACE_YY_DECL is declared since ACE_YY_DECL expands to function
+// prototypes that use ACE_YYSTYPE.
+typedef union
+{
+ int type_;
+ ACE_Location_Node *location_node_;
+ ACE_Parse_Node *parse_node_;
+ ACE_Static_Node *static_node_;
+ ACE_Service_Type *svc_record_;
+ ACE_TCHAR *ident_;
+} ACE_YYSTYPE;
+
+// Forward declaration
+struct ace_yy_buffer_state;
+
+/// Create and push a new lexer buffer on to the buffer stack for use
+/// when scanning the given file.
+void ace_yy_push_buffer (FILE *file,
+ ace_yy_buffer_state *&buffer);
+
+/// Create and push a new lexer buffer on to the buffer stack for use
+/// when scanning the given directive.
+void ace_yy_push_buffer (const ACE_TCHAR *directive,
+ ace_yy_buffer_state *&buffer);
+
+/// Pop the current lexer buffer off of the buffer stack and
+/// deallocate it.
+void ace_yy_pop_buffer (ace_yy_buffer_state *buf);
+
+/// Performs the parsing
+#ifdef ACE_YYPARSE_PARAM
+int ace_yyparse (void *);
+#else
+int ace_yyparse (void);
+#endif
+
+/// Performs the lexical analysis
+ACE_YY_DECL;
+
+/// Name of input stream
+extern FILE *ace_yyin;
+
+/// Error handling routine required by YACC or BISON
+void ace_yyerror (const ACE_TCHAR *);
+
+/// Keeps track of the current line number for error-handling routine
+extern int ace_yylineno;
+
+/// Keeps track of the number of errors encountered so far
+extern int ace_yyerrno;
+
+/// Holds the lexeme for the current token
+extern ACE_TCHAR *ace_yytext;
+
+/// Holds the length of the lexeme for the current token
+extern int ace_yyleng;
+
+/// Factory that creates a new ACE_Service_Type_Impl.
+extern ACE_Service_Type_Impl *
+ace_create_service_type (const ACE_TCHAR *,
+ int,
+ void *,
+ unsigned int,
+ ACE_Service_Object_Exterminator = 0);
+
+
+#include "ace/post.h"
+
+#endif /* ACE_SVC_CONF_H */
diff --git a/ace/Svcconf/Svc_Conf.l b/ace/Svcconf/Svc_Conf.l
new file mode 100644
index 00000000000..bb1f3e2dc0c
--- /dev/null
+++ b/ace/Svcconf/Svc_Conf.l
@@ -0,0 +1,140 @@
+%{
+// $Id$
+// Sample lexical analysis for regular expression subset. Must be
+// compiled with FLEX and an ANSI C++ compiler.
+
+// Lexical tokens values defined by YACC.
+#include "ace/Svc_Conf.h"
+#include "ace/Svc_Conf_Tokens.h"
+#include "ace/Svc_Conf_Lexer_Guard.h"
+
+ACE_RCSID (ace,
+ Svc_Conf_l,
+ "$Id$")
+
+// Keeps track of the current line for debugging output.
+int yylineno = 1;
+
+#define token(x) x
+%}
+
+%s PARAMETERS
+%s NORMAL
+
+letter [a-zA-Z_]
+letter_or_digit [a-zA-Z_0-9]
+digit [0-9]
+ident {letter}{letter_or_digit}*
+pathname ([A-Za-z\%]:)?[a-zA-Z_0-9/\%\.\\~-]+
+symbol [ -~]
+string (\"{symbol}*\"|\'{symbol}*\')
+white_space [ \t]
+newline \n
+other .
+
+%%
+
+^#{other}*$ ; /* EMPTY */
+dynamic { return token (ACE_DYNAMIC); }
+static { return token (ACE_STATIC); }
+suspend { return token (ACE_SUSPEND); }
+resume { return token (ACE_RESUME); }
+remove { return token (ACE_REMOVE); }
+stream { return token (ACE_USTREAM); }
+Module { return token (ACE_MODULE_T); }
+Service_Object { return token (ACE_SVC_OBJ_T); }
+STREAM { return token (ACE_STREAM_T); }
+active { return token (ACE_ACTIVE); }
+inactive { return token (ACE_INACTIVE); }
+":" { return token (':'); }
+"*" { return token ('*'); }
+"(" { return token ('('); }
+")" { return token (')'); }
+"{" { return token ('{'); }
+"}" { return token ('}'); }
+{string} {
+ // Check for first type of string, i.e.,
+ // "double quotes" delimited.
+ ACE_TCHAR *s = ACE_OS::strrchr (yytext, '"');
+ if (s == 0)
+ // Check for second type of string, i.e.,
+ // 'single quotes' delimited.
+ s = ACE_OS::strrchr (yytext, '\'');
+
+ ACE_ASSERT (s != 0);
+ // Eliminate the opening and closing double or
+ // single quotes.
+ *s = '\0';
+ yyleng -= 1;
+ yylval->ident_ = ACE_SVC_CONF_PARAM->obstack.copy (yytext + 1, yyleng);
+ return token (ACE_STRING); }
+{ident} {
+ yylval->ident_ = ACE_SVC_CONF_PARAM->obstack.copy (yytext, yyleng);
+ return token (ACE_IDENT);
+ }
+{pathname} {
+ yylval->ident_ = ACE_SVC_CONF_PARAM->obstack.copy (yytext, yyleng);
+ return token (ACE_PATHNAME);
+ }
+{white_space}+ ; /* EMPTY */
+{newline} { ACE_SVC_CONF_PARAM->yylineno++; ace_yylineno++; }
+{other} {
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("unknown character = (%d"),
+ *yytext));
+ if (ACE_OS::ace_isprint (*yytext))
+ ACE_ERROR ((LM_ERROR, ACE_LIB_TEXT ("|%c"), *yytext));
+ ACE_ERROR ((LM_ERROR, ACE_LIB_TEXT (")\n")));
+ }
+<<EOF>> { yyterminate(); }
+%%
+int
+yywrap (void)
+{
+ ::fflush (yyin);
+ yytext[0] = '#';
+ yyleng = 0;
+
+ return 1;
+}
+
+void
+yy_push_buffer (FILE *file, yy_buffer_state *&buffer)
+{
+ // External synchronization is required.
+
+ if (buffer == 0)
+ buffer = yy_create_buffer (file, YY_BUF_SIZE);
+
+ yy_switch_to_buffer (buffer);
+}
+
+void
+yy_push_buffer (const ACE_TCHAR *directive, yy_buffer_state *&buffer)
+{
+ // External synchronization is required.
+
+ // yyparse() may invoke yylex() multiple times when parsing
+ // a single directive. Prevent a new buffer from created during
+ // each call to yylex().
+ if (YY_CURRENT_BUFFER != 0
+ && directive == YY_CURRENT_BUFFER->yy_ch_buf)
+ return;
+
+ if (buffer == 0)
+ {
+ // yy_scan_string() already switches the buffer so there is
+ // no need to explicitly make the switch.
+ buffer = yy_scan_string (directive);
+ }
+ else
+ yy_switch_to_buffer (buffer);
+}
+
+void
+yy_pop_buffer (yy_buffer_state *buffer)
+{
+ // External synchronization is required.
+
+ yy_switch_to_buffer (buffer);
+}
diff --git a/ace/Svcconf/Svc_Conf.y b/ace/Svcconf/Svc_Conf.y
new file mode 100644
index 00000000000..326c9d9b442
--- /dev/null
+++ b/ace/Svcconf/Svc_Conf.y
@@ -0,0 +1,464 @@
+%{
+// $Id$
+
+#include "ace/ARGV.h"
+#include "ace/Svc_Conf.h"
+#include "ace/Module.h"
+#include "ace/Stream.h"
+
+ACE_RCSID (ace,
+ Svc_Conf_y,
+ "$Id$")
+
+// Prototypes.
+static ACE_Module_Type *ace_get_module (ACE_Static_Node *str_rec,
+ ACE_Static_Node *svc_type);
+static ACE_Module_Type *ace_get_module (ACE_Static_Node *str_rec,
+ const ACE_TCHAR *svc_name);
+
+#define YYDEBUG_LEXER_TEXT (yytext[yyleng] = '\0', yytext)
+
+// Force the pretty debugging code to compile.
+// #define YYDEBUG 1
+
+// Keeps track of the number of errors encountered so far.
+int yyerrno = 0;
+
+%}
+
+%token ACE_DYNAMIC ACE_STATIC ACE_SUSPEND ACE_RESUME ACE_REMOVE ACE_USTREAM
+%token ACE_MODULE_T ACE_STREAM_T ACE_SVC_OBJ_T ACE_ACTIVE ACE_INACTIVE
+%token ACE_PATHNAME ACE_IDENT ACE_STRING
+
+%start svc_config_entries
+
+%type <ident_> ACE_IDENT ACE_STRING ACE_PATHNAME pathname parameters_opt
+%type <type_> type status
+%type <parse_node_> dynamic static suspend resume remove module_list stream
+%type <parse_node_> stream_modules module svc_config_entry
+%type <static_node_> stream_ops
+%type <svc_record_> svc_location
+%type <location_node_> svc_initializer
+
+// Generate a pure (reentrant) parser -- GNU Bison only
+%pure_parser
+
+%%
+
+svc_config_entries
+ : svc_config_entries svc_config_entry
+ {
+ if ($2 != 0)
+ {
+ $2->apply (); delete $2;
+ }
+ ACE_SVC_CONF_PARAM->obstack.release ();
+ }
+ | svc_config_entries error
+ {
+ ACE_SVC_CONF_PARAM->obstack.release ();
+ }
+ | /* EMPTY */
+ ;
+
+svc_config_entry
+ : dynamic
+ | static
+ | suspend
+ | resume
+ | remove
+ | stream
+ ;
+
+dynamic
+ : ACE_DYNAMIC svc_location parameters_opt
+ {
+ if ($2 != 0)
+ $$ = new ACE_Dynamic_Node ($2, $3);
+ else
+ $$ = 0;
+ }
+ ;
+
+static
+ : ACE_STATIC ACE_IDENT parameters_opt
+ {
+ $$ = new ACE_Static_Node ($2, $3);
+ }
+ ;
+
+suspend
+ : ACE_SUSPEND ACE_IDENT
+ {
+ $$ = new ACE_Suspend_Node ($2);
+ }
+ ;
+
+resume
+ : ACE_RESUME ACE_IDENT
+ {
+ $$ = new ACE_Resume_Node ($2);
+ }
+ ;
+
+remove
+ : ACE_REMOVE ACE_IDENT
+ {
+ $$ = new ACE_Remove_Node ($2);
+ }
+ ;
+
+stream
+ : ACE_USTREAM stream_ops stream_modules
+ {
+ $$ = new ACE_Stream_Node ($2, $3);
+ }
+ | ACE_USTREAM ACE_IDENT { $<static_node_>$ = new ACE_Static_Node ($2); } stream_modules
+ {
+ $$ = new ACE_Dummy_Node ($<static_node_>3, $4);
+ }
+ ;
+
+stream_ops
+ : dynamic
+ {
+ }
+ | static
+ {
+ }
+ ;
+
+stream_modules
+ : '{'
+ {
+ // Initialize left context...
+ $<static_node_>$ = $<static_node_>0;
+ }
+ module_list '}'
+ {
+ $$ = $3;
+ }
+ | /* EMPTY */ { $$ = 0; }
+ ;
+
+module_list
+ : module_list module
+ {
+ if ($2 != 0)
+ {
+ $2->link ($1);
+ $$ = $2;
+ }
+ }
+ | /* EMPTY */ { $$ = 0; }
+ ;
+
+module
+ : dynamic
+ {
+ ACE_Static_Node *svc_type = $<static_node_>1;
+
+ if (svc_type != 0)
+ {
+ ACE_Static_Node *module = $<static_node_>-1;
+
+ ACE_ARGV args (svc_type->parameters ());
+ ACE_Module_Type *mt = ace_get_module (module,
+ svc_type);
+ ACE_Stream_Type *st =
+ ACE_dynamic_cast (ACE_Stream_Type *,
+ ACE_const_cast (ACE_Service_Type_Impl *,
+ module->record ()->type ()));
+
+ if (mt->init (args.argc (), args.argv ()) == -1
+ || st->push (mt) == -1)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("dynamic initialization failed for Module %s\n"),
+ svc_type->name ()));
+ ACE_SVC_CONF_PARAM->yyerrno++;
+ }
+ }
+ }
+ | static
+ {
+ ACE_Module_Type *mt = ace_get_module ($<static_node_>-1, $<static_node_>1->name ());
+
+ if (((ACE_Stream_Type *) ($<static_node_>-1)->record ()->type ())->push (mt) == -1)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("Problem with static\n")));
+ ACE_SVC_CONF_PARAM->yyerrno++;
+ }
+ }
+ | suspend
+ {
+ ACE_Module_Type *mt = ace_get_module ($<static_node_>-1,
+ $<static_node_>1->name ());
+ if (mt != 0)
+ mt->suspend ();
+ }
+ | resume
+ {
+ ACE_Module_Type *mt = ace_get_module ($<static_node_>-1,
+ $<static_node_>1->name ());
+ if (mt != 0)
+ mt->resume ();
+ }
+ | remove
+ {
+ ACE_Static_Node *stream = $<static_node_>-1;
+ ACE_Static_Node *module = $<static_node_>1;
+ ACE_Module_Type *mt = ace_get_module (stream,
+ module->name ());
+
+ ACE_Stream_Type *st =
+ ACE_dynamic_cast (ACE_Stream_Type *,
+ ACE_const_cast (ACE_Service_Type_Impl *,
+ stream->record ()->type ()));
+ if (mt != 0 && st->remove (mt) == -1)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("cannot remove Module_Type %s from STREAM_Type %s\n"),
+ module->name (),
+ stream->name ()));
+ ACE_SVC_CONF_PARAM->yyerrno++;
+ }
+ }
+ ;
+
+svc_location
+ : ACE_IDENT type svc_initializer status
+ {
+ u_int flags
+ = ACE_Service_Type::DELETE_THIS
+ | ($3->dispose () == 0 ? 0 : ACE_Service_Type::DELETE_OBJ);
+ ACE_Service_Object_Exterminator gobbler = 0;
+ void *sym = $3->symbol (&gobbler);
+
+ if (sym != 0)
+ {
+ ACE_Service_Type_Impl *stp
+ = ace_create_service_type ($1,
+ $2,
+ sym,
+ flags,
+ gobbler);
+ $$ = new ACE_Service_Type ($1,
+ stp,
+ $3->handle (),
+ $4);
+ }
+ else
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("Unable to find service: %s\n"),
+ $1));
+ ++ACE_SVC_CONF_PARAM->yyerrno;
+ $$ = 0;
+ }
+ delete $3;
+ }
+ ;
+
+status
+ : ACE_ACTIVE
+ {
+ $$ = 1;
+ }
+ | ACE_INACTIVE
+ {
+ $$ = 0;
+ }
+ | /* EMPTY */
+ {
+ $$ = 1;
+ }
+ ;
+
+svc_initializer
+ : pathname ':' ACE_IDENT
+ {
+ $$ = new ACE_Object_Node ($1, $3);
+ }
+ | pathname ':' ACE_IDENT '(' ')'
+ {
+ $$ = new ACE_Function_Node ($1, $3);
+ }
+ | ':' ACE_IDENT '(' ')'
+ {
+ $$ = new ACE_Static_Function_Node ($2);
+ }
+ ;
+
+type
+ : ACE_MODULE_T '*'
+ {
+ $$ = ACE_MODULE_T;
+ }
+ | ACE_SVC_OBJ_T '*'
+ {
+ $$ = ACE_SVC_OBJ_T;
+ }
+ | ACE_STREAM_T '*'
+ {
+ $$ = ACE_STREAM_T;
+ }
+ ;
+
+parameters_opt
+ : ACE_STRING
+ | /* EMPTY */ { $$ = 0; }
+ ;
+
+pathname
+ : ACE_PATHNAME
+ | ACE_IDENT
+ | ACE_STRING
+ ;
+
+%%
+// Prints the error string to standard output. Cleans up the error
+// messages.
+
+void
+yyerror (const ACE_TCHAR *s)
+{
+#if defined (ACE_NLOGGING)
+ ACE_UNUSED_ARG (s);
+#endif /* ACE_NLOGGING */
+
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("[error %d] on line %d: %s\n"),
+ yyerrno,
+ yylineno,
+ s));
+}
+
+// Note that SRC_REC represents left context, which is the STREAM *
+// record.
+
+static ACE_Module_Type *
+ace_get_module (ACE_Static_Node *str_rec,
+ const ACE_TCHAR *svc_name)
+{
+ const ACE_Service_Type *sr = str_rec->record ();
+ const ACE_Service_Type_Impl *type = sr->type ();
+ ACE_Stream_Type *st = sr == 0
+ ? 0
+ : ACE_dynamic_cast (ACE_Stream_Type *,
+ ACE_const_cast (ACE_Service_Type_Impl *,
+ type));
+ ACE_Module_Type *mt = st == 0 ? 0 : st->find (svc_name);
+
+ if (sr == 0 || st == 0 || mt == 0)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("cannot locate Module_Type %s in STREAM_Type %s\n"),
+ svc_name,
+ str_rec->name ()));
+ yyerrno++;
+ }
+
+ return mt;
+}
+
+static ACE_Module_Type *
+ace_get_module (ACE_Static_Node *str_rec,
+ ACE_Static_Node *svc_type)
+{
+ const ACE_Service_Type *sr = str_rec->record ();
+ const ACE_Service_Type_Impl *type = sr->type ();
+ ACE_Stream_Type *st = sr == 0 ? 0 : (ACE_Stream_Type *) type;
+ const ACE_Service_Type *sv = svc_type->record ();
+ type = sv->type ();
+ ACE_Module_Type *mt = (ACE_Module_Type *) type;
+ const ACE_TCHAR *module_type_name = svc_type->name ();
+
+ if (sr == 0 || st == 0 || mt == 0)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("cannot locate Module_Type %s or STREAM_Type %s\n"),
+ module_type_name,
+ str_rec->name ()));
+ yyerrno++;
+ }
+
+ // Make sure that the Module has the same name as the
+ // Module_Type object from the svc.conf file.
+ ACE_Module<ACE_SYNCH> *mp = (ACE_Module<ACE_SYNCH> *) mt->object ();
+
+ if (ACE_OS::strcmp (mp->name (), module_type_name) != 0)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_LIB_TEXT ("warning: assigning Module_Type name %s to Module %s since names differ\n"),
+ module_type_name,
+ mp->name ()));
+ mp->name (module_type_name);
+ }
+
+ return mt;
+}
+
+ACE_Service_Type_Impl *
+ace_create_service_type (const ACE_TCHAR *name,
+ int type,
+ void *symbol,
+ u_int flags,
+ ACE_Service_Object_Exterminator gobbler)
+{
+ ACE_Service_Type_Impl *stp = 0;
+
+ // Note, the only place we need to put a case statement. This is
+ // also the place where we'd put the RTTI tests, if the compiler
+ // actually supported them!
+
+ switch (type)
+ {
+ case ACE_SVC_OBJ_T:
+ ACE_NEW_RETURN (stp,
+ ACE_Service_Object_Type ((ACE_Service_Object *) symbol,
+ name, flags,
+ gobbler),
+ 0);
+ break;
+ case ACE_MODULE_T:
+ ACE_NEW_RETURN (stp,
+ ACE_Module_Type (symbol, name, flags),
+ 0);
+ break;
+ case ACE_STREAM_T:
+ ACE_NEW_RETURN (stp,
+ ACE_Stream_Type (symbol, name, flags),
+ 0);
+ break;
+ default:
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("unknown case\n")));
+ yyerrno++;
+ break;
+ }
+ return stp;
+}
+
+#if defined (DEBUGGING)
+// Current line number.
+int yylineno = 1;
+
+// Name given on the command-line to envoke the program.
+ACE_TCHAR *program_name;
+
+// Main driver program.
+
+int
+main (int argc, char *argv[])
+{
+ ACE_Svc_Conf_Param param (stdin);
+
+ // Try to reopen any filename argument to use YYIN.
+ if (argc > 1 && (yyin = freopen (argv[1], "r", stdin)) == 0)
+ (void) ::fprintf (stderr, "usage: %s [file]\n", argv[0]), ACE_OS::exit (1);
+
+ return yyparse (&param);
+}
+#endif /* DEBUGGING */
diff --git a/ace/Svcconf/Svc_Conf_Lexer_Guard.cpp b/ace/Svcconf/Svc_Conf_Lexer_Guard.cpp
new file mode 100644
index 00000000000..13848feaac9
--- /dev/null
+++ b/ace/Svcconf/Svc_Conf_Lexer_Guard.cpp
@@ -0,0 +1,36 @@
+// -*- C++ -*-
+
+#include "ace/Svc_Conf.h"
+
+#include "ace/Svc_Conf_Lexer_Guard.h"
+
+ACE_RCSID (ace,
+ Svc_Conf_Lexer_Guard,
+ "$Id$")
+
+ACE_Svc_Conf_Lexer_Guard::ACE_Svc_Conf_Lexer_Guard (ACE_Svc_Conf_Param *param)
+ : buffer_ (0)
+{
+ // External synchronization is required.
+
+ // Note that allocation/deallocation is done once during the
+ // processing of a service configurator directive. Memory
+ // managements is done at a higher level, not in this class. This
+ // is necessary to prevent an allocation/deallocation from occurring
+ // when parsing/scanning each token.
+
+ if (param->type == ACE_Svc_Conf_Param::SVC_CONF_FILE)
+ ::ace_yy_push_buffer (param->source.file, param->buffer);
+ else
+ ::ace_yy_push_buffer (param->source.directive,
+ param->buffer);
+
+ this->buffer_ = param->buffer;
+}
+
+ACE_Svc_Conf_Lexer_Guard::~ACE_Svc_Conf_Lexer_Guard (void)
+{
+ // External synchronization is required.
+
+ ::ace_yy_pop_buffer (this->buffer_);
+}
diff --git a/ace/Svcconf/Svc_Conf_Lexer_Guard.h b/ace/Svcconf/Svc_Conf_Lexer_Guard.h
new file mode 100644
index 00000000000..4e68bb60ed5
--- /dev/null
+++ b/ace/Svcconf/Svc_Conf_Lexer_Guard.h
@@ -0,0 +1,79 @@
+// -*- C++ -*-
+
+//=============================================================================
+/**
+ * @file Svc_Conf_Lexer_Guard.h
+ *
+ * $Id$
+ *
+ * @author Ossama Othman <ossama@uci.edu>
+ */
+//=============================================================================
+
+#ifndef ACE_SVC_CONF_LEXER_GUARD_H
+#define ACE_SVC_CONF_LEXER_GUARD_H
+
+#include "ace/pre.h"
+
+#include "ace/config-all.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+/// Forward declarations
+class ACE_Svc_Conf_Param;
+
+struct ace_yy_buffer_state;
+
+/**
+ * @class ACE_Svc_Conf_Lexer_Guard
+ *
+ * @brief "Guard" that ensures lexer buffer switching is
+ * exception-safe.
+ *
+ * Buffers are switched, if necessary, each time a token is
+ * parsed/scanned. The buffer switching must be synchronized
+ * externally. This class performs no synchronization.
+ *
+ * @note Note that allocation/deallocation is done once during the
+ * processing of a service configurator directive. Memory
+ * managements is done at a higher level, not in this class.
+ * This is necessary to prevent an allocation/deallocation from
+ * occurring when parsing/scanning each token.
+ */
+class ACE_Svc_Conf_Lexer_Guard
+{
+public:
+
+ /// Constructor
+ /**
+ * Switches buffers, if necessary, when token scanning first
+ * begins. Allocation of the buffer will also occur if one has not
+ * already been allocated. This operation effectively pushes a
+ * buffer on to a stack.
+ */
+ ACE_Svc_Conf_Lexer_Guard (ACE_Svc_Conf_Param *param);
+
+ /// Destructor
+ /**
+ * Switches buffers, if necessary when token scanning completes. No
+ * buffer deallocation occurs here. Buffers are deallocated when
+ * parsing of the entire directive is done, not when scanning of a
+ * single token is done. This operation effective pops a buffer off
+ * of a stack.
+ */
+ ~ACE_Svc_Conf_Lexer_Guard (void);
+
+private:
+
+ /// Lexer buffer that corresponds to the current Service
+ /// Configurator file/direct scan.
+ ace_yy_buffer_state *buffer_;
+
+};
+
+
+#include "ace/post.h"
+
+#endif /* ACE_SVC_CONF_LEXER_GUARD_H */
diff --git a/ace/Svcconf/Svc_Conf_Tokens.h b/ace/Svcconf/Svc_Conf_Tokens.h
new file mode 100644
index 00000000000..14a41622c1d
--- /dev/null
+++ b/ace/Svcconf/Svc_Conf_Tokens.h
@@ -0,0 +1,16 @@
+// $Id$
+#define ACE_DYNAMIC 257
+#define ACE_STATIC 258
+#define ACE_SUSPEND 259
+#define ACE_RESUME 260
+#define ACE_REMOVE 261
+#define ACE_USTREAM 262
+#define ACE_MODULE_T 263
+#define ACE_STREAM_T 264
+#define ACE_SVC_OBJ_T 265
+#define ACE_ACTIVE 266
+#define ACE_INACTIVE 267
+#define ACE_PATHNAME 268
+#define ACE_IDENT 269
+#define ACE_STRING 270
+
diff --git a/ace/Svcconf/Svc_Conf_l.cpp b/ace/Svcconf/Svc_Conf_l.cpp
new file mode 100644
index 00000000000..be53770e146
--- /dev/null
+++ b/ace/Svcconf/Svc_Conf_l.cpp
@@ -0,0 +1,1841 @@
+#define ACE_YY_NO_UNPUT
+/* A lexical scanner generated by flex */
+
+/* Scanner skeleton version:
+ * $Header$
+ */
+
+#define FLEX_SCANNER
+#define ACE_YY_FLEX_MAJOR_VERSION 2
+#define ACE_YY_FLEX_MINOR_VERSION 5
+
+/* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */
+#ifdef c_plusplus
+#ifndef __cplusplus
+#define __cplusplus
+#endif
+#endif
+
+
+#ifdef __cplusplus
+
+#include "ace/OS.h"
+#include "ace/Object_Manager.h"
+
+/* Use prototypes in function declarations. */
+#define ACE_YY_USE_PROTOS
+
+/* The "const" storage-class-modifier is valid. */
+#define ACE_YY_USE_CONST
+
+#else /* ! __cplusplus */
+
+#if __STDC__
+
+#define ACE_YY_USE_PROTOS
+#define ACE_YY_USE_CONST
+
+#endif /* __STDC__ */
+#endif /* ! __cplusplus */
+
+#ifdef __TURBOC__
+ #pragma warn -rch
+ #pragma warn -use
+#include /**/ <io.h>
+#include /**/ <stdlib.h>
+#define ACE_YY_USE_CONST
+#define ACE_YY_USE_PROTOS
+#endif
+
+#ifdef ACE_YY_USE_CONST
+#define ace_yyconst const
+#else
+#define ace_yyconst
+#endif
+
+
+#ifdef ACE_YY_USE_PROTOS
+#define ACE_YY_PROTO(proto) proto
+#else
+#define ACE_YY_PROTO(proto) ()
+#endif
+
+/* Returned upon end-of-file. */
+#define ACE_YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index. If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define ACE_YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/* Enter a start condition. This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN ace_yy_start = 1 + 2 *
+
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state. The ACE_YYSTATE alias is for lex
+ * compatibility.
+ */
+#define ACE_YY_START ((ace_yy_start - 1) / 2)
+#define ACE_YYSTATE ACE_YY_START
+
+/* Action number for EOF rule of a given start state. */
+#define ACE_YY_STATE_EOF(state) (ACE_YY_END_OF_BUFFER + state + 1)
+
+/* Special action meaning "start processing a new file". */
+#define ACE_YY_NEW_FILE ace_yyrestart( ace_yyin )
+
+#define ACE_YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#define ACE_YY_BUF_SIZE 16384
+
+typedef struct ace_yy_buffer_state *ACE_YY_BUFFER_STATE;
+
+extern int ace_yyleng;
+extern FILE *ace_yyin, *ace_yyout;
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+/* The funky do-while in the following #define is used to turn the definition
+ * int a single C statement (which needs a semi-colon terminator). This
+ * avoids problems with code like:
+ *
+ * if ( condition_holds )
+ * ace_yyless( 5 );
+ * else
+ * do_something_else();
+ *
+ * Prior to using the do-while the compiler would get upset at the
+ * "else" because it interpreted the "if" statement as being all
+ * done when it reached the ';' after the ace_yyless() call.
+ */
+
+/* Return all but the first 'n' matched characters back to the input stream. */
+
+#define ace_yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up ace_yytext. */ \
+ *ace_yy_cp = ace_yy_hold_char; \
+ ACE_YY_RESTORE_ACE_YY_MORE_OFFSET \
+ ace_yy_c_buf_p = ace_yy_cp = ace_yy_bp + n - ACE_YY_MORE_ADJ; \
+ ACE_YY_DO_BEFORE_ACTION; /* set up ace_yytext again */ \
+ } \
+ while ( 0 )
+
+#if 0
+#define unput(c) ace_yyunput( c, ace_yytext_ptr )
+#endif /* 0 */
+
+/* The following is because we cannot portably get our hands on size_t
+ * (without autoconf's help, which isn't available because we want
+ * flex-generated scanners to compile on their own).
+ */
+typedef unsigned int ace_yy_size_t;
+
+
+struct ace_yy_buffer_state
+ {
+ FILE *ace_yy_input_file;
+
+ ACE_TCHAR *ace_yy_ch_buf; /* input buffer */
+ ACE_TCHAR *ace_yy_buf_pos; /* current position in input buffer */
+
+ /* Size of input buffer in bytes, not including room for EOB
+ * characters.
+ */
+ ace_yy_size_t ace_yy_buf_size;
+
+ /* Number of characters read into ace_yy_ch_buf, not including EOB
+ * characters.
+ */
+ int ace_yy_n_chars;
+
+ /* Whether we "own" the buffer - i.e., we know we created it,
+ * and can realloc() it to grow it, and should free() it to
+ * delete it.
+ */
+ int ace_yy_is_our_buffer;
+
+ /* Whether this is an "interactive" input source; if so, and
+ * if we're using stdio for input, then we want to use getc()
+ * instead of fread(), to make sure we stop fetching input after
+ * each newline.
+ */
+ int ace_yy_is_interactive;
+
+ /* Whether we're considered to be at the beginning of a line.
+ * If so, '^' rules will be active on the next match, otherwise
+ * not.
+ */
+ int ace_yy_at_bol;
+
+ /* Whether to try to fill the input buffer when we reach the
+ * end of it.
+ */
+ int ace_yy_fill_buffer;
+
+ int ace_yy_buffer_status;
+#define ACE_YY_BUFFER_NEW 0
+#define ACE_YY_BUFFER_NORMAL 1
+ /* When an EOF's been seen but there's still some text to process
+ * then we mark the buffer as ACE_YY_EOF_PENDING, to indicate that we
+ * shouldn't try reading from the input source any more. We might
+ * still have a bunch of tokens to match, though, because of
+ * possible backing-up.
+ *
+ * When we actually see the EOF, we change the status to "new"
+ * (via ace_yyrestart()), so that the user can continue scanning by
+ * just pointing ace_yyin at a new input file.
+ */
+#define ACE_YY_BUFFER_EOF_PENDING 2
+ };
+
+static ACE_YY_BUFFER_STATE ace_yy_current_buffer = 0;
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ */
+#define ACE_YY_CURRENT_BUFFER ace_yy_current_buffer
+
+
+/* ace_yy_hold_char holds the character lost when ace_yytext is formed. */
+static ACE_TCHAR ace_yy_hold_char;
+
+static int ace_yy_n_chars; /* number of characters read into ace_yy_ch_buf */
+
+
+int ace_yyleng;
+
+/* Points to current character in buffer. */
+static ACE_TCHAR *ace_yy_c_buf_p = (ACE_TCHAR *) 0;
+static int ace_yy_init = 1; /* whether we need to initialize */
+static int ace_yy_start = 0; /* start state number */
+
+/* Flag which is used to allow ace_yywrap()'s to do buffer switches
+ * instead of setting up a fresh ace_yyin. A bit of a hack ...
+ */
+static int ace_yy_did_buffer_switch_on_eof;
+
+void ace_yyrestart ACE_YY_PROTO(( FILE *input_file ));
+
+void ace_yy_switch_to_buffer ACE_YY_PROTO(( ACE_YY_BUFFER_STATE new_buffer ));
+void ace_yy_load_buffer_state ACE_YY_PROTO(( void ));
+ACE_YY_BUFFER_STATE ace_yy_create_buffer ACE_YY_PROTO(( FILE *file, int size ));
+void ace_yy_delete_buffer ACE_YY_PROTO(( ACE_YY_BUFFER_STATE b ));
+void ace_yy_init_buffer ACE_YY_PROTO(( ACE_YY_BUFFER_STATE b, FILE *file ));
+void ace_yy_flush_buffer ACE_YY_PROTO(( ACE_YY_BUFFER_STATE b ));
+#define ACE_YY_FLUSH_BUFFER ace_yy_flush_buffer( ace_yy_current_buffer )
+
+ACE_YY_BUFFER_STATE ace_yy_scan_buffer ACE_YY_PROTO(( ACE_TCHAR *base, ace_yy_size_t size ));
+ACE_YY_BUFFER_STATE ace_yy_scan_string ACE_YY_PROTO(( ace_yyconst ACE_TCHAR *ace_yy_str ));
+ACE_YY_BUFFER_STATE ace_yy_scan_bytes ACE_YY_PROTO(( ace_yyconst ACE_TCHAR *bytes, int len ));
+
+static void *ace_yy_flex_alloc ACE_YY_PROTO(( ace_yy_size_t ));
+static void *ace_yy_flex_realloc ACE_YY_PROTO(( void *, ace_yy_size_t ));
+static void ace_yy_flex_free ACE_YY_PROTO(( void * ));
+
+#define ace_yy_new_buffer ace_yy_create_buffer
+
+#define ace_yy_set_interactive(is_interactive) \
+ { \
+ if ( ! ace_yy_current_buffer ) \
+ ace_yy_current_buffer = ace_yy_create_buffer( ace_yyin, ACE_YY_BUF_SIZE ); \
+ ace_yy_current_buffer->ace_yy_is_interactive = is_interactive; \
+ }
+
+#define ace_yy_set_bol(at_bol) \
+ { \
+ if ( ! ace_yy_current_buffer ) \
+ ace_yy_current_buffer = ace_yy_create_buffer( ace_yyin, ACE_YY_BUF_SIZE ); \
+ ace_yy_current_buffer->ace_yy_at_bol = at_bol; \
+ }
+
+#define ACE_YY_AT_BOL() (ace_yy_current_buffer->ace_yy_at_bol)
+
+typedef ACE_TCHAR ACE_YY_CHAR;
+FILE *ace_yyin = (FILE *) 0, *ace_yyout = (FILE *) 0;
+typedef int ace_yy_state_type;
+extern ACE_TCHAR *ace_yytext;
+#define ace_yytext_ptr ace_yytext
+
+static ace_yy_state_type ace_yy_get_previous_state ACE_YY_PROTO(( void ));
+static ace_yy_state_type ace_yy_try_NUL_trans ACE_YY_PROTO(( ace_yy_state_type current_state ));
+static int ace_yy_get_next_buffer ACE_YY_PROTO(( void ));
+static void ace_yy_fatal_error ACE_YY_PROTO(( ace_yyconst ACE_TCHAR msg[] ));
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up ace_yytext.
+ */
+#define ACE_YY_DO_BEFORE_ACTION \
+ ace_yytext_ptr = ace_yy_bp; \
+ ace_yyleng = (int) (ace_yy_cp - ace_yy_bp); \
+ ace_yy_hold_char = *ace_yy_cp; \
+ *ace_yy_cp = '\0'; \
+ ace_yy_c_buf_p = ace_yy_cp;
+
+#define ACE_YY_NUM_RULES 25
+#define ACE_YY_END_OF_BUFFER 26
+static ace_yyconst short int ace_yy_accept[107] =
+ { 0,
+ 0, 0, 0, 0, 0, 0, 26, 24, 22, 23,
+ 24, 21, 24, 15, 16, 14, 21, 13, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 17, 18, 24,
+ 22, 0, 19, 21, 0, 0, 19, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 0, 1, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 8, 10, 20, 11, 20, 20, 6, 5,
+ 3, 7, 20, 20, 2, 20, 4, 20, 12, 20,
+
+ 20, 20, 20, 20, 9, 0
+ } ;
+
+static ace_yyconst int ace_yy_ec[256] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 2, 3,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 4, 5, 6, 7, 5, 8, 5, 9, 10,
+ 11, 12, 5, 5, 13, 13, 13, 14, 14, 14,
+ 14, 14, 14, 14, 14, 14, 14, 15, 5, 5,
+ 5, 5, 5, 5, 16, 17, 17, 17, 18, 17,
+ 17, 17, 17, 17, 17, 17, 19, 17, 20, 17,
+ 17, 21, 22, 23, 17, 17, 17, 17, 17, 17,
+ 5, 13, 5, 5, 24, 5, 25, 26, 27, 28,
+
+ 29, 17, 17, 17, 30, 31, 17, 32, 33, 34,
+ 35, 36, 17, 37, 38, 39, 40, 41, 17, 17,
+ 42, 17, 43, 5, 44, 13, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1
+ } ;
+
+static ace_yyconst int ace_yy_meta[45] =
+ { 0,
+ 1, 1, 1, 2, 2, 2, 2, 3, 2, 2,
+ 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 2, 2
+ } ;
+
+static ace_yyconst short int ace_yy_base[112] =
+ { 0,
+ 0, 132, 0, 127, 0, 123, 129, 437, 43, 437,
+ 122, 112, 109, 437, 437, 437, 102, 437, 38, 41,
+ 42, 51, 54, 55, 64, 65, 74, 437, 437, 104,
+ 56, 93, 86, 70, 69, 66, 65, 75, 78, 87,
+ 88, 96, 97, 107, 108, 111, 125, 58, 437, 129,
+ 137, 141, 145, 149, 153, 157, 163, 171, 175, 181,
+ 187, 193, 199, 203, 207, 213, 217, 223, 233, 234,
+ 242, 252, 253, 261, 262, 265, 271, 274, 277, 285,
+ 289, 300, 301, 310, 311, 320, 323, 324, 333, 334,
+ 343, 344, 347, 353, 356, 359, 365, 371, 368, 374,
+
+ 377, 386, 389, 390, 398, 437, 428, 49, 430, 45,
+ 433
+ } ;
+
+static ace_yyconst short int ace_yy_def[112] =
+ { 0,
+ 106, 1, 1, 1, 1, 1, 106, 106, 106, 106,
+ 107, 108, 109, 106, 106, 106, 108, 106, 110, 110,
+ 110, 110, 110, 110, 110, 110, 110, 106, 106, 111,
+ 106, 107, 107, 108, 108, 109, 109, 110, 110, 110,
+ 110, 110, 110, 110, 110, 110, 110, 111, 106, 110,
+ 110, 110, 110, 110, 110, 110, 110, 110, 110, 110,
+ 110, 110, 110, 110, 110, 110, 110, 110, 110, 110,
+ 110, 110, 110, 110, 110, 110, 110, 110, 110, 110,
+ 110, 110, 110, 110, 110, 110, 110, 110, 110, 110,
+ 110, 110, 110, 110, 110, 110, 110, 110, 110, 110,
+
+ 110, 110, 110, 110, 110, 0, 106, 106, 106, 106,
+ 106
+ } ;
+
+static ace_yyconst short int ace_yy_nxt[482] =
+ { 0,
+ 8, 9, 10, 9, 8, 11, 8, 12, 13, 14,
+ 15, 16, 17, 17, 18, 19, 19, 19, 20, 19,
+ 19, 21, 19, 22, 23, 19, 19, 24, 19, 25,
+ 19, 19, 19, 19, 19, 19, 26, 27, 19, 19,
+ 19, 19, 28, 29, 31, 34, 31, 38, 34, 34,
+ 34, 34, 35, 34, 34, 35, 35, 31, 34, 31,
+ 49, 34, 34, 34, 40, 106, 34, 34, 35, 35,
+ 41, 34, 34, 37, 37, 39, 34, 34, 35, 35,
+ 42, 34, 34, 106, 106, 34, 34, 34, 35, 106,
+ 34, 33, 106, 45, 34, 34, 43, 44, 33, 34,
+
+ 34, 106, 106, 34, 34, 50, 49, 51, 34, 34,
+ 106, 106, 46, 47, 34, 34, 106, 37, 34, 34,
+ 34, 106, 106, 34, 52, 106, 35, 33, 106, 30,
+ 54, 55, 34, 30, 53, 58, 34, 34, 30, 106,
+ 56, 34, 106, 106, 34, 57, 106, 59, 34, 34,
+ 106, 106, 34, 34, 62, 106, 34, 34, 106, 106,
+ 34, 34, 60, 106, 34, 34, 106, 106, 61, 34,
+ 34, 106, 106, 65, 64, 34, 106, 106, 34, 66,
+ 106, 63, 34, 34, 106, 106, 106, 34, 34, 106,
+ 106, 67, 106, 34, 34, 106, 106, 106, 106, 34,
+
+ 34, 106, 68, 70, 106, 34, 34, 106, 73, 69,
+ 34, 34, 106, 106, 34, 34, 71, 106, 72, 34,
+ 34, 106, 106, 106, 34, 34, 106, 106, 74, 34,
+ 34, 106, 106, 106, 106, 34, 106, 106, 106, 76,
+ 34, 34, 106, 75, 106, 34, 34, 106, 106, 34,
+ 106, 77, 106, 106, 34, 79, 106, 78, 81, 34,
+ 34, 106, 80, 106, 34, 34, 106, 106, 34, 34,
+ 82, 84, 34, 34, 34, 106, 106, 34, 34, 106,
+ 83, 34, 106, 34, 34, 106, 34, 85, 106, 34,
+ 86, 106, 34, 106, 87, 106, 34, 34, 106, 106,
+
+ 88, 34, 89, 106, 106, 90, 106, 34, 34, 106,
+ 106, 91, 34, 34, 106, 106, 106, 34, 34, 106,
+ 106, 92, 34, 34, 106, 106, 106, 34, 106, 106,
+ 34, 34, 34, 93, 106, 34, 34, 106, 106, 94,
+ 34, 34, 106, 106, 106, 34, 34, 106, 106, 95,
+ 34, 34, 106, 106, 34, 34, 34, 106, 106, 34,
+ 34, 106, 106, 34, 96, 34, 34, 106, 34, 106,
+ 106, 34, 34, 106, 97, 34, 98, 34, 34, 106,
+ 34, 34, 106, 34, 34, 106, 34, 99, 106, 34,
+ 100, 106, 106, 34, 106, 106, 34, 34, 34, 101,
+
+ 106, 34, 34, 106, 106, 34, 106, 102, 106, 106,
+ 34, 106, 106, 106, 103, 104, 106, 106, 106, 106,
+ 106, 106, 106, 106, 106, 106, 106, 106, 105, 32,
+ 32, 36, 36, 48, 48, 48, 7, 106, 106, 106,
+ 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
+ 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
+ 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
+ 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
+ 106
+ } ;
+
+static ace_yyconst short int ace_yy_chk[482] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 9, 19, 9, 110, 20, 21,
+ 19, 108, 19, 20, 21, 20, 21, 31, 22, 31,
+ 48, 23, 24, 22, 21, 22, 23, 24, 23, 24,
+ 21, 25, 26, 37, 36, 20, 25, 26, 25, 26,
+ 23, 27, 38, 35, 34, 39, 27, 38, 27, 38,
+ 39, 33, 39, 26, 40, 41, 24, 25, 32, 40,
+
+ 41, 40, 41, 42, 43, 39, 30, 40, 42, 43,
+ 42, 43, 27, 27, 44, 45, 17, 13, 46, 44,
+ 45, 44, 45, 46, 41, 46, 12, 11, 7, 6,
+ 43, 44, 47, 4, 42, 46, 50, 47, 2, 47,
+ 45, 50, 0, 50, 51, 45, 0, 46, 52, 51,
+ 0, 51, 53, 52, 51, 52, 54, 53, 0, 53,
+ 55, 54, 47, 54, 56, 55, 0, 55, 50, 56,
+ 57, 56, 0, 54, 53, 57, 0, 57, 58, 55,
+ 0, 52, 59, 58, 0, 58, 0, 59, 60, 59,
+ 0, 56, 0, 60, 61, 60, 0, 0, 0, 61,
+
+ 62, 61, 57, 59, 0, 62, 63, 62, 62, 58,
+ 64, 63, 0, 63, 65, 64, 60, 64, 61, 65,
+ 66, 65, 0, 0, 67, 66, 0, 66, 63, 67,
+ 68, 67, 0, 0, 0, 68, 0, 68, 0, 65,
+ 69, 70, 0, 64, 0, 69, 70, 69, 70, 71,
+ 0, 66, 0, 0, 71, 68, 71, 67, 70, 72,
+ 73, 0, 69, 0, 72, 73, 72, 73, 74, 75,
+ 71, 73, 76, 74, 75, 74, 75, 76, 77, 76,
+ 72, 78, 0, 77, 79, 77, 78, 74, 78, 79,
+ 75, 79, 80, 0, 76, 0, 81, 80, 0, 80,
+
+ 77, 81, 78, 81, 0, 79, 0, 82, 83, 0,
+ 0, 80, 82, 83, 82, 83, 0, 84, 85, 0,
+ 0, 81, 84, 85, 84, 85, 0, 86, 0, 0,
+ 87, 88, 86, 82, 86, 87, 88, 87, 88, 85,
+ 89, 90, 0, 0, 0, 89, 90, 89, 90, 87,
+ 91, 92, 0, 0, 93, 91, 92, 91, 92, 93,
+ 94, 93, 0, 95, 88, 94, 96, 94, 95, 0,
+ 95, 96, 97, 96, 93, 99, 94, 97, 98, 97,
+ 99, 100, 99, 98, 101, 98, 100, 96, 100, 101,
+ 98, 101, 0, 102, 0, 0, 103, 104, 102, 100,
+
+ 102, 103, 104, 103, 104, 105, 0, 101, 0, 0,
+ 105, 0, 105, 0, 102, 103, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 104, 107,
+ 107, 109, 109, 111, 111, 111, 106, 106, 106, 106,
+ 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
+ 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
+ 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
+ 106, 106, 106, 106, 106, 106, 106, 106, 106, 106,
+ 106
+ } ;
+
+static ace_yy_state_type ace_yy_last_accepting_state;
+static ACE_TCHAR *ace_yy_last_accepting_cpos;
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+#define ace_yymore() ace_yymore_used_but_not_detected
+#define ACE_YY_MORE_ADJ 0
+#define ACE_YY_RESTORE_ACE_YY_MORE_OFFSET
+ACE_TCHAR *ace_yytext;
+#define INITIAL 0
+// $Id$
+// Sample lexical analysis for regular expression subset. Must be
+// compiled with FLEX and an ANSI C++ compiler.
+
+// Lexical tokens values defined by YACC.
+#include "ace/Svc_Conf.h"
+#include "ace/Svc_Conf_Tokens.h"
+#include "ace/Svc_Conf_Lexer_Guard.h"
+
+ACE_RCSID (ace,
+ Svc_Conf_l,
+ "$Id$")
+
+// Keeps track of the current line for debugging output.
+int ace_yylineno = 1;
+
+#define token(x) x
+#define PARAMETERS 1
+
+#define NORMAL 2
+
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef ACE_YY_SKIP_ACE_YYWRAP
+#ifdef __cplusplus
+extern "C" int ace_yywrap ACE_YY_PROTO(( void ));
+#else
+extern int ace_yywrap ACE_YY_PROTO(( void ));
+#endif
+#endif
+
+#ifndef ACE_YY_NO_UNPUT
+static void ace_yyunput ACE_YY_PROTO(( int c, ACE_TCHAR *buf_ptr ));
+#endif
+
+#ifndef ace_yytext_ptr
+static void ace_yy_flex_strncpy ACE_YY_PROTO(( ACE_TCHAR *, ace_yyconst ACE_TCHAR *, int ));
+#endif
+
+#ifdef ACE_YY_NEED_STRLEN
+static int ace_yy_flex_strlen ACE_YY_PROTO(( ace_yyconst ACE_TCHAR * ));
+#endif
+
+#ifndef ACE_YY_NO_INPUT
+#ifdef __cplusplus
+static int ace_yyinput ACE_YY_PROTO(( void ));
+#else
+static int input ACE_YY_PROTO(( void ));
+#endif
+#endif
+
+#if ACE_YY_STACK_USED
+static int ace_yy_start_stack_ptr = 0;
+static int ace_yy_start_stack_depth = 0;
+static int *ace_yy_start_stack = 0;
+#ifndef ACE_YY_NO_PUSH_STATE
+static void ace_yy_push_state ACE_YY_PROTO(( int new_state ));
+#endif
+#ifndef ACE_YY_NO_POP_STATE
+static void ace_yy_pop_state ACE_YY_PROTO(( void ));
+#endif
+#ifndef ACE_YY_NO_TOP_STATE
+static int ace_yy_top_state ACE_YY_PROTO(( void ));
+#endif
+
+#else
+#define ACE_YY_NO_PUSH_STATE 1
+#define ACE_YY_NO_POP_STATE 1
+#define ACE_YY_NO_TOP_STATE 1
+#endif
+
+#ifdef ACE_YY_MALLOC_DECL
+ACE_YY_MALLOC_DECL
+#else
+#if __STDC__
+#ifndef __cplusplus
+#include /**/ <stdlib.h>
+#endif
+#else
+/* Just try to get by without declaring the routines. This will fail
+ * miserably on non-ANSI systems for which sizeof(size_t) != sizeof(int)
+ * or sizeof(void*) != sizeof(int).
+ */
+#endif
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef ACE_YY_READ_BUF_SIZE
+#define ACE_YY_READ_BUF_SIZE 8192
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+
+#ifndef ACE_SVC_CONF_ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ACE_SVC_CONF_ECHO (void) fwrite( ace_yytext, ace_yyleng, 1, ace_yyout )
+#endif
+
+/* Gets input and stuffs it into "buf". number of characters read, or ACE_YY_NULL,
+ * is returned in "result".
+ */
+#ifndef ACE_YY_INPUT
+#define ACE_YY_INPUT(buf,result,max_size) \
+ if ( ace_yy_current_buffer->ace_yy_is_interactive ) \
+ { \
+ int c = '*', n; \
+ for ( n = 0; n < max_size && \
+ (c = getc( ace_yyin )) != EOF && c != '\n'; ++n ) \
+ buf[n] = (ACE_TCHAR) c; \
+ if ( c == '\n' ) \
+ buf[n++] = (ACE_TCHAR) c; \
+ if ( c == EOF && ferror( ace_yyin ) ) \
+ ACE_YY_FATAL_ERROR(ACE_LIB_TEXT( "input in flex scanner failed") ); \
+ result = n; \
+ } \
+ else if ( ((result = fread( buf, sizeof (ACE_TCHAR), max_size, ace_yyin )) == 0) \
+ && ferror( ace_yyin ) ) \
+ ACE_YY_FATAL_ERROR(ACE_LIB_TEXT("input in flex scanner failed") );
+#endif
+
+/* No semi-colon after return; correct usage is to write "ace_yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef ace_yyterminate
+#define ace_yyterminate() return ACE_YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef ACE_YY_START_STACK_INCR
+#define ACE_YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef ACE_YY_FATAL_ERROR
+#define ACE_YY_FATAL_ERROR(msg) ace_yy_fatal_error( msg )
+#endif
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef ACE_YY_DECL
+#define ACE_YY_DECL int ace_yylex ACE_YY_PROTO(( void ))
+#endif
+
+/* Code executed at the beginning of each rule, after ace_yytext and ace_yyleng
+ * have been set up.
+ */
+#ifndef ACE_YY_USER_ACTION
+#define ACE_YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef ACE_YY_BREAK
+#define ACE_YY_BREAK break;
+#endif
+
+#define ACE_YY_RULE_SETUP \
+ if ( ace_yyleng > 0 ) \
+ ace_yy_current_buffer->ace_yy_at_bol = \
+ (ace_yytext[ace_yyleng - 1] == '\n'); \
+ ACE_YY_USER_ACTION
+
+ACE_YY_DECL
+ {
+ ACE_MT (ACE_GUARD_RETURN (ACE_SYNCH_RECURSIVE_MUTEX,
+ ace_mon,
+ *ACE_Static_Object_Lock::instance (),
+ -1));
+
+ ACE_Svc_Conf_Lexer_Guard ace_lexer_guard (ACE_SVC_CONF_PARAM);
+
+ register ace_yy_state_type ace_yy_current_state;
+ register ACE_TCHAR *ace_yy_cp=0, *ace_yy_bp=0;
+ register int ace_yy_act;
+
+
+
+
+ if ( ace_yy_init )
+ {
+ ace_yy_init = 0;
+
+#ifdef ACE_YY_USER_INIT
+ ACE_YY_USER_INIT;
+#endif
+
+ if ( ! ace_yy_start )
+ ace_yy_start = 1; /* first start state */
+
+ if ( ! ace_yyin )
+ ace_yyin = stdin;
+
+ if ( ! ace_yyout )
+ ace_yyout = stdout;
+
+ if ( ! ace_yy_current_buffer )
+ ace_yy_current_buffer =
+ ace_yy_create_buffer( ace_yyin, ACE_YY_BUF_SIZE );
+
+ ace_yy_load_buffer_state();
+ }
+
+ while ( 1 ) /* loops until end-of-file is reached */
+ {
+ ace_yy_cp = ace_yy_c_buf_p;
+
+ /* Support of ace_yytext. */
+ *ace_yy_cp = ace_yy_hold_char;
+
+ /* ace_yy_bp points to the position in ace_yy_ch_buf of the start of
+ * the current run.
+ */
+ ace_yy_bp = ace_yy_cp;
+
+ ace_yy_current_state = ace_yy_start;
+ ace_yy_current_state += ACE_YY_AT_BOL();
+ace_yy_match:
+ do
+ {
+ register ACE_YY_CHAR ace_yy_c = ace_yy_ec[ACE_YY_SC_TO_UI(*ace_yy_cp)];
+ if ( ace_yy_accept[ace_yy_current_state] )
+ {
+ ace_yy_last_accepting_state = ace_yy_current_state;
+ ace_yy_last_accepting_cpos = ace_yy_cp;
+ }
+ while ( ace_yy_chk[ace_yy_base[ace_yy_current_state] + ace_yy_c] != ace_yy_current_state )
+ {
+ ace_yy_current_state = (int) ace_yy_def[ace_yy_current_state];
+ if ( ace_yy_current_state >= 107 )
+ ace_yy_c = ace_yy_meta[(unsigned int) ace_yy_c];
+ }
+ ace_yy_current_state = ace_yy_nxt[ace_yy_base[ace_yy_current_state] + (unsigned int) ace_yy_c];
+ ++ace_yy_cp;
+ }
+ while ( ace_yy_base[ace_yy_current_state] != 437 );
+
+ace_yy_find_action:
+ ace_yy_act = ace_yy_accept[ace_yy_current_state];
+ if ( ace_yy_act == 0 )
+ { /* have to back up */
+ ace_yy_cp = ace_yy_last_accepting_cpos;
+ ace_yy_current_state = ace_yy_last_accepting_state;
+ ace_yy_act = ace_yy_accept[ace_yy_current_state];
+ }
+
+ ACE_YY_DO_BEFORE_ACTION;
+
+
+do_action: /* This label is used only to access EOF actions. */
+
+
+ switch ( ace_yy_act )
+ { /* beginning of action switch */
+ case 0: /* must back up */
+ /* undo the effects of ACE_YY_DO_BEFORE_ACTION */
+ *ace_yy_cp = ace_yy_hold_char;
+ ace_yy_cp = ace_yy_last_accepting_cpos;
+ ace_yy_current_state = ace_yy_last_accepting_state;
+ goto ace_yy_find_action;
+
+case 1:
+*ace_yy_cp = ace_yy_hold_char; /* undo effects of setting up ace_yytext */
+ace_yy_c_buf_p = ace_yy_cp -= 1;
+ACE_YY_DO_BEFORE_ACTION; /* set up ace_yytext again */
+ACE_YY_RULE_SETUP
+; /* EMPTY */
+ ACE_YY_BREAK
+case 2:
+ACE_YY_RULE_SETUP
+{ return token (ACE_DYNAMIC); }
+ // ACE_YY_BREAK
+case 3:
+ACE_YY_RULE_SETUP
+{ return token (ACE_STATIC); }
+ // ACE_YY_BREAK
+case 4:
+ACE_YY_RULE_SETUP
+{ return token (ACE_SUSPEND); }
+ // ACE_YY_BREAK
+case 5:
+ACE_YY_RULE_SETUP
+{ return token (ACE_RESUME); }
+ // ACE_YY_BREAK
+case 6:
+ACE_YY_RULE_SETUP
+{ return token (ACE_REMOVE); }
+ // ACE_YY_BREAK
+case 7:
+ACE_YY_RULE_SETUP
+{ return token (ACE_USTREAM); }
+ // ACE_YY_BREAK
+case 8:
+ACE_YY_RULE_SETUP
+{ return token (ACE_MODULE_T); }
+ // ACE_YY_BREAK
+case 9:
+ACE_YY_RULE_SETUP
+{ return token (ACE_SVC_OBJ_T); }
+ // ACE_YY_BREAK
+case 10:
+ACE_YY_RULE_SETUP
+{ return token (ACE_STREAM_T); }
+ // ACE_YY_BREAK
+case 11:
+ACE_YY_RULE_SETUP
+{ return token (ACE_ACTIVE); }
+ // ACE_YY_BREAK
+case 12:
+ACE_YY_RULE_SETUP
+{ return token (ACE_INACTIVE); }
+ // ACE_YY_BREAK
+case 13:
+ACE_YY_RULE_SETUP
+{ return token (':'); }
+ // ACE_YY_BREAK
+case 14:
+ACE_YY_RULE_SETUP
+{ return token ('*'); }
+ // ACE_YY_BREAK
+case 15:
+ACE_YY_RULE_SETUP
+{ return token ('('); }
+ // ACE_YY_BREAK
+case 16:
+ACE_YY_RULE_SETUP
+{ return token (')'); }
+ // ACE_YY_BREAK
+case 17:
+ACE_YY_RULE_SETUP
+{ return token ('{'); }
+ // ACE_YY_BREAK
+case 18:
+ACE_YY_RULE_SETUP
+{ return token ('}'); }
+ // ACE_YY_BREAK
+case 19:
+ACE_YY_RULE_SETUP
+{
+ // Check for first type of string, i.e.,
+ // "double quotes" delimited.
+ ACE_TCHAR *s = ACE_OS::strrchr (ace_yytext, '"');
+ if (s == 0)
+ // Check for second type of string, i.e.,
+ // 'single quotes' delimited.
+ s = ACE_OS::strrchr (ace_yytext, '\'');
+
+ ACE_ASSERT (s != 0);
+ // Eliminate the opening and closing double or
+ // single quotes.
+ *s = '\0';
+ ace_yyleng -= 1;
+ ace_yylval->ident_ = ACE_SVC_CONF_PARAM->obstack.copy (ace_yytext + 1, ace_yyleng);
+ return token (ACE_STRING); }
+ // ACE_YY_BREAK
+case 20:
+ACE_YY_RULE_SETUP
+{
+ ace_yylval->ident_ = ACE_SVC_CONF_PARAM->obstack.copy (ace_yytext, ace_yyleng);
+ return token (ACE_IDENT);
+ }
+ // ACE_YY_BREAK
+case 21:
+ACE_YY_RULE_SETUP
+{
+ ace_yylval->ident_ = ACE_SVC_CONF_PARAM->obstack.copy (ace_yytext, ace_yyleng);
+ return token (ACE_PATHNAME);
+ }
+ // ACE_YY_BREAK
+case 22:
+ACE_YY_RULE_SETUP
+; /* EMPTY */
+ ACE_YY_BREAK
+case 23:
+ACE_YY_RULE_SETUP
+{ ACE_SVC_CONF_PARAM->yylineno++; ace_yylineno++; }
+ ACE_YY_BREAK
+case 24:
+ACE_YY_RULE_SETUP
+{
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("unknown character = (%d"),
+ *ace_yytext));
+ if (ACE_OS::ace_isprint (*ace_yytext))
+ ACE_ERROR ((LM_ERROR, ACE_LIB_TEXT ("|%c"), *ace_yytext));
+ ACE_ERROR ((LM_ERROR, ACE_LIB_TEXT (")\n")));
+ }
+ ACE_YY_BREAK
+case ACE_YY_STATE_EOF(INITIAL):
+case ACE_YY_STATE_EOF(PARAMETERS):
+case ACE_YY_STATE_EOF(NORMAL):
+{ ace_yyterminate(); }
+// ACE_YY_BREAK
+case 25:
+ACE_YY_RULE_SETUP
+ACE_SVC_CONF_ECHO;
+ ACE_YY_BREAK
+
+ case ACE_YY_END_OF_BUFFER:
+ {
+ /* Amount of text matched not including the EOB ACE_TCHAR. */
+ int ace_yy_amount_of_matched_text = (int) (ace_yy_cp - ace_yytext_ptr) - 1;
+
+ /* Undo the effects of ACE_YY_DO_BEFORE_ACTION. */
+ *ace_yy_cp = ace_yy_hold_char;
+ ACE_YY_RESTORE_ACE_YY_MORE_OFFSET
+
+ if ( ace_yy_current_buffer->ace_yy_buffer_status == ACE_YY_BUFFER_NEW )
+ {
+ /* We're scanning a new file or input source. It's
+ * possible that this happened because the user
+ * just pointed ace_yyin at a new source and called
+ * ace_yylex(). If so, then we have to assure
+ * consistency between ace_yy_current_buffer and our
+ * globals. Here is the right place to do so, because
+ * this is the first action (other than possibly a
+ * back-up) that will match for the new input source.
+ */
+ ace_yy_n_chars = ace_yy_current_buffer->ace_yy_n_chars;
+ ace_yy_current_buffer->ace_yy_input_file = ace_yyin;
+ ace_yy_current_buffer->ace_yy_buffer_status = ACE_YY_BUFFER_NORMAL;
+ }
+
+ /* Note that here we test for ace_yy_c_buf_p "<=" to the position
+ * of the first EOB in the buffer, since ace_yy_c_buf_p will
+ * already have been incremented past the NUL character
+ * (since all states make transitions on EOB to the
+ * end-of-buffer state). Contrast this with the test
+ * in input().
+ */
+ if ( ace_yy_c_buf_p <= &ace_yy_current_buffer->ace_yy_ch_buf[ace_yy_n_chars] )
+ { /* This was really a NUL. */
+ ace_yy_state_type ace_yy_next_state;
+
+ ace_yy_c_buf_p = ace_yytext_ptr + ace_yy_amount_of_matched_text;
+
+ ace_yy_current_state = ace_yy_get_previous_state();
+
+ /* Okay, we're now positioned to make the NUL
+ * transition. We couldn't have
+ * ace_yy_get_previous_state() go ahead and do it
+ * for us because it doesn't know how to deal
+ * with the possibility of jamming (and we don't
+ * want to build jamming into it because then it
+ * will run more slowly).
+ */
+
+ ace_yy_next_state = ace_yy_try_NUL_trans( ace_yy_current_state );
+
+ ace_yy_bp = ace_yytext_ptr + ACE_YY_MORE_ADJ;
+
+ if ( ace_yy_next_state )
+ {
+ /* Consume the NUL. */
+ ace_yy_cp = ++ace_yy_c_buf_p;
+ ace_yy_current_state = ace_yy_next_state;
+ goto ace_yy_match;
+ }
+
+ else
+ {
+ ace_yy_cp = ace_yy_c_buf_p;
+ goto ace_yy_find_action;
+ }
+ }
+
+ else switch ( ace_yy_get_next_buffer() )
+ {
+ case EOB_ACT_END_OF_FILE:
+ {
+ ace_yy_did_buffer_switch_on_eof = 0;
+
+ if ( ace_yywrap() )
+ {
+ /* Note: because we've taken care in
+ * ace_yy_get_next_buffer() to have set up
+ * ace_yytext, we can now set up
+ * ace_yy_c_buf_p so that if some total
+ * hoser (like flex itself) wants to
+ * call the scanner after we return the
+ * ACE_YY_NULL, it'll still work - another
+ * ACE_YY_NULL will get returned.
+ */
+ ace_yy_c_buf_p = ace_yytext_ptr + ACE_YY_MORE_ADJ;
+
+ ace_yy_act = ACE_YY_STATE_EOF(ACE_YY_START);
+ goto do_action;
+ }
+
+ else
+ {
+ if ( ! ace_yy_did_buffer_switch_on_eof )
+ ACE_YY_NEW_FILE;
+ }
+ break;
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ ace_yy_c_buf_p =
+ ace_yytext_ptr + ace_yy_amount_of_matched_text;
+
+ ace_yy_current_state = ace_yy_get_previous_state();
+
+ ace_yy_cp = ace_yy_c_buf_p;
+ ace_yy_bp = ace_yytext_ptr + ACE_YY_MORE_ADJ;
+ goto ace_yy_match;
+
+ case EOB_ACT_LAST_MATCH:
+ ace_yy_c_buf_p =
+ &ace_yy_current_buffer->ace_yy_ch_buf[ace_yy_n_chars];
+
+ ace_yy_current_state = ace_yy_get_previous_state();
+
+ ace_yy_cp = ace_yy_c_buf_p;
+ ace_yy_bp = ace_yytext_ptr + ACE_YY_MORE_ADJ;
+ goto ace_yy_find_action;
+ }
+ break;
+ }
+
+ default:
+ ACE_YY_FATAL_ERROR(
+ ACE_LIB_TEXT("fatal flex scanner internal error--no action found") );
+ } /* end of action switch */
+ } /* end of scanning one token */
+ } /* end of ace_yylex */
+
+
+/* ace_yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ * EOB_ACT_LAST_MATCH -
+ * EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ * EOB_ACT_END_OF_FILE - end of file
+ */
+
+static int ace_yy_get_next_buffer()
+ {
+ register ACE_TCHAR *dest = ace_yy_current_buffer->ace_yy_ch_buf;
+ register ACE_TCHAR *source = ace_yytext_ptr;
+ register int number_to_move, i;
+ int ret_val;
+
+ if ( ace_yy_c_buf_p > &ace_yy_current_buffer->ace_yy_ch_buf[ace_yy_n_chars + 1] )
+ ACE_YY_FATAL_ERROR(
+ ACE_LIB_TEXT("fatal flex scanner internal error--end of buffer missed") );
+
+ if ( ace_yy_current_buffer->ace_yy_fill_buffer == 0 )
+ { /* Don't try to fill the buffer, so this is an EOF. */
+ if ( ace_yy_c_buf_p - ace_yytext_ptr - ACE_YY_MORE_ADJ == 1 )
+ {
+ /* We matched a single character, the EOB, so
+ * treat this as a final EOF.
+ */
+ return EOB_ACT_END_OF_FILE;
+ }
+
+ else
+ {
+ /* We matched some text prior to the EOB, first
+ * process it.
+ */
+ return EOB_ACT_LAST_MATCH;
+ }
+ }
+
+ /* Try to read more data. */
+
+ /* First move last chars to start of buffer. */
+ number_to_move = (int) (ace_yy_c_buf_p - ace_yytext_ptr) - 1;
+
+ for ( i = 0; i < number_to_move; ++i )
+ *(dest++) = *(source++);
+
+ if ( ace_yy_current_buffer->ace_yy_buffer_status == ACE_YY_BUFFER_EOF_PENDING )
+ /* don't do the read, it's not guaranteed to return an EOF,
+ * just force an EOF
+ */
+ ace_yy_current_buffer->ace_yy_n_chars = ace_yy_n_chars = 0;
+
+ else
+ {
+ int num_to_read =
+ ace_yy_current_buffer->ace_yy_buf_size - number_to_move - 1;
+
+ while ( num_to_read <= 0 )
+ { /* Not enough room in the buffer - grow it. */
+#ifdef ACE_YY_USES_REJECT
+ ACE_YY_FATAL_ERROR(ACE_LIB_TEXT(
+"input buffer overflow, can't enlarge buffer because scanner uses REJECT") );
+#else
+
+ /* just a shorter name for the current buffer */
+ ACE_YY_BUFFER_STATE b = ace_yy_current_buffer;
+
+ int ace_yy_c_buf_p_offset =
+ (int) (ace_yy_c_buf_p - b->ace_yy_ch_buf);
+
+ if ( b->ace_yy_is_our_buffer )
+ {
+ int new_size = b->ace_yy_buf_size * 2;
+
+ if ( new_size <= 0 )
+ b->ace_yy_buf_size += b->ace_yy_buf_size / 8;
+ else
+ b->ace_yy_buf_size *= 2;
+
+ b->ace_yy_ch_buf = (ACE_TCHAR *)
+ /* Include room in for 2 EOB chars. */
+ ace_yy_flex_realloc( (void *) b->ace_yy_ch_buf,
+ (b->ace_yy_buf_size + 2)*sizeof(ACE_TCHAR));
+ }
+ else
+ /* Can't grow it, we don't own it. */
+ b->ace_yy_ch_buf = 0;
+
+ if ( ! b->ace_yy_ch_buf )
+ ACE_YY_FATAL_ERROR(ACE_LIB_TEXT(
+ "fatal error - scanner input buffer overflow") );
+
+ ace_yy_c_buf_p = &b->ace_yy_ch_buf[ace_yy_c_buf_p_offset];
+
+ num_to_read = ace_yy_current_buffer->ace_yy_buf_size -
+ number_to_move - 1;
+#endif
+ }
+
+ if ( num_to_read * sizeof (ACE_TCHAR) > ACE_YY_READ_BUF_SIZE )
+ num_to_read = ACE_YY_READ_BUF_SIZE/sizeof (ACE_TCHAR);
+
+ /* Read in more data. */
+ ACE_YY_INPUT( (&ace_yy_current_buffer->ace_yy_ch_buf[number_to_move]),
+ ace_yy_n_chars, num_to_read );
+
+ ace_yy_current_buffer->ace_yy_n_chars = ace_yy_n_chars;
+ }
+
+ if ( ace_yy_n_chars == 0 )
+ {
+ if ( number_to_move == ACE_YY_MORE_ADJ )
+ {
+ ret_val = EOB_ACT_END_OF_FILE;
+ ace_yyrestart( ace_yyin );
+ }
+
+ else
+ {
+ ret_val = EOB_ACT_LAST_MATCH;
+ ace_yy_current_buffer->ace_yy_buffer_status =
+ ACE_YY_BUFFER_EOF_PENDING;
+ }
+ }
+
+ else
+ ret_val = EOB_ACT_CONTINUE_SCAN;
+
+ ace_yy_n_chars += number_to_move;
+ ace_yy_current_buffer->ace_yy_ch_buf[ace_yy_n_chars] = ACE_YY_END_OF_BUFFER_CHAR;
+ ace_yy_current_buffer->ace_yy_ch_buf[ace_yy_n_chars + 1] = ACE_YY_END_OF_BUFFER_CHAR;
+
+ ace_yytext_ptr = &ace_yy_current_buffer->ace_yy_ch_buf[0];
+
+ return ret_val;
+ }
+
+
+/* ace_yy_get_previous_state - get the state just before the EOB ACE_TCHAR was reached */
+
+static ace_yy_state_type ace_yy_get_previous_state()
+ {
+ register ace_yy_state_type ace_yy_current_state;
+ register ACE_TCHAR *ace_yy_cp;
+
+ ace_yy_current_state = ace_yy_start;
+ ace_yy_current_state += ACE_YY_AT_BOL();
+
+ for ( ace_yy_cp = ace_yytext_ptr + ACE_YY_MORE_ADJ; ace_yy_cp < ace_yy_c_buf_p; ++ace_yy_cp )
+ {
+ register ACE_YY_CHAR ace_yy_c = (*ace_yy_cp ? ace_yy_ec[ACE_YY_SC_TO_UI(*ace_yy_cp)] : 1);
+ if ( ace_yy_accept[ace_yy_current_state] )
+ {
+ ace_yy_last_accepting_state = ace_yy_current_state;
+ ace_yy_last_accepting_cpos = ace_yy_cp;
+ }
+ while ( ace_yy_chk[ace_yy_base[ace_yy_current_state] + ace_yy_c] != ace_yy_current_state )
+ {
+ ace_yy_current_state = (int) ace_yy_def[ace_yy_current_state];
+ if ( ace_yy_current_state >= 107 )
+ ace_yy_c = ace_yy_meta[(unsigned int) ace_yy_c];
+ }
+ ace_yy_current_state = ace_yy_nxt[ace_yy_base[ace_yy_current_state] + (unsigned int) ace_yy_c];
+ }
+
+ return ace_yy_current_state;
+ }
+
+
+/* ace_yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ * next_state = ace_yy_try_NUL_trans( current_state );
+ */
+
+#ifdef ACE_YY_USE_PROTOS
+static ace_yy_state_type ace_yy_try_NUL_trans( ace_yy_state_type ace_yy_current_state )
+#else
+static ace_yy_state_type ace_yy_try_NUL_trans( ace_yy_current_state )
+ace_yy_state_type ace_yy_current_state;
+#endif
+ {
+ register int ace_yy_is_jam;
+ register ACE_TCHAR *ace_yy_cp = ace_yy_c_buf_p;
+
+ register ACE_YY_CHAR ace_yy_c = 1;
+ if ( ace_yy_accept[ace_yy_current_state] )
+ {
+ ace_yy_last_accepting_state = ace_yy_current_state;
+ ace_yy_last_accepting_cpos = ace_yy_cp;
+ }
+ while ( ace_yy_chk[ace_yy_base[ace_yy_current_state] + ace_yy_c] != ace_yy_current_state )
+ {
+ ace_yy_current_state = (int) ace_yy_def[ace_yy_current_state];
+ if ( ace_yy_current_state >= 107 )
+ ace_yy_c = ace_yy_meta[(unsigned int) ace_yy_c];
+ }
+ ace_yy_current_state = ace_yy_nxt[ace_yy_base[ace_yy_current_state] + (unsigned int) ace_yy_c];
+ ace_yy_is_jam = (ace_yy_current_state == 106);
+
+ return ace_yy_is_jam ? 0 : ace_yy_current_state;
+ }
+
+
+#ifndef ACE_YY_NO_UNPUT
+#ifdef ACE_YY_USE_PROTOS
+static void ace_yyunput( int c, register ACE_TCHAR *ace_yy_bp )
+#else
+static void ace_yyunput( c, ace_yy_bp )
+int c;
+register ACE_TCHAR *ace_yy_bp;
+#endif
+ {
+ register ACE_TCHAR *ace_yy_cp = ace_yy_c_buf_p;
+
+ /* undo effects of setting up ace_yytext */
+ *ace_yy_cp = ace_yy_hold_char;
+
+ if ( ace_yy_cp < ace_yy_current_buffer->ace_yy_ch_buf + 2 )
+ { /* need to shift things up to make room */
+ /* +2 for EOB chars. */
+ register int number_to_move = ace_yy_n_chars + 2;
+ register ACE_TCHAR *dest = &ace_yy_current_buffer->ace_yy_ch_buf[
+ ace_yy_current_buffer->ace_yy_buf_size + 2];
+ register ACE_TCHAR *source =
+ &ace_yy_current_buffer->ace_yy_ch_buf[number_to_move];
+
+ while ( source > ace_yy_current_buffer->ace_yy_ch_buf )
+ *--dest = *--source;
+
+ ace_yy_cp += (int) (dest - source);
+ ace_yy_bp += (int) (dest - source);
+ ace_yy_current_buffer->ace_yy_n_chars =
+ ace_yy_n_chars = ace_yy_current_buffer->ace_yy_buf_size;
+
+ if ( ace_yy_cp < ace_yy_current_buffer->ace_yy_ch_buf + 2 )
+ ACE_YY_FATAL_ERROR(ACE_LIB_TEXT( "flex scanner push-back overflow") );
+ }
+
+ *--ace_yy_cp = (ACE_TCHAR) c;
+
+
+ ace_yytext_ptr = ace_yy_bp;
+ ace_yy_hold_char = *ace_yy_cp;
+ ace_yy_c_buf_p = ace_yy_cp;
+ }
+#endif /* ifndef ACE_YY_NO_UNPUT */
+
+
+#ifdef __cplusplus
+static int ace_yyinput()
+#else
+static int input()
+#endif
+ {
+ int c;
+
+ *ace_yy_c_buf_p = ace_yy_hold_char;
+
+ if ( *ace_yy_c_buf_p == ACE_YY_END_OF_BUFFER_CHAR )
+ {
+ /* ace_yy_c_buf_p now points to the character we want to return.
+ * If this occurs *before* the EOB characters, then it's a
+ * valid NUL; if not, then we've hit the end of the buffer.
+ */
+ if ( ace_yy_c_buf_p < &ace_yy_current_buffer->ace_yy_ch_buf[ace_yy_n_chars] )
+ /* This was really a NUL. */
+ *ace_yy_c_buf_p = '\0';
+
+ else
+ { /* need more input */
+ int offset = ace_yy_c_buf_p - ace_yytext_ptr;
+ ++ace_yy_c_buf_p;
+
+ switch ( ace_yy_get_next_buffer() )
+ {
+ case EOB_ACT_LAST_MATCH:
+ /* This happens because ace_yy_g_n_b()
+ * sees that we've accumulated a
+ * token and flags that we need to
+ * try matching the token before
+ * proceeding. But for input(),
+ * there's no matching to consider.
+ * So convert the EOB_ACT_LAST_MATCH
+ * to EOB_ACT_END_OF_FILE.
+ */
+
+ /* Reset buffer status. */
+ ace_yyrestart( ace_yyin );
+
+ /* fall through */
+
+ case EOB_ACT_END_OF_FILE:
+ {
+ if ( ace_yywrap() )
+ return EOF;
+
+ if ( ! ace_yy_did_buffer_switch_on_eof )
+ ACE_YY_NEW_FILE;
+#ifdef __cplusplus
+ return ace_yyinput();
+#else
+ return input();
+#endif
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ ace_yy_c_buf_p = ace_yytext_ptr + offset;
+ break;
+ }
+ }
+ }
+
+ c = *(unsigned char *) ace_yy_c_buf_p; /* cast for 8-bit char's */
+ *ace_yy_c_buf_p = '\0'; /* preserve ace_yytext */
+ ace_yy_hold_char = *++ace_yy_c_buf_p;
+
+ ace_yy_current_buffer->ace_yy_at_bol = (c == '\n');
+
+ return c;
+ }
+
+
+#ifdef ACE_YY_USE_PROTOS
+void ace_yyrestart( FILE *input_file )
+#else
+void ace_yyrestart( input_file )
+FILE *input_file;
+#endif
+ {
+ if ( ! ace_yy_current_buffer )
+ ace_yy_current_buffer = ace_yy_create_buffer( ace_yyin, ACE_YY_BUF_SIZE );
+
+ ace_yy_init_buffer( ace_yy_current_buffer, input_file );
+ ace_yy_load_buffer_state();
+ }
+
+
+#ifdef ACE_YY_USE_PROTOS
+void ace_yy_switch_to_buffer( ACE_YY_BUFFER_STATE new_buffer )
+#else
+void ace_yy_switch_to_buffer( new_buffer )
+ACE_YY_BUFFER_STATE new_buffer;
+#endif
+ {
+ if ( ace_yy_current_buffer == new_buffer )
+ return;
+
+ if ( ace_yy_current_buffer )
+ {
+ /* Flush out information for old buffer. */
+ *ace_yy_c_buf_p = ace_yy_hold_char;
+ ace_yy_current_buffer->ace_yy_buf_pos = ace_yy_c_buf_p;
+ ace_yy_current_buffer->ace_yy_n_chars = ace_yy_n_chars;
+ }
+
+ ace_yy_current_buffer = new_buffer;
+ ace_yy_load_buffer_state();
+
+ /* We don't actually know whether we did this switch during
+ * EOF (ace_yywrap()) processing, but the only time this flag
+ * is looked at is after ace_yywrap() is called, so it's safe
+ * to go ahead and always set it.
+ */
+ ace_yy_did_buffer_switch_on_eof = 1;
+ }
+
+
+#ifdef ACE_YY_USE_PROTOS
+void ace_yy_load_buffer_state( void )
+#else
+void ace_yy_load_buffer_state()
+#endif
+ {
+ ace_yy_n_chars = ace_yy_current_buffer->ace_yy_n_chars;
+ ace_yytext_ptr = ace_yy_c_buf_p = ace_yy_current_buffer->ace_yy_buf_pos;
+ ace_yyin = ace_yy_current_buffer->ace_yy_input_file;
+ ace_yy_hold_char = *ace_yy_c_buf_p;
+ }
+
+
+#ifdef ACE_YY_USE_PROTOS
+ACE_YY_BUFFER_STATE ace_yy_create_buffer( FILE *file, int size )
+#else
+ACE_YY_BUFFER_STATE ace_yy_create_buffer( file, size )
+FILE *file;
+int size;
+#endif
+ {
+ ACE_YY_BUFFER_STATE b;
+
+ b = (ACE_YY_BUFFER_STATE) ace_yy_flex_alloc( sizeof( struct ace_yy_buffer_state ) );
+ if ( ! b )
+ ACE_YY_FATAL_ERROR(ACE_LIB_TEXT( "out of dynamic memory in ace_yy_create_buffer()") );
+
+ b->ace_yy_buf_size = size;
+
+ /* ace_yy_ch_buf has to be 2 characters longer than the size given because
+ * we need to put in 2 end-of-buffer characters.
+ */
+ b->ace_yy_ch_buf = (ACE_TCHAR *) ace_yy_flex_alloc( (b->ace_yy_buf_size + 2 ) * sizeof (ACE_TCHAR));
+ if ( ! b->ace_yy_ch_buf )
+ ACE_YY_FATAL_ERROR(ACE_LIB_TEXT( "out of dynamic memory in ace_yy_create_buffer()") );
+
+ b->ace_yy_is_our_buffer = 1;
+
+ ace_yy_init_buffer( b, file );
+
+ return b;
+ }
+
+
+#ifdef ACE_YY_USE_PROTOS
+void ace_yy_delete_buffer( ACE_YY_BUFFER_STATE b )
+#else
+void ace_yy_delete_buffer( b )
+ACE_YY_BUFFER_STATE b;
+#endif
+ {
+ if ( ! b )
+ return;
+
+ if ( b == ace_yy_current_buffer )
+ ace_yy_current_buffer = (ACE_YY_BUFFER_STATE) 0;
+
+ if ( b->ace_yy_is_our_buffer )
+ ace_yy_flex_free( (void *) b->ace_yy_ch_buf );
+
+ ace_yy_flex_free( (void *) b );
+ }
+
+
+#ifndef ACE_YY_ALWAYS_INTERACTIVE
+#ifndef ACE_YY_NEVER_INTERACTIVE
+extern int nop_isatty ACE_YY_PROTO(( int ));
+#endif
+#endif
+
+#ifdef ACE_YY_USE_PROTOS
+void ace_yy_init_buffer( ACE_YY_BUFFER_STATE b, FILE *file )
+#else
+void ace_yy_init_buffer( b, file )
+ACE_YY_BUFFER_STATE b;
+FILE *file;
+#endif
+
+
+ {
+ ace_yy_flush_buffer( b );
+
+ b->ace_yy_input_file = file;
+ b->ace_yy_fill_buffer = 1;
+
+#if ACE_YY_ALWAYS_INTERACTIVE
+ b->ace_yy_is_interactive = 1;
+#else
+#if ACE_YY_NEVER_INTERACTIVE
+ b->ace_yy_is_interactive = 0;
+#else
+ b->ace_yy_is_interactive = file ? (ACE_OS::isatty( fileno (file) ) > 0) : 0;
+#endif
+#endif
+ }
+
+
+#ifdef ACE_YY_USE_PROTOS
+void ace_yy_flush_buffer( ACE_YY_BUFFER_STATE b )
+#else
+void ace_yy_flush_buffer( b )
+ACE_YY_BUFFER_STATE b;
+#endif
+
+ {
+ if ( ! b )
+ return;
+
+ b->ace_yy_n_chars = 0;
+
+ /* We always need two end-of-buffer characters. The first causes
+ * a transition to the end-of-buffer state. The second causes
+ * a jam in that state.
+ */
+ b->ace_yy_ch_buf[0] = ACE_YY_END_OF_BUFFER_CHAR;
+ b->ace_yy_ch_buf[1] = ACE_YY_END_OF_BUFFER_CHAR;
+
+ b->ace_yy_buf_pos = &b->ace_yy_ch_buf[0];
+
+ b->ace_yy_at_bol = 1;
+ b->ace_yy_buffer_status = ACE_YY_BUFFER_NEW;
+
+ if ( b == ace_yy_current_buffer )
+ ace_yy_load_buffer_state();
+ }
+
+
+#ifndef ACE_YY_NO_SCAN_BUFFER
+#ifdef ACE_YY_USE_PROTOS
+ACE_YY_BUFFER_STATE ace_yy_scan_buffer( ACE_TCHAR *base, ace_yy_size_t size )
+#else
+ACE_YY_BUFFER_STATE ace_yy_scan_buffer( base, size )
+ACE_TCHAR *base;
+ace_yy_size_t size;
+#endif
+ {
+ ACE_YY_BUFFER_STATE b;
+
+ if ( size < 2 ||
+ base[size-2] != ACE_YY_END_OF_BUFFER_CHAR ||
+ base[size-1] != ACE_YY_END_OF_BUFFER_CHAR )
+ /* They forgot to leave room for the EOB's. */
+ return 0;
+
+ b = (ACE_YY_BUFFER_STATE) ace_yy_flex_alloc( sizeof( struct ace_yy_buffer_state ) );
+ if ( ! b )
+ ACE_YY_FATAL_ERROR(ACE_LIB_TEXT( "out of dynamic memory in ace_yy_scan_buffer()" ));
+
+ b->ace_yy_buf_size = size - 2; /* "- 2" to take care of EOB's */
+ b->ace_yy_buf_pos = b->ace_yy_ch_buf = base;
+ b->ace_yy_is_our_buffer = 0;
+ b->ace_yy_input_file = 0;
+ b->ace_yy_n_chars = b->ace_yy_buf_size;
+ b->ace_yy_is_interactive = 0;
+ b->ace_yy_at_bol = 1;
+ b->ace_yy_fill_buffer = 0;
+ b->ace_yy_buffer_status = ACE_YY_BUFFER_NEW;
+
+ ace_yy_switch_to_buffer( b );
+
+ return b;
+ }
+#endif
+
+
+#ifndef ACE_YY_NO_SCAN_STRING
+#ifdef ACE_YY_USE_PROTOS
+ACE_YY_BUFFER_STATE ace_yy_scan_string( ace_yyconst ACE_TCHAR *ace_yy_str )
+#else
+ACE_YY_BUFFER_STATE ace_yy_scan_string( ace_yy_str )
+ace_yyconst ACE_TCHAR *ace_yy_str;
+#endif
+ {
+ int len;
+ for ( len = 0; ace_yy_str[len]; ++len )
+ ;
+
+ return ace_yy_scan_bytes( ace_yy_str, len );
+ }
+#endif
+
+
+#ifndef ACE_YY_NO_SCAN_BYTES
+#ifdef ACE_YY_USE_PROTOS
+ACE_YY_BUFFER_STATE ace_yy_scan_bytes( ace_yyconst ACE_TCHAR *bytes, int len )
+#else
+ACE_YY_BUFFER_STATE ace_yy_scan_bytes( bytes, len )
+ace_yyconst ACE_TCHAR *bytes;
+int len;
+#endif
+ {
+ ACE_YY_BUFFER_STATE b;
+ ACE_TCHAR *buf;
+ ace_yy_size_t n;
+ int i;
+
+ /* Get memory for full buffer, including space for trailing EOB's. */
+ n = len + 2;
+ buf = (ACE_TCHAR *) ace_yy_flex_alloc( n * sizeof (ACE_TCHAR));
+ if ( ! buf )
+ ACE_YY_FATAL_ERROR(ACE_LIB_TEXT( "out of dynamic memory in ace_yy_scan_bytes()" ));
+
+ for ( i = 0; i < len; ++i )
+ buf[i] = bytes[i];
+
+ buf[len] = buf[len+1] = ACE_YY_END_OF_BUFFER_CHAR;
+
+ b = ace_yy_scan_buffer( buf, n );
+ if ( ! b )
+ ACE_YY_FATAL_ERROR(ACE_LIB_TEXT( "bad buffer in ace_yy_scan_bytes()") );
+
+ /* It's okay to grow etc. this buffer, and we should throw it
+ * away when we're done.
+ */
+ b->ace_yy_is_our_buffer = 1;
+
+ return b;
+ }
+#endif
+
+
+#ifndef ACE_YY_NO_PUSH_STATE
+#ifdef ACE_YY_USE_PROTOS
+static void ace_yy_push_state( int new_state )
+#else
+static void ace_yy_push_state( new_state )
+int new_state;
+#endif
+ {
+ if ( ace_yy_start_stack_ptr >= ace_yy_start_stack_depth )
+ {
+ ace_yy_size_t new_size;
+
+ ace_yy_start_stack_depth += ACE_YY_START_STACK_INCR;
+ new_size = ace_yy_start_stack_depth * sizeof( int );
+
+ if ( ! ace_yy_start_stack )
+ ace_yy_start_stack = (int *) ace_yy_flex_alloc( new_size );
+
+ else
+ ace_yy_start_stack = (int *) ace_yy_flex_realloc(
+ (void *) ace_yy_start_stack, new_size );
+
+ if ( ! ace_yy_start_stack )
+ ACE_YY_FATAL_ERROR(ACE_LIB_TEXT(
+ "out of memory expanding start-condition stack" ));
+ }
+
+ ace_yy_start_stack[ace_yy_start_stack_ptr++] = ACE_YY_START;
+
+ BEGIN(new_state);
+ }
+#endif
+
+
+#ifndef ACE_YY_NO_POP_STATE
+static void ace_yy_pop_state()
+ {
+ if ( --ace_yy_start_stack_ptr < 0 )
+ ACE_YY_FATAL_ERROR(ACE_LIB_TEXT( "start-condition stack underflow" ));
+
+ BEGIN(ace_yy_start_stack[ace_yy_start_stack_ptr]);
+ }
+#endif
+
+
+#ifndef ACE_YY_NO_TOP_STATE
+static int ace_yy_top_state()
+ {
+ return ace_yy_start_stack[ace_yy_start_stack_ptr - 1];
+ }
+#endif
+
+#ifndef ACE_YY_EXIT_FAILURE
+#define ACE_YY_EXIT_FAILURE 2
+#endif
+
+#ifdef ACE_YY_USE_PROTOS
+static void ace_yy_fatal_error( ace_yyconst ACE_TCHAR msg[] )
+#else
+static void ace_yy_fatal_error( msg )
+ACE_TCHAR msg[];
+#endif
+ {
+ (void) ACE_OS::fprintf( stderr, ACE_LIB_TEXT("%s\n"), msg );
+ exit( ACE_YY_EXIT_FAILURE );
+ }
+
+
+
+/* Redefine ace_yyless() so it works in section 3 code. */
+
+#undef ace_yyless
+#define ace_yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up ace_yytext. */ \
+ ace_yytext[ace_yyleng] = ace_yy_hold_char; \
+ ace_yy_c_buf_p = ace_yytext + n; \
+ ace_yy_hold_char = *ace_yy_c_buf_p; \
+ *ace_yy_c_buf_p = '\0'; \
+ ace_yyleng = n; \
+ } \
+ while ( 0 )
+
+
+/* Internal utility routines. */
+
+#ifndef ace_yytext_ptr
+#ifdef ACE_YY_USE_PROTOS
+static void ace_yy_flex_strncpy( ACE_TCHAR *s1, ace_yyconst ACE_TCHAR *s2, int n )
+#else
+static void ace_yy_flex_strncpy( s1, s2, n )
+ACE_TCHAR *s1;
+ace_yyconst ACE_TCHAR *s2;
+int n;
+#endif
+ {
+ register int i;
+ for ( i = 0; i < n; ++i )
+ s1[i] = s2[i];
+ }
+#endif
+
+#ifdef ACE_YY_NEED_STRLEN
+#ifdef ACE_YY_USE_PROTOS
+static int ace_yy_flex_strlen( ace_yyconst ACE_TCHAR *s )
+#else
+static int ace_yy_flex_strlen( s )
+ace_yyconst ACE_TCHAR *s;
+#endif
+ {
+ register int n;
+ for ( n = 0; s[n]; ++n )
+ ;
+
+ return n;
+ }
+#endif
+
+
+#ifdef ACE_YY_USE_PROTOS
+static void *ace_yy_flex_alloc( ace_yy_size_t size )
+#else
+static void *ace_yy_flex_alloc( size )
+ace_yy_size_t size;
+#endif
+ {
+ return (void *) malloc( size );
+ }
+
+#ifdef ACE_YY_USE_PROTOS
+static void *ace_yy_flex_realloc( void *ptr, ace_yy_size_t size )
+#else
+static void *ace_yy_flex_realloc( ptr, size )
+void *ptr;
+ace_yy_size_t size;
+#endif
+ {
+ /* The cast to (char *) in the following accommodates both
+ * implementations that use char* generic pointers, and those
+ * that use void* generic pointers. It works with the latter
+ * because both ANSI C and C++ allow castless assignment from
+ * any pointer type to void*, and deal with argument conversions
+ * as though doing an assignment.
+ */
+ return (void *) realloc( (char *) ptr, size );
+ }
+
+#ifdef ACE_YY_USE_PROTOS
+static void ace_yy_flex_free( void *ptr )
+#else
+static void ace_yy_flex_free( ptr )
+void *ptr;
+#endif
+ {
+ free( ACE_MALLOC_T (ptr) );
+ }
+
+#if ACE_YY_MAIN
+int main()
+ {
+ ace_yylex();
+ return 0;
+ }
+#endif
+
+int
+ace_yywrap (void)
+{
+ ::fflush (ace_yyin);
+ ace_yytext[0] = '#';
+ ace_yyleng = 0;
+
+ return 1;
+}
+
+void
+ace_yy_push_buffer (FILE *file, ace_yy_buffer_state *&buffer)
+{
+ // External synchronization is required.
+
+ if (buffer == 0)
+ buffer = ace_yy_create_buffer (file, ACE_YY_BUF_SIZE);
+
+ ace_yy_switch_to_buffer (buffer);
+}
+
+void
+ace_yy_push_buffer (const ACE_TCHAR *directive, ace_yy_buffer_state *&buffer)
+{
+ // External synchronization is required.
+
+ // ace_yyparse() may invoke ace_yylex() multiple times when parsing
+ // a single directive. Prevent a new buffer from created during
+ // each call to ace_yylex().
+ if (ACE_YY_CURRENT_BUFFER != 0
+ && directive == ACE_YY_CURRENT_BUFFER->ace_yy_ch_buf)
+ return;
+
+ if (buffer == 0)
+ {
+ // ace_yy_scan_string() already switches the buffer so there is
+ // no need to explicitly make the switch.
+ buffer = ace_yy_scan_string (directive);
+ }
+ else
+ ace_yy_switch_to_buffer (buffer);
+}
+
+void
+ace_yy_pop_buffer (ace_yy_buffer_state *buffer)
+{
+ // External synchronization is required.
+
+ ace_yy_switch_to_buffer (buffer);
+}
diff --git a/ace/Svcconf/Svc_Conf_y.cpp b/ace/Svcconf/Svc_Conf_y.cpp
new file mode 100644
index 00000000000..5c76230b920
--- /dev/null
+++ b/ace/Svcconf/Svc_Conf_y.cpp
@@ -0,0 +1,1406 @@
+
+/* A Bison parser, made from Svc_Conf.y
+ by GNU Bison version 1.28 */
+
+#define ACE_YYBISON 1 /* Identify Bison output. */
+
+#define ACE_DYNAMIC 257
+#define ACE_STATIC 258
+#define ACE_SUSPEND 259
+#define ACE_RESUME 260
+#define ACE_REMOVE 261
+#define ACE_USTREAM 262
+#define ACE_MODULE_T 263
+#define ACE_STREAM_T 264
+#define ACE_SVC_OBJ_T 265
+#define ACE_ACTIVE 266
+#define ACE_INACTIVE 267
+#define ACE_PATHNAME 268
+#define ACE_IDENT 269
+#define ACE_STRING 270
+
+
+// $Id$
+
+#include "ace/ARGV.h"
+#include "ace/Svc_Conf.h"
+#include "ace/Module.h"
+#include "ace/Stream.h"
+
+ACE_RCSID (ace,
+ Svc_Conf_y,
+ "$Id$")
+
+// Prototypes.
+static ACE_Module_Type *ace_get_module (ACE_Static_Node *str_rec,
+ ACE_Static_Node *svc_type);
+static ACE_Module_Type *ace_get_module (ACE_Static_Node *str_rec,
+ const ACE_TCHAR *svc_name);
+
+#define ACE_YYDEBUG_LEXER_TEXT (ace_yytext[ace_yyleng] = '\0', ace_yytext)
+
+// Force the pretty debugging code to compile.
+// #define ACE_YYDEBUG 1
+
+// Keeps track of the number of errors encountered so far.
+int ace_yyerrno = 0;
+
+#include <stdio.h>
+
+#ifndef __cplusplus
+#ifndef __STDC__
+#define const
+#endif
+#endif
+
+
+
+#define ACE_YYFINAL 66
+#define ACE_YYFLAG -32768
+#define ACE_YYNTBASE 23
+
+#define ACE_YYTRANSLATE(x) ((unsigned)(x) <= 270 ? ace_yytranslate[x] : 43)
+
+static const ACE_TCHAR ace_yytranslate[] = { 0,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 20,
+ 21, 22, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 19, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 17, 2, 18, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 1, 3, 4, 5, 6,
+ 7, 8, 9, 10, 11, 12, 13, 14, 15, 16
+};
+
+#if ACE_YYDEBUG != 0
+static const short ace_yyprhs[] = { 0,
+ 0, 3, 6, 7, 9, 11, 13, 15, 17, 19,
+ 23, 27, 30, 33, 36, 40, 41, 46, 48, 50,
+ 51, 56, 57, 60, 61, 63, 65, 67, 69, 71,
+ 76, 78, 80, 81, 85, 91, 96, 99, 102, 105,
+ 107, 108, 110, 112
+};
+
+static const short ace_yyrhs[] = { 23,
+ 24, 0, 23, 1, 0, 0, 25, 0, 26, 0,
+ 27, 0, 28, 0, 29, 0, 30, 0, 3, 37,
+ 41, 0, 4, 15, 41, 0, 5, 15, 0, 6,
+ 15, 0, 7, 15, 0, 8, 32, 33, 0, 0,
+ 8, 15, 31, 33, 0, 25, 0, 26, 0, 0,
+ 17, 34, 35, 18, 0, 0, 35, 36, 0, 0,
+ 25, 0, 26, 0, 27, 0, 28, 0, 29, 0,
+ 15, 40, 39, 38, 0, 12, 0, 13, 0, 0,
+ 42, 19, 15, 0, 42, 19, 15, 20, 21, 0,
+ 19, 15, 20, 21, 0, 9, 22, 0, 11, 22,
+ 0, 10, 22, 0, 16, 0, 0, 14, 0, 15,
+ 0, 16, 0
+};
+
+#endif
+
+#if ACE_YYDEBUG != 0
+static const short ace_yyrline[] = { 0,
+ 49, 57, 61, 65, 66, 67, 68, 69, 70, 74,
+ 84, 91, 98, 105, 112, 116, 117, 123, 126, 132,
+ 137, 141, 145, 153, 157, 183, 194, 201, 208, 231,
+ 265, 269, 273, 280, 284, 288, 295, 299, 303, 310,
+ 311, 315, 316, 317
+};
+#endif
+
+
+#if ACE_YYDEBUG != 0 || defined (ACE_YYERROR_VERBOSE)
+
+static const ACE_TCHAR * const ace_yytname[] = { ACE_LIB_TEXT("$"),
+ ACE_LIB_TEXT("error"),
+ ACE_LIB_TEXT("$undefined."),
+ ACE_LIB_TEXT("ACE_DYNAMIC"),
+ ACE_LIB_TEXT("ACE_STATIC"),
+ ACE_LIB_TEXT("ACE_SUSPEND"),
+ ACE_LIB_TEXT("ACE_RESUME"),
+ ACE_LIB_TEXT("ACE_REMOVE"),
+ ACE_LIB_TEXT("ACE_USTREAM"),
+ ACE_LIB_TEXT("ACE_MODULE_T"),
+ ACE_LIB_TEXT("ACE_STREAM_T"),
+ ACE_LIB_TEXT("ACE_SVC_OBJ_T"),
+ ACE_LIB_TEXT("ACE_ACTIVE"),
+ ACE_LIB_TEXT("ACE_INACTIVE"),
+ ACE_LIB_TEXT("ACE_PATHNAME"),
+ ACE_LIB_TEXT("ACE_IDENT"),
+ ACE_LIB_TEXT("ACE_STRING"),
+ ACE_LIB_TEXT("'{'"),
+ ACE_LIB_TEXT("'}'"),
+ ACE_LIB_TEXT("':'"),
+ ACE_LIB_TEXT("'('"),
+ ACE_LIB_TEXT("')'"),
+ ACE_LIB_TEXT("'*'"),
+ ACE_LIB_TEXT("svc_config_entries"),
+ ACE_LIB_TEXT("svc_config_entry"),
+ ACE_LIB_TEXT("dynamic"),
+ ACE_LIB_TEXT("static"),
+ ACE_LIB_TEXT("suspend"),
+ ACE_LIB_TEXT("resume"),
+ ACE_LIB_TEXT("remove"),
+ ACE_LIB_TEXT("stream"),
+ ACE_LIB_TEXT("@1"),
+ ACE_LIB_TEXT("stream_ops"),
+ ACE_LIB_TEXT("stream_modules"),
+
+ ACE_LIB_TEXT("@2"),
+ ACE_LIB_TEXT("module_list"),
+ ACE_LIB_TEXT("module"),
+ ACE_LIB_TEXT("svc_location"),
+ ACE_LIB_TEXT("status"),
+ ACE_LIB_TEXT("svc_initializer"),
+ ACE_LIB_TEXT("type"),
+ ACE_LIB_TEXT("parameters_opt"),
+ ACE_LIB_TEXT("pathname"),
+ NULL
+};
+#endif
+
+static const short ace_yyr1[] = { 0,
+ 23, 23, 23, 24, 24, 24, 24, 24, 24, 25,
+ 26, 27, 28, 29, 30, 31, 30, 32, 32, 34,
+ 33, 33, 35, 35, 36, 36, 36, 36, 36, 37,
+ 38, 38, 38, 39, 39, 39, 40, 40, 40, 41,
+ 41, 42, 42, 42
+};
+
+static const short ace_yyr2[] = { 0,
+ 2, 2, 0, 1, 1, 1, 1, 1, 1, 3,
+ 3, 2, 2, 2, 3, 0, 4, 1, 1, 0,
+ 4, 0, 2, 0, 1, 1, 1, 1, 1, 4,
+ 1, 1, 0, 3, 5, 4, 2, 2, 2, 1,
+ 0, 1, 1, 1
+};
+
+static const short ace_yydefact[] = { 3,
+ 0, 2, 0, 0, 0, 0, 0, 0, 1, 4,
+ 5, 6, 7, 8, 9, 0, 41, 41, 12, 13,
+ 14, 16, 18, 19, 22, 0, 0, 0, 0, 40,
+ 10, 11, 22, 20, 15, 37, 39, 38, 42, 43,
+ 44, 0, 33, 0, 17, 24, 0, 31, 32, 30,
+ 0, 0, 0, 34, 21, 25, 26, 27, 28, 29,
+ 23, 36, 0, 35, 0, 0
+};
+
+static const short ace_yydefgoto[] = { 1,
+ 9, 10, 11, 12, 13, 14, 15, 33, 25, 35,
+ 46, 52, 61, 17, 50, 43, 29, 31, 44
+};
+
+static const short ace_yypact[] = {-32768,
+ 20,-32768, 1, 3, 7, 14, 18, 4,-32768,-32768,
+-32768,-32768,-32768,-32768,-32768, 21, 19, 19,-32768,-32768,
+-32768,-32768,-32768,-32768, -2, 12, 15, 16, -5,-32768,
+-32768,-32768, -2,-32768,-32768,-32768,-32768,-32768,-32768,-32768,
+-32768, 24, 0, 17,-32768,-32768, 22,-32768,-32768,-32768,
+ 25, -1, 26, 23,-32768,-32768,-32768,-32768,-32768,-32768,
+-32768,-32768, 27,-32768, 41,-32768
+};
+
+static const short ace_yypgoto[] = {-32768,
+-32768, -8, -7, -6, -3, 2,-32768,-32768,-32768, 28,
+-32768,-32768,-32768,-32768,-32768,-32768,-32768, 32,-32768
+};
+
+
+#define ACE_YYLAST 61
+
+
+static const short ace_yytable[] = { 23,
+ 24, 3, 4, 5, 6, 7, 3, 4, 39, 40,
+ 41, 48, 49, 42, 34, 16, 55, 18, 22, 65,
+ 2, 19, 3, 4, 5, 6, 7, 8, 20, 26,
+ 27, 28, 21, 36, 30, 51, 37, 38, 47, 54,
+ 66, 53, 63, 56, 57, 58, 62, 64, 59, 32,
+ 0, 0, 0, 60, 0, 0, 0, 0, 0, 0,
+ 45
+};
+
+static const short ace_yycheck[] = { 8,
+ 8, 3, 4, 5, 6, 7, 3, 4, 14, 15,
+ 16, 12, 13, 19, 17, 15, 18, 15, 15, 0,
+ 1, 15, 3, 4, 5, 6, 7, 8, 15, 9,
+ 10, 11, 15, 22, 16, 19, 22, 22, 15, 15,
+ 0, 20, 20, 52, 52, 52, 21, 21, 52, 18,
+ -1, -1, -1, 52, -1, -1, -1, -1, -1, -1,
+ 33
+};
+#define ACE_YYPURE 1
+
+/* -*-C-*- Note some compilers choke on comments on `#line' lines. */
+
+/* This file comes from bison-1.28. */
+
+/* Skeleton output parser for bison,
+ Copyright (C) 1984, 1989, 1990 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+/* As a special exception, when this file is copied by Bison into a
+ Bison output file, you may use that output file without restriction.
+ This special exception was added by the Free Software Foundation
+ in version 1.24 of Bison. */
+
+/* This is the parser code that is written into each bison parser
+ when the %semantic_parser declaration is not specified in the grammar.
+ It was written by Richard Stallman by simplifying the hairy parser
+ used when %semantic_parser is specified. */
+
+#ifndef ACE_YYSTACK_USE_ALLOCA
+#ifdef alloca
+#define ACE_YYSTACK_USE_ALLOCA
+#else /* alloca not defined */
+#ifdef __GNUC__
+#define ACE_YYSTACK_USE_ALLOCA
+#define alloca __builtin_alloca
+#else /* not GNU C. */
+#if (!defined (__STDC__) && defined (sparc)) || defined (__sparc__) || defined (__sparc) || defined (__sgi) || (defined (__sun) && defined (__i386))
+#define ACE_YYSTACK_USE_ALLOCA
+#include <alloca.h>
+#else /* not sparc */
+/* We think this test detects Watcom and Microsoft C. */
+/* This used to test MSDOS, but that is a bad idea
+ since that symbol is in the user namespace. */
+#if (defined (_MSDOS) || defined (_MSDOS_)) && !defined (__TURBOC__)
+#if 0 /* No need for malloc.h, which pollutes the namespace;
+ instead, just don't use alloca. */
+#include <malloc.h>
+#endif
+#else /* not MSDOS, or __TURBOC__ */
+#if defined(_AIX)
+/* I don't know what this was needed for, but it pollutes the namespace.
+ So I turned it off. rms, 2 May 1997. */
+/* #include <malloc.h> */
+ #pragma alloca
+#define ACE_YYSTACK_USE_ALLOCA
+#else /* not MSDOS, or __TURBOC__, or _AIX */
+#if 0
+#ifdef __hpux /* haible@ilog.fr says this works for HPUX 9.05 and up,
+ and on HPUX 10. Eventually we can turn this on. */
+#define ACE_YYSTACK_USE_ALLOCA
+#define alloca __builtin_alloca
+#endif /* __hpux */
+#endif
+#endif /* not _AIX */
+#endif /* not MSDOS, or __TURBOC__ */
+#endif /* not sparc */
+#endif /* not GNU C */
+#endif /* alloca not defined */
+#endif /* ACE_YYSTACK_USE_ALLOCA not defined */
+
+#ifdef ACE_YYSTACK_USE_ALLOCA
+#define ACE_YYSTACK_ALLOC alloca
+#else
+#define ACE_YYSTACK_ALLOC malloc
+#endif
+
+/* Note: there must be only one dollar sign in this file.
+ It is replaced by the list of actions, each action
+ as one case of the switch. */
+
+#define ace_yyerrok (ace_yyerrstatus = 0)
+#define ace_yyclearin (ace_yychar = ACE_YYEMPTY)
+#define ACE_YYEMPTY -2
+#define ACE_YYEOF 0
+#define ACE_YYACCEPT goto ace_yyacceptlab
+#define ACE_YYABORT goto ace_yyabortlab
+#define ACE_YYERROR goto ace_yyerrlab1
+/* Like ACE_YYERROR except do call ace_yyerror.
+ This remains here temporarily to ease the
+ transition to the new meaning of ACE_YYERROR, for GCC.
+ Once GCC version 2 has supplanted version 1, this can go. */
+#define ACE_YYFAIL goto ace_yyerrlab
+#define ACE_YYRECOVERING() (!!ace_yyerrstatus)
+#define ACE_YYBACKUP(token, value) \
+do \
+ if (ace_yychar == ACE_YYEMPTY && ace_yylen == 1) \
+ { ace_yychar = (token), ace_yylval = (value); \
+ ace_yychar1 = ACE_YYTRANSLATE (ace_yychar); \
+ ACE_YYPOPSTACK; \
+ goto ace_yybackup; \
+ } \
+ else \
+ { ace_yyerror (ACE_LIB_TEXT("syntax error: cannot back up")); ACE_YYERROR; } \
+while (0)
+
+#define ACE_YYTERROR 1
+#define ACE_YYERRCODE 256
+
+#ifndef ACE_YYPURE
+#define ACE_YYLEX ace_yylex()
+#endif
+
+#ifdef ACE_YYPURE
+#ifdef ACE_YYLSP_NEEDED
+#ifdef ACE_YYLEX_PARAM
+#define ACE_YYLEX ace_yylex(&ace_yylval, &ace_yylloc, ACE_YYLEX_PARAM)
+#else
+#define ACE_YYLEX ace_yylex(&ace_yylval, &ace_yylloc)
+#endif
+#else /* not ACE_YYLSP_NEEDED */
+#ifdef ACE_YYLEX_PARAM
+#define ACE_YYLEX ace_yylex(&ace_yylval, ACE_YYLEX_PARAM)
+#else
+#define ACE_YYLEX ace_yylex(&ace_yylval)
+#endif
+#endif /* not ACE_YYLSP_NEEDED */
+#endif
+
+/* If nonreentrant, generate the variables here */
+
+#ifndef ACE_YYPURE
+
+int ace_yychar; /* the lookahead symbol */
+ACE_YYSTYPE ace_yylval; /* the semantic value of the */
+ /* lookahead symbol */
+
+#ifdef ACE_YYLSP_NEEDED
+ACE_YYLTYPE ace_yylloc; /* location data for the lookahead */
+ /* symbol */
+#endif
+
+int ace_yynerrs; /* number of parse errors so far */
+#endif /* not ACE_YYPURE */
+
+#if ACE_YYDEBUG != 0
+int ace_yydebug; /* nonzero means print parse trace */
+/* Since this is uninitialized, it does not stop multiple parsers
+ from coexisting. */
+#endif
+
+/* ACE_YYINITDEPTH indicates the initial size of the parser's stacks */
+
+#ifndef ACE_YYINITDEPTH
+#define ACE_YYINITDEPTH 200
+#endif
+
+/* ACE_YYMAXDEPTH is the maximum size the stacks can grow to
+ (effective only if the built-in stack extension method is used). */
+
+#if ACE_YYMAXDEPTH == 0
+#undef ACE_YYMAXDEPTH
+#endif
+
+#ifndef ACE_YYMAXDEPTH
+#define ACE_YYMAXDEPTH 10000
+#endif
+
+/* Define __ace_yy_memcpy. Note that the size argument
+ should be passed with type unsigned int, because that is what the non-GCC
+ definitions require. With GCC, __builtin_memcpy takes an arg
+ of type size_t, but it can handle unsigned int. */
+
+#if __GNUC__ > 1 /* GNU C and GNU C++ define this. */
+#define __ace_yy_memcpy(TO,FROM,COUNT) __builtin_memcpy(TO,FROM,COUNT)
+#else /* not GNU C or C++ */
+#ifndef __cplusplus
+
+/* This is the most reliable way to avoid incompatibilities
+ in available built-in functions on various systems. */
+static void
+__ace_yy_memcpy (to, from, count)
+ ACE_TCHAR *to;
+ ACE_TCHAR *from;
+ unsigned int count;
+{
+ register ACE_TCHAR *f = from;
+ register ACE_TCHAR *t = to;
+ register int i = count;
+
+ while (i-- > 0)
+ *t++ = *f++;
+}
+
+#else /* __cplusplus */
+
+/* This is the most reliable way to avoid incompatibilities
+ in available built-in functions on various systems. */
+static void
+__ace_yy_memcpy (ACE_TCHAR *to, ACE_TCHAR *from, unsigned int count)
+{
+ register ACE_TCHAR *t = to;
+ register ACE_TCHAR *f = from;
+ register int i = count;
+
+ while (i-- > 0)
+ *t++ = *f++;
+}
+
+#endif
+#endif
+
+
+
+/* The user can define ACE_YYPARSE_PARAM as the name of an argument to be passed
+ into ace_yyparse. The argument should have type void *.
+ It should actually point to an object.
+ Grammar actions can access the variable by casting it
+ to the proper pointer type. */
+
+#ifdef ACE_YYPARSE_PARAM
+#ifdef __cplusplus
+#define ACE_YYPARSE_PARAM_ARG void *ACE_YYPARSE_PARAM
+#define ACE_YYPARSE_PARAM_DECL
+#else /* not __cplusplus */
+#define ACE_YYPARSE_PARAM_ARG ACE_YYPARSE_PARAM
+#define ACE_YYPARSE_PARAM_DECL void *ACE_YYPARSE_PARAM;
+#endif /* not __cplusplus */
+#else /* not ACE_YYPARSE_PARAM */
+#define ACE_YYPARSE_PARAM_ARG
+#define ACE_YYPARSE_PARAM_DECL
+#endif /* not ACE_YYPARSE_PARAM */
+
+/* Prevent warning if -Wstrict-prototypes. */
+#ifdef __GNUC__
+#ifdef ACE_YYPARSE_PARAM
+int ace_yyparse (void *);
+#else
+int ace_yyparse (void);
+#endif
+#endif
+
+int
+ace_yyparse(ACE_YYPARSE_PARAM_ARG)
+ ACE_YYPARSE_PARAM_DECL
+{
+ register int ace_yystate;
+ register int ace_yyn;
+ register short *ace_yyssp;
+ register ACE_YYSTYPE *ace_yyvsp;
+ int ace_yyerrstatus; /* number of tokens to shift before error messages enabled */
+ int ace_yychar1 = 0; /* lookahead token as an internal (translated) token number */
+
+ short ace_yyssa[ACE_YYINITDEPTH]; /* the state stack */
+ ACE_YYSTYPE ace_yyvsa[ACE_YYINITDEPTH]; /* the semantic value stack */
+
+ short *ace_yyss = ace_yyssa; /* refer to the stacks thru separate pointers */
+ ACE_YYSTYPE *ace_yyvs = ace_yyvsa; /* to allow ace_yyoverflow to reallocate them elsewhere */
+
+#ifdef ACE_YYLSP_NEEDED
+ ACE_YYLTYPE ace_yylsa[ACE_YYINITDEPTH]; /* the location stack */
+ ACE_YYLTYPE *ace_yyls = ace_yylsa;
+ ACE_YYLTYPE *ace_yylsp;
+
+#define ACE_YYPOPSTACK (ace_yyvsp--, ace_yyssp--, ace_yylsp--)
+#else
+#define ACE_YYPOPSTACK (ace_yyvsp--, ace_yyssp--)
+#endif
+
+ int ace_yystacksize = ACE_YYINITDEPTH;
+ int ace_yyfree_stacks = 0;
+
+#ifdef ACE_YYPURE
+ int ace_yychar;
+ ACE_YYSTYPE ace_yylval;
+ int ace_yynerrs;
+#ifdef ACE_YYLSP_NEEDED
+ ACE_YYLTYPE ace_yylloc;
+#endif
+#endif
+
+ ACE_YYSTYPE ace_yyval; /* the variable used to return */
+ /* semantic values from the action */
+ /* routines */
+
+ int ace_yylen;
+
+#if ACE_YYDEBUG != 0
+ if (ace_yydebug)
+ ACE_OS::fprintf(stderr, ACE_LIB_TEXT("Starting parse\n"));
+#endif
+
+ ace_yystate = 0;
+ ace_yyerrstatus = 0;
+ ace_yynerrs = 0;
+ ace_yychar = ACE_YYEMPTY; /* Cause a token to be read. */
+
+ /* Initialize stack pointers.
+ Waste one element of value and location stack
+ so that they stay on the same level as the state stack.
+ The wasted elements are never initialized. */
+
+ ace_yyssp = ace_yyss - 1;
+ ace_yyvsp = ace_yyvs;
+#ifdef ACE_YYLSP_NEEDED
+ ace_yylsp = ace_yyls;
+#endif
+
+/* Push a new state, which is found in ace_yystate . */
+/* In all cases, when you get here, the value and location stacks
+ have just been pushed. so pushing a state here evens the stacks. */
+ace_yynewstate:
+
+ *++ace_yyssp = ace_yystate;
+
+ if (ace_yyssp >= ace_yyss + ace_yystacksize - 1)
+ {
+ /* Give user a chance to reallocate the stack */
+ /* Use copies of these so that the &'s don't force the real ones into memory. */
+ ACE_YYSTYPE *ace_yyvs1 = ace_yyvs;
+ short *ace_yyss1 = ace_yyss;
+#ifdef ACE_YYLSP_NEEDED
+ ACE_YYLTYPE *ace_yyls1 = ace_yyls;
+#endif
+
+ /* Get the current used size of the three stacks, in elements. */
+ int size = ace_yyssp - ace_yyss + 1;
+
+#ifdef ace_yyoverflow
+ /* Each stack pointer address is followed by the size of
+ the data in use in that stack, in bytes. */
+#ifdef ACE_YYLSP_NEEDED
+ /* This used to be a conditional around just the two extra args,
+ but that might be undefined if ace_yyoverflow is a macro. */
+ ace_yyoverflow(ACE_LIB_TEXT("parser stack overflow"),
+ &ace_yyss1, size * sizeof (*ace_yyssp),
+ &ace_yyvs1, size * sizeof (*ace_yyvsp),
+ &ace_yyls1, size * sizeof (*ace_yylsp),
+ &ace_yystacksize);
+#else
+ ace_yyoverflow(ACE_LIB_TEXT("parser stack overflow"),
+ &ace_yyss1, size * sizeof (*ace_yyssp),
+ &ace_yyvs1, size * sizeof (*ace_yyvsp),
+ &ace_yystacksize);
+#endif
+
+ ace_yyss = ace_yyss1; ace_yyvs = ace_yyvs1;
+#ifdef ACE_YYLSP_NEEDED
+ ace_yyls = ace_yyls1;
+#endif
+#else /* no ace_yyoverflow */
+ /* Extend the stack our own way. */
+ if (ace_yystacksize >= ACE_YYMAXDEPTH)
+ {
+ ace_yyerror(ACE_LIB_TEXT("parser stack overflow"));
+ if (ace_yyfree_stacks)
+ {
+ free (ace_yyss);
+ free (ace_yyvs);
+#ifdef ACE_YYLSP_NEEDED
+ free (ace_yyls);
+#endif
+ }
+ return 2;
+ }
+ ace_yystacksize *= 2;
+ if (ace_yystacksize > ACE_YYMAXDEPTH)
+ ace_yystacksize = ACE_YYMAXDEPTH;
+#ifndef ACE_YYSTACK_USE_ALLOCA
+ ace_yyfree_stacks = 1;
+#endif
+ ace_yyss = (short *) ACE_YYSTACK_ALLOC (ace_yystacksize * sizeof (*ace_yyssp));
+ __ace_yy_memcpy ((ACE_TCHAR *)ace_yyss, (ACE_TCHAR *)ace_yyss1,
+ size * (unsigned int) sizeof (*ace_yyssp));
+ ace_yyvs = (ACE_YYSTYPE *) ACE_YYSTACK_ALLOC (ace_yystacksize * sizeof (*ace_yyvsp));
+ __ace_yy_memcpy ((ACE_TCHAR *)ace_yyvs, (ACE_TCHAR *)ace_yyvs1,
+ size * (unsigned int) sizeof (*ace_yyvsp));
+#ifdef ACE_YYLSP_NEEDED
+ ace_yyls = (ACE_YYLTYPE *) ACE_YYSTACK_ALLOC (ace_yystacksize * sizeof (*ace_yylsp));
+ __ace_yy_memcpy ((ACE_TCHAR *)ace_yyls, (ACE_TCHAR *)ace_yyls1,
+ size * (unsigned int) sizeof (*ace_yylsp));
+#endif
+#endif /* no ace_yyoverflow */
+
+ ace_yyssp = ace_yyss + size - 1;
+ ace_yyvsp = ace_yyvs + size - 1;
+#ifdef ACE_YYLSP_NEEDED
+ ace_yylsp = ace_yyls + size - 1;
+#endif
+
+#if ACE_YYDEBUG != 0
+ if (ace_yydebug)
+ ACE_OS::fprintf(stderr, ACE_LIB_TEXT("Stack size increased to %d\n"), ace_yystacksize);
+#endif
+
+ if (ace_yyssp >= ace_yyss + ace_yystacksize - 1)
+ ACE_YYABORT;
+ }
+
+#if ACE_YYDEBUG != 0
+ if (ace_yydebug)
+ ACE_OS::fprintf(stderr, ACE_LIB_TEXT("Entering state %d\n"), ace_yystate);
+#endif
+
+ goto ace_yybackup;
+ ace_yybackup:
+
+/* Do appropriate processing given the current state. */
+/* Read a lookahead token if we need one and don't already have one. */
+/* ace_yyresume: */
+
+ /* First try to decide what to do without reference to lookahead token. */
+
+ ace_yyn = ace_yypact[ace_yystate];
+ if (ace_yyn == ACE_YYFLAG)
+ goto ace_yydefault;
+
+ /* Not known => get a lookahead token if don't already have one. */
+
+ /* ace_yychar is either ACE_YYEMPTY or ACE_YYEOF
+ or a valid token in external form. */
+
+ if (ace_yychar == ACE_YYEMPTY)
+ {
+#if ACE_YYDEBUG != 0
+ if (ace_yydebug)
+ ACE_OS::fprintf(stderr, ACE_LIB_TEXT("Reading a token: "));
+#endif
+ ace_yychar = ACE_YYLEX;
+ }
+
+ /* Convert token to internal form (in ace_yychar1) for indexing tables with */
+
+ if (ace_yychar <= 0) /* This means end of input. */
+ {
+ ace_yychar1 = 0;
+ ace_yychar = ACE_YYEOF; /* Don't call ACE_YYLEX any more */
+
+#if ACE_YYDEBUG != 0
+ if (ace_yydebug)
+ ACE_OS::fprintf(stderr, ACE_LIB_TEXT("Now at end of input.\n"));
+#endif
+ }
+ else
+ {
+ ace_yychar1 = ACE_YYTRANSLATE(ace_yychar);
+
+#if ACE_YYDEBUG != 0
+ if (ace_yydebug)
+ {
+ ACE_OS::fprintf (stderr, ACE_LIB_TEXT("Next token is %d (%s"), ace_yychar, ace_yytname[ace_yychar1]);
+ /* Give the individual parser a way to print the precise meaning
+ of a token, for further debugging info. */
+#ifdef ACE_YYPRINT
+ ACE_YYPRINT (stderr, ace_yychar, ace_yylval);
+#endif
+ ACE_OS::fprintf (stderr, ACE_LIB_TEXT(")\n"));
+ }
+#endif
+ }
+
+ ace_yyn += ace_yychar1;
+ if (ace_yyn < 0 || ace_yyn > ACE_YYLAST || ace_yycheck[ace_yyn] != ace_yychar1)
+ goto ace_yydefault;
+
+ ace_yyn = ace_yytable[ace_yyn];
+
+ /* ace_yyn is what to do for this token type in this state.
+ Negative => reduce, -ace_yyn is rule number.
+ Positive => shift, ace_yyn is new state.
+ New state is final state => don't bother to shift,
+ just return success.
+ 0, or most negative number => error. */
+
+ if (ace_yyn < 0)
+ {
+ if (ace_yyn == ACE_YYFLAG)
+ goto ace_yyerrlab;
+ ace_yyn = -ace_yyn;
+ goto ace_yyreduce;
+ }
+ else if (ace_yyn == 0)
+ goto ace_yyerrlab;
+
+ if (ace_yyn == ACE_YYFINAL)
+ ACE_YYACCEPT;
+
+ /* Shift the lookahead token. */
+
+#if ACE_YYDEBUG != 0
+ if (ace_yydebug)
+ ACE_OS::fprintf(stderr, ACE_LIB_TEXT("Shifting token %d (%s), "), ace_yychar, ace_yytname[ace_yychar1]);
+#endif
+
+ /* Discard the token being shifted unless it is eof. */
+ if (ace_yychar != ACE_YYEOF)
+ ace_yychar = ACE_YYEMPTY;
+
+ *++ace_yyvsp = ace_yylval;
+#ifdef ACE_YYLSP_NEEDED
+ *++ace_yylsp = ace_yylloc;
+#endif
+
+ /* count tokens shifted since error; after three, turn off error status. */
+ if (ace_yyerrstatus) ace_yyerrstatus--;
+
+ ace_yystate = ace_yyn;
+ goto ace_yynewstate;
+
+/* Do the default action for the current state. */
+ace_yydefault:
+
+ ace_yyn = ace_yydefact[ace_yystate];
+ if (ace_yyn == 0)
+ goto ace_yyerrlab;
+
+/* Do a reduction. ace_yyn is the number of a rule to reduce with. */
+ace_yyreduce:
+ ace_yylen = ace_yyr2[ace_yyn];
+ if (ace_yylen > 0)
+ ace_yyval = ace_yyvsp[1-ace_yylen]; /* implement default value of the action */
+
+#if ACE_YYDEBUG != 0
+ if (ace_yydebug)
+ {
+ int i;
+
+ ACE_OS::fprintf (stderr, ACE_LIB_TEXT("Reducing via rule %d (line %d), "),
+ ace_yyn, ace_yyrline[ace_yyn]);
+
+ /* Print the symbols being reduced, and their result. */
+ for (i = ace_yyprhs[ace_yyn]; ace_yyrhs[i] > 0; i++)
+ ACE_OS::fprintf (stderr, ACE_LIB_TEXT("%s "), ace_yytname[ace_yyrhs[i]]);
+ ACE_OS::fprintf (stderr, ACE_LIB_TEXT(" -> %s\n"), ace_yytname[ace_yyr1[ace_yyn]]);
+ }
+#endif
+
+
+ switch (ace_yyn) {
+
+case 1:
+{
+ if (ace_yyvsp[0].parse_node_ != 0)
+ {
+ ace_yyvsp[0].parse_node_->apply (); delete ace_yyvsp[0].parse_node_;
+ }
+ ACE_SVC_CONF_PARAM->obstack.release ();
+ ;
+ break;}
+case 2:
+{
+ ACE_SVC_CONF_PARAM->obstack.release ();
+ ;
+ break;}
+case 10:
+{
+ if (ace_yyvsp[-1].svc_record_ != 0)
+ ace_yyval.parse_node_ = new ACE_Dynamic_Node (ace_yyvsp[-1].svc_record_, ace_yyvsp[0].ident_);
+ else
+ ace_yyval.parse_node_ = 0;
+ ;
+ break;}
+case 11:
+{
+ ace_yyval.parse_node_ = new ACE_Static_Node (ace_yyvsp[-1].ident_, ace_yyvsp[0].ident_);
+ ;
+ break;}
+case 12:
+{
+ ace_yyval.parse_node_ = new ACE_Suspend_Node (ace_yyvsp[0].ident_);
+ ;
+ break;}
+case 13:
+{
+ ace_yyval.parse_node_ = new ACE_Resume_Node (ace_yyvsp[0].ident_);
+ ;
+ break;}
+case 14:
+{
+ ace_yyval.parse_node_ = new ACE_Remove_Node (ace_yyvsp[0].ident_);
+ ;
+ break;}
+case 15:
+{
+ ace_yyval.parse_node_ = new ACE_Stream_Node (ace_yyvsp[-1].static_node_, ace_yyvsp[0].parse_node_);
+ ;
+ break;}
+case 16:
+{ ace_yyval.static_node_ = new ACE_Static_Node (ace_yyvsp[0].ident_); ;
+ break;}
+case 17:
+{
+ ace_yyval.parse_node_ = new ACE_Dummy_Node (ace_yyvsp[-1].static_node_, ace_yyvsp[0].parse_node_);
+ ;
+ break;}
+case 18:
+{
+ ;
+ break;}
+case 19:
+{
+ ;
+ break;}
+case 20:
+{
+ // Initialize left context...
+ ace_yyval.static_node_ = ace_yyvsp[-1].static_node_;
+ ;
+ break;}
+case 21:
+{
+ ace_yyval.parse_node_ = ace_yyvsp[-1].parse_node_;
+ ;
+ break;}
+case 22:
+{ ace_yyval.parse_node_ = 0; ;
+ break;}
+case 23:
+{
+ if (ace_yyvsp[0].parse_node_ != 0)
+ {
+ ace_yyvsp[0].parse_node_->link (ace_yyvsp[-1].parse_node_);
+ ace_yyval.parse_node_ = ace_yyvsp[0].parse_node_;
+ }
+ ;
+ break;}
+case 24:
+{ ace_yyval.parse_node_ = 0; ;
+ break;}
+case 25:
+{
+ ACE_Static_Node *svc_type = ace_yyvsp[0].static_node_;
+
+ if (svc_type != 0)
+ {
+ ACE_Static_Node *module = ace_yyvsp[-2].static_node_;
+
+ ACE_ARGV args (svc_type->parameters ());
+ ACE_Module_Type *mt = ace_get_module (module,
+ svc_type);
+ ACE_Stream_Type *st =
+ ACE_dynamic_cast (ACE_Stream_Type *,
+ ACE_const_cast (ACE_Service_Type_Impl *,
+ module->record ()->type ()));
+
+ if (mt->init (args.argc (), args.argv ()) == -1
+ || st->push (mt) == -1)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("dynamic initialization failed for Module %s\n"),
+ svc_type->name ()));
+ ACE_SVC_CONF_PARAM->yyerrno++;
+ }
+ }
+ ;
+ break;}
+case 26:
+{
+ ACE_Module_Type *mt = ace_get_module (ace_yyvsp[-2].static_node_, ace_yyvsp[0].static_node_->name ());
+
+ if (((ACE_Stream_Type *) (ace_yyvsp[-2].static_node_)->record ()->type ())->push (mt) == -1)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("Problem with static\n")));
+ ACE_SVC_CONF_PARAM->yyerrno++;
+ }
+ ;
+ break;}
+case 27:
+{
+ ACE_Module_Type *mt = ace_get_module (ace_yyvsp[-2].static_node_,
+ ace_yyvsp[0].static_node_->name ());
+ if (mt != 0)
+ mt->suspend ();
+ ;
+ break;}
+case 28:
+{
+ ACE_Module_Type *mt = ace_get_module (ace_yyvsp[-2].static_node_,
+ ace_yyvsp[0].static_node_->name ());
+ if (mt != 0)
+ mt->resume ();
+ ;
+ break;}
+case 29:
+{
+ ACE_Static_Node *stream = ace_yyvsp[-2].static_node_;
+ ACE_Static_Node *module = ace_yyvsp[0].static_node_;
+ ACE_Module_Type *mt = ace_get_module (stream,
+ module->name ());
+
+ ACE_Stream_Type *st =
+ ACE_dynamic_cast (ACE_Stream_Type *,
+ ACE_const_cast (ACE_Service_Type_Impl *,
+ stream->record ()->type ()));
+ if (mt != 0 && st->remove (mt) == -1)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("cannot remove Module_Type %s from STREAM_Type %s\n"),
+ module->name (),
+ stream->name ()));
+ ACE_SVC_CONF_PARAM->yyerrno++;
+ }
+ ;
+ break;}
+case 30:
+{
+ u_int flags
+ = ACE_Service_Type::DELETE_THIS
+ | (ace_yyvsp[-1].location_node_->dispose () == 0 ? 0 : ACE_Service_Type::DELETE_OBJ);
+ ACE_Service_Object_Exterminator gobbler = 0;
+ void *sym = ace_yyvsp[-1].location_node_->symbol (&gobbler);
+
+ if (sym != 0)
+ {
+ ACE_Service_Type_Impl *stp
+ = ace_create_service_type (ace_yyvsp[-3].ident_,
+ ace_yyvsp[-2].type_,
+ sym,
+ flags,
+ gobbler);
+ ace_yyval.svc_record_ = new ACE_Service_Type (ace_yyvsp[-3].ident_,
+ stp,
+ ace_yyvsp[-1].location_node_->handle (),
+ ace_yyvsp[0].type_);
+ }
+ else
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("Unable to find service: %s\n"),
+ ace_yyvsp[-3].ident_));
+ ++ACE_SVC_CONF_PARAM->yyerrno;
+ ace_yyval.svc_record_ = 0;
+ }
+ delete ace_yyvsp[-1].location_node_;
+ ;
+ break;}
+case 31:
+{
+ ace_yyval.type_ = 1;
+ ;
+ break;}
+case 32:
+{
+ ace_yyval.type_ = 0;
+ ;
+ break;}
+case 33:
+{
+ ace_yyval.type_ = 1;
+ ;
+ break;}
+case 34:
+{
+ ace_yyval.location_node_ = new ACE_Object_Node (ace_yyvsp[-2].ident_, ace_yyvsp[0].ident_);
+ ;
+ break;}
+case 35:
+{
+ ace_yyval.location_node_ = new ACE_Function_Node (ace_yyvsp[-4].ident_, ace_yyvsp[-2].ident_);
+ ;
+ break;}
+case 36:
+{
+ ace_yyval.location_node_ = new ACE_Static_Function_Node (ace_yyvsp[-2].ident_);
+ ;
+ break;}
+case 37:
+{
+ ace_yyval.type_ = ACE_MODULE_T;
+ ;
+ break;}
+case 38:
+{
+ ace_yyval.type_ = ACE_SVC_OBJ_T;
+ ;
+ break;}
+case 39:
+{
+ ace_yyval.type_ = ACE_STREAM_T;
+ ;
+ break;}
+case 41:
+{ ace_yyval.ident_ = 0; ;
+ break;}
+}
+ /* the action file gets copied in in place of this dollarsign */
+
+
+ ace_yyvsp -= ace_yylen;
+ ace_yyssp -= ace_yylen;
+#ifdef ACE_YYLSP_NEEDED
+ ace_yylsp -= ace_yylen;
+#endif
+
+#if ACE_YYDEBUG != 0
+ if (ace_yydebug)
+ {
+ short *ssp1 = ace_yyss - 1;
+ ACE_OS::fprintf (stderr, ACE_LIB_TEXT("state stack now"));
+ while (ssp1 != ace_yyssp)
+ ACE_OS::fprintf (stderr, ACE_LIB_TEXT(" %d"), *++ssp1);
+ ACE_OS::fprintf (stderr, ACE_LIB_TEXT("\n"));
+ }
+#endif
+
+ *++ace_yyvsp = ace_yyval;
+
+#ifdef ACE_YYLSP_NEEDED
+ ace_yylsp++;
+ if (ace_yylen == 0)
+ {
+ ace_yylsp->first_line = ace_yylloc.first_line;
+ ace_yylsp->first_column = ace_yylloc.first_column;
+ ace_yylsp->last_line = (ace_yylsp-1)->last_line;
+ ace_yylsp->last_column = (ace_yylsp-1)->last_column;
+ ace_yylsp->text = 0;
+ }
+ else
+ {
+ ace_yylsp->last_line = (ace_yylsp+ace_yylen-1)->last_line;
+ ace_yylsp->last_column = (ace_yylsp+ace_yylen-1)->last_column;
+ }
+#endif
+
+ /* Now "shift" the result of the reduction.
+ Determine what state that goes to,
+ based on the state we popped back to
+ and the rule number reduced by. */
+
+ ace_yyn = ace_yyr1[ace_yyn];
+
+ ace_yystate = ace_yypgoto[ace_yyn - ACE_YYNTBASE] + *ace_yyssp;
+ if (ace_yystate >= 0 && ace_yystate <= ACE_YYLAST && ace_yycheck[ace_yystate] == *ace_yyssp)
+ ace_yystate = ace_yytable[ace_yystate];
+ else
+ ace_yystate = ace_yydefgoto[ace_yyn - ACE_YYNTBASE];
+
+ goto ace_yynewstate;
+
+ace_yyerrlab: /* here on detecting error */
+
+ if (! ace_yyerrstatus)
+ /* If not already recovering from an error, report this error. */
+ {
+ ++ace_yynerrs;
+
+#ifdef ACE_YYERROR_VERBOSE
+ ace_yyn = ace_yypact[ace_yystate];
+
+ if (ace_yyn > ACE_YYFLAG && ace_yyn < ACE_YYLAST)
+ {
+ int size = 0;
+ ACE_TCHAR *msg;
+ int x, count;
+
+ count = 0;
+ /* Start X at -ace_yyn if nec to avoid negative indexes in ace_yycheck. */
+ for (x = (ace_yyn < 0 ? -ace_yyn : 0);
+ x < (sizeof(ace_yytname) / sizeof(ACE_TCHAR *)); x++)
+ if (ace_yycheck[x + ace_yyn] == x)
+ size += ACE_OS::strlen(ace_yytname[x]) + 15, count++;
+ msg = new ACE_TCHAR[size + 15];
+ if (msg != 0)
+ {
+ ACE_OS::strcpy(msg, ACE_LIB_TEXT("parse error"));
+
+ if (count < 5)
+ {
+ count = 0;
+ for (x = (ace_yyn < 0 ? -ace_yyn : 0);
+ x < (sizeof(ace_yytname) / sizeof(ACE_TCHAR *)); x++)
+ if (ace_yycheck[x + ace_yyn] == x)
+ {
+ ACE_OS::strcat(msg, count == 0 ? ACE_LIB_TEXT(", expecting `") : ACE_LIB_TEXT(" or `"));
+ ACE_OS::strcat(msg, ACE_TEXT_CHAR_TO_TCHAR (ace_yytname[x]));
+ ACE_OS::strcat(msg, ACE_LIB_TEXT("'"));
+ count++;
+ }
+ }
+ ace_yyerror(msg);
+ delete [] msg;
+ }
+ else
+ ace_yyerror (ACE_LIB_TEXT("parse error; also virtual memory exceeded"));
+ }
+ else
+#endif /* ACE_YYERROR_VERBOSE */
+ ace_yyerror(ACE_LIB_TEXT("parse error"));
+ }
+
+ goto ace_yyerrlab1;
+ace_yyerrlab1: /* here on error raised explicitly by an action */
+
+ if (ace_yyerrstatus == 3)
+ {
+ /* if just tried and failed to reuse lookahead token after an error, discard it. */
+
+ /* return failure if at end of input */
+ if (ace_yychar == ACE_YYEOF)
+ ACE_YYABORT;
+
+#if ACE_YYDEBUG != 0
+ if (ace_yydebug)
+ ACE_OS::fprintf(stderr, ACE_LIB_TEXT("Discarding token %d (%s).\n"), ace_yychar, ace_yytname[ace_yychar1]);
+#endif
+
+ ace_yychar = ACE_YYEMPTY;
+ }
+
+ /* Else will try to reuse lookahead token
+ after shifting the error token. */
+
+ ace_yyerrstatus = 3; /* Each real token shifted decrements this */
+
+ goto ace_yyerrhandle;
+
+ace_yyerrdefault: /* current state does not do anything special for the error token. */
+
+#if 0
+ /* This is wrong; only states that explicitly want error tokens
+ should shift them. */
+ ace_yyn = ace_yydefact[ace_yystate]; /* If its default is to accept any token, ok. Otherwise pop it.*/
+ if (ace_yyn) goto ace_yydefault;
+#endif
+
+ace_yyerrpop: /* pop the current state because it cannot handle the error token */
+
+ if (ace_yyssp == ace_yyss) ACE_YYABORT;
+ ace_yyvsp--;
+ ace_yystate = *--ace_yyssp;
+#ifdef ACE_YYLSP_NEEDED
+ ace_yylsp--;
+#endif
+
+#if ACE_YYDEBUG != 0
+ if (ace_yydebug)
+ {
+ short *ssp1 = ace_yyss - 1;
+ ACE_OS::fprintf (stderr, ACE_LIB_TEXT("Error: state stack now"));
+ while (ssp1 != ace_yyssp)
+ ACE_OS::fprintf (stderr, ACE_LIB_TEXT(" %d"), *++ssp1);
+ ACE_OS::fprintf (stderr, ACE_LIB_TEXT("\n"));
+ }
+#endif
+
+ace_yyerrhandle:
+
+ ace_yyn = ace_yypact[ace_yystate];
+ if (ace_yyn == ACE_YYFLAG)
+ goto ace_yyerrdefault;
+
+ ace_yyn += ACE_YYTERROR;
+ if (ace_yyn < 0 || ace_yyn > ACE_YYLAST || ace_yycheck[ace_yyn] != ACE_YYTERROR)
+ goto ace_yyerrdefault;
+
+ ace_yyn = ace_yytable[ace_yyn];
+ if (ace_yyn < 0)
+ {
+ if (ace_yyn == ACE_YYFLAG)
+ goto ace_yyerrpop;
+ ace_yyn = -ace_yyn;
+ goto ace_yyreduce;
+ }
+ else if (ace_yyn == 0)
+ goto ace_yyerrpop;
+
+ if (ace_yyn == ACE_YYFINAL)
+ ACE_YYACCEPT;
+
+#if ACE_YYDEBUG != 0
+ if (ace_yydebug)
+ ACE_OS::fprintf(stderr, ACE_LIB_TEXT("Shifting error token, "));
+#endif
+
+ *++ace_yyvsp = ace_yylval;
+#ifdef ACE_YYLSP_NEEDED
+ *++ace_yylsp = ace_yylloc;
+#endif
+
+ ace_yystate = ace_yyn;
+ goto ace_yynewstate;
+
+ ace_yyacceptlab:
+ /* ACE_YYACCEPT comes here. */
+ if (ace_yyfree_stacks)
+ {
+ free (ace_yyss);
+ free (ace_yyvs);
+#ifdef ACE_YYLSP_NEEDED
+ free (ace_yyls);
+#endif
+ }
+ return 0;
+
+ ace_yyabortlab:
+ /* ACE_YYABORT comes here. */
+ if (ace_yyfree_stacks)
+ {
+ free (ace_yyss);
+ free (ace_yyvs);
+#ifdef ACE_YYLSP_NEEDED
+ free (ace_yyls);
+#endif
+ }
+ return 1;
+}
+
+// Prints the error string to standard output. Cleans up the error
+// messages.
+
+void
+ace_yyerror (const ACE_TCHAR *s)
+{
+#if defined (ACE_NLOGGING)
+ ACE_UNUSED_ARG (s);
+#endif /* ACE_NLOGGING */
+
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("[error %d] on line %d: %s\n"),
+ ace_yyerrno,
+ ace_yylineno,
+ s));
+}
+
+// Note that SRC_REC represents left context, which is the STREAM *
+// record.
+
+static ACE_Module_Type *
+ace_get_module (ACE_Static_Node *str_rec,
+ const ACE_TCHAR *svc_name)
+{
+ const ACE_Service_Type *sr = str_rec->record ();
+ const ACE_Service_Type_Impl *type = sr->type ();
+ ACE_Stream_Type *st = sr == 0
+ ? 0
+ : ACE_dynamic_cast (ACE_Stream_Type *,
+ ACE_const_cast (ACE_Service_Type_Impl *,
+ type));
+ ACE_Module_Type *mt = st == 0 ? 0 : st->find (svc_name);
+
+ if (sr == 0 || st == 0 || mt == 0)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("cannot locate Module_Type %s in STREAM_Type %s\n"),
+ svc_name,
+ str_rec->name ()));
+ ace_yyerrno++;
+ }
+
+ return mt;
+}
+
+static ACE_Module_Type *
+ace_get_module (ACE_Static_Node *str_rec,
+ ACE_Static_Node *svc_type)
+{
+ const ACE_Service_Type *sr = str_rec->record ();
+ const ACE_Service_Type_Impl *type = sr->type ();
+ ACE_Stream_Type *st = sr == 0 ? 0 : (ACE_Stream_Type *) type;
+ const ACE_Service_Type *sv = svc_type->record ();
+ type = sv->type ();
+ ACE_Module_Type *mt = (ACE_Module_Type *) type;
+ const ACE_TCHAR *module_type_name = svc_type->name ();
+
+ if (sr == 0 || st == 0 || mt == 0)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("cannot locate Module_Type %s or STREAM_Type %s\n"),
+ module_type_name,
+ str_rec->name ()));
+ ace_yyerrno++;
+ }
+
+ // Make sure that the Module has the same name as the
+ // Module_Type object from the svc.conf file.
+ ACE_Module<ACE_SYNCH> *mp = (ACE_Module<ACE_SYNCH> *) mt->object ();
+
+ if (ACE_OS::strcmp (mp->name (), module_type_name) != 0)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_LIB_TEXT ("warning: assigning Module_Type name %s to Module %s since names differ\n"),
+ module_type_name,
+ mp->name ()));
+ mp->name (module_type_name);
+ }
+
+ return mt;
+}
+
+ACE_Service_Type_Impl *
+ace_create_service_type (const ACE_TCHAR *name,
+ int type,
+ void *symbol,
+ u_int flags,
+ ACE_Service_Object_Exterminator gobbler)
+{
+ ACE_Service_Type_Impl *stp = 0;
+
+ // Note, the only place we need to put a case statement. This is
+ // also the place where we'd put the RTTI tests, if the compiler
+ // actually supported them!
+
+ switch (type)
+ {
+ case ACE_SVC_OBJ_T:
+ ACE_NEW_RETURN (stp,
+ ACE_Service_Object_Type ((ACE_Service_Object *) symbol,
+ name, flags,
+ gobbler),
+ 0);
+ break;
+ case ACE_MODULE_T:
+ ACE_NEW_RETURN (stp,
+ ACE_Module_Type (symbol, name, flags),
+ 0);
+ break;
+ case ACE_STREAM_T:
+ ACE_NEW_RETURN (stp,
+ ACE_Stream_Type (symbol, name, flags),
+ 0);
+ break;
+ default:
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("unknown case\n")));
+ ace_yyerrno++;
+ break;
+ }
+ return stp;
+}
+
+#if defined (DEBUGGING)
+// Current line number.
+int ace_yylineno = 1;
+
+// Name given on the command-line to envoke the program.
+ACE_TCHAR *program_name;
+
+// Main driver program.
+
+int
+main (int argc, ACE_TCHAR *argv[])
+{
+ ACE_Svc_Conf_Param param (stdin);
+
+ // Try to reopen any filename argument to use ACE_YYIN.
+ if (argc > 1 && (ace_yyin = freopen (argv[1], ACE_LIB_TEXT("r"), stdin)) == 0)
+ ACE_OS::fprintf (stderr, ACE_LIB_TEXT("usage: %s [file]\n"), argv[0]), ACE_OS::exit (1);
+
+ return ace_yyparse (&param);
+}
+#endif /* DEBUGGING */
diff --git a/ace/Svcconf/Svc_Handler.cpp b/ace/Svcconf/Svc_Handler.cpp
new file mode 100644
index 00000000000..9614a404e12
--- /dev/null
+++ b/ace/Svcconf/Svc_Handler.cpp
@@ -0,0 +1,512 @@
+// $Id$
+
+#ifndef ACE_SVC_HANDLER_C
+#define ACE_SVC_HANDLER_C
+
+#include "ace/Svc_Handler.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "ace/Object_Manager.h"
+#include "ace/Connection_Recycling_Strategy.h"
+
+#include "ace/Dynamic.h"
+
+ACE_RCSID(ace, Svc_Handler, "$Id$")
+
+#define PR_ST_1 ACE_PEER_STREAM_1
+#define PR_ST_2 ACE_PEER_STREAM_2
+
+template <PR_ST_1, ACE_SYNCH_DECL> void *
+ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::operator new (size_t,
+ void *p)
+{
+ ACE_TRACE ("ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::operator new (NOOP, 2 parameters)");
+ return p;
+}
+
+#if !defined (ACE_LACKS_PLACEMENT_OPERATOR_DELETE)
+template <PR_ST_1, ACE_SYNCH_DECL> void
+ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::operator delete (void *,
+ void *)
+{
+ ACE_TRACE ("ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::operator delete (NOOP, 2 parameters)");
+ return;
+}
+#endif /* ACE_LACKS_PLACEMENT_OPERATOR_DELETE */
+
+template <PR_ST_1, ACE_SYNCH_DECL> void *
+ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::operator new (size_t n)
+{
+ ACE_TRACE ("ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::operator new");
+
+ ACE_Dynamic *const dynamic_instance = ACE_Dynamic::instance ();
+
+ if (dynamic_instance == 0)
+ {
+ // If this ACE_ASSERT fails, it may be due to running of out TSS
+ // keys. Try using ACE_HAS_TSS_EMULATION, or increasing
+ // ACE_DEFAULT_THREAD_KEYS if already using TSS emulation.
+ ACE_ASSERT (dynamic_instance != 0);
+
+ ACE_throw_bad_alloc;
+ }
+ else
+ {
+ // Allocate the memory and store it (usually in thread-specific
+ // storage, depending on config flags).
+ dynamic_instance->set ();
+
+ return ::new char[n];
+ }
+}
+
+#if defined (ACE_HAS_NEW_NOTHROW)
+template <PR_ST_1, ACE_SYNCH_DECL> void *
+ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::operator new (size_t n,
+ const nothrow_t&)
+{
+ ACE_TRACE ("ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::operator new(nothrow)");
+
+ ACE_Dynamic *const dynamic_instance = ACE_Dynamic::instance ();
+
+ if (dynamic_instance == 0)
+ {
+ // If this ACE_ASSERT fails, it may be due to running of out TSS
+ // keys. Try using ACE_HAS_TSS_EMULATION, or increasing
+ // ACE_DEFAULT_THREAD_KEYS if already using TSS emulation.
+ ACE_ASSERT (dynamic_instance != 0);
+
+ return 0;
+ }
+ else
+ {
+ // Allocate the memory and store it (usually in thread-specific
+ // storage, depending on config flags).
+ dynamic_instance->set ();
+
+ return ::new(nothrow) char[n];
+ }
+}
+#endif /* ACE_HAS_NEW_NOTHROW */
+
+template <PR_ST_1, ACE_SYNCH_DECL> void
+ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::destroy (void)
+{
+ ACE_TRACE ("ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::destroy");
+
+ // Only delete ourselves if we're not owned by a module and have
+ // been allocated dynamically.
+ if (this->mod_ == 0 && this->dynamic_ && this->closing_ == 0)
+ // Will call the destructor, which automatically calls <shutdown>.
+ // Note that if we are *not* allocated dynamically then the
+ // destructor will call <shutdown> automatically when it gets run
+ // during cleanup.
+ delete this;
+}
+
+template <PR_ST_1, ACE_SYNCH_DECL> void
+ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::operator delete (void *obj)
+{
+ ACE_TRACE ("ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::operator delete");
+ // You cannot delete a 'void*' (X3J16/95-0087 5.3.5.3), but we know
+ // the pointer was created using new char[] (see operator new code),
+ // so we use a cast:
+ char *tmp = (char *) obj;
+ ::delete [] tmp;
+}
+
+// Default constructor.
+
+template <PR_ST_1, ACE_SYNCH_DECL>
+ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::ACE_Svc_Handler (ACE_Thread_Manager *tm,
+ ACE_Message_Queue<ACE_SYNCH_USE> *mq,
+ ACE_Reactor *reactor)
+ : ACE_Task<ACE_SYNCH_USE> (tm, mq),
+ closing_ (0),
+ recycler_ (0),
+ recycling_act_ (0)
+{
+ ACE_TRACE ("ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::ACE_Svc_Handler");
+
+ this->reactor (reactor);
+
+ // This clever idiom transparently checks if we were allocated
+ // dynamically. This information is used by the <destroy> method to
+ // decide if we need to delete <this>... The idiom is based on a
+ // paper by Michael van Rooyen (mrooyen@cellnet.co.uk) that appeared
+ // in the April '96 issue of the C++ Report. We've spruced it up to
+ // work correctly in multi-threaded programs by using our ACE_TSS
+ // class.
+ this->dynamic_ = ACE_Dynamic::instance ()->is_dynamic ();
+
+ if (this->dynamic_ != 0)
+ // Make sure to reset the flag.
+ ACE_Dynamic::instance ()->reset ();
+}
+
+// Default behavior for a ACE_Svc_Handler object is to be registered
+// with the ACE_Reactor (thereby ensuring single threading).
+
+template <PR_ST_1, ACE_SYNCH_DECL> int
+ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::open (void *)
+{
+ ACE_TRACE ("ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::open");
+#if defined (ACE_DEBUGGING)
+ ACE_TCHAR buf[BUFSIZ];
+ ACE_PEER_STREAM_ADDR client_addr;
+
+ if (this->peer_.get_remote_addr (client_addr) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_LIB_TEXT ("%p\n"),
+ ACE_LIB_TEXT ("get_remote_addr")),
+ -1);
+ else if (client_addr.addr_to_string (buf, sizeof buf) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_LIB_TEXT ("%p\n"),
+ ACE_LIB_TEXT ("can't obtain peer's address")),
+ -1);
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_LIB_TEXT ("connected to %s on fd %d\n"),
+ buf,
+ this->peer_.get_handle ()));
+#endif /* ACE_DEBUGGING */
+ if (this->reactor ()
+ && this->reactor ()->register_handler
+ (this,
+ ACE_Event_Handler::READ_MASK) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_LIB_TEXT ("%p\n"),
+ ACE_LIB_TEXT ("unable to register client handler")),
+ -1);
+ return 0;
+}
+
+// Perform termination activities.
+
+template <PR_ST_1, ACE_SYNCH_DECL> void
+ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::shutdown (void)
+{
+ ACE_TRACE ("ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::shutdown");
+
+ // Deregister this handler with the ACE_Reactor.
+ if (this->reactor ())
+ {
+ ACE_Reactor_Mask mask = ACE_Event_Handler::ALL_EVENTS_MASK |
+ ACE_Event_Handler::DONT_CALL;
+
+ // Make sure there are no timers.
+ this->reactor ()->cancel_timer (this);
+
+ if (this->peer ().get_handle () != ACE_INVALID_HANDLE)
+ // Remove self from reactor.
+ this->reactor ()->remove_handler (this, mask);
+ }
+
+ // Remove self from the recycler.
+ if (this->recycler ())
+ this->recycler ()->purge (this->recycling_act_);
+
+ this->peer ().close ();
+}
+
+template <PR_ST_1, ACE_SYNCH_DECL> void
+ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::cleanup_hint (void **act_holder)
+{
+ ACE_TRACE ("ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::cleanup_hint");
+
+ // Remove as hint.
+ if (this->recycler ())
+ this->recycler ()->cleanup_hint (this->recycling_act_,
+ act_holder);
+}
+
+template <PR_ST_1, ACE_SYNCH_DECL> void
+ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::dump (void) const
+{
+ ACE_TRACE ("ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::dump");
+
+ this->peer_.dump ();
+ ACE_DEBUG ((LM_DEBUG,
+ "dynamic_ = %d\n",
+ this->dynamic_));
+ ACE_DEBUG ((LM_DEBUG,
+ "closing_ = %d\n",
+ this->closing_));
+ ACE_DEBUG ((LM_DEBUG,
+ "recycler_ = %d\n",
+ this->recycler_));
+ ACE_DEBUG ((LM_DEBUG,
+ "recycling_act_ = %d\n",
+ this->recycling_act_));
+}
+
+template <PR_ST_1, ACE_SYNCH_DECL> ACE_PEER_STREAM &
+ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::peer (void) const
+{
+ ACE_TRACE ("ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::peer");
+ return (ACE_PEER_STREAM &) this->peer_;
+}
+
+// Extract the underlying I/O descriptor.
+
+template <PR_ST_1, ACE_SYNCH_DECL> ACE_HANDLE
+ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::get_handle (void) const
+{
+ ACE_TRACE ("ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::get_handle");
+ return this->peer_.get_handle ();
+}
+
+// Set the underlying I/O descriptor.
+
+template <PR_ST_1, ACE_SYNCH_DECL> void
+ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::set_handle (ACE_HANDLE h)
+{
+ ACE_TRACE ("ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::set_handle");
+ this->peer_.set_handle (h);
+}
+
+template <PR_ST_1, ACE_SYNCH_DECL>
+ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::~ACE_Svc_Handler (void)
+{
+ ACE_TRACE ("ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::~ACE_Svc_Handler");
+
+ if (this->closing_ == 0)
+ {
+ // We're closing down now, so make sure not to call ourselves
+ // recursively via other calls to handle_close() (e.g., from the
+ // Timer_Queue).
+ this->closing_ = 1;
+
+ this->shutdown ();
+ }
+}
+
+template <PR_ST_1, ACE_SYNCH_DECL> int
+ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::handle_close (ACE_HANDLE,
+ ACE_Reactor_Mask)
+{
+ ACE_TRACE ("ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::handle_close");
+
+ this->destroy ();
+ return 0;
+}
+
+template <PR_ST_1, ACE_SYNCH_DECL> int
+ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::handle_timeout (const ACE_Time_Value &,
+ const void *)
+{
+ ACE_TRACE ("ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::handle_timeout");
+ return this->handle_close ();
+}
+
+template <PR_ST_1, ACE_SYNCH_DECL> int
+ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::close (unsigned long)
+{
+ ACE_TRACE ("ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::close");
+ return this->handle_close ();
+}
+
+template <PR_ST_1, ACE_SYNCH_DECL> int
+ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::init (int argc, ACE_TCHAR *argv[])
+{
+ ACE_TRACE ("ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::init");
+ ACE_UNUSED_ARG (argc);
+ ACE_UNUSED_ARG (argv);
+ return -1;
+}
+
+template <PR_ST_1, ACE_SYNCH_DECL> int
+ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::fini (void)
+{
+ ACE_TRACE ("ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::fini");
+ return -1;
+}
+
+template <PR_ST_1, ACE_SYNCH_DECL> int
+ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::info (ACE_TCHAR **, size_t) const
+{
+ ACE_TRACE ("ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::info");
+ return -1;
+}
+
+template <PR_ST_1, ACE_SYNCH_DECL> int
+ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::idle (u_long flags)
+{
+ if (this->recycler ())
+ return this->recycler ()->cache (this->recycling_act_);
+ else
+ return this->close (flags);
+}
+
+template <PR_ST_1, ACE_SYNCH_DECL> int
+ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::recycle_state (ACE_Recyclable_State new_state)
+{
+ if (this->recycler ())
+ return this->recycler ()->recycle_state (this->recycling_act_,
+ new_state);
+
+ return 0;
+}
+
+template <PR_ST_1, ACE_SYNCH_DECL> ACE_Recyclable_State
+ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::recycle_state (void) const
+{
+ if (this->recycler ())
+ return this->recycler ()->recycle_state (this->recycling_act_);
+
+ return ACE_RECYCLABLE_UNKNOWN;
+}
+
+template <PR_ST_1, ACE_SYNCH_DECL> void
+ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::recycler (ACE_Connection_Recycling_Strategy *recycler,
+ const void *recycling_act)
+{
+ ACE_TRACE ("ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::recycler");
+ this->recycler_ = recycler;
+ this->recycling_act_ = recycling_act;
+}
+
+template <PR_ST_1, ACE_SYNCH_DECL> ACE_Connection_Recycling_Strategy *
+ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::recycler (void) const
+{
+ ACE_TRACE ("ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::recycler");
+ return this->recycler_;
+}
+
+template <PR_ST_1, ACE_SYNCH_DECL> const void *
+ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::recycling_act (void) const
+{
+ ACE_TRACE ("ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::recycling_act");
+ return this->recycling_act_;
+}
+
+template <PR_ST_1, ACE_SYNCH_DECL> int
+ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::recycle (void *)
+{
+ ACE_TRACE ("ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::recycle");
+ // By default, the object is ready and willing to be recycled.
+ return 0;
+}
+
+template <PR_ST_1, ACE_SYNCH_DECL>
+ACE_Buffered_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::~ACE_Buffered_Svc_Handler (void)
+{
+ this->flush ();
+}
+
+template <PR_ST_1, ACE_SYNCH_DECL>
+ACE_Buffered_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::ACE_Buffered_Svc_Handler (ACE_Thread_Manager *tm,
+ ACE_Message_Queue<ACE_SYNCH_USE> *mq,
+ ACE_Reactor *reactor,
+ size_t maximum_buffer_size,
+ ACE_Time_Value *timeout)
+ : ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE> (tm, mq, reactor),
+ maximum_buffer_size_ (maximum_buffer_size),
+ current_buffer_size_ (0),
+ timeoutp_ (timeout)
+{
+ ACE_TRACE ("ACE_Buffered_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::ACE_Buffered_Svc_Handler");
+
+ if (this->timeoutp_ != 0)
+ {
+ this->interval_ = *timeout;
+ this->next_timeout_ = ACE_OS::gettimeofday () + this->interval_;
+ }
+}
+
+template <PR_ST_1, ACE_SYNCH_DECL> int
+ACE_Buffered_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::put (ACE_Message_Block *mb,
+ ACE_Time_Value *tv)
+{
+ ACE_GUARD_RETURN (ACE_SYNCH_MUTEX_T, m, this->msg_queue ()->lock (), -1);
+
+ // Enqueue <mb> onto the message queue.
+ if (this->putq (mb, tv) == -1)
+ return -1;
+ else
+ {
+ // Update the current number of bytes on the queue.
+ this->current_buffer_size_ += mb->total_size ();
+
+ // Flush the buffer when the number of bytes exceeds the maximum
+ // buffer size or when the timeout period has elapsed.
+ if (this->current_buffer_size_ >= this->maximum_buffer_size_
+ || (this->timeoutp_ != 0
+ && this->next_timeout_ <= ACE_OS::gettimeofday ()))
+ return this->flush ();
+ else
+ return 0;
+ }
+}
+
+// Flush the buffer.
+
+template <PR_ST_1, ACE_SYNCH_DECL> int
+ACE_Buffered_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::flush (void)
+{
+ ACE_GUARD_RETURN (ACE_SYNCH_MUTEX_T, m, this->msg_queue ()->lock (), -1);
+
+ ACE_Message_Queue_Iterator<ACE_SYNCH_USE> iterator (*this->msg_queue ());
+ ACE_Message_Block *mblk;
+ int result = 0;
+
+ // Get the first <ACE_Message_Block> so that we can write everything
+ // out via the <send_n>.
+ if (iterator.next (mblk) != 0)
+ result = this->peer ().send_n (mblk);
+
+ // Remove all the <ACE_Message_Block>s in the <ACE_Message_Queue>
+ // and <release> their memory.
+ while (this->msg_queue ()->is_empty () == 0)
+ {
+ if (this->msg_queue ()->dequeue_head (mblk) == -1)
+ break;
+
+ mblk->release ();
+ }
+
+ if (this->timeoutp_ != 0)
+ // Update the next timeout period by adding the interval.
+ this->next_timeout_ += this->interval_;
+
+ this->current_buffer_size_ = 0;
+
+ return result;
+}
+
+template <PR_ST_1, ACE_SYNCH_DECL> void
+ACE_Buffered_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::dump (void) const
+{
+ ACE_TRACE ("ACE_Buffered_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::dump");
+
+ ACE_Buffered_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::dump ();
+ ACE_DEBUG ((LM_DEBUG,
+ "maximum_buffer_size_ = %d\n",
+ this->maximum_buffer_size_));
+ ACE_DEBUG ((LM_DEBUG,
+ "current_buffer_size_ = %d\n",
+ this->current_buffer_size_));
+ if (this->timeoutp_ != 0)
+ ACE_DEBUG ((LM_DEBUG,
+ "next_timeout_.sec = %d, next_timeout_.usec = %d\n",
+ this->next_timeout_.sec (),
+ this->next_timeout_.usec ()));
+ else
+ ACE_DEBUG ((LM_DEBUG,
+ "timeoutp_ == NULL"));
+}
+
+template <PR_ST_1, ACE_SYNCH_DECL> int
+ACE_Buffered_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::handle_timeout (const ACE_Time_Value &,
+ const void *)
+{
+ ACE_TRACE ("ACE_Buffered_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::handle_timeout");
+ return 0;
+}
+
+#undef PR_ST_1
+#undef PR_ST_2
+#endif /* ACE_SVC_HANDLER_C */
diff --git a/ace/Svcconf/Svc_Handler.h b/ace/Svcconf/Svc_Handler.h
new file mode 100644
index 00000000000..054c950b7a1
--- /dev/null
+++ b/ace/Svcconf/Svc_Handler.h
@@ -0,0 +1,322 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Svc_Handler.h
+ *
+ * $Id$
+ *
+ * @author Douglas Schmidt <schmidt@cs.wustl.edu> and
+ * Irfan Pyrarli <irfan@cs.wustl.edu>
+ */
+//=============================================================================
+
+#ifndef ACE_SVC_HANDLER_H
+#define ACE_SVC_HANDLER_H
+#include "ace/pre.h"
+
+// Forward decls.
+class ACE_Connection_Recycling_Strategy;
+
+#include "ace/Synch_Options.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "ace/Task.h"
+#include "ace/Service_Config.h"
+#include "ace/Recyclable.h"
+
+/**
+ * @class ACE_Svc_Handler
+ *
+ * @brief Defines the interface for a service that exchanges data with
+ * its connected peer.
+ *
+ * This class provides a well-defined interface that the
+ * Acceptor and Connector pattern factories use as their target.
+ * Typically, client applications will subclass ACE_Svc_Handler
+ * and do all the interesting work in the subclass. One thing
+ * that the ACE_Svc_Handler does contain is a PEER_STREAM
+ * endpoint that is initialized by an ACE_Acceptor or
+ * ACE_Connector when a connection is established successfully.
+ * This endpoint is used to exchange data between a
+ * ACE_Svc_Handler and the peer it is connected with.
+ */
+template <ACE_PEER_STREAM_1, ACE_SYNCH_DECL>
+class ACE_Svc_Handler : public ACE_Task<ACE_SYNCH_USE>
+{
+public:
+ // = Initialization and termination methods.
+ /**
+ * Constructor initializes the <thr_mgr> and <mq> by passing them
+ * down to the <ACE_Task> base class. The <reactor> is passed to
+ * the <ACE_Event_Handler>.
+ */
+ ACE_Svc_Handler (ACE_Thread_Manager *thr_mgr = 0,
+ ACE_Message_Queue<ACE_SYNCH_USE> *mq = 0,
+ ACE_Reactor *reactor = ACE_Reactor::instance ());
+
+ /// Destructor.
+ virtual ~ACE_Svc_Handler (void);
+
+ /// Activate the client handler. This is typically called by the
+ /// <ACE_Acceptor> or <ACE_Connector>.
+ virtual int open (void * = 0);
+
+ /**
+ * Object termination hook -- application-specific cleanup code goes
+ * here. This function is called by the idle() function if the object
+ * does not have a ACE_Connection_Recycling_Strategy associated with it.
+ * Also, due to this class's derivation from <ACE_Task>, <close> is
+ * also called when a thread activated with this object exits. See
+ * <ACE_Task::close> for further details. The default action of this
+ * function is to call <handle_close> with the default arguments.
+ */
+ virtual int close (u_long flags = 0);
+
+ /**
+ * Call this method if you want to recycling the <Svc_Handler>
+ * instead of closing it. If the object does not have a recycler,
+ * it will be closed.
+ */
+ virtual int idle (u_long flags = 0);
+
+ /**
+ * Call this method if you want to get/set the state of the
+ * <Svc_Handler>. If the object does not have a recycler, this call
+ * will have no effect (and the accessor will return
+ * ACE_RECYCLABLE_UNKNOWN).
+ */
+ virtual ACE_Recyclable_State recycle_state (void) const;
+ virtual int recycle_state (ACE_Recyclable_State new_state);
+
+ /**
+ * When the svc_handle is no longer needed around as a hint, call
+ * this method. In addition, reset <*act_holder> to zero if
+ * <act_holder != 0>.
+ */
+ virtual void cleanup_hint (void **act_holder = 0);
+
+ // = Dynamic linking hooks.
+ /// Default version does no work and returns -1. Must be overloaded
+ /// by application developer to do anything meaningful.
+ virtual int init (int argc, ACE_TCHAR *argv[]);
+
+ /// Default version does no work and returns -1. Must be overloaded
+ /// by application developer to do anything meaningful.
+ virtual int fini (void);
+
+ /// Default version does no work and returns -1. Must be overloaded
+ /// by application developer to do anything meaningful.
+ virtual int info (ACE_TCHAR **info_string, size_t length) const;
+
+ // = Demultiplexing hooks.
+
+ /**
+ * Perform termination activities on the SVC_HANDLER. The default
+ * behavior is to close down the <peer_> (to avoid descriptor leaks)
+ * and to <destroy> this object (to avoid memory leaks)! If you
+ * don't want this behavior make sure you override this method...
+ */
+ virtual int handle_close (ACE_HANDLE = ACE_INVALID_HANDLE,
+ ACE_Reactor_Mask = ACE_Event_Handler::ALL_EVENTS_MASK);
+
+ /// Default behavior when timeouts occur is to close down the
+ /// <Svc_Handler> by calling <handle_close>.
+ virtual int handle_timeout (const ACE_Time_Value &time,
+ const void *);
+
+ /// Get the underlying handle associated with the <peer_>.
+ virtual ACE_HANDLE get_handle (void) const;
+
+ /// Set the underlying handle associated with the <peer_>.
+ virtual void set_handle (ACE_HANDLE);
+
+ /// Returns the underlying PEER_STREAM. Used by
+ /// <ACE_Acceptor::accept> and <ACE_Connector::connect> factories
+ ACE_PEER_STREAM &peer (void) const;
+
+ /// Overloaded new operator. This method unobtrusively records if a
+ /// <Svc_Handler> is allocated dynamically, which allows it to clean
+ /// itself up correctly whether or not it's allocated statically or
+ /// dynamically.
+ void *operator new (size_t n);
+
+#if defined (ACE_HAS_NEW_NOTHROW)
+ /// Overloaded new operator, nothrow_t variant. Unobtrusively records if a
+ /// <Svc_Handler> is allocated dynamically, which allows it to clean
+ /// itself up correctly whether or not it's allocated statically or
+ /// dynamically.
+ void *operator new (size_t n, const nothrow_t&);
+#endif
+
+ /// This operator permits "placement new" on a per-object basis.
+ void * operator new (size_t n,
+ void *p);
+
+ /**
+ * Call this to free up dynamically allocated <Svc_Handlers>
+ * (otherwise you will get memory leaks). In general, you should
+ * call this method rather than <delete> since this method knows
+ * whether or not the object was allocated dynamically, and can act
+ * accordingly (i.e., deleting it if it was allocated dynamically).
+ */
+ virtual void destroy (void);
+
+ /**
+ * This really should be private so that users are forced to call
+ * <destroy>. Unfortunately, the C++ standard doesn't allow there
+ * to be a public new and a private delete. It is a bad idea to
+ * call this method directly, so use <destroy> instead, unless you
+ * know for sure that you've allocated the object dynamically.
+ */
+ void operator delete (void *);
+
+#if !defined (ACE_LACKS_PLACEMENT_OPERATOR_DELETE)
+ /**
+ * This operator is necessary to complement the class-specific
+ * operator new above. Unfortunately, it's not portable to all C++
+ * compilers...
+ */
+ void operator delete (void *, void *);
+#endif /* ACE_LACKS_PLACEMENT_OPERATOR_DELETE */
+
+ /// Close down the descriptor and unregister from the Reactor
+ void shutdown (void);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+public:
+
+ // = The following methods are not suppose to be public.
+
+ // Because friendship is *not* inherited in C++, these methods have
+ // to be public.
+
+ // = Accessors to set/get the connection recycler.
+
+ /// Set the recycler and the <recycling_act> that is used during
+ /// purging and caching.
+ virtual void recycler (ACE_Connection_Recycling_Strategy *recycler,
+ const void *recycling_act);
+
+ /// Get the recycler.
+ virtual ACE_Connection_Recycling_Strategy *recycler (void) const;
+
+ /// Get the recycling act.
+ virtual const void *recycling_act (void) const;
+
+ /**
+ * Upcall made by the recycler when it is about to recycle the
+ * connection. This gives the object a chance to prepare itself for
+ * recycling. Return 0 if the object is ready for recycling, -1 on
+ * failures.
+ */
+ virtual int recycle (void * = 0);
+
+protected:
+ /// Maintain connection with client.
+ ACE_PEER_STREAM peer_;
+
+ /// Have we been dynamically created?
+ int dynamic_;
+
+ /// Keeps track of whether we are in the process of closing (required
+ /// to avoid circular calls to <handle_close>).
+ char closing_;
+
+ /// Pointer to the connection recycler.
+ ACE_Connection_Recycling_Strategy *recycler_;
+
+ /// Asynchronous Completion Token (ACT) to be used to when talking to
+ /// the recycler.
+ const void *recycling_act_;
+};
+
+/**
+ * @class ACE_Buffered_Svc_Handler
+ *
+ * @brief Defines the interface for a service that exchanges data with
+ * its connected peer and supports buffering.
+ *
+ * The buffering feature makes it possible to queue up
+ * <ACE_Message_Blocks> in an <ACE_Message_Queue> until (1) the
+ * queue is "full" or (2) a period of time elapses, at which
+ * point the queue is "flushed" via <sendv_n> to the peer.
+ */
+template <ACE_PEER_STREAM_1, ACE_SYNCH_DECL>
+class ACE_Buffered_Svc_Handler : public ACE_Svc_Handler<ACE_PEER_STREAM_2, ACE_SYNCH_USE>
+{
+public:
+ // = Initialization and termination methods.
+ /**
+ * Constructor initializes the <thr_mgr> and <mq> by passing them
+ * down to the <ACE_Task> base class. The <reactor> is passed to
+ * the <ACE_Event_Handler>. The <max_buffer_size> and
+ * <relative_timeout> are used to determine at what point to flush
+ * the <mq>. By default, there's no buffering at all. The
+ * <relative_timeout> value is interpreted to be in a unit that's
+ * relative to the current time returned by <ACE_OS::gettimeofday>.
+ */
+ ACE_Buffered_Svc_Handler (ACE_Thread_Manager *thr_mgr = 0,
+ ACE_Message_Queue<ACE_SYNCH_USE> *mq = 0,
+ ACE_Reactor *reactor = ACE_Reactor::instance (),
+ size_t max_buffer_size = 0,
+ ACE_Time_Value *relative_timeout = 0);
+
+ /// Destructor, which calls <flush>.
+ virtual ~ACE_Buffered_Svc_Handler (void);
+
+ /**
+ * Insert the <ACE_Message_Block> chain rooted at <message_block>
+ * into the <ACE_Message_Queue> with the designated <timeout>. The
+ * <flush> method will be called if this <put> causes the number of
+ * bytes to exceed the maximum buffer size or if the timeout period
+ * has elapsed.
+ */
+ virtual int put (ACE_Message_Block *message_block,
+ ACE_Time_Value *timeout = 0);
+
+ /// Flush the <ACE_Message_Queue>, which writes all the queued
+ /// <ACE_Message_Block>s to the <PEER_STREAM>.
+ virtual int flush (void);
+
+ /// This method is not currently implemented -- this is where the
+ /// integration with the <Reactor> would occur.
+ virtual int handle_timeout (const ACE_Time_Value &time,
+ const void *);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+protected:
+ /// Maximum size the <Message_Queue> can be before we have to flush
+ /// the buffer.
+ size_t maximum_buffer_size_;
+
+ /// Current size in bytes of the <Message_Queue> contents.
+ size_t current_buffer_size_;
+
+ /// Timeout value used to control when the buffer is flushed.
+ ACE_Time_Value next_timeout_;
+
+ /// Interval of the timeout.
+ ACE_Time_Value interval_;
+
+ /// Timeout pointer.
+ ACE_Time_Value *timeoutp_;
+};
+
+#if defined (ACE_TEMPLATES_REQUIRE_SOURCE)
+#include "ace/Svc_Handler.cpp"
+#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */
+
+#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA)
+#pragma implementation ("Svc_Handler.cpp")
+#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */
+
+#include "ace/post.h"
+#endif /* ACE_SVC_HANDLER_H */
diff --git a/ace/Svcconf/svc_export.h b/ace/Svcconf/svc_export.h
new file mode 100644
index 00000000000..b10b4f33bc5
--- /dev/null
+++ b/ace/Svcconf/svc_export.h
@@ -0,0 +1,44 @@
+// -*- C++ -*-
+// $Id$
+// Definition for Win32 Export directives.
+
+// This file was generated by generate_export_file.pl
+// but needed to be altered to support ACE_BUILD_SVC_DLL
+// instead of ACE_SVC_BUILD_DLL which was already being
+// used.
+
+// ------------------------------
+#if !defined (ACE_SVC_EXPORT_H)
+#define ACE_SVC_EXPORT_H
+
+#include "ace/config-all.h"
+
+#if defined (ACE_AS_STATIC_LIBS) && !defined (ACE_SVC_HAS_DLL)
+# define ACE_SVC_HAS_DLL 0
+#endif /* ACE_AS_STATIC_LIBS && ACE_SVC_HAS_DLL */
+
+#if !defined (ACE_SVC_HAS_DLL)
+#define ACE_SVC_HAS_DLL 1
+#endif /* ! ACE_SVC_HAS_DLL */
+
+#if defined (ACE_SVC_HAS_DLL)
+# if (ACE_SVC_HAS_DLL == 1)
+# if defined (ACE_BUILD_SVC_DLL) || defined (ACE_SVC_BUILD_DLL)
+# define ACE_Svc_Export ACE_Proper_Export_Flag
+# define ACE_SVC_SINGLETON_DECLARATION(T) ACE_EXPORT_SINGLETON_DECLARATION (T)
+# else
+# define ACE_Svc_Export ACE_Proper_Import_Flag
+# define ACE_SVC_SINGLETON_DECLARATION(T) ACE_IMPORT_SINGLETON_DECLARATION (T)
+# endif /* ACE_BUILD_SVC_DLL */
+# else
+# define ACE_Svc_Export
+# define ACE_SVC_SINGLETON_DECLARATION(T)
+# endif /* ! ACE_SVC_HAS_DLL == 1 */
+#else
+# define ACE_Svc_Export
+# define ACE_SVC_SINGLETON_DECLARATION(T)
+#endif /* ACE_SVC_HAS_DLL */
+
+#endif /* ACE_SVC_EXPORT_H */
+
+// End of auto generated file.
diff --git a/ace/Threads/Activation_Queue.cpp b/ace/Threads/Activation_Queue.cpp
new file mode 100644
index 00000000000..0463b8178a7
--- /dev/null
+++ b/ace/Threads/Activation_Queue.cpp
@@ -0,0 +1,109 @@
+// $Id$
+
+#include "ace/Threads/Activation_Queue.h"
+
+#if !defined (__ACE_INLINE__)
+#include "ace/Threads/Activation_Queue.i"
+#endif /* __ACE_INLINE__ */
+
+ACE_RCSID(ace, Activation_Queue, "$Id$")
+
+// Dump the state of an object.
+
+void
+ACE_Activation_Queue::dump (void) const
+{
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_LIB_TEXT ("delete_queue_ = %d\n"),
+ this->delete_queue_));
+ ACE_DEBUG ((LM_INFO, ACE_LIB_TEXT ("queue_: \n")));
+ if (this->queue_)
+ this->queue_->dump();
+ else
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("(NULL)\n")));
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+ACE_Activation_Queue::ACE_Activation_Queue (ACE_Message_Queue<ACE_SYNCH> *new_queue,
+ ACE_Allocator *alloc,
+ ACE_Allocator *db_alloc)
+ : delete_queue_ (0)
+ , allocator_(alloc)
+ , data_block_allocator_(db_alloc)
+{
+ if (this->allocator_ == 0)
+ this->allocator_ = ACE_Allocator::instance ();
+
+ if (new_queue)
+ this->queue_ = new_queue;
+ else
+ {
+ ACE_NEW (this->queue_,
+ ACE_Message_Queue<ACE_SYNCH>);
+ this->delete_queue_ = 1;
+ }
+}
+
+ACE_Activation_Queue::~ACE_Activation_Queue (void)
+{
+ if (this->delete_queue_ != 0)
+ delete this->queue_;
+}
+
+ACE_Method_Request *
+ACE_Activation_Queue::dequeue (ACE_Time_Value *tv)
+{
+ ACE_Message_Block *mb;
+
+ // Dequeue the message.
+ if (this->queue_->dequeue_head (mb, tv) != -1)
+ {
+ // Get the next <Method_Request>.
+ ACE_Method_Request *mr =
+ ACE_reinterpret_cast (ACE_Method_Request *,
+ mb->base ());
+ // Delete the message block.
+ mb->release ();
+ return mr;
+ }
+ else
+ return 0;
+}
+
+int
+ACE_Activation_Queue::enqueue (ACE_Method_Request *mr,
+ ACE_Time_Value *tv)
+{
+ ACE_Message_Block *mb;
+
+ // We pass sizeof (*mr) here so that flow control will work
+ // correctly. Since we also pass <mr> note that no unnecessary
+ // memory is actually allocated -- just the size field is set.
+ ACE_NEW_MALLOC_RETURN (mb,
+ ACE_static_cast(ACE_Message_Block *,
+ this->allocator_->malloc (sizeof (ACE_Message_Block))),
+ ACE_Message_Block (sizeof (*mr), // size
+ ACE_Message_Block::MB_DATA, // type
+ 0, // cont
+ (char *) mr, // data
+ 0, // allocator
+ 0, // locking strategy
+ mr->priority (), // priority
+ ACE_Time_Value::zero, // execution time
+ ACE_Time_Value::max_time, // absolute time of deadline
+ this->data_block_allocator_, // data_block allocator
+ this->allocator_), // message_block allocator
+ -1);
+
+ // Enqueue in priority order.
+ int result = this->queue_->enqueue_prio (mb, tv);
+
+ // Free ACE_Message_Block if enqueue_prio failed.
+ if (result == -1)
+ ACE_DES_FREE (mb, this->allocator_->free, ACE_Message_Block);
+
+ return result;
+}
+
+
diff --git a/ace/Threads/Activation_Queue.h b/ace/Threads/Activation_Queue.h
new file mode 100644
index 00000000000..c6fe043c502
--- /dev/null
+++ b/ace/Threads/Activation_Queue.h
@@ -0,0 +1,109 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Activation_Queue.h
+ *
+ * $Id$
+ *
+ * @author Andres Kruse <Andres.Kruse@cern.ch>
+ * @author Douglas C. Schmidt <schmidt@cs.wustl.edu>
+ */
+//=============================================================================
+
+#ifndef ACE_ACTIVATION_QUEUE_H
+#define ACE_ACTIVATION_QUEUE_H
+#include "ace/pre.h"
+
+#include "ace/Threads/Synch_T.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "ace/Threads/Message_Queue.h"
+#include "ace/Method_Request.h"
+
+// Be compatible with the terminology in the POSA2 book!
+#define ACE_Activation_List ACE_Activation_Queue
+
+/**
+ * @class ACE_Activation_Queue
+ *
+ * @brief Reifies a method into a request. Subclasses typically
+ * represent necessary state and behavior.
+ *
+ * A <Method_Request> is inserted in the <Activation_Queue>,
+ * where it is subsequently removed by the <Scheduler>, which
+ * invokes its <call> method..
+ */
+class ACE_Export ACE_Activation_Queue
+{
+public:
+ // = Initialization and termination methods.
+ /// Constructor.
+ ACE_Activation_Queue (ACE_Message_Queue<ACE_SYNCH> *new_queue = 0,
+ ACE_Allocator *alloc = 0,
+ ACE_Allocator *db_alloc = 0);
+
+ /// Destructor.
+ virtual ~ACE_Activation_Queue (void);
+
+ // = Activate Queue operations.
+
+ // For the following two methods if <timeout> == 0, the caller will
+ // block until action is possible, else will wait until the absolute
+ // time specified in *<timeout> elapses. These calls will return,
+ // however, when queue is closed, deactivated, when a signal occurs,
+ // or if the time specified in timeout elapses, (in which case errno
+ // = EWOULDBLOCK).
+
+ /// Dequeue the next available <Method_Request>.
+ ACE_Method_Request *dequeue (ACE_Time_Value *tv = 0);
+
+ /// Enqueue the <Method_Request> in priority order. The priority is
+ /// determined by the <priority> method of the <new_message_request>.
+ int enqueue (ACE_Method_Request *new_method_request,
+ ACE_Time_Value *tv = 0);
+
+ /// Get the current number of method objects in the queue.
+ int method_count (void) const;
+
+ /// Returns 1 if the queue is empty, 0 otherwise.
+ int is_empty (void) const;
+
+ /// Returns 1 if the queue is full, 0 otherwise.
+ int is_full (void) const;
+
+ /// Dump the state of an request.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+protected:
+ /// Stores the <Method_Requests>.
+ ACE_Message_Queue<ACE_SYNCH> *queue_;
+
+ /// Keeps track of whether we need to delete the queue.
+ int delete_queue_;
+
+private:
+ /// Allocation strategy of the queue.
+ ACE_Allocator *allocator_;
+
+ /// Allocation strategy of the message blocks.
+ ACE_Allocator *data_block_allocator_;
+
+ // = Prevent assignment and initialization.
+ ACE_UNIMPLEMENTED_FUNC (void operator= (const ACE_Activation_Queue &))
+ ACE_UNIMPLEMENTED_FUNC (ACE_Activation_Queue (const ACE_Activation_Queue &))
+};
+
+#if defined (__ACE_INLINE__)
+#include "ace/Activation_Queue.i"
+#endif /* __ACE_INLINE__ */
+
+#include "ace/post.h"
+#endif /* ACE_ACTIVATION_QUEUE_H */
+
diff --git a/ace/Threads/Activation_Queue.i b/ace/Threads/Activation_Queue.i
new file mode 100644
index 00000000000..0a70b9f6c49
--- /dev/null
+++ b/ace/Threads/Activation_Queue.i
@@ -0,0 +1,22 @@
+/* -*- C++ -*- */
+// $Id$
+
+// Activation_Queue.i
+
+ACE_INLINE int
+ACE_Activation_Queue::method_count (void) const
+{
+ return queue_->message_count ();
+}
+
+ACE_INLINE int
+ACE_Activation_Queue::is_full (void) const
+{
+ return queue_->is_full ();
+}
+
+ACE_INLINE int
+ACE_Activation_Queue::is_empty (void) const
+{
+ return queue_->is_empty ();
+}
diff --git a/ace/Threads/Atomic_Op.cpp b/ace/Threads/Atomic_Op.cpp
new file mode 100644
index 00000000000..df82902efcb
--- /dev/null
+++ b/ace/Threads/Atomic_Op.cpp
@@ -0,0 +1,83 @@
+#ifndef ACE_ATOMIC_OP_C
+#define ACE_ATOMIC_OP_C
+
+#include "ace/Atomic_Op.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#if !defined (__ACE_INLINE__)
+// On non-Win32 platforms, this code will be treated as normal code.
+#if !defined (ACE_WIN32)
+#include "ace/Atomic_Op.i"
+#endif /* !ACE_WIN32 */
+#endif /* __ACE_INLINE__ */
+
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Atomic_Op_Ex)
+ACE_ALLOC_HOOK_DEFINE(ACE_Atomic_Op)
+
+ACE_RCSID(ace, Atomic_Op, "$Id$")
+
+// *************************************************
+template <class ACE_LOCK, class TYPE> ACE_LOCK &
+ACE_Atomic_Op_Ex<ACE_LOCK, TYPE>::mutex (void)
+{
+ // ACE_TRACE ("ACE_Atomic_Op_Ex<ACE_LOCK, TYPE>::mutex");
+ return this->mutex_;
+}
+
+template <class ACE_LOCK, class TYPE> void
+ACE_Atomic_Op_Ex<ACE_LOCK, TYPE>::dump (void) const
+{
+ // ACE_TRACE ("ACE_Atomic_Op_Ex<ACE_LOCK, TYPE>::dump");
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+ this->mutex_.dump ();
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+template <class ACE_LOCK, class TYPE>
+ACE_Atomic_Op_Ex<ACE_LOCK, TYPE>::ACE_Atomic_Op_Ex
+ (ACE_LOCK &mtx)
+ : mutex_ (mtx),
+ value_ (0)
+{
+ // ACE_TRACE ("ACE_Atomic_Op_Ex<ACE_LOCK, TYPE>::ACE_Atomic_Op_Ex");
+}
+
+template <class ACE_LOCK, class TYPE>
+ACE_Atomic_Op_Ex<ACE_LOCK, TYPE>::ACE_Atomic_Op_Ex
+ (ACE_LOCK &mtx, const TYPE &c)
+ : mutex_ (mtx),
+ value_ (c)
+{
+// ACE_TRACE ("ACE_Atomic_Op_Ex<ACE_LOCK, TYPE>::ACE_Atomic_Op_Ex");
+}
+
+// ****************************************************************
+
+template <class ACE_LOCK, class TYPE>
+ACE_Atomic_Op<ACE_LOCK, TYPE>::ACE_Atomic_Op (void)
+ : ACE_Atomic_Op_Ex < ACE_LOCK,TYPE > (this->own_mutex_)
+{
+ // ACE_TRACE ("ACE_Atomic_Op<ACE_LOCK, TYPE>::ACE_Atomic_Op");
+}
+
+template <class ACE_LOCK, class TYPE>
+ACE_Atomic_Op<ACE_LOCK, TYPE>::ACE_Atomic_Op (const TYPE &c)
+ : ACE_Atomic_Op_Ex < ACE_LOCK,TYPE > (this->own_mutex_, c)
+{
+ // ACE_TRACE ("ACE_Atomic_Op<ACE_LOCK, TYPE>::ACE_Atomic_Op");
+}
+
+template <class ACE_LOCK, class TYPE> ACE_INLINE
+ACE_Atomic_Op<ACE_LOCK, TYPE>::ACE_Atomic_Op
+ (const ACE_Atomic_Op<ACE_LOCK, TYPE> &rhs)
+ : ACE_Atomic_Op_Ex < ACE_LOCK,TYPE >
+ ( this->own_mutex_, rhs.value() )
+{
+// ACE_TRACE ("ACE_Atomic_Op<ACE_LOCK, TYPE>::ACE_Atomic_Op");
+}
+
+#endif /*ACE_ATOMIC_OP */
diff --git a/ace/Threads/Atomic_Op.h b/ace/Threads/Atomic_Op.h
new file mode 100644
index 00000000000..42e5f15ba08
--- /dev/null
+++ b/ace/Threads/Atomic_Op.h
@@ -0,0 +1,191 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Atomic_Op.h
+ *
+ * $Id$
+ *
+ * @author Douglas C. Schmidt <schmidt@uci.edu>
+ */
+//=============================================================================
+
+#ifndef ACE_ATOMIC_OP_H
+#define ACE_ATOMIC_OP_H
+#include "ace/pre.h"
+
+#include "ace/config-all.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "ace/Synch.h"
+
+
+/**
+ * @class ACE_Atomic_Op_Ex
+ *
+ * @brief Transparently parameterizes synchronization into basic
+ * arithmetic operations.
+ *
+ * This class is described in an article in the July/August 1994
+ * issue of the C++ Report magazine. It implements a
+ * templatized version of the Decorator pattern from the GoF book.
+ */
+template <class ACE_LOCK, class TYPE>
+class ACE_Atomic_Op_Ex
+{
+public:
+ // = Initialization methods.
+
+ /// Initialize <value_> to 0.
+ ACE_Atomic_Op_Ex (ACE_LOCK &mtx);
+
+ /// Initialize <value_> to c.
+ ACE_Atomic_Op_Ex (ACE_LOCK &mtx, const TYPE &c);
+
+ // = Accessors.
+
+ /// Atomically pre-increment <value_>.
+ TYPE operator++ (void);
+
+ /// Atomically post-increment <value_>.
+ TYPE operator++ (int);
+
+ /// Atomically increment <value_> by i.
+ TYPE operator+= (const TYPE &i);
+
+ /// Atomically pre-decrement <value_>.
+ TYPE operator-- (void);
+
+ /// Atomically post-decrement <value_>.
+ TYPE operator-- (int);
+
+ /// Atomically decrement <value_> by i.
+ TYPE operator-= (const TYPE &i);
+
+ /// Atomically compare <value_> with i.
+ int operator== (const TYPE &i) const;
+
+ /// Atomically compare <value_> with i.
+ int operator!= (const TYPE &i) const;
+
+ /// Atomically check if <value_> greater than or equal to i.
+ int operator>= (const TYPE &i) const;
+
+ /// Atomically check if <value_> greater than i.
+ int operator> (const TYPE &rhs) const;
+
+ /// Atomically check if <value_> less than or equal to i.
+ int operator<= (const TYPE &rhs) const;
+
+ /// Atomically check if <value_> less than i.
+ int operator< (const TYPE &rhs) const;
+
+ /// Atomically assign i to <value_>.
+ void operator= (const TYPE &i);
+
+ /// Atomically assign <rhs> to <value_>.
+ void operator= (const ACE_Atomic_Op_Ex<ACE_LOCK, TYPE> &rhs);
+
+ /// Explicitly return <value_>.
+ TYPE value (void) const;
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ // ACE_ALLOC_HOOK_DECLARE;
+ // Declare the dynamic allocation hooks.
+
+ /// Manage copying...
+ ACE_Atomic_Op_Ex (const ACE_Atomic_Op_Ex<ACE_LOCK, TYPE> &);
+
+ /**
+ * Returns a reference to the underlying <ACE_LOCK>. This makes it
+ * possible to acquire the lock explicitly, which can be useful in
+ * some cases if you instantiate the <ACE_Atomic_Op> with an
+ * <ACE_Recursive_Mutex> or <ACE_Process_Mutex>. NOTE: the right
+ * name would be lock_, but HP/C++ will choke on that!
+ */
+ ACE_LOCK &mutex (void);
+
+ /**
+ * Explicitly return <value_> (by reference). This gives the user
+ * full, unrestricted access to the underlying value. This method
+ * will usually be used in conjunction with explicit access to the
+ * lock. Use with care ;-)
+ */
+ TYPE &value_i (void);
+
+private:
+ /// Type of synchronization mechanism.
+ ACE_LOCK &mutex_;
+
+ /// Current object decorated by the atomic op.
+ TYPE value_;
+};
+
+template <class ACE_LOCK, class TYPE>
+class ACE_Atomic_Op : public ACE_Atomic_Op_Ex <ACE_LOCK, TYPE>
+{
+public:
+ /// Initialize <value_> to 0.
+ ACE_Atomic_Op (void);
+
+ /// Initialize <value_> to c.
+ ACE_Atomic_Op (const TYPE &c);
+
+ /// Manage copying...
+ ACE_Atomic_Op (const ACE_Atomic_Op<ACE_LOCK, TYPE> &);
+
+ /// Atomically assign i to <value_>.
+ void operator= (const TYPE &i);
+
+ /// Atomically assign <rhs> to <value_>.
+ void operator= (const ACE_Atomic_Op_Ex<ACE_LOCK, TYPE> &rhs);
+
+private:
+ /// Type of synchronization mechanism.
+ ACE_LOCK own_mutex_;
+};
+
+
+#if defined (__ACE_INLINE__)
+// On non-Win32 platforms, this code will be inlined
+#if !defined (ACE_WIN32)
+#include "ace/Atomic_Op.i"
+#endif /* !ACE_WIN32 */
+#endif /* __ACE_INLINE__ */
+
+#if defined (ACE_TEMPLATES_REQUIRE_SOURCE)
+
+#include "Atomic_Op.cpp"
+// On Win32 platforms, this code will be included as template source
+// code and will not be inlined. Therefore, we first turn off
+// ACE_INLINE, set it to be nothing, include the code, and then turn
+// ACE_INLINE back to its original setting. All this nonsense is
+// necessary, since the generic template code that needs to be
+// specialized cannot be inlined, else the compiler will ignore the
+// specialization code. Also, the specialization code *must* be
+// inlined or the compiler will ignore the specializations.
+#if defined (ACE_WIN32)
+#undef ACE_INLINE
+#define ACE_INLINE
+#include "ace/Atomic_Op.i"
+#undef ACE_INLINE
+#if defined (__ACE_INLINE__)
+#define ACE_INLINE inline
+#else
+#define ACE_INLINE
+#endif /* __ACE_INLINE__ */
+#endif /* ACE_WIN32 */
+#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */
+
+
+#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA)
+#pragma implementation ("Atomic_Op.cpp")
+#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */
+
+#include "ace/post.h"
+#endif /*ACE_ATOMIC_OP_H*/
diff --git a/ace/Threads/Atomic_Op.i b/ace/Threads/Atomic_Op.i
new file mode 100644
index 00000000000..33ee42fa79f
--- /dev/null
+++ b/ace/Threads/Atomic_Op.i
@@ -0,0 +1,219 @@
+// -*- C++ -*-
+// $Id$
+
+template <class ACE_LOCK, class TYPE> ACE_INLINE TYPE
+ACE_Atomic_Op_Ex<ACE_LOCK, TYPE>::operator++ (void)
+{
+// ACE_TRACE ("ACE_Atomic_Op_Ex<ACE_LOCK, TYPE>::operator++");
+ ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, this->value_);
+ return ++this->value_;
+}
+
+template <class ACE_LOCK, class TYPE> ACE_INLINE TYPE
+ACE_Atomic_Op_Ex<ACE_LOCK, TYPE>::operator+= (const TYPE &i)
+{
+// ACE_TRACE ("ACE_Atomic_Op_Ex<ACE_LOCK, TYPE>::operator+=");
+ ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, this->value_);
+ return this->value_ += i;
+}
+
+template <class ACE_LOCK, class TYPE> ACE_INLINE TYPE
+ACE_Atomic_Op_Ex<ACE_LOCK, TYPE>::operator-- (void)
+{
+// ACE_TRACE ("ACE_Atomic_Op_Ex<ACE_LOCK, TYPE>::operator--");
+ ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, this->value_);
+ return --this->value_;
+}
+
+template <class ACE_LOCK, class TYPE> ACE_INLINE TYPE
+ACE_Atomic_Op_Ex<ACE_LOCK, TYPE>::operator-= (const TYPE &i)
+{
+// ACE_TRACE ("ACE_Atomic_Op_Ex<ACE_LOCK, TYPE>::operator-=");
+ ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, this->value_);
+ return this->value_ -= i;
+}
+
+template <class ACE_LOCK, class TYPE> ACE_INLINE
+ACE_Atomic_Op_Ex<ACE_LOCK, TYPE>::ACE_Atomic_Op_Ex (const ACE_Atomic_Op_Ex<ACE_LOCK, TYPE> &rhs)
+ : mutex_ (rhs.mutex_)
+{
+// ACE_TRACE ("ACE_Atomic_Op_Ex<ACE_LOCK, TYPE>::ACE_Atomic_Op_Ex");
+ *this = rhs; // Invoke the assignment operator.
+}
+
+template <class ACE_LOCK, class TYPE> ACE_INLINE TYPE
+ACE_Atomic_Op_Ex<ACE_LOCK, TYPE>::operator++ (int)
+{
+// ACE_TRACE ("ACE_Atomic_Op_Ex<ACE_LOCK, TYPE>::operator++");
+ ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, this->value_);
+ return this->value_++;
+}
+
+template <class ACE_LOCK, class TYPE> ACE_INLINE TYPE
+ACE_Atomic_Op_Ex<ACE_LOCK, TYPE>::operator-- (int)
+{
+// ACE_TRACE ("ACE_Atomic_Op_Ex<ACE_LOCK, TYPE>::operator--");
+ ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, this->value_);
+ return this->value_--;
+}
+
+template <class ACE_LOCK, class TYPE> ACE_INLINE int
+ACE_Atomic_Op_Ex<ACE_LOCK, TYPE>::operator== (const TYPE &i) const
+{
+// ACE_TRACE ("ACE_Atomic_Op_Ex<ACE_LOCK, TYPE>::operator==");
+ ACE_GUARD_RETURN (ACE_LOCK, ace_mon, (ACE_LOCK &) this->mutex_, -1);
+ return this->value_ == i;
+}
+
+template <class ACE_LOCK, class TYPE> ACE_INLINE int
+ACE_Atomic_Op_Ex<ACE_LOCK, TYPE>::operator!= (const TYPE &i) const
+{
+// ACE_TRACE ("ACE_Atomic_Op_Ex<ACE_LOCK, TYPE>::operator!=");
+ return !(*this == i);
+}
+
+template <class ACE_LOCK, class TYPE> ACE_INLINE int
+ACE_Atomic_Op_Ex<ACE_LOCK, TYPE>::operator>= (const TYPE &i) const
+{
+// ACE_TRACE ("ACE_Atomic_Op_Ex<ACE_LOCK, TYPE>::operator>=");
+ ACE_GUARD_RETURN (ACE_LOCK, ace_mon, (ACE_LOCK &) this->mutex_, -1);
+ return this->value_ >= i;
+}
+
+template <class ACE_LOCK, class TYPE> ACE_INLINE int
+ACE_Atomic_Op_Ex<ACE_LOCK, TYPE>::operator> (const TYPE &rhs) const
+{
+// ACE_TRACE ("ACE_Atomic_Op_Ex<ACE_LOCK, TYPE>::operator>");
+ ACE_GUARD_RETURN (ACE_LOCK, ace_mon, (ACE_LOCK &) this->mutex_, -1);
+ return this->value_ > rhs;
+}
+
+template <class ACE_LOCK, class TYPE> ACE_INLINE int
+ACE_Atomic_Op_Ex<ACE_LOCK, TYPE>::operator<= (const TYPE &rhs) const
+{
+// ACE_TRACE ("ACE_Atomic_Op_Ex<ACE_LOCK, TYPE>::operator<=");
+ ACE_GUARD_RETURN (ACE_LOCK, ace_mon, (ACE_LOCK &) this->mutex_, -1);
+ return this->value_ <= rhs;
+}
+
+template <class ACE_LOCK, class TYPE> ACE_INLINE int
+ACE_Atomic_Op_Ex<ACE_LOCK, TYPE>::operator< (const TYPE &rhs) const
+{
+// ACE_TRACE ("ACE_Atomic_Op_Ex<ACE_LOCK, TYPE>::operator<");
+ ACE_GUARD_RETURN (ACE_LOCK, ace_mon, (ACE_LOCK &) this->mutex_, -1);
+ return this->value_ < rhs;
+}
+
+template <class ACE_LOCK, class TYPE> ACE_INLINE void
+ACE_Atomic_Op_Ex<ACE_LOCK, TYPE>::operator= (const ACE_Atomic_Op_Ex<ACE_LOCK, TYPE> &rhs)
+{
+// ACE_TRACE ("ACE_Atomic_Op_Ex<ACE_LOCK, TYPE>::operator=");
+ if (&rhs == this)
+ return; // Avoid deadlock...
+ ACE_GUARD (ACE_LOCK, ace_mon, this->mutex_);
+ // This will call ACE_Atomic_Op_Ex::TYPE(), which will ensure the value
+ // of <rhs> is acquired atomically.
+
+ this->value_ = rhs.value ();
+}
+
+template <class ACE_LOCK, class TYPE> ACE_INLINE TYPE
+ACE_Atomic_Op_Ex<ACE_LOCK, TYPE>::value (void) const
+{
+// ACE_TRACE ("ACE_Atomic_Op_Ex<ACE_LOCK, TYPE>::value");
+ ACE_GUARD_RETURN (ACE_LOCK, ace_mon, (ACE_LOCK &) this->mutex_, this->value_);
+ return this->value_;
+}
+
+template <class ACE_LOCK, class TYPE> ACE_INLINE TYPE &
+ACE_Atomic_Op_Ex<ACE_LOCK, TYPE>::value_i (void)
+{
+ // Explicitly return <value_> (by reference). This gives the user
+ // full, unrestricted access to the underlying value. This method
+ // will usually be used in conjunction with explicit access to the
+ // lock. Use with care ;-)
+ return this->value_;
+}
+
+template <class ACE_LOCK, class TYPE> ACE_INLINE void
+ACE_Atomic_Op_Ex<ACE_LOCK, TYPE>::operator= (const TYPE &i)
+{
+// ACE_TRACE ("ACE_Atomic_Op_Ex<ACE_LOCK, TYPE>::operator=");
+ ACE_GUARD (ACE_LOCK, ace_mon, (ACE_LOCK &) this->mutex_);
+ this->value_ = i;
+}
+
+//
+// ACE_Atomic_Op inline functions
+//
+
+template <class ACE_LOCK, class TYPE> ACE_INLINE void
+ACE_Atomic_Op<ACE_LOCK, TYPE>::operator= (const TYPE &i)
+{
+ ACE_Atomic_Op_Ex <ACE_LOCK,TYPE> ::operator= (i);
+}
+
+template <class ACE_LOCK, class TYPE> ACE_INLINE void
+ACE_Atomic_Op<ACE_LOCK, TYPE>::operator= (const ACE_Atomic_Op_Ex<ACE_LOCK, TYPE> &rhs)
+{
+ ACE_Atomic_Op_Ex <ACE_LOCK,TYPE> ::operator= (rhs);
+}
+
+// These specializations have been added to ACE_Atomic_Op_Ex to make the
+// implementation faster on Win32 that has OS support for doing this
+// quickly through methods like InterlockedIncrement and
+// InterlockedDecrement
+
+#if defined (ACE_WIN32)
+
+// FUZZ: disable check_for_inline
+
+ACE_TEMPLATE_SPECIALIZATION
+inline long
+ACE_Atomic_Op_Ex<ACE_Thread_Mutex, long>::operator++ (void)
+{
+ return ::InterlockedIncrement (&this->value_);
+}
+
+ACE_TEMPLATE_SPECIALIZATION
+inline long
+ACE_Atomic_Op_Ex<ACE_Thread_Mutex, long>::operator-- (void)
+{
+ return ::InterlockedDecrement (&this->value_);
+}
+
+ACE_TEMPLATE_SPECIALIZATION
+inline void
+ACE_Atomic_Op_Ex<ACE_Thread_Mutex, long>::operator= (const long &i)
+{
+ ::InterlockedExchange (&this->value_,
+ i);
+}
+
+ACE_TEMPLATE_SPECIALIZATION
+inline void
+ACE_Atomic_Op_Ex<ACE_Thread_Mutex, long>::operator= (const ACE_Atomic_Op_Ex<ACE_Thread_Mutex, long> &rhs)
+{
+ ::InterlockedExchange (&this->value_,
+ rhs.value ());
+}
+
+#if defined (ACE_HAS_INTERLOCKED_EXCHANGEADD)
+
+ACE_TEMPLATE_SPECIALIZATION
+inline long
+ACE_Atomic_Op_Ex<ACE_Thread_Mutex, long>::operator+= (const long &i)
+{
+ return ::InterlockedExchangeAdd (&this->value_, i);
+}
+
+ACE_TEMPLATE_SPECIALIZATION
+inline long
+ACE_Atomic_Op_Ex<ACE_Thread_Mutex, long>::operator-= (const long &i)
+{
+ return ::InterlockedExchangeAdd (&this->value_, -i);
+}
+
+#endif /* ACE_HAS_INTERLOCKED_EXCHANGEADD */
+
+#endif /* ACE_WIN32 */
diff --git a/ace/Threads/File_Lock.cpp b/ace/Threads/File_Lock.cpp
new file mode 100644
index 00000000000..7f9c3048aa7
--- /dev/null
+++ b/ace/Threads/File_Lock.cpp
@@ -0,0 +1,78 @@
+// $Id$
+
+#include "ace/File_Lock.h"
+#include "ace/Log_Msg.h"
+
+#if !defined (__ACE_INLINE__)
+#include "ace/File_Lock.inl"
+#endif /* __ACE_INLINE__ */
+
+ACE_RCSID(ace, File_Lock, "$Id$")
+
+ACE_ALLOC_HOOK_DEFINE(ACE_File_Lock)
+
+void
+ACE_File_Lock::dump (void) const
+{
+// ACE_TRACE ("ACE_File_Lock::dump");
+
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+ this->lock_.dump ();
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+ACE_File_Lock::ACE_File_Lock (ACE_HANDLE h,
+ int unlink_in_destructor)
+ : removed_ (0),
+ unlink_in_destructor_ (unlink_in_destructor)
+{
+// ACE_TRACE ("ACE_File_Lock::ACE_File_Lock");
+ if (ACE_OS::flock_init (&this->lock_) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("%p\n"),
+ ACE_LIB_TEXT ("ACE_File_Lock::ACE_File_Lock")));
+ this->set_handle (h);
+}
+
+ACE_File_Lock::ACE_File_Lock (const ACE_TCHAR *name,
+ int flags,
+ mode_t perms,
+ int unlink_in_destructor)
+ : unlink_in_destructor_ (unlink_in_destructor)
+{
+// ACE_TRACE ("ACE_File_Lock::ACE_File_Lock");
+
+ if (this->open (name, flags, perms) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("%p %s\n"),
+ ACE_LIB_TEXT ("ACE_File_Lock::ACE_File_Lock"),
+ name));
+}
+
+int
+ACE_File_Lock::open (const ACE_TCHAR *name,
+ int flags,
+ mode_t perms)
+{
+// ACE_TRACE ("ACE_File_Lock::open");
+ this->removed_ = 0;
+ return ACE_OS::flock_init (&this->lock_, flags, name, perms);
+}
+
+ACE_File_Lock::~ACE_File_Lock (void)
+{
+// ACE_TRACE ("ACE_File_Lock::~ACE_File_Lock");
+ this->remove (this->unlink_in_destructor_);
+}
+
+// These are instantiated both with and without ACE_HAS_THREADS.
+
+#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION)
+
+// template class ACE_Guard<ACE_File_Lock>;
+
+#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA)
+
+// #pragma instantiate ACE_Guard<ACE_File_Lock>
+
+#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */
diff --git a/ace/Threads/File_Lock.h b/ace/Threads/File_Lock.h
new file mode 100644
index 00000000000..afc549a0ff0
--- /dev/null
+++ b/ace/Threads/File_Lock.h
@@ -0,0 +1,164 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file File_Lock.h
+ *
+ * $Id$
+ *
+ * @author Douglas C. Schmidt <schmidt@cs.wustl.edu>
+ */
+//=============================================================================
+
+#ifndef ACE_FILE_LOCK_H
+#define ACE_FILE_LOCK_H
+#include "ace/pre.h"
+
+#include "ace/OS.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+/**
+ * @class ACE_File_Lock
+ *
+ * @brief A wrapper around the UNIX file locking mechanism.
+ *
+ * Allows us to "adapt" the UNIX file locking mechanisms to work
+ * with all of our Guard stuff...
+ */
+class ACE_Export ACE_File_Lock
+{
+public:
+ /**
+ * Set the <handle_> of the File_Lock to <handle>. Note that this
+ * constructor assumes ownership of the <handle> and will close it
+ * down in <remove>. If you want the <handle> to stay open when
+ * <remove> is called make sure to call <dup> on the <handle>.
+ * If you don't want the file unlinked in the destructor pass a
+ * zero value for <unlink_in_destructor>.
+ */
+ ACE_File_Lock (ACE_HANDLE handle = ACE_INVALID_HANDLE,
+ int unlink_in_destructor = 1);
+
+ /// Open the <filename> with <flags> and <mode> and set the result
+ /// to <handle_>. If you don't want the file unlinked in the
+ /// destructor pass a zero value for <unlink_in_destructor>.
+ ACE_File_Lock (const ACE_TCHAR *filename,
+ int flags,
+ mode_t mode = 0,
+ int unlink_in_destructor = 1);
+
+ /// Open the <filename> with <flags> and <mode> and set the result to
+ /// <handle_>.
+ int open (const ACE_TCHAR *filename,
+ int flags,
+ mode_t mode = 0);
+
+ /// Remove a File lock by releasing it and closing down the <handle_>.
+ ~ACE_File_Lock (void);
+
+ /// Remove a File lock by releasing it and closing down the
+ /// <handle_>. If <unlink_file> is non-0 then we unlink the file.
+ int remove (int unlink_file = 1);
+
+ /**
+ * Note, for interface uniformity with other synchronization
+ * wrappers we include the <acquire> method. This is implemented as
+ * a write-lock to be on the safe-side...
+ */
+ int acquire (short whence = 0, off_t start = 0, off_t len = 1);
+
+ /**
+ * Note, for interface uniformity with other synchronization
+ * wrappers we include the <tryacquire> method. This is implemented
+ * as a write-lock to be on the safe-side... Returns -1 on failure.
+ * If we "failed" because someone else already had the lock, <errno>
+ * is set to <EBUSY>.
+ */
+ int tryacquire (short whence = 0, off_t start = 0, off_t len = 1);
+
+ /// Unlock a readers/writer lock.
+ int release (short whence = 0, off_t start = 0, off_t len = 1);
+
+ /// Acquire a write lock, but block if any readers or a
+ /// writer hold the lock.
+ int acquire_write (short whence = 0, off_t start = 0, off_t len = 1);
+
+ /**
+ * Conditionally acquire a write lock (i.e., won't block). Returns
+ * -1 on failure. If we "failed" because someone else already had
+ * the lock, <errno> is set to <EBUSY>.
+ */
+ int tryacquire_write (short whence = 0, off_t start = 0, off_t len = 1);
+
+ /**
+ * Conditionally upgrade to a write lock (i.e., won't block). Returns
+ * -1 on failure. If we "failed" because someone else already had
+ * the lock, <errno> is set to <EBUSY>.
+ */
+ int tryacquire_write_upgrade (short whence = 0,
+ off_t start = 0,
+ off_t len = 1);
+
+ /**
+ * Acquire a read lock, but block if a writer hold the lock.
+ * Returns -1 on failure. If we "failed" because someone else
+ * already had the lock, <errno> is set to <EBUSY>.
+ */
+ int acquire_read (short whence = 0, off_t start = 0, off_t len = 1);
+
+ /**
+ * Conditionally acquire a read lock (i.e., won't block). Returns
+ * -1 on failure. If we "failed" because someone else already had
+ * the lock, <errno> is set to <EBUSY>.
+ */
+ int tryacquire_read (short whence = 0, off_t start = 0, off_t len = 1);
+
+ /// Get underlying <ACE_HANDLE> for the file.
+ ACE_HANDLE get_handle (void) const;
+
+ /**
+ * Set underlying <ACE_HANDLE>. Note that this method assumes
+ * ownership of the <handle> and will close it down in <remove>. If
+ * you want the <handle> to stay open when <remove> is called make
+ * sure to call <dup> on the <handle> before closing it. You are
+ * responsible for the closing the existing <handle> before
+ * overwriting it.
+ */
+ void set_handle (ACE_HANDLE);
+
+ /// Dump state of the object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+protected:
+ /// Locking structure for OS record locks.
+ ACE_OS::ace_flock_t lock_;
+
+ /// Keeps track of whether <remove> has been called yet to avoid
+ /// multiple <remove> calls, e.g., explicitly and implicitly in the
+ /// destructor. This flag isn't protected by a lock, so make sure
+ /// that you don't have multiple threads simultaneously calling
+ /// <remove> on the same object, which is a bad idea anyway...
+ int removed_;
+
+ /// Keeps track of whether to unlink the underlying file in the
+ /// destructor.
+ int unlink_in_destructor_;
+
+private:
+ // = Prevent assignment and initialization.
+ void operator= (const ACE_File_Lock &);
+ ACE_File_Lock (const ACE_File_Lock &);
+};
+
+#if defined (__ACE_INLINE__)
+#include "ace/File_Lock.inl"
+#endif /* __ACE_INLINE__ */
+
+#include "ace/post.h"
+#endif /* ACE_FILE_LOCK_H */
diff --git a/ace/Threads/File_Lock.inl b/ace/Threads/File_Lock.inl
new file mode 100644
index 00000000000..a0dc79dcc7b
--- /dev/null
+++ b/ace/Threads/File_Lock.inl
@@ -0,0 +1,89 @@
+/* -*- C++ -*- */
+// $Id$
+
+ACE_INLINE int
+ACE_File_Lock::acquire_read (short whence, off_t start, off_t len)
+{
+// ACE_TRACE ("ACE_File_Lock::acquire_read");
+ return ACE_OS::flock_rdlock (&this->lock_, whence, start, len);
+}
+
+ACE_INLINE int
+ACE_File_Lock::tryacquire_read (short whence, off_t start, off_t len)
+{
+// ACE_TRACE ("ACE_File_Lock::tryacquire_read");
+ return ACE_OS::flock_tryrdlock (&this->lock_, whence, start, len);
+}
+
+ACE_INLINE int
+ACE_File_Lock::tryacquire_write (short whence, off_t start, off_t len)
+{
+// ACE_TRACE ("ACE_File_Lock::tryacquire_write");
+ return ACE_OS::flock_trywrlock (&this->lock_, whence, start, len);
+}
+
+ACE_INLINE int
+ACE_File_Lock::tryacquire_write_upgrade (short whence, off_t start, off_t len)
+{
+// ACE_TRACE ("ACE_File_Lock::tryacquire_write_upgrade");
+ return ACE_OS::flock_trywrlock (&this->lock_, whence, start, len);
+}
+
+ACE_INLINE int
+ACE_File_Lock::tryacquire (short whence, off_t start, off_t len)
+{
+// ACE_TRACE ("ACE_File_Lock::tryacquire");
+ return this->tryacquire_write (whence, start, len);
+}
+
+ACE_INLINE int
+ACE_File_Lock::acquire_write (short whence, off_t start, off_t len)
+{
+// ACE_TRACE ("ACE_File_Lock::acquire_write");
+ return ACE_OS::flock_wrlock (&this->lock_, whence, start, len);
+}
+
+ACE_INLINE int
+ACE_File_Lock::acquire (short whence, off_t start, off_t len)
+{
+// ACE_TRACE ("ACE_File_Lock::acquire");
+ return this->acquire_write (whence, start, len);
+}
+
+ACE_INLINE int
+ACE_File_Lock::release (short whence, off_t start, off_t len)
+{
+// ACE_TRACE ("ACE_File_Lock::release");
+ return ACE_OS::flock_unlock (&this->lock_, whence, start, len);
+}
+
+ACE_INLINE int
+ACE_File_Lock::remove (int unlink_file)
+{
+// ACE_TRACE ("ACE_File_Lock::remove");
+
+ int result = 0;
+
+ if (this->removed_ == 0)
+ {
+ this->removed_ = 1;
+ result = ACE_OS::flock_destroy (&this->lock_,
+ unlink_file);
+ }
+ return result;
+}
+
+ACE_INLINE ACE_HANDLE
+ACE_File_Lock::get_handle (void) const
+{
+// ACE_TRACE ("ACE_File_Lock::get_handle");
+ return this->lock_.handle_;
+}
+
+ACE_INLINE void
+ACE_File_Lock::set_handle (ACE_HANDLE h)
+{
+// ACE_TRACE ("ACE_File_Lock::set_handle");
+ this->lock_.handle_ = h;
+ this->removed_ = 0;
+}
diff --git a/ace/Threads/Makefile b/ace/Threads/Makefile
new file mode 100644
index 00000000000..d75c4c95f54
--- /dev/null
+++ b/ace/Threads/Makefile
@@ -0,0 +1,65 @@
+# $Id$
+
+#----------------------------------------------------------------------------
+# Makefile for the libACE_Threads
+#----------------------------------------------------------------------------
+
+MAKEFILE = Makefile
+LIBOS = libACE_Threads
+LIB = $(LIBOS).a
+SHLIB = $(LIBOS).$(SOEXT)
+
+
+#----------------------------------------------------------------------------
+# Include macros and targets
+#----------------------------------------------------------------------------
+
+include $(ACE_ROOT)/include/makeinclude/wrapper_macros.GNU
+
+####
+#### ACE_COMPONENTS support.
+####
+FILES += \
+ Activation_Queue\
+ Atomic_Op\
+ File_Lock\
+ Process\
+ Process_Manager\
+ Process_Mutex\
+ Process_Semaphore\
+ RW_Process_Mutex\
+ Synch\
+ Synch_Options\
+ Synch_T\
+ Thread_Adapter\
+ Thread_Control\
+ Thread\
+ Thread_Exit\
+ Thread_Manager\
+ Token
+
+LSRC = $(addsuffix .cpp,$(FILES))
+
+include $(ACE_ROOT)/include/makeinclude/macros.GNU
+include $(ACE_ROOT)/include/makeinclude/rules.common.GNU
+include $(ACE_ROOT)/include/makeinclude/rules.nested.GNU
+include $(ACE_ROOT)/include/makeinclude/rules.lib.GNU
+include $(ACE_ROOT)/include/makeinclude/rules.local.GNU
+
+INSTALL =
+
+clean:
+ $(RM) -f $(LIBOS).a $(LIBOS).so
+
+#----------------------------------------------------------------------------
+# Local targets
+#----------------------------------------------------------------------------
+
+
+
+#----------------------------------------------------------------------------
+# Dependencies
+#----------------------------------------------------------------------------
+# DO NOT DELETE THIS LINE -- g++dep uses it.
+# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY.
+
diff --git a/ace/Threads/Process.cpp b/ace/Threads/Process.cpp
new file mode 100644
index 00000000000..932e355072a
--- /dev/null
+++ b/ace/Threads/Process.cpp
@@ -0,0 +1,893 @@
+// $Id$
+
+#include "ace/OS.h"
+#include "ace/Process.h"
+#include "ace/ARGV.h"
+#include "ace/Signal.h"
+#include "ace/SString.h"
+#include "ace/Log_Msg.h"
+
+#if !defined (__ACE_INLINE__)
+#include "ace/Process.i"
+#endif /* __ACE_INLINE__ */
+
+ACE_RCSID (ace, Process, "$Id$")
+
+ACE_Process::ACE_Process (void)
+ :
+#if !defined (ACE_WIN32)
+ child_id_ (ACE_INVALID_PID),
+#endif /* !defined (ACE_WIN32) */
+ exit_code_ (0)
+{
+#if defined (ACE_WIN32)
+ ACE_OS::memset ((void *) &this->process_info_,
+ 0,
+ sizeof this->process_info_);
+#endif /* ACE_WIN32 */
+}
+
+ACE_Process::~ACE_Process (void)
+{
+#if defined (ACE_WIN32)
+ // Free resources allocated in kernel.
+ ACE_OS::close (this->process_info_.hThread);
+ ACE_OS::close (this->process_info_.hProcess);
+#endif /* ACE_WIN32 */
+ // If any handles were duplicated for the child process and
+ // still not closed, get them now.
+ this->close_dup_handles ();
+}
+
+int
+ACE_Process::prepare (ACE_Process_Options &)
+{
+ return 0;
+}
+
+pid_t
+ACE_Process::spawn (ACE_Process_Options &options)
+{
+ if (prepare (options) < 0)
+ return ACE_INVALID_PID;
+
+ // Stash the passed/duped handle sets away in this object for later
+ // closing if needed or requested. At the same time, figure out which
+ // ones to include in command line options if that's needed below.
+ ACE_Handle_Set *set_p = 0;
+ if (options.dup_handles (this->dup_handles_))
+ set_p = &this->dup_handles_;
+ else if (options.passed_handles (this->handles_passed_))
+ set_p = &this->handles_passed_;
+
+ // If we are going to end up running a new program (i.e. Win32, or
+ // NO_EXEC option is set) then get any handles passed in the options,
+ // and tack them onto the command line with +H <handle> options,
+ // unless the command line runs out of space.
+ // Note that we're using the knowledge that all the options, argvs, etc.
+ // passed to the options are all sitting in the command_line_buf. Any
+ // call to get the argv then splits them out. So, regardless of the
+ // platform, tack them all onto the command line buf and take it
+ // from there.
+ if (set_p && !ACE_BIT_ENABLED (options.creation_flags (),
+ ACE_Process_Options::NO_EXEC))
+ {
+ int maxlen = 0;
+ ACE_TCHAR *cmd_line_buf = options.command_line_buf (&maxlen);
+ size_t max_len = ACE_static_cast (size_t, maxlen);
+ size_t curr_len = ACE_OS::strlen (cmd_line_buf);
+ ACE_Handle_Set_Iterator h_iter (*set_p);
+ // Because the length of the to-be-formatted +H option is not
+ // known, and we don't have a snprintf, guess at the space
+ // needed (20 chars), and use that as a limit.
+ for (ACE_HANDLE h = h_iter ();
+ h != ACE_INVALID_HANDLE && curr_len + 20 < max_len;
+ h = h_iter ())
+ {
+ curr_len += ACE_OS::sprintf (&cmd_line_buf[curr_len],
+ ACE_LIB_TEXT (" +H %d"),
+ h);
+ }
+ }
+
+#if defined (ACE_WIN32)
+ BOOL fork_result =
+ ACE_TEXT_CreateProcess (0,
+ options.command_line_buf (),
+ options.get_process_attributes (),
+ options.get_thread_attributes (),
+ options.handle_inheritence (),
+ options.creation_flags (),
+ options.env_buf (), // environment variables
+ options.working_directory (),
+ options.startup_info (),
+ &this->process_info_);
+
+ if (fork_result)
+ {
+ parent (this->getpid ());
+ return this->getpid ();
+ }
+ return ACE_INVALID_PID;
+
+#elif defined (CHORUS)
+ // This only works if we exec. Chorus does not really support
+ // forking.
+ if (ACE_BIT_ENABLED (options.creation_flags (),
+ ACE_Process_Options::NO_EXEC))
+ ACE_NOTSUP_RETURN (ACE_INVALID_PID);
+
+ // These are all currently unsupported.
+ if (options.get_stdin () != ACE_INVALID_HANDLE)
+ ACE_NOTSUP_RETURN (ACE_INVALID_PID);
+ if (options.get_stdout () != ACE_INVALID_HANDLE)
+ ACE_NOTSUP_RETURN (ACE_INVALID_PID);
+ if (options.get_stderr () != ACE_INVALID_HANDLE)
+ ACE_NOTSUP_RETURN (ACE_INVALID_PID);
+ if (options.working_directory () != 0)
+ ACE_NOTSUP_RETURN (ACE_INVALID_PID);
+
+ if (options.env_argv ()[0] == 0)
+ // command-line args
+ this->child_id_ = ACE_OS::execvp (options.process_name (),
+ options.command_line_argv ());
+ else
+ {
+ // Add the new environment variables to the environment context
+ // of the context before doing an <execvp>.
+ for (char *const *user_env = options.env_argv ();
+ *user_env != 0;
+ user_env++)
+ if (ACE_OS::putenv (*user_env) != 0)
+ return ACE_INVALID_PID;
+
+ // Now the forked process has both inherited variables and the
+ // user's supplied variables.
+ this->child_id_ = ACE_OS::execvp (options.process_name (),
+ options.command_line_argv ());
+ }
+
+ return this->child_id_;
+#else /* ACE_WIN32 */
+ // Fork the new process.
+ this->child_id_ = ACE::fork (options.process_name (),
+ options.avoid_zombies ());
+
+ if (this->child_id_ == 0)
+ {
+ // If we're the child and the options specified a non-default
+ // process group, try to set our pgid to it. This allows the
+ // <ACE_Process_Manager> to wait for processes by their
+ // process-group.
+ if (options.getgroup () != ACE_INVALID_PID
+ && ACE_OS::setpgid (0,
+ options.getgroup ()) < 0)
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("%p.\n"),
+ ACE_LIB_TEXT ("ACE_Process::spawn: setpgid failed.")));
+
+#if !defined (ACE_LACKS_SETREGID)
+ if (options.getrgid () != (uid_t) -1
+ || options.getegid () != (uid_t) -1)
+ if (ACE_OS::setregid (options.getrgid (),
+ options.getegid ()) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("%p.\n"),
+ ACE_LIB_TEXT ("ACE_Process::spawn: setregid failed.")));
+#endif /* ACE_LACKS_SETREGID */
+
+#if !defined (ACE_LACKS_SETREUID)
+ // Set user and group id's.
+ if (options.getruid () != (uid_t) -1
+ || options.geteuid () != (uid_t) -1)
+ if (ACE_OS::setreuid (options.getruid (),
+ options.geteuid ()) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("%p.\n"),
+ ACE_LIB_TEXT ("ACE_Process::spawn: setreuid failed.")));
+#endif /* ACE_LACKS_SETREUID */
+
+ this->child (ACE_OS::getppid ());
+ }
+ else if (this->child_id_ != -1)
+ this->parent (this->child_id_);
+
+ // If we're not supposed to exec, return the process id.
+ if (ACE_BIT_ENABLED (options.creation_flags (),
+ ACE_Process_Options::NO_EXEC))
+ return this->child_id_;
+
+ switch (this->child_id_)
+ {
+ case -1:
+ // Error.
+ return ACE_INVALID_PID;
+ case 0:
+ // Child process...exec the
+ {
+ if (options.get_stdin () != ACE_INVALID_HANDLE
+ && ACE_OS::dup2 (options.get_stdin (),
+ ACE_STDIN) == -1)
+ ACE_OS::exit (errno);
+ else if (options.get_stdout () != ACE_INVALID_HANDLE
+ && ACE_OS::dup2 (options.get_stdout (),
+ ACE_STDOUT) == -1)
+ ACE_OS::exit (errno);
+ else if (options.get_stderr () != ACE_INVALID_HANDLE
+ && ACE_OS::dup2 (options.get_stderr (),
+ ACE_STDERR) == -1)
+ ACE_OS::exit (errno);
+
+ // close down unneeded descriptors
+ ACE_OS::close (options.get_stdin ());
+ ACE_OS::close (options.get_stdout ());
+ ACE_OS::close (options.get_stderr ());
+
+ // If we must, set the working directory for the child
+ // process.
+ if (options.working_directory () != 0)
+ ACE_OS::chdir (options.working_directory ());
+ // Should check for error here!
+
+ // Child process executes the command.
+ int result = 0;
+
+ if (options.env_argv ()[0] == 0)
+ // command-line args
+ result = ACE_OS::execvp (options.process_name (),
+ options.command_line_argv ());
+ else
+ {
+#if defined (ghs)
+ // GreenHills 1.8.8 (for VxWorks 5.3.x) can't compile this
+ // code. Processes aren't supported on VxWorks anyways.
+ ACE_NOTSUP_RETURN (ACE_INVALID_PID);
+#else
+ // Add the new environment variables to the environment
+ // context of the context before doing an <execvp>.
+ for (char *const *user_env = options.env_argv ();
+ *user_env != 0;
+ user_env++)
+ if (ACE_OS::putenv (*user_env) != 0)
+ return ACE_INVALID_PID;
+
+ // Now the forked process has both inherited variables and
+ // the user's supplied variables.
+ result = ACE_OS::execvp (options.process_name (),
+ options.command_line_argv ());
+#endif /* ghs */
+ }
+ if (result == -1)
+ {
+ // If the execv fails, this child needs to exit.
+
+ // Exit with the errno so that the calling process can
+ // catch this and figure out what went wrong.
+ ACE_OS::exit (errno);
+ }
+ // ... otherwise, this is never reached.
+ return 0;
+ }
+ default:
+ // Server process. The fork succeeded.
+ return this->child_id_;
+ }
+#endif /* ACE_WIN32 */
+}
+
+void
+ACE_Process::parent (pid_t)
+{
+ // nothing to do
+}
+
+void
+ACE_Process::child (pid_t)
+{
+ // nothing to do
+}
+
+void
+ACE_Process::unmanage (void)
+{
+ // nothing to do
+}
+
+int
+ACE_Process::running (void) const
+{
+#if defined (ACE_WIN32)
+ DWORD code;
+
+ BOOL result = ::GetExitCodeProcess (this->gethandle (),
+ &code);
+ return result && code == STILL_ACTIVE;
+#else
+ return ACE_OS::kill (this->getpid (),
+ 0) == 0
+ || errno != ESRCH;
+#endif /* ACE_WIN32 */
+}
+
+pid_t
+ACE_Process::wait (const ACE_Time_Value &tv,
+ ACE_exitcode *status)
+{
+#if defined (ACE_WIN32)
+ // Don't try to get the process exit status if wait failed so we can
+ // keep the original error code intact.
+ switch (::WaitForSingleObject (process_info_.hProcess,
+ tv.msec ()))
+ {
+ case WAIT_OBJECT_0:
+ if (status != 0)
+ // The error status of <GetExitCodeProcess> is nonetheless not
+ // tested because we don't know how to return the value.
+ ::GetExitCodeProcess (process_info_.hProcess,
+ status);
+ return this->getpid ();
+ case WAIT_TIMEOUT:
+ errno = ETIME;
+ return 0;
+ default:
+ ACE_OS::set_errno_to_last_error ();
+ return -1;
+ }
+#else /* ACE_WIN32 */
+ if (tv == ACE_Time_Value::zero)
+ ACE_OSCALL_RETURN (ACE_OS::waitpid (this->child_id_,
+ status,
+ WNOHANG),
+ int, ACE_INVALID_PID);
+
+ if (tv == ACE_Time_Value::max_time)
+ return this->wait (status);
+
+ ACE_Time_Value wait_until = ACE_OS::gettimeofday () + tv;
+
+ for (;;)
+ {
+ int result = ACE_OS::waitpid (this->getpid (),
+ status,
+ WNOHANG);
+ if (result != 0)
+ return result;
+
+ ACE_Sig_Set alarm_or_child;
+
+ alarm_or_child.sig_add (SIGALRM);
+ alarm_or_child.sig_add (SIGCHLD);
+
+ ACE_Time_Value time_left = wait_until - ACE_OS::gettimeofday ();
+
+ // If ACE_OS::ualarm doesn't have sub-second resolution:
+ time_left += ACE_Time_Value (0, 500000);
+ time_left.usec (0);
+
+ if (time_left <= ACE_Time_Value::zero)
+ return 0; // timeout
+
+ ACE_OS::ualarm (time_left);
+ if (ACE_OS::sigwait (alarm_or_child) == -1)
+ return ACE_INVALID_PID;
+ }
+#endif /* ACE_WIN32 */
+}
+
+void
+ACE_Process::close_dup_handles (void)
+{
+ if (this->dup_handles_.num_set () > 0)
+ {
+ ACE_Handle_Set_Iterator h_iter (this->dup_handles_);
+ for (ACE_HANDLE h = h_iter ();
+ h != ACE_INVALID_HANDLE;
+ h = h_iter ())
+ ACE_OS::closesocket (h);
+ this->dup_handles_.reset ();
+ }
+ return;
+}
+
+void
+ACE_Process::close_passed_handles (void)
+{
+ if (this->handles_passed_.num_set () > 0)
+ {
+ ACE_Handle_Set_Iterator h_iter (this->handles_passed_);
+ for (ACE_HANDLE h = h_iter ();
+ h != ACE_INVALID_HANDLE;
+ h = h_iter ())
+ ACE_OS::closesocket (h);
+ this->handles_passed_.reset ();
+ }
+ return;
+}
+
+
+ACE_Process_Options::ACE_Process_Options (int ie,
+ int cobl,
+ int ebl,
+ int mea)
+ :
+#if !defined (ACE_HAS_WINCE)
+ inherit_environment_ (ie),
+#endif /* ACE_HAS_WINCE */
+ creation_flags_ (0),
+ avoid_zombies_ (0),
+#if !defined (ACE_HAS_WINCE)
+#if defined (ACE_WIN32)
+ environment_inherited_ (0),
+ handle_inheritence_ (TRUE),
+ process_attributes_ (NULL),
+ thread_attributes_ (NULL),
+#else /* ACE_WIN32 */
+ stdin_ (ACE_INVALID_HANDLE),
+ stdout_ (ACE_INVALID_HANDLE),
+ stderr_ (ACE_INVALID_HANDLE),
+ ruid_ ((uid_t) -1),
+ euid_ ((uid_t) -1),
+ rgid_ ((uid_t) -1),
+ egid_ ((uid_t) -1),
+#endif /* ACE_WIN32 */
+ set_handles_called_ (0),
+ environment_buf_index_ (0),
+ environment_argv_index_ (0),
+ environment_buf_ (0),
+ environment_buf_len_ (ebl),
+ max_environment_args_ (mea),
+ max_environ_argv_index_ (mea - 1),
+#endif /* !ACE_HAS_WINCE */
+ command_line_argv_calculated_ (0),
+ command_line_buf_ (0),
+ command_line_buf_len_ (cobl),
+ process_group_ (ACE_INVALID_PID)
+{
+ ACE_NEW (command_line_buf_,
+ ACE_TCHAR[cobl]);
+ command_line_buf_[0] = '\0';
+
+#if !defined (ACE_HAS_WINCE)
+ working_directory_[0] = '\0';
+ ACE_NEW (environment_buf_,
+ ACE_TCHAR[ebl]);
+ ACE_NEW (environment_argv_,
+ ACE_TCHAR *[mea]);
+ environment_buf_[0] = '\0';
+ environment_argv_[0] = 0;
+ process_name_[0] = '\0';
+#if defined (ACE_WIN32)
+ ACE_OS::memset ((void *) &this->startup_info_,
+ 0,
+ sizeof this->startup_info_);
+ this->startup_info_.cb = sizeof this->startup_info_;
+#endif /* ACE_WIN32 */
+#endif /* !ACE_HAS_WINCE */
+}
+
+#if !defined (ACE_HAS_WINCE)
+#if defined (ACE_WIN32)
+void
+ACE_Process_Options::inherit_environment (void)
+{
+ // Ensure only once execution.
+ if (environment_inherited_)
+ return;
+ environment_inherited_ = 1;
+
+ // Get the existing environment.
+ ACE_TCHAR *existing_environment = ACE_OS::getenvstrings ();
+
+ int slot = 0;
+
+ while (existing_environment[slot] != '\0')
+ {
+ int len = ACE_OS::strlen (existing_environment + slot);
+
+ // Add the string to our env buffer.
+ if (this->setenv_i (existing_environment + slot, len) == -1)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("%p.\n"),
+ ACE_LIB_TEXT ("ACE_Process_Options::ACE_Process_Options")));
+ break;
+ }
+
+ // Skip to the next word.
+ slot += len + 1;
+ }
+
+ ACE_TEXT_FreeEnvironmentStrings (existing_environment);
+}
+
+#else /* defined ACE_WIN32 */
+
+ACE_TCHAR * const *
+ACE_Process_Options::env_argv (void)
+{
+ return environment_argv_;
+}
+
+#endif /* ACE_WIN32 */
+
+int
+ACE_Process_Options::setenv (ACE_TCHAR *envp[])
+{
+ int i = 0;
+ while (envp[i])
+ {
+ if (this->setenv_i (envp[i],
+ ACE_OS::strlen (envp[i])) == -1)
+ return -1;
+ i++;
+ }
+
+#if defined (ACE_WIN32)
+ if (inherit_environment_)
+ this->inherit_environment ();
+#endif /* ACE_WIN32 */
+
+ return 0;
+}
+
+int
+ACE_Process_Options::setenv (const ACE_TCHAR *format, ...)
+{
+ ACE_TCHAR stack_buf[DEFAULT_COMMAND_LINE_BUF_LEN];
+
+ // Start varargs.
+ va_list argp;
+ va_start (argp, format);
+
+ // Add the rest of the varargs.
+ ACE_OS::vsprintf (stack_buf,
+ format,
+ argp);
+ // End varargs.
+ va_end (argp);
+
+ // Append the string to are environment buffer.
+ if (this->setenv_i (stack_buf,
+ ACE_OS::strlen (stack_buf)) == -1)
+ return -1;
+
+#if defined (ACE_WIN32)
+ if (inherit_environment_)
+ this->inherit_environment ();
+#endif /* ACE_WIN32 */
+
+ return 0;
+}
+
+int
+ACE_Process_Options::setenv (const ACE_TCHAR *variable_name,
+ const ACE_TCHAR *format, ...)
+{
+ ACE_TCHAR newformat[DEFAULT_COMMAND_LINE_BUF_LEN];
+
+ // Add in the variable name.
+ ACE_OS::sprintf (newformat,
+ ACE_LIB_TEXT ("%s=%s"),
+ variable_name,
+ format);
+
+ ACE_TCHAR stack_buf[DEFAULT_COMMAND_LINE_BUF_LEN];
+
+ // Start varargs.
+ va_list argp;
+ va_start (argp, format);
+
+ // Add the rest of the varargs.
+ ACE_OS::vsprintf (stack_buf, newformat, argp);
+
+ // End varargs.
+ va_end (argp);
+
+ // Append the string to our environment buffer.
+ if (this->setenv_i (stack_buf,
+ ACE_OS::strlen (stack_buf)) == -1)
+ return -1;
+
+#if defined (ACE_WIN32)
+ if (inherit_environment_)
+ this->inherit_environment ();
+#endif /* ACE_WIN32 */
+
+ return 0;
+}
+
+int
+ACE_Process_Options::setenv_i (ACE_TCHAR *assignment,
+ int len)
+{
+ // Add one for the null char.
+ len++;
+
+ // If environment larger than allocated buffer return. Also check to
+ // make sure we have enough room.
+ if (environment_argv_index_ == max_environ_argv_index_
+ || (len + environment_buf_index_) >= environment_buf_len_)
+ return -1;
+
+ // Copy the new environment string.
+ ACE_OS::memcpy (environment_buf_ + environment_buf_index_,
+ assignment,
+ len * sizeof (ACE_TCHAR));
+
+ // Update the argv array.
+ environment_argv_[environment_argv_index_++] =
+ environment_buf_ + environment_buf_index_;
+ environment_argv_[environment_argv_index_] = 0;
+
+ // Update our index.
+ environment_buf_index_ += len;
+
+ // Make sure the buffer is null-terminated.
+ environment_buf_[environment_buf_index_] = '\0';
+ return 0;
+}
+
+int
+ACE_Process_Options::set_handles (ACE_HANDLE std_in,
+ ACE_HANDLE std_out,
+ ACE_HANDLE std_err)
+{
+ this->set_handles_called_ = 1;
+#if defined (ACE_WIN32)
+
+ // Tell the new process to use our std handles.
+ this->startup_info_.dwFlags = STARTF_USESTDHANDLES;
+
+ if (std_in == ACE_INVALID_HANDLE)
+ std_in = ACE_STDIN;
+ if (std_out == ACE_INVALID_HANDLE)
+ std_out = ACE_STDOUT;
+ if (std_err == ACE_INVALID_HANDLE)
+ std_err = ACE_STDERR;
+
+ if (!::DuplicateHandle (::GetCurrentProcess (),
+ std_in,
+ ::GetCurrentProcess (),
+ &this->startup_info_.hStdInput,
+ 0,
+ TRUE,
+ DUPLICATE_SAME_ACCESS))
+ return -1;
+
+ if (!::DuplicateHandle (::GetCurrentProcess (),
+ std_out,
+ ::GetCurrentProcess (),
+ &this->startup_info_.hStdOutput,
+ 0,
+ TRUE,
+ DUPLICATE_SAME_ACCESS))
+ return -1;
+
+ if (!::DuplicateHandle (::GetCurrentProcess (),
+ std_err,
+ ::GetCurrentProcess (),
+ &this->startup_info_.hStdError,
+ 0,
+ TRUE,
+ DUPLICATE_SAME_ACCESS))
+ return -1;
+#else /* ACE_WIN32 */
+ this->stdin_ = ACE_OS::dup (std_in);
+ this->stdout_ = ACE_OS::dup (std_out);
+ this->stderr_ = ACE_OS::dup (std_err);
+#endif /* ACE_WIN32 */
+
+ return 0; // Success.
+}
+#endif /* !ACE_HAS_WINCE */
+
+ACE_Process_Options::~ACE_Process_Options (void)
+{
+#if !defined (ACE_HAS_WINCE)
+ if (set_handles_called_)
+ {
+#if defined (ACE_WIN32)
+ ACE_OS::close (startup_info_.hStdInput);
+ ACE_OS::close (startup_info_.hStdOutput);
+ ACE_OS::close (startup_info_.hStdError);
+#else /* ACE_WIN32 */
+ ACE_OS::close (stdin_);
+ ACE_OS::close (stdout_);
+ ACE_OS::close (stderr_);
+#endif /* ACE_WIN32 */
+ set_handles_called_ = 0;
+ }
+ delete [] environment_buf_;
+ delete [] environment_argv_;
+#endif /* !ACE_HAS_WINCE */
+ delete [] command_line_buf_;
+}
+
+int
+ACE_Process_Options::command_line (const ACE_TCHAR *const argv[])
+{
+ // @@ Factor out the code between this
+ int i = 0;
+
+ if (argv[i])
+ {
+ ACE_OS::strcat (command_line_buf_, argv[i]);
+ while (argv[++i])
+ {
+ ACE_OS::strcat (command_line_buf_,
+ ACE_LIB_TEXT (" "));
+ ACE_OS::strcat (command_line_buf_,
+ argv[i]);
+ }
+ }
+
+ return 0; // Success.
+}
+
+int
+ACE_Process_Options::command_line (const ACE_TCHAR *format, ...)
+{
+ // Store all ... args in argp.
+ va_list argp;
+ va_start (argp, format);
+
+ // sprintf the format and args into command_line_buf__.
+ ACE_OS::vsprintf (command_line_buf_,
+ format,
+ argp);
+
+ // Useless macro.
+ va_end (argp);
+
+ return 0;
+}
+
+#if defined (ACE_HAS_WCHAR) && !defined (ACE_HAS_WINCE)
+/**
+ * @note Not available on Windows CE because it doesn't have a char version of
+ * vsprintf.
+ */
+int
+ACE_Process_Options::command_line (const ACE_ANTI_TCHAR *format, ...)
+{
+ ACE_ANTI_TCHAR *anti_clb;
+ ACE_NEW_RETURN (anti_clb,
+ ACE_ANTI_TCHAR[this->command_line_buf_len_],
+ -1);
+
+ // Store all ... args in argp.
+ va_list argp;
+ va_start (argp, format);
+
+ // sprintf the format and args into command_line_buf_.
+ ACE_OS::vsprintf (anti_clb,
+ format,
+ argp);
+
+ // Useless macro.
+ va_end (argp);
+
+ ACE_OS::strcpy (this->command_line_buf_,
+ ACE_TEXT_ANTI_TO_TCHAR (anti_clb));
+
+ delete [] anti_clb;
+
+ return 0;
+}
+#endif /* ACE_HAS_WCHAR && !ACE_HAS_WINCE */
+
+ACE_TCHAR *
+ACE_Process_Options::env_buf (void)
+{
+#if !defined (ACE_HAS_WINCE)
+ if (environment_buf_[0] == '\0')
+ return 0;
+ else
+ return environment_buf_;
+#else
+ return 0;
+#endif /* !ACE_HAS_WINCE */
+}
+
+ACE_TCHAR * const *
+ACE_Process_Options::command_line_argv (void)
+{
+ if (command_line_argv_calculated_ == 0)
+ {
+ command_line_argv_calculated_ = 1;
+
+ // This tokenizer will replace all spaces with end-of-string
+ // characters and will preserve text between "" and '' pairs.
+ ACE_Tokenizer parser (command_line_buf_);
+ parser.delimiter_replace (' ', '\0');
+ parser.preserve_designators ('\"', '\"'); // "
+ parser.preserve_designators ('\'', '\'');
+
+ int x = 0;
+ do
+ command_line_argv_[x] = parser.next ();
+ while (command_line_argv_[x] != 0
+ // substract one for the ending zero.
+ && ++x < MAX_COMMAND_LINE_OPTIONS - 1);
+
+ command_line_argv_[x] = 0;
+ }
+
+ return command_line_argv_;
+}
+
+
+// Cause the specified handle to be passed to a child process
+// when it's spawned.
+int
+ACE_Process_Options::pass_handle (ACE_HANDLE h)
+{
+# if defined (ACE_WIN32)
+# if defined (ACE_HAS_WINCE)
+ ACE_NOTSUP_RETURN (-1);
+# else
+
+ // This is oriented towards socket handles... may need some adjustment
+ // for non-sockets.
+ // This is all based on an MSDN article:
+ // http://support.microsoft.com/support/kb/articles/Q150/5/23.asp
+ // If on Win95/98, the handle needs to be duplicated for the to-be-spawned
+ // process. On WinNT, they get inherited by the child process automatically.
+ // If the handle is duplicated, remember the duplicate so it can be
+ // closed later. Can't be closed now, or the child won't get it.
+ OSVERSIONINFO osvi;
+ ZeroMemory (&osvi, sizeof (osvi));
+ osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
+ // If this is Win95/98 or we can't tell, duplicate the handle.
+ if (!GetVersionEx (&osvi) || osvi.dwPlatformId != VER_PLATFORM_WIN32_NT)
+ {
+ HANDLE dup_handle;
+ if (!DuplicateHandle (GetCurrentProcess (),
+ ACE_static_cast (HANDLE, h),
+ GetCurrentProcess (),
+ &dup_handle,
+ 0,
+ TRUE, // Inheritable
+ DUPLICATE_SAME_ACCESS))
+ return -1;
+ dup_handles_.set_bit (ACE_static_cast (ACE_HANDLE, dup_handle));
+ }
+# endif /* ACE_HAS_WINCE */
+#endif /* ACE_WIN32 */
+
+ this->handles_passed_.set_bit (h);
+
+ return 0;
+}
+
+// Get a copy of the handles the ACE_Process_Options duplicated
+// for the spawned process.
+int
+ACE_Process_Options::dup_handles (ACE_Handle_Set &set) const
+{
+ if (this->dup_handles_.num_set () == 0)
+ return 0;
+ set.reset ();
+ set = this->dup_handles_;
+ return 1;
+}
+
+// Get a copy of the handles passed to the spawned process. This
+// will be the set of handles previously passed to @arg pass_handle().
+int
+ACE_Process_Options::passed_handles (ACE_Handle_Set &set) const
+{
+ if (this->handles_passed_.num_set () == 0)
+ return 0;
+ set.reset ();
+ set = this->handles_passed_;
+ return 1;
+}
+
+ACE_Managed_Process::ACE_Managed_Process (void)
+{
+}
+
+ACE_Managed_Process::~ACE_Managed_Process (void)
+{
+}
diff --git a/ace/Threads/Process.h b/ace/Threads/Process.h
new file mode 100644
index 00000000000..796cba44b4b
--- /dev/null
+++ b/ace/Threads/Process.h
@@ -0,0 +1,557 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Process.h
+ *
+ * $Id$
+ *
+ * @author Tim Harrison <harrison@cs.wustl.edu>
+ */
+//=============================================================================
+
+#ifndef ACE_PROCESS_H
+#define ACE_PROCESS_H
+#include "ace/pre.h"
+
+#include "ace/OS.h"
+#include "ace/Handle_Set.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+/**
+ * @class ACE_Process_Options
+ *
+ * @brief Process Options
+ *
+ * This class controls the options passed to <CreateProcess> (or <fork>
+ * and <exec>).
+ * Notice that on Windows CE, creating a process merely means
+ * instantiating a new process. You can't set the handles (since
+ * there's no stdin, stdout and stderr,) specify process/thread
+ * options, set environment,... So, basically, this class only
+ * set the command line and nothing else.
+ * Notice that on UNIX platforms, if the <setenv> is used, the
+ * <spawn> is using the <execve> system call. It means that the
+ * <command_line> should include a full path to the program file
+ * (<execve> does not search the PATH). If <setenv> is not used
+ * then, the <spawn> is using the <execvp> which searches for the
+ * program file in the PATH variable.
+ */
+class ACE_Export ACE_Process_Options
+{
+public:
+ enum
+ {
+ DEFAULT_COMMAND_LINE_BUF_LEN = 1024,
+ // UNIX process creation flags.
+#if defined (ACE_WIN32)
+ NO_EXEC = 0
+#else
+ NO_EXEC = 1
+#endif /* ACE_WIN32 */
+ };
+
+protected:
+ // = Default settings not part of public Interface.
+ //
+ // @@todo These sizes should be taken from the appropriate
+ // POSIX/system header files and/or defined dynamically.
+ enum
+ {
+ MAX_COMMAND_LINE_OPTIONS = 128,
+ ENVIRONMENT_BUFFER = 16 * 1024, // 16K
+ MAX_ENVIRONMENT_ARGS = 512 //
+ };
+
+public:
+ /**
+ * If <inherit_environment> == 1, the new process will inherit the
+ * environment of the current process. <command_line_buf_len> is the
+ * max strlen for command-line arguments.
+ */
+ ACE_Process_Options (int inherit_environment = 1,
+ int command_line_buf_len = DEFAULT_COMMAND_LINE_BUF_LEN,
+ int env_buf_len = ENVIRONMENT_BUFFER,
+ int max_env_args = MAX_ENVIRONMENT_ARGS);
+
+ /// Destructor.
+ ~ACE_Process_Options (void);
+
+ // = Methods to set process creation options portably.
+
+ /**
+ * Set the standard handles of the new process to the respective
+ * handles. If you want to affect a subset of the handles, make
+ * sure to set the others to ACE_INVALID_HANDLE. Returns 0 on
+ * success, -1 on failure.
+ */
+ int set_handles (ACE_HANDLE std_in,
+ ACE_HANDLE std_out = ACE_INVALID_HANDLE,
+ ACE_HANDLE std_err = ACE_INVALID_HANDLE);
+
+ /// <format> must be of the form "VARIABLE=VALUE". There can not be
+ /// any spaces between VARIABLE and the equal sign.
+ int setenv (const ACE_TCHAR *format,
+ ...);
+
+ /**
+ * Set a single environment variable, <variable_name>. Since
+ * different platforms separate each environment variable
+ * differently, you must call this method once for each variable.
+ * <format> can be any printf format string. So options->setenv
+ * ("FOO","one + two = %s", "three") will result in "FOO=one + two =
+ * three".
+ */
+ int setenv (const ACE_TCHAR *variable_name,
+ const ACE_TCHAR *format,
+ ...);
+
+ /// Same as above with argv format. <envp> must be null terminated.
+ int setenv (ACE_TCHAR *envp[]);
+
+ /// Set the working directory for the process. strlen of <wd> must
+ /// be <= MAXPATHLEN.
+ void working_directory (const char *wd);
+
+#if defined (ACE_HAS_WCHAR)
+ /// wchar_t version of working_directory
+ void working_directory (const wchar_t *wd);
+#endif /* ACE_HAS_WCHAR */
+
+ /**
+ * Set the command-line arguments. <format> can use any printf
+ * formats. The first token in <format> should be the path to the
+ * application. This can either be a full path, relative path, or
+ * just an executable name. If an executable name is used, we rely
+ * on the platform's support for searching paths. Since we need a
+ * path to run a process, this method *must* be called! Returns 0
+ * on success, -1 on failure.
+ */
+ int command_line (const ACE_TCHAR *format, ...);
+
+#if defined (ACE_HAS_WCHAR) && !defined (ACE_HAS_WINCE)
+ /// Anti-TChar version of command_line ()
+ int command_line (const ACE_ANTI_TCHAR *format, ...);
+#endif /* ACE_HAS_WCHAR && !ACE_HAS_WINCE */
+
+ /// Same as above in argv format. <argv> must be null terminated.
+ int command_line (const ACE_TCHAR * const argv[]);
+
+ // = Set/get the pathname used to name the process.
+ /**
+ * Specify the full path or relative path, or just the executable
+ * name for the process. If this is set, then <name> will be used to
+ * create the process instead of argv[0] set in the command
+ * line. This is here so that you can supply something other than
+ * executable name as argv[0].
+ */
+ void process_name (const ACE_TCHAR *name);
+
+ /// Return the process_name. If the <process_name(name)> set
+ /// method is not called, this method will return argv[0].
+ const ACE_TCHAR *process_name (void);
+
+ // = Set/get creation flags.
+ /// Get the creation flags.
+ /// Set the creation flags.
+ u_long creation_flags (void) const;
+ void creation_flags (u_long);
+
+ // = <ACE_Process> uses these operations to retrieve option values.
+
+ /// Current working directory. Returns "" if nothing has been set.
+ ACE_TCHAR *working_directory (void);
+
+ /// Buffer of command-line options. Returns exactly what was passed
+ /// to this->command_line. If @arg max_len is not 0, receives the
+ /// maximum length of the command line buffer.
+ ACE_TCHAR *command_line_buf (int *max_len = 0);
+
+ /**
+ * argv-style command-line options. Parses and modifies the string
+ * created from <command_line_>. All spaces not in quotes ("" or
+ * '') are replaced with null (\0) bytes. An argv array is built
+ * and returned with each entry pointing to the start of
+ * null-terminated string. Returns { 0 } if nothing has been set.
+ */
+ ACE_TCHAR * const *command_line_argv (void);
+
+ /**
+ * Null-terminated buffer of null terminated strings. Each string
+ * is an environment assignment "VARIABLE=value". This buffer
+ * should end with two null characters.
+ */
+ ACE_TCHAR *env_buf (void);
+
+ // = Get/set process group.
+ /// On UNIX, these methods are used by the <ACE_Process_Manager> to
+ /// manage groups of processes.
+ pid_t getgroup (void) const;
+ pid_t setgroup (pid_t pgrp);
+
+ /// Default is TRUE.
+ /// Allows disabling of handle inheritence.
+ int handle_inheritence (void);
+ void handle_inheritence (int);
+
+ /// Cause the specified handle to be passed to a child process
+ /// when it runs a new program image.
+ /**
+ * The specified handle value will be included in the spawned
+ * process's command line as @arg +H @arg handle, if a new
+ * program is spawned (always on Win32; else if NO_EXEC is not
+ * set in creation flags). The passed handle value will be
+ * duplicated if on Win32 less capable than NT.
+ * @return 0 if success, -1 if failure.
+ */
+ int pass_handle (ACE_HANDLE);
+
+ /// Get a copy of the handles the ACE_Process_Options duplicated
+ /// for the spawned process.
+ /**
+ * Any handles created through duplication of those passed into
+ * @arg pass_handle are returned in @arg set.
+ * @return 0 if there were no handles to return; 1 if there were.
+ */
+ int dup_handles (ACE_Handle_Set &set) const;
+
+ /// Get a copy of the handles passed to the spawned process. This
+ /// will be the set of handles previously passed to @arg pass_handle().
+ /**
+ * Any handles previously passed to @arg pass_handle are returned
+ * in @arg set.
+ * @return 0 if there were no handles to return; 1 if there were.
+ */
+ int passed_handles (ACE_Handle_Set &set) const;
+
+ /// Set value for avoid_zombies (has no real effect except on *nix).
+ /// Get current value for avoid_zombies.
+ void avoid_zombies (int);
+ int avoid_zombies (void);
+
+#if defined (ACE_WIN32)
+ // = Non-portable accessors for when you "just have to use them."
+
+ /// Used for setting and getting.
+ ACE_TEXT_STARTUPINFO *startup_info (void);
+
+ /// Get the process_attributes. Returns NULL if
+ /// set_process_attributes has not been set.
+ LPSECURITY_ATTRIBUTES get_process_attributes (void) const;
+
+ /// If this is called, a non-null process attributes is sent to
+ /// CreateProcess.
+ LPSECURITY_ATTRIBUTES set_process_attributes (void);
+
+ /// Get the thread_attributes. Returns NULL if set_thread_attributes
+ /// has not been set.
+ LPSECURITY_ATTRIBUTES get_thread_attributes (void) const;
+
+ /// If this is called, a non-null thread attributes is sent to
+ /// CreateProcess.
+ LPSECURITY_ATTRIBUTES set_thread_attributes (void);
+
+#else /* All things not WIN32 */
+
+ /// argv-style array of environment settings.
+ ACE_TCHAR *const *env_argv (void);
+
+ // = Accessors for the standard handles.
+ ACE_HANDLE get_stdin (void);
+ ACE_HANDLE get_stdout (void);
+ ACE_HANDLE get_stderr (void);
+
+ // = Set/get real & effective user & group id associated with user.
+ int setreugid (const ACE_TCHAR* user);
+ void setruid (uid_t id);
+ void seteuid (uid_t id);
+ void setrgid (uid_t id);
+ void setegid (uid_t id);
+ uid_t getruid (void);
+ uid_t geteuid (void);
+ uid_t getrgid (void);
+ uid_t getegid (void);
+#endif /* ACE_WIN32 */
+protected:
+
+#if !defined (ACE_HAS_WINCE)
+ /// Add <assignment> to environment_buf_ and adjust
+ /// environment_argv_. <len> is the strlen of <assignment>.
+ int setenv_i (ACE_TCHAR *assignment, int len);
+
+ /// Whether the child process inherits the current process
+ /// environment.
+ int inherit_environment_;
+#endif /* !ACE_HAS_WINCE */
+
+ /// Default 0.
+ u_long creation_flags_;
+
+ /// Avoid zombies for spawned processes.
+ int avoid_zombies_;
+
+#if defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)
+ /// Helper function to grab win32 environment and stick it in
+ /// environment_buf_ using this->setenv_i.
+ void inherit_environment (void);
+
+ /// Ensures once only call to inherit environment.
+ int environment_inherited_;
+
+ ACE_TEXT_STARTUPINFO startup_info_;
+
+ /// Default TRUE.
+ BOOL handle_inheritence_;
+
+ /// Pointer to security_buf1_.
+ LPSECURITY_ATTRIBUTES process_attributes_;
+
+ /// Pointer to security_buf2_.
+ LPSECURITY_ATTRIBUTES thread_attributes_;
+
+ /// Data for process_attributes_.
+ SECURITY_ATTRIBUTES security_buf1_;
+
+ /// Data for thread_attributes_.
+ SECURITY_ATTRIBUTES security_buf2_;
+
+#else /* !ACE_WIN32 */
+ ACE_HANDLE stdin_;
+ ACE_HANDLE stdout_;
+ ACE_HANDLE stderr_;
+
+ // = Real & effective user & group id's.
+ // These should be set to -1 to leave unchanged (default).
+ uid_t ruid_;
+ uid_t euid_;
+ uid_t rgid_;
+ uid_t egid_;
+#endif /* ACE_WIN32 */
+
+#if !defined (ACE_HAS_WINCE)
+ /// Is 1 if stdhandles was called.
+ int set_handles_called_;
+
+ /// Pointer into environment_buf_. This should point to the next
+ /// free spot.
+ int environment_buf_index_;
+
+ /// Pointer to environment_argv_.
+ int environment_argv_index_;
+
+ /// Pointer to buffer of the environment settings.
+ ACE_TCHAR *environment_buf_;
+
+ /// Size of the environment buffer. Configurable
+ int environment_buf_len_;
+
+ /// Pointers into environment_buf_.
+ ACE_TCHAR **environment_argv_;
+
+ /// Maximum number of environment variables. Configurable
+ int max_environment_args_;
+
+ /// Maximum index of environment_argv_ buffer
+ int max_environ_argv_index_;
+
+ /// The current working directory.
+ ACE_TCHAR working_directory_[MAXPATHLEN + 1];
+#endif /* !ACE_HAS_WINCE */
+
+ /// Ensures command_line_argv is only calculated once.
+ int command_line_argv_calculated_;
+
+ /// Pointer to buffer of command-line arguments. E.g., "-f foo -b bar".
+ ACE_TCHAR *command_line_buf_;
+
+ /// Max length of command_line_buf_
+ int command_line_buf_len_;
+
+ /// Argv-style command-line arguments.
+ ACE_TCHAR *command_line_argv_[MAX_COMMAND_LINE_OPTIONS];
+
+ /// Process-group on Unix; unused on Win32.
+ pid_t process_group_;
+
+ /// Set of handles that were passed in pass_handle ().
+ ACE_Handle_Set handles_passed_;
+ /// Results of duplicating handles passed in pass_handle ().
+ ACE_Handle_Set dup_handles_;
+
+ /// Pathname for the process. Relative path or absolute path or just
+ /// the program name.
+ ACE_TCHAR process_name_[MAXPATHLEN + 1];
+};
+
+/**
+ * @class ACE_Process
+ *
+ * @brief Process
+ *
+ * A Portable encapsulation for creating new processes.
+ * Notice that on UNIX platforms, if the <setenv> is used, the
+ * <spawn> is using the <execve> system call. It means that the
+ * <command_line> should include a full path to the program file
+ * (<execve> does not search the PATH). If <setenv> is not used
+ * then, the <spawn> is using the <execvp> which searches for the
+ * program file in the PATH variable.
+ */
+class ACE_Export ACE_Process
+{
+public:
+
+ /// Default construction. Must use <ACE_Process::spawn> to start.
+ ACE_Process (void);
+
+ /// Destructor.
+ virtual ~ACE_Process (void);
+
+ /**
+ * Called just before <ACE_OS::fork> in the <spawn>. If this
+ * returns non-zero, the <spawn> is aborted (and returns
+ * ACE_INVALID_PID). The default simply returns zero.
+ */
+ virtual int prepare (ACE_Process_Options &options);
+
+ /**
+ * Launch a new process as described by <options>. Returns the
+ * process id of the newly spawned child on success or -1 on
+ * failure.
+ */
+ virtual pid_t spawn (ACE_Process_Options &options);
+
+ /// Called just after <ACE_OS::fork> in the parent's context, if the
+ /// <fork> succeeds. The default is to do nothing.
+ virtual void parent (pid_t child);
+
+ /**
+ * Called just after <ACE_OS::fork> in the child's context. The
+ * default does nothing. This function is *not* called on Win32
+ * because the process-creation scheme does not allow it.
+ */
+ virtual void child (pid_t parent);
+
+ /// Called by a <Process_Manager> that is removing this Process from
+ /// its table of managed Processes. Default is to do nothing.
+ virtual void unmanage (void);
+
+ /**
+ * Wait for the process we've created to exit. If <status> != 0, it
+ * points to an integer where the function store the exit status of
+ * child process to. If <wait_options> == <WNOHANG> then return 0
+ * and don't block if the child process hasn't exited yet. A return
+ * value of -1 represents the <wait> operation failed, otherwise,
+ * the child process id is returned.
+ */
+ pid_t wait (ACE_exitcode *status = 0,
+ int wait_options = 0);
+
+ /**
+ * Timed wait for the process we've created to exit. A return value
+ * of -1 indicates that the something failed; 0 indicates that a
+ * timeout occurred. Otherwise, the child's process id is returned.
+ * If <status> != 0, it points to an integer where the function
+ * stores the child's exit status.
+ *
+ * NOTE: on UNIX platforms this function uses <ualarm>, i.e., it
+ * overwrites any existing alarm. In addition, it steals all
+ * <SIGCHLD>s during the timeout period, which will break another
+ * <ACE_Process_Manager> in the same process that's expecting
+ * <SIGCHLD> to kick off process reaping.
+ */
+ pid_t wait (const ACE_Time_Value &tv,
+ ACE_exitcode *status = 0);
+
+ /// Send the process a signal. This is only portable to operating
+ /// systems that support signals, such as UNIX/POSIX.
+ int kill (int signum = SIGINT);
+
+ /**
+ * Terminate the process abruptly using <ACE::terminate_process>.
+ * This call doesn't give the process a chance to cleanup, so use it
+ * with caution...
+ */
+ int terminate (void);
+
+ /// Return the process id of the new child process.
+ pid_t getpid (void) const;
+
+ /// Return the handle of the process, if it has one.
+ ACE_HANDLE gethandle (void) const;
+
+ /// Return 1 if running; 0 otherwise.
+ int running (void) const;
+
+ /// Return the Process' exit code
+ int exit_code (void) const;
+
+ /// Set the Process' exit code (completely unrelated to whether the
+ /// Process has actually exited)!
+ void exit_code (int code);
+
+ /// Close all the handles in the set obtained from the
+ /// @arg ACE_Process_Options::dup_handles object used to spawn
+ /// the process.
+ void close_dup_handles (void);
+
+ /// Close all the handles in the set obtained from the
+ /// @arg ACE_Process_Options::passed_handles object used to spawn
+ /// the process.
+ void close_passed_handles (void);
+
+#if defined (ACE_WIN32)
+ PROCESS_INFORMATION process_info (void);
+#endif /* ACE_WIN32 */
+
+protected:
+#if defined (ACE_WIN32)
+ PROCESS_INFORMATION process_info_;
+#else /* ACE_WIN32 */
+ /// Process id of the child.
+ pid_t child_id_;
+#endif /* ACE_WIN32 */
+ int exit_code_;
+
+ /// Set of handles that were passed to the child process.
+ ACE_Handle_Set handles_passed_;
+ /// Handle duplicates made for the child process.
+ ACE_Handle_Set dup_handles_;
+};
+
+
+/**
+ * @class ACE_Managed_Process
+ *
+ * @brief A process easily managed by ACE_Process_Manager.
+ *
+ * @arg ACE_Managed_Process is just an @arg ACE_Process with an
+ * @arg unmanage method that deletes the instance.
+ * This class is only valid for use as a dynamically-allocated object!
+ */
+class ACE_Export ACE_Managed_Process : public ACE_Process
+{
+public:
+ ACE_Managed_Process ();
+
+ virtual void unmanage (void);
+ // Cleanup by deleting <this>.
+
+private:
+ virtual ~ACE_Managed_Process (void);
+ // Make sure that we're allocated dynamically!
+
+ friend class ace_dewarn_gplusplus;
+ // Keep G++ happy...
+};
+
+#include "ace/SString.h"
+
+#if defined (__ACE_INLINE__)
+#include "ace/Process.i"
+#endif /* __ACE_INLINE__ */
+
+#include "ace/post.h"
+#endif /* ACE_PROCESS_H */
diff --git a/ace/Threads/Process.i b/ace/Threads/Process.i
new file mode 100644
index 00000000000..3b4f8e198d5
--- /dev/null
+++ b/ace/Threads/Process.i
@@ -0,0 +1,379 @@
+/* -*- C++ -*- */
+// $Id$
+
+#if defined (ACE_WIN32)
+
+ACE_INLINE PROCESS_INFORMATION
+ACE_Process::process_info (void)
+{
+ return process_info_;
+}
+#endif /* ACE_WIN32 */
+
+ACE_INLINE ACE_HANDLE
+ACE_Process::gethandle (void) const
+{
+#if defined (ACE_WIN32)
+ return process_info_.hProcess;
+#else
+ return ACE_HANDLE (child_id_);
+#endif /* ACE_WIN32 */
+}
+
+ACE_INLINE pid_t
+ACE_Process::getpid (void)
+ const
+{
+#if defined (ACE_WIN32)
+ return process_info_.dwProcessId;
+#else /* ACE_WIN32 */
+ return child_id_;
+#endif /* ACE_WIN32 */
+}
+
+ACE_INLINE pid_t
+ACE_Process::wait (ACE_exitcode *status,
+ int wait_options)
+{
+ return ACE_OS::wait (this->getpid (),
+ status,
+ wait_options
+#if defined (ACE_WIN32)
+ , process_info_.hProcess
+#endif /* ACE_WIN32 */
+ );
+}
+
+ACE_INLINE int
+ACE_Process::kill (int signum)
+{
+ return ACE_OS::kill (this->getpid (),
+ signum);
+}
+
+ACE_INLINE int
+ACE_Process::terminate (void)
+{
+ return ACE::terminate_process (this->getpid ());
+}
+
+ACE_INLINE int
+ACE_Process::exit_code (void) const
+{
+ return this->exit_code_;
+}
+
+ACE_INLINE void
+ACE_Process::exit_code (int code)
+{
+ this->exit_code_ = code;
+}
+
+ACE_INLINE u_long
+ACE_Process_Options::creation_flags (void) const
+{
+#if defined (UNICODE) && defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)
+ return creation_flags_ | CREATE_UNICODE_ENVIRONMENT;
+#else
+ return creation_flags_;
+#endif /* UNICODE */
+}
+
+ACE_INLINE void
+ACE_Process_Options::creation_flags (u_long cf)
+{
+ creation_flags_ = cf;
+}
+
+ACE_INLINE pid_t
+ACE_Process_Options::getgroup (void) const
+{
+ return process_group_;
+}
+
+ACE_INLINE pid_t
+ACE_Process_Options::setgroup (pid_t pgrp)
+{
+ pid_t old = process_group_;
+ process_group_ = pgrp;
+ return old;
+}
+
+ACE_INLINE int
+ACE_Process_Options::handle_inheritence (void)
+{
+#if defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)
+ return handle_inheritence_;
+#else
+ ACE_NOTSUP_RETURN (0); // This is a benign error.
+#endif /* ACE_WIN32 && ! ACE_HAS_WINCE */
+}
+
+ACE_INLINE void
+ACE_Process_Options::handle_inheritence (int hi)
+{
+#if defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)
+ handle_inheritence_ = hi;
+#else
+ ACE_UNUSED_ARG (hi);
+ ACE_NOTSUP;
+#endif /* !ACE_HAS_WINCE */
+}
+
+ACE_INLINE int
+ACE_Process_Options::avoid_zombies (void)
+{
+ return avoid_zombies_;
+}
+ACE_INLINE void
+ACE_Process_Options::avoid_zombies (int avoid_zombies)
+{
+ avoid_zombies_ = avoid_zombies;
+}
+
+#if defined (ACE_WIN32)
+
+ACE_INLINE ACE_TEXT_STARTUPINFO *
+ACE_Process_Options::startup_info (void)
+{
+#if !defined (ACE_HAS_WINCE)
+ return &startup_info_;
+#else
+ return 0;
+#endif /* !ACE_HAS_WINCE */
+}
+
+ACE_INLINE LPSECURITY_ATTRIBUTES
+ACE_Process_Options::get_process_attributes (void) const
+{
+#if !defined (ACE_HAS_WINCE)
+ return process_attributes_;
+#else
+ return 0;
+#endif /* !ACE_HAS_WINCE */
+}
+
+ACE_INLINE LPSECURITY_ATTRIBUTES
+ACE_Process_Options::set_process_attributes (void)
+{
+#if !defined (ACE_HAS_WINCE)
+ process_attributes_ = &security_buf1_;
+ return process_attributes_;
+#else
+ return 0;
+#endif /* !ACE_HAS_WINCE */
+}
+
+ACE_INLINE LPSECURITY_ATTRIBUTES
+ACE_Process_Options::get_thread_attributes (void) const
+{
+#if !defined (ACE_HAS_WINCE)
+ return thread_attributes_;
+#else
+ return 0;
+#endif /* !ACE_HAS_WINCE */
+}
+
+ACE_INLINE LPSECURITY_ATTRIBUTES
+ACE_Process_Options::set_thread_attributes (void)
+{
+#if !defined (ACE_HAS_WINCE)
+ thread_attributes_ = &security_buf2_;
+ return thread_attributes_;
+#else
+ return 0;
+#endif /* !ACE_HAS_WINCE */
+}
+
+#else /* !defined (ACE_WIN32) */
+
+ACE_INLINE ACE_HANDLE
+ACE_Process_Options::get_stdin (void)
+{
+ return stdin_;
+}
+
+ACE_INLINE ACE_HANDLE
+ACE_Process_Options::get_stdout (void)
+{
+ return stdout_;
+}
+
+ACE_INLINE ACE_HANDLE
+ACE_Process_Options::get_stderr (void)
+{
+ return stderr_;
+}
+
+ACE_INLINE int
+ACE_Process_Options::setreugid (const char* user)
+{
+#if !defined (ACE_LACKS_PWD_FUNCTIONS)
+ struct passwd *ent = ACE_OS::getpwnam (user);
+
+ if (ent != 0)
+ {
+ this->euid_ = ent->pw_uid;
+ this->ruid_ = ent->pw_uid;
+ this->egid_ = ent->pw_gid;
+ this->rgid_ = ent->pw_gid;
+ return 0;
+ }
+ else
+ return -1;
+#else
+ ACE_UNUSED_ARG (user);
+ ACE_NOTSUP_RETURN (-1);
+#endif /* ACE_LACKS_PWD_FUNCTIONS */
+}
+
+ACE_INLINE void
+ACE_Process_Options::setruid (uid_t id)
+{
+ this->ruid_ = id;
+}
+
+ACE_INLINE void
+ACE_Process_Options::seteuid (uid_t id)
+{
+ this->euid_ = id;
+}
+
+ACE_INLINE void
+ACE_Process_Options::setrgid (uid_t id)
+{
+ this->rgid_ = id;
+}
+
+ACE_INLINE void
+ACE_Process_Options::setegid (uid_t id)
+{
+ this->egid_ = id;
+}
+
+ACE_INLINE uid_t
+ACE_Process_Options::getruid (void)
+{
+ return this->ruid_;
+}
+
+ACE_INLINE uid_t
+ACE_Process_Options::geteuid (void)
+{
+ return this->euid_;
+}
+
+ACE_INLINE uid_t
+ACE_Process_Options::getrgid (void)
+{
+ return this->rgid_;
+}
+
+ACE_INLINE uid_t
+ACE_Process_Options::getegid (void)
+{
+ return this->egid_;
+}
+#endif /* ACE_WIN32 */
+
+ACE_INLINE ACE_TCHAR *
+ACE_Process_Options::command_line_buf (int *max_lenp)
+{
+ if (max_lenp != 0)
+ *max_lenp = this->command_line_buf_len_;
+ return this->command_line_buf_;
+}
+
+ACE_INLINE ACE_TCHAR *
+ACE_Process_Options::working_directory (void)
+{
+#if !defined (ACE_HAS_WINCE)
+ if (working_directory_[0] == '\0')
+ return 0;
+ else
+ return working_directory_;
+#else
+ return 0;
+#endif /* !ACE_HAS_WINCE */
+}
+
+ACE_INLINE void
+ACE_Process_Options::working_directory (const char *wd)
+{
+#if !defined(ACE_HAS_WINCE)
+ ACE_OS::strcpy (working_directory_, ACE_TEXT_CHAR_TO_TCHAR (wd));
+#else
+ ACE_UNUSED_ARG (wd);
+#endif /* !ACE_HAS_WINCE */
+}
+
+#if defined (ACE_HAS_WCHAR)
+ACE_INLINE void
+ACE_Process_Options::working_directory (const wchar_t *wd)
+{
+#if !defined(ACE_HAS_WINCE)
+ ACE_OS::strcpy (working_directory_, ACE_TEXT_WCHAR_TO_TCHAR (wd));
+#else
+ ACE_UNUSED_ARG (wd);
+#endif /* !ACE_HAS_WINCE */
+}
+#endif /* ACE_HAS_WCHAR */
+
+ACE_INLINE void
+ACE_Process_Options::process_name (const ACE_TCHAR *p)
+{
+ ACE_OS::strcpy (this->process_name_, p);
+}
+
+ACE_INLINE const ACE_TCHAR *
+ACE_Process_Options::process_name (void)
+{
+ if (process_name_[0] == '\0')
+ this->process_name (this->command_line_argv ()[0]);
+
+ return this->process_name_;
+}
+
+ACE_INLINE void
+ACE_Managed_Process::unmanage (void)
+{
+ delete this;
+}
+
+#if defined (ACE_HAS_WINCE)
+// Here is a collection of inline functions which are defined only
+// under CE. They are not empty on most other platforms.
+
+ACE_INLINE int
+ACE_Process_Options::setenv (ACE_TCHAR *envp[])
+{
+ ACE_UNUSED_ARG (envp);
+ return -1;
+}
+
+ACE_INLINE int
+ACE_Process_Options::setenv (const ACE_TCHAR *format, ...)
+{
+ return -1;
+}
+
+ACE_INLINE int
+ACE_Process_Options::setenv (const ACE_TCHAR *variable_name,
+ const ACE_TCHAR *format,
+ ...)
+{
+ return -1;
+}
+
+ACE_INLINE int
+ACE_Process_Options::set_handles (ACE_HANDLE std_in,
+ ACE_HANDLE std_out,
+ ACE_HANDLE std_err)
+{
+ ACE_UNUSED_ARG (std_in);
+ ACE_UNUSED_ARG (std_out);
+ ACE_UNUSED_ARG (std_err);
+ return -1;
+}
+
+#endif /* ACE_HAS_WINCE */
diff --git a/ace/Threads/Process_Manager.cpp b/ace/Threads/Process_Manager.cpp
new file mode 100644
index 00000000000..46d5eb58c6d
--- /dev/null
+++ b/ace/Threads/Process_Manager.cpp
@@ -0,0 +1,941 @@
+// $Id$
+
+// Process_Manager.cpp
+#include "ace/Synch_T.h"
+#include "ace/Process.h"
+#include "ace/Signal.h"
+#include "ace/Process_Manager.h"
+#include "ace/Object_Manager.h"
+#include "ace/Log_Msg.h"
+
+#if !defined (__ACE_INLINE__)
+#include "ace/Process_Manager.i"
+#endif /* __ACE_INLINE__ */
+
+ACE_RCSID(ace, Process_Manager, "$Id$")
+
+#if defined (ACE_HAS_SIG_C_FUNC)
+extern "C" void
+ACE_Process_Manager_cleanup (void *instance, void *arg)
+{
+ ACE_Process_Manager::cleanup (instance, arg);
+}
+#endif
+
+void
+ACE_Process_Manager::cleanup (void *, void *)
+{
+ ACE_Process_Manager::close_singleton ();
+}
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Process_Manager)
+
+// Singleton instance.
+ACE_Process_Manager *ACE_Process_Manager::instance_ = 0;
+
+// Controls whether the <Process_Manager> is deleted when we shut down
+// (we can only delete it safely if we created it!)
+int ACE_Process_Manager::delete_instance_ = 0;
+
+ACE_Process_Descriptor::~ACE_Process_Descriptor (void)
+{
+}
+
+void
+ACE_Process_Descriptor::dump (void) const
+{
+ ACE_TRACE ("ACE_Process_Descriptor::dump");
+
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\nproc_id_ = %d"),
+ this->process_->getpid( )));
+
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+void
+ACE_Process_Manager::dump (void) const
+{
+ ACE_TRACE ("ACE_Process_Manager::dump");
+
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\nmax_process_table_size_ = %d"), this->max_process_table_size_));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\ncurrent_count_ = %d"), this->current_count_));
+
+ for (size_t i = 0; i < this->current_count_; i++)
+ this->process_table_[i].dump ();
+
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+ACE_Process_Descriptor::ACE_Process_Descriptor (void)
+ : process_ (0),
+ exit_notify_ (0)
+{
+ ACE_TRACE ("ACE_Process_Descriptor::ACE_Process_Descriptor");
+}
+
+ACE_Process_Manager *
+ACE_Process_Manager::instance (void)
+{
+ ACE_TRACE ("ACE_Process_Manager::instance");
+
+ if (ACE_Process_Manager::instance_ == 0)
+ {
+ // Perform Double-Checked Locking Optimization.
+ ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon,
+ *ACE_Static_Object_Lock::instance (), 0));
+
+ if (ACE_Process_Manager::instance_ == 0)
+ {
+ ACE_NEW_RETURN (ACE_Process_Manager::instance_,
+ ACE_Process_Manager,
+ 0);
+ ACE_Process_Manager::delete_instance_ = 1;
+
+ // Register with the Object_Manager so that the wrapper to
+ // delete the proactor will be called when Object_Manager is
+ // being terminated.
+
+#if defined ACE_HAS_SIG_C_FUNC
+ ACE_Object_Manager::at_exit (ACE_Process_Manager::instance_,
+ ACE_Process_Manager_cleanup,
+ 0);
+#else
+ ACE_Object_Manager::at_exit (ACE_Process_Manager::instance_,
+ ACE_Process_Manager::cleanup,
+ 0);
+#endif /* ACE_HAS_SIG_C_FUNC */
+
+ }
+ }
+
+ return ACE_Process_Manager::instance_;
+}
+
+ACE_Process_Manager *
+ACE_Process_Manager::instance (ACE_Process_Manager *tm)
+{
+ ACE_TRACE ("ACE_Process_Manager::instance");
+ ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon,
+ *ACE_Static_Object_Lock::instance (), 0));
+
+ ACE_Process_Manager *t = ACE_Process_Manager::instance_;
+ // We can't safely delete it since we don't know who created it!
+ ACE_Process_Manager::delete_instance_ = 0;
+
+ // Register with the Object_Manager so that the wrapper to
+ // delete the proactor will be called when Object_Manager is
+ // being terminated.
+
+#if defined ACE_HAS_SIG_C_FUNC
+ ACE_Object_Manager::at_exit (ACE_Process_Manager::instance_,
+ ACE_Process_Manager_cleanup,
+ 0);
+#else
+ ACE_Object_Manager::at_exit (ACE_Process_Manager::instance_,
+ ACE_Process_Manager::cleanup,
+ 0);
+#endif /* ACE_HAS_SIG_C_FUNC */
+
+ ACE_Process_Manager::instance_ = tm;
+ return t;
+}
+
+void
+ACE_Process_Manager::close_singleton( void )
+{
+ ACE_TRACE ("ACE_Process_Manager::close_singleton");
+
+ ACE_MT (ACE_GUARD (ACE_Recursive_Thread_Mutex, ace_mon,
+ *ACE_Static_Object_Lock::instance ()));
+
+ if (ACE_Process_Manager::delete_instance_)
+ {
+ delete ACE_Process_Manager::instance_;
+ ACE_Process_Manager::instance_ = 0;
+ ACE_Process_Manager::delete_instance_ = 0;
+ }
+}
+
+int
+ACE_Process_Manager::resize (size_t size)
+{
+ ACE_TRACE ("ACE_Process_Manager::resize");
+
+ ACE_Process_Descriptor *temp;
+
+ ACE_NEW_RETURN (temp,
+ ACE_Process_Descriptor[size],
+ -1);
+
+ for (size_t i = 0;
+ i < this->current_count_;
+ i++)
+ // Structure assignment.
+ temp[i] = this->process_table_[i];
+
+ this->max_process_table_size_ = size;
+
+ delete [] this->process_table_;
+
+ this->process_table_ = temp;
+ return 0;
+}
+
+// Create and initialize the table to keep track of the process pool.
+
+int
+ACE_Process_Manager::open (size_t size,
+ ACE_Reactor *r)
+{
+ ACE_TRACE ("ACE_Process_Manager::open");
+
+#if !defined (ACE_LACKS_SETPGID)
+ // Set up a process group so that the thread that opened this
+ // Manager will be able to put children into its own group and wait
+ // for them.
+ if (ACE_OS::setpgid (0, 0) == -1)
+ ACE_ERROR ((LM_WARNING,
+ ACE_LIB_TEXT ("%p.\n"),
+ ACE_LIB_TEXT ("ACE_Process_Manager::open: can't create a ")
+ ACE_LIB_TEXT ("process group; some wait functions may fail")));
+#endif /* ACE_LACKS_SETPGID */
+
+ if (r)
+ {
+ ACE_Event_Handler::reactor (r);
+#if !defined (ACE_WIN32) && !defined (ACE_PSOS)
+ // Register signal handler object.
+ if (reactor ()->register_handler
+ (SIGCHLD, this) == -1)
+ ACE_ERROR ((LM_ERROR,
+ "%p\n%a",
+ "register_handler",
+ 1));
+#endif // !defined(ACE_WIN32) && !defined (ACE_PSOS)
+ }
+
+ ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1));
+
+ if (this->max_process_table_size_ < size)
+ this->resize (size);
+ return 0;
+}
+
+// Initialize the synchronization variables.
+
+ACE_Process_Manager::ACE_Process_Manager (size_t size,
+ ACE_Reactor *r)
+ : ACE_Event_Handler (),
+ process_table_ (0),
+ max_process_table_size_ (0),
+ current_count_ (0),
+ default_exit_handler_ (0)
+#if defined (ACE_HAS_THREADS)
+ , lock_ ()
+#endif /* ACE_HAS_THREADS */
+{
+ ACE_TRACE ("ACE_Process_Manager::ACE_Process_Manager");
+
+ if (this->open (size,
+ r) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("%p\n"),
+ ACE_LIB_TEXT ("ACE_Process_Manager")));
+}
+
+// Close up and release all resources.
+
+int
+ACE_Process_Manager::close (void)
+{
+ ACE_TRACE ("ACE_Process_Manager::close");
+
+#if !defined (ACE_WIN32)
+ if (this->reactor ())
+ {
+ this->reactor ()->remove_handler (this, 0);
+ this->reactor (0);
+ }
+#endif /* !ACE_WIN32 */
+
+ ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1));
+
+ if (this->process_table_ != 0)
+ {
+ while (this->current_count_ > 0)
+ this->remove_proc (0);
+
+ delete [] this->process_table_;
+ this->process_table_ = 0;
+ this->max_process_table_size_ = 0;
+ this->current_count_ = 0;
+ }
+
+ if (this->default_exit_handler_ != 0)
+ this->default_exit_handler_->handle_close (ACE_INVALID_HANDLE,0);
+ this->default_exit_handler_ = 0;
+
+ return 0;
+}
+
+ACE_Process_Manager::~ACE_Process_Manager (void)
+{
+ ACE_TRACE ("ACE_Process_Manager::~ACE_Process_Manager");
+ this->close ();
+}
+
+#if !defined (ACE_WIN32)
+
+// This is called when the Reactor notices that a Process has exited.
+// What has actually happened is a SIGCHLD invoked the <handle_signal>
+// routine, which fooled the Reactor into thinking that this routine
+// needed to be called. Since we don't know which Process exited, we
+// must reap as many exit statuses as are immediately available.
+
+int
+ACE_Process_Manager::handle_input (ACE_HANDLE)
+{
+ ACE_TRACE ("ACE_Process_Manager::handle_input");
+
+ pid_t pid;
+
+ do
+ pid = this->wait (0,
+ ACE_Time_Value::zero);
+ while (pid != 0 && pid != ACE_INVALID_PID);
+
+ return 0;
+}
+
+#endif /* !ACE_WIN32 */
+
+// On Unix, this routine is called asynchronously when a SIGCHLD is
+// received. We just tweak the reactor so that it'll call back our
+// <handle_input> function, which allows us to handle Process exits
+// synchronously.
+//
+// On Win32, this routine is called synchronously, and is passed the
+// HANDLE of the Process that exited, so we can do all our work here.
+
+int
+ACE_Process_Manager::handle_signal (int,
+ siginfo_t *si,
+ ucontext_t *)
+{
+#if defined (ACE_WIN32)
+ ACE_HANDLE proc = si->si_handle_;
+ ACE_exitcode status = 0;
+ BOOL result = ::GetExitCodeProcess (proc,
+ &status);
+ if (result)
+ {
+ if (status != STILL_ACTIVE)
+ {
+ {
+ ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, lock_, -1));
+
+ ssize_t i = this->find_proc (proc);
+#if 0
+ pid_t pid = i != -1
+ ? process_table_[i].process_->getpid ()
+ : ACE_INVALID_PID;
+#endif
+ this->notify_proc_handler (i, status);
+ this->remove_proc (i);
+ }
+ return -1; // remove this HANDLE/Event_Handler combination
+ }
+ else
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_LIB_TEXT ("Process still active")
+ ACE_LIB_TEXT (" -- shouldn't have been called yet!\n")),
+ 0); // return 0 : stay registered
+ }
+ else
+ {
+ // <GetExitCodeProcess> failed.
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_LIB_TEXT ("GetExitCodeProcess failed")),
+ -1); // return -1: unregister
+ }
+#else /* !ACE_WIN32 */
+ ACE_UNUSED_ARG (si);
+ return reactor ()->notify
+ (this,
+ ACE_Event_Handler::READ_MASK);
+#endif /* !ACE_WIN32 */
+}
+
+int
+ACE_Process_Manager::register_handler (ACE_Event_Handler *eh,
+ pid_t pid)
+{
+ ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1));
+
+ if (pid == ACE_INVALID_PID)
+ {
+ if (this->default_exit_handler_ != 0)
+ this->default_exit_handler_->handle_close
+ (ACE_INVALID_HANDLE,
+ 0);
+ this->default_exit_handler_ = eh;
+ return 0;
+ }
+
+ ssize_t i = this->find_proc (pid);
+
+ if (i == -1)
+ // set "process not found" error
+ return -1;
+
+ ACE_Process_Descriptor &proc_desc = this->process_table_[i];
+
+ if (proc_desc.exit_notify_ != 0)
+ proc_desc.exit_notify_->handle_close
+ (ACE_INVALID_HANDLE,
+ 0);
+ proc_desc.exit_notify_ = eh;
+ return 0;
+}
+
+// Create a new process.
+
+pid_t
+ACE_Process_Manager::spawn (ACE_Process_Options &options)
+{
+ ACE_Process *process;
+ ACE_NEW_RETURN (process,
+ ACE_Managed_Process,
+ ACE_INVALID_PID);
+
+ return spawn (process, options);
+}
+
+// Create a new process.
+
+pid_t
+ACE_Process_Manager::spawn (ACE_Process *process,
+ ACE_Process_Options &options)
+{
+ ACE_TRACE ("ACE_Process_Manager::spawn");
+
+ if (options.getgroup () == ACE_INVALID_PID)
+ options.setgroup (ACE_OS::getpid ());
+
+ pid_t pid = process->spawn (options);
+
+ // Only include the pid in the parent's table.
+ if (pid == ACE_INVALID_PID
+ || pid == 0)
+ return pid;
+
+ ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex,
+ ace_mon, this->lock_, -1));
+
+ if (this->append_proc (process) == -1)
+ // bad news: spawned, but not registered in table.
+ return ACE_INVALID_PID;
+
+ return pid;
+}
+
+// Create N new processs.
+
+int
+ACE_Process_Manager::spawn_n (size_t n,
+ ACE_Process_Options &options,
+ pid_t *child_pids)
+{
+ ACE_TRACE ("ACE_Process_Manager::spawn_n");
+
+ if (child_pids != 0)
+ for (size_t i = 0;
+ i < n;
+ ++i)
+ child_pids[i] = ACE_INVALID_PID;
+
+ for (size_t i = 0;
+ i < n;
+ i++)
+ {
+ pid_t pid = this->spawn (options);
+ if (pid == ACE_INVALID_PID || pid == 0)
+ // We're in the child or something's gone wrong.
+ return pid;
+ else if (child_pids != 0)
+ child_pids[i] = pid;
+ }
+
+ return 0;
+}
+
+// Append a process into the pool (does not check for duplicates).
+// Must be called with locks held.
+
+int
+ACE_Process_Manager::append_proc (ACE_Process *proc)
+{
+ ACE_TRACE ("ACE_Process_Manager::append_proc");
+
+ // Try to resize the array to twice its existing size if we run out
+ // of space...
+ if (this->current_count_ >= this->max_process_table_size_
+ && this->resize (this->max_process_table_size_ * 2) == -1)
+ return -1;
+ else
+ {
+ ACE_Process_Descriptor &proc_desc =
+ this->process_table_[this->current_count_];
+
+ proc_desc.process_ = proc;
+ proc_desc.exit_notify_ = 0;
+
+#if defined (ACE_WIN32)
+ // If we have a Reactor, then we're supposed to reap Processes
+ // automagically. Get a handle to this new Process and tell the
+ // Reactor we're interested in <handling_input> on it.
+
+ ACE_Reactor *r = this->reactor ();
+ if (r != 0)
+ r->register_handler (this,
+ proc->gethandle ());
+#endif /* ACE_WIN32 */
+
+ this->current_count_++;
+ return 0;
+ }
+}
+
+// Insert a process into the pool (checks for duplicates and doesn't
+// allow them to be inserted twice).
+
+int
+ACE_Process_Manager::insert_proc (ACE_Process *proc)
+{
+ ACE_TRACE ("ACE_Process_Manager::insert_proc");
+
+ // Check for duplicates and bail out if they're already
+ // registered...
+ if (this->find_proc (proc->getpid ()) != -1)
+ return -1;
+
+ return this->append_proc (proc);
+}
+
+// Remove a process from the pool.
+
+int
+ACE_Process_Manager::remove (pid_t pid)
+{
+ ACE_TRACE ("ACE_Process_Manager::remove");
+
+ ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1));
+
+ ssize_t i = this->find_proc (pid);
+
+ if (i != -1)
+ return this->remove_proc (i);
+
+ // set "process not found" error
+ return -1;
+}
+
+// Remove a process from the pool. Must be called with locks held.
+
+int
+ACE_Process_Manager::remove_proc (size_t i)
+{
+ ACE_TRACE ("ACE_Process_Manager::remove_proc");
+
+ // If there's an exit_notify_ <Event_Handler> for this pid, call its
+ // <handle_close> method.
+
+ if (this->process_table_[i].exit_notify_ != 0)
+ {
+ this->process_table_[i].exit_notify_->handle_close
+ (this->process_table_[i].process_->gethandle(),
+ 0);
+ this->process_table_[i].exit_notify_ = 0;
+ }
+
+#if defined (ACE_WIN32)
+ ACE_Reactor *r = this->reactor ();
+ if (r != 0)
+ r->remove_handler (this->process_table_[i].process_->gethandle (),
+ ACE_Event_Handler::DONT_CALL);
+#endif /* ACE_WIN32 */
+
+ this->process_table_[i].process_->unmanage ();
+
+ this->process_table_[i].process_ = 0;
+
+ this->current_count_--;
+
+ if (this->current_count_ > 0)
+ // Compact the table by moving the last item into the slot vacated
+ // by the index being removed (this is a structure assignment).
+ this->process_table_[i] =
+ this->process_table_[this->current_count_];
+
+ return 0;
+}
+
+int
+ACE_Process_Manager::terminate (pid_t pid)
+{
+ ACE_TRACE ("ACE_Process_Manager::terminate");
+
+ ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1));
+
+ // Check for duplicates and bail out if they're already
+ // registered...
+ ssize_t i = this->find_proc (pid);
+
+ if (i == -1)
+ // set "no such process" error
+ return -1;
+
+ int result = ACE::terminate_process (pid);
+
+ if (result != -1)
+ {
+ // Save/restore errno.
+ ACE_Errno_Guard error (errno);
+ this->remove_proc (i);
+ return 0;
+ }
+ else
+ return -1;
+}
+
+int
+ACE_Process_Manager::terminate (pid_t pid,
+ int sig)
+{
+ ACE_TRACE ("ACE_Process_Manager::terminate");
+
+ ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1));
+
+ // Check for duplicates and bail out if they're already
+ // registered...
+ ssize_t i = this->find_proc (pid);
+
+ if (i == -1)
+ // set "no such process" error
+ return -1;
+
+ return ACE_OS::kill (pid, sig);
+}
+
+// Locate the index in the table associated with <pid>. Must be
+// called with the lock held.
+
+ssize_t
+ACE_Process_Manager::find_proc (pid_t pid)
+{
+ ACE_TRACE ("ACE_Process_Manager::find_proc");
+
+ for (size_t i = 0; i < this->current_count_; ++i)
+ if (pid == this->process_table_[i].process_->getpid ())
+ return i;
+
+ return -1;
+}
+
+#if defined (ACE_WIN32)
+// Locate the index in the table associated with <h>. Must be
+// called with the lock held.
+
+ssize_t
+ACE_Process_Manager::find_proc (ACE_HANDLE h)
+{
+ ACE_TRACE ("ACE_Process_Manager::find_proc");
+
+ for (size_t i = 0; i < this->current_count_; ++i)
+ if (h == this->process_table_[i].process_->gethandle ())
+ return i;
+
+ return -1;
+}
+#endif /* ACE_WIN32 */
+
+// Wait for all the Processs to exit, or until <timeout> elapses.
+// Returns the number of Processes remaining, or -1 on an error.
+
+int
+ACE_Process_Manager::wait (const ACE_Time_Value &timeout)
+{
+ ACE_TRACE ("ACE_Process_Manager::wait");
+
+ ACE_Time_Value until = timeout;
+ ACE_Time_Value remaining = timeout;
+
+ if (until < ACE_Time_Value::max_time)
+ until += ACE_OS::gettimeofday ();
+
+ while (current_count_ > 0)
+ {
+ pid_t pid = this->wait (0, remaining);
+
+ if (pid == ACE_INVALID_PID) // wait() failed
+ return -1;
+ else if (pid == 0) // timeout
+ break;
+
+ remaining = until < ACE_Time_Value::max_time
+ ? until - ACE_OS::gettimeofday ()
+ : ACE_Time_Value::max_time;
+
+ if (remaining <= ACE_Time_Value::zero)
+ break;
+
+ // else Process terminated...wait for more...
+ }
+ return current_count_;
+}
+
+// Collect a single child process' exit status. Store the exit code
+// in *<stat_loc> if non-zero. Call the appropriate exit_notify. If
+// <pid> == 0, wait for any of the Process_Manager's children (or as
+// near as possible -- on Unix, we might accidentally get some other
+// Process_Manager's Process, or an unmanaged Process, or a child
+// process started by some other means.
+
+pid_t
+ACE_Process_Manager::wait (pid_t pid,
+ ACE_exitcode *status)
+{
+ ACE_TRACE ("ACE_Process_Manager::wait");
+
+ return this->wait (pid,
+ ACE_Time_Value::max_time,
+ status);
+}
+
+// Collect a single child processes' exit status, unless <timeout>
+// elapses before the process exits. Same caveats about accidental
+// Process reaping on Unix as above.
+
+pid_t
+ACE_Process_Manager::wait (pid_t pid,
+ const ACE_Time_Value &timeout,
+ ACE_exitcode *status)
+{
+ ACE_TRACE ("ACE_Process_Manager::wait");
+
+ ACE_exitcode local_stat = 0;
+ if (status == 0)
+ status = &local_stat;
+
+ *status = 0;
+
+ ssize_t idx = -1;
+ ACE_Process *proc = 0;
+
+ ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1));
+
+ if (pid != 0)
+ {
+ idx = this->find_proc (pid);
+ if (idx == -1)
+ return ACE_INVALID_PID;
+ else
+ proc = process_table_[idx].process_;
+ }
+
+ if (proc != 0)
+ pid = proc->wait (timeout, status);
+ else
+ {
+ // Wait for any Process spawned by this Process_Manager.
+#if defined (ACE_WIN32)
+ HANDLE *handles;
+
+ ACE_NEW_RETURN (handles,
+ HANDLE[current_count_],
+ ACE_INVALID_PID);
+
+ for (size_t i = 0;
+ i < current_count_;
+ ++i)
+ handles[i] =
+ process_table_[i].process_->gethandle ();
+
+ DWORD result = ::WaitForMultipleObjects (current_count_,
+ handles,
+ FALSE,
+ timeout == ACE_Time_Value::max_time
+ ? INFINITE
+ : timeout.msec ());
+ if (result == WAIT_FAILED)
+ pid = ACE_INVALID_PID;
+ else if (result == WAIT_TIMEOUT)
+ pid = 0;
+ else
+ {
+ // Green Hills produces a warning that result >= WAIT_OBJECT_0 is
+ // a pointless comparison because WAIT_OBJECT_0 is zero and DWORD is
+ // unsigned long, so this test is skipped for Green Hills.
+ // Same for mingw.
+# if defined (ghs) || defined (__MINGW32__)
+ ACE_ASSERT (result < WAIT_OBJECT_0 + current_count_);
+# else
+ ACE_ASSERT (result >= WAIT_OBJECT_0
+ && result < WAIT_OBJECT_0 + current_count_);
+# endif
+
+ idx = this->find_proc (handles[result - WAIT_OBJECT_0]);
+
+ if (idx != -1)
+ {
+ pid = process_table_[idx].process_->getpid ();
+ result = ::GetExitCodeProcess (handles[result - WAIT_OBJECT_0],
+ status);
+ if (result == 0)
+ {
+ // <GetExitCodeProcess> failed!
+ this->remove_proc (idx);
+ pid = ACE_INVALID_PID;
+ }
+ }
+ else
+ {
+ // uh oh...handle removed from process_table_, even though
+ // we're holding a lock!
+ delete [] handles;
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_LIB_TEXT ("Process removed")
+ ACE_LIB_TEXT (" -- somebody's ignoring the lock!\n")),
+ -1);
+ }
+ }
+
+ delete [] handles;
+#else /* !defined(ACE_WIN32) */
+ if (timeout == ACE_Time_Value::max_time)
+ pid = ACE_OS::waitpid (-(ACE_OS::getpid ()),
+ status,
+ 0);
+ else if (timeout == ACE_Time_Value::zero)
+ pid = ACE_OS::waitpid (-(ACE_OS::getpid ()),
+ status,
+ WNOHANG);
+ else
+ {
+ ACE_Time_Value wait_until =
+ timeout + ACE_OS::gettimeofday();
+
+ for (;;)
+ {
+ pid = ACE_OS::waitpid (-(ACE_OS::getpid()),
+ status,
+ WNOHANG);
+ if (pid != 0)
+ // "no such children" error, or got one!
+ break;
+
+ ACE_Sig_Set alarm_or_child;
+
+ alarm_or_child.sig_add (SIGALRM);
+ alarm_or_child.sig_add (SIGCHLD);
+
+ ACE_Time_Value time_left = wait_until - ACE_OS::gettimeofday ();
+
+ // if ACE_OS::ualarm doesn't have sub-second resolution:
+ time_left += ACE_Time_Value (0, 500000);
+ time_left.usec (0);
+
+ if (time_left <= ACE_Time_Value::zero) {
+ pid = 0;
+ break;
+ }
+
+ ACE_OS::ualarm (time_left);
+ ACE_OS::sigwait (alarm_or_child);
+ }
+ }
+#endif /* !defined (ACE_WIN32) */
+ }
+
+ if (pid != ACE_INVALID_PID && pid != 0)
+ {
+ if (proc == 0)
+ {
+ idx = this->find_proc (pid);
+ if (idx == -1)
+ {
+ // oops, reaped an unmanaged process!
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_LIB_TEXT ("(%P|%t) oops, reaped unmanaged %d\n"),
+ pid));
+ return pid;
+ }
+ else
+ proc = process_table_[idx].process_;
+ }
+ else
+ ACE_ASSERT (pid == proc->getpid ());
+
+ this->notify_proc_handler (idx,
+ *status);
+ this->remove_proc (idx);
+ }
+
+ return pid;
+}
+
+// Legacy method:
+
+int
+ACE_Process_Manager::reap (pid_t pid,
+ ACE_exitcode *stat_loc,
+ int options)
+{
+ ACE_TRACE ("ACE_Process_Manager::reap");
+
+ return this->wait (pid,
+ (ACE_BIT_ENABLED (options, WNOHANG)
+ ? ACE_Time_Value::zero
+ : ACE_Time_Value::max_time),
+ stat_loc);
+}
+
+// Notify either the process-specific handler or the generic handler.
+// If process-specific, call handle_close on the handler. Returns 1
+// if process found, 0 if not. Must be called with locks held.
+
+int
+ACE_Process_Manager::notify_proc_handler (size_t i,
+ ACE_exitcode exit_code)
+{
+ if (i < current_count_)
+ {
+ ACE_Process_Descriptor &proc_desc =
+ this->process_table_[i];
+
+ proc_desc.process_->exit_code (exit_code);
+
+ if (proc_desc.exit_notify_ != 0)
+ proc_desc.exit_notify_->handle_exit (proc_desc.process_);
+ else if (this->default_exit_handler_ != 0
+ && this->default_exit_handler_->handle_exit (proc_desc.process_) < 0)
+ {
+ this->default_exit_handler_->handle_close
+ (ACE_INVALID_HANDLE,
+ 0);
+ this->default_exit_handler_ = 0;
+ }
+ return 1;
+ }
+ else
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_LIB_TEXT ("(%P:%t|%T) ACE_Process_Manager::notify_proc_handler:"),
+ ACE_LIB_TEXT (" unknown/unmanaged process reaped\n")));
+ return 0;
+ }
+}
diff --git a/ace/Threads/Process_Manager.h b/ace/Threads/Process_Manager.h
new file mode 100644
index 00000000000..dade19e1001
--- /dev/null
+++ b/ace/Threads/Process_Manager.h
@@ -0,0 +1,398 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Process_Manager.h
+ *
+ * $Id$
+ *
+ * @author Douglas C. Schmidt <schmidt@cs.wustl.edu>
+ */
+//=============================================================================
+
+
+#ifndef ACE_PROCESS_MANAGER_H
+#define ACE_PROCESS_MANAGER_H
+#include "ace/pre.h"
+
+#include "ace/Synch.h"
+#include "ace/Reactor.h"
+#include "ace/Event_Handler.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "ace/Process.h"
+
+/**
+ * @class ACE_Process_Descriptor
+ *
+ * @brief Information describing each process that's controlled by an
+ * <ACE_Process_Manager>.
+ */
+class ACE_Export ACE_Process_Descriptor
+{
+private:
+ friend class ACE_Process_Manager;
+
+ /// Default ctor/dtor.
+ ACE_Process_Descriptor (void);
+ ~ACE_Process_Descriptor (void);
+
+ /// Describes the process itself.
+ ACE_Process *process_;
+
+ /// function to call when process exits
+ ACE_Event_Handler *exit_notify_;
+
+ /// Dump the state of an object.
+ void dump (void) const;
+};
+
+/**
+ * @class ACE_Process_Manager
+ *
+ * @brief Manages a group of processes.
+ *
+ * This class allows applications to control groups of processes,
+ * similar to how the <ACE_Thread_Manager> controls groups of
+ * threads. Naturally, it doesn't work at all on platforms, such
+ * as VxWorks or pSoS, that don't support process.
+ * There are two (main) ways of using <ACE_Process_Manager>,
+ * depending on how involved you wish to be with the termination
+ * of managed <ACE_Process>es. If you just want <Process>es to
+ * go away when they're finished, simply register the
+ * <Process_Manager> with an <ACE_Reactor>:
+ * ACE_Process_Manager mgr( 100, some_reactor )
+ * -or-
+ * ACE_Process_Manager mgr;
+ * ...
+ * mgr.open( 100, some_reactor );
+ * Then, the <Process_Manager> will clean up after any
+ * <Process>es that it spawns. (On Unix, this means executing a
+ * wait(2) to collect the exit status -- and avoid zombie
+ * processes; on Win32, it means closing the process and thread
+ * HANDLEs that are created when CreateProcess is called.)
+ * If, on the other hand (and for some inexplicable reason) you
+ * want to explicitly invoke the terminated <Process> cleanup
+ * code, then *don't* register the <Process_Manager> with a
+ * Reactor, and be sure to call one of the
+ * <Process_Manager::wait> functions whenever there might be
+ * managed <Process>es that have exited.
+ * Note that in either case, <Process_Manager> allows you to
+ * register "<Event_Handlers>" to be called when a specific
+ * <Process> exits, or when any <Process> without a specific
+ * <Event_Handler> exits. When a <Process> exits, the
+ * appropriate <Event_Handler>'s <handle_input> is called; the
+ * <ACE_HANDLE> passed is either the Process' HANDLE (on Win32),
+ * or its pid cast to an <ACE_HANDLE> (on unix).
+ * It is also possible to call the <Process_Manager::wait>
+ * functions even though the <Process_Manager> is registered with
+ * a <Reactor>.
+ * Note also that the wait functions are "sloppy" on Unix,
+ * because there's no good way to wait for a subset of the
+ * children of a process. The wait functions may end up
+ * collecting the exit status of a process that's not managed by
+ * the <Process_Manager> whose <wait> you invoked. It's best to
+ * only use a single <Process_Manager>, and to create all
+ * subprocesses by calling that <Process_Manager>'s <spawn>
+ * method.
+ * Incidentally, when you register your <Process_Manager> with a
+ * <Reactor> its notification pipe is used to help "reap" the
+ * available exit statuses. Therefore, you must not use a
+ * <Reactor> whose notify pipe has been disabled. Here's the
+ * sequence of steps used to reap the exit statuses in this case:
+ * + The <Process_Manager> registers a signal handler for
+ * SIGCHLD.
+ * + The SIGCHLD handler, when invoked, uses the <Reactor>'s
+ * <notify> method to inform the <Reactor> to wake up.
+ * + Next, the <Reactor> calls the <Process_Manager>'s
+ * <handle_input>, this happens synchronously, not in
+ * sighandler-space.
+ * + The <handle_input> method collects all available exit
+ * statuses.
+ */
+class ACE_Export ACE_Process_Manager : protected ACE_Event_Handler
+{
+public:
+ friend class ACE_Process_Control;
+
+ enum
+ {
+ DEFAULT_SIZE = 100
+ };
+
+ // = Initialization and termination methods.
+ /**
+ * Initialize an <ACE_Process_Manager> with a table containing up to
+ * <size> processes. This table resizes itself automatically as
+ * needed. If a non-NULL <reactor> is provided, this
+ * <ACE_Process_Manager> uses it to notify an application when a
+ * process it controls exits. By default, however, we don't use an
+ * <ACE_Reactor>.
+ */
+ ACE_Process_Manager (size_t size = ACE_Process_Manager::DEFAULT_SIZE,
+ ACE_Reactor *reactor = 0);
+
+ /**
+ * Initialize an <ACE_Process_Manager> with a table containing up to
+ * <size> processes. This table resizes itself automatically as
+ * needed. If a non-NULL <reactor> is provided, this
+ * <ACE_Process_Manager> uses it to notify an application when a
+ * process it controls exits. By default, however, we don't use an
+ * <ACE_Reactor>.
+ */
+ int open (size_t size = DEFAULT_SIZE,
+ ACE_Reactor *r = 0);
+
+ /// Release all resources. Do not wait for processes to exit.
+ int close (void);
+
+ /// Destructor releases all resources and does not wait for processes
+ /// to exit.
+ virtual ~ACE_Process_Manager (void);
+
+ // = Singleton accessors.
+ /// Get pointer to a process-wide <ACE_Process_Manager>.
+ static ACE_Process_Manager *instance (void);
+
+ /// Set pointer to a process-wide <ACE_Process_Manager> and return
+ /// existing pointer.
+ static ACE_Process_Manager *instance (ACE_Process_Manager *);
+
+ /// Delete the dynamically allocated singleton.
+ static void close_singleton (void);
+
+ /// Cleanup method, used by the <ACE_Object_Manager> to destroy the
+ /// singleton.
+ static void cleanup (void *instance, void *arg);
+
+ // = Process creation methods.
+
+ /**
+ * Create a new process by passing <options> to <proc.spawn>. On
+ * success, returns the process id of the child that was created.
+ * On failure, returns ACE_INVALID_PID.
+ */
+ pid_t spawn (ACE_Process *proc,
+ ACE_Process_Options &options);
+
+ /**
+ * Create a new process by passing <options> to
+ * <ACE_Process::spawn>. On success, returns the process id of the
+ * child that was created. On failure, returns ACE_INVALID_PID.
+ */
+ pid_t spawn (ACE_Process_Options &options);
+
+ /**
+ * Create <n> new processes by passing <options> to
+ * <ACE_Process::spawn>, which is called <n> times. If <child_pids>
+ * is non-0 it is expected to be an array of <n> <pid_t>'s, which
+ * are filled in with the process ids of each newly created process.
+ * Returns 0 on success and -1 on failure.
+ */
+ int spawn_n (size_t n,
+ ACE_Process_Options &options,
+ pid_t *child_pids = 0);
+
+ // = Process synchronization operations.
+
+ /**
+ * Block until there are no more child processes running that were
+ * <spawn>ed by this <ACE_Process_Manager>. Unlike the <wait> call
+ * below, this method does not require a signal handler or
+ * <ACE_OS::sigwait> because it simply blocks synchronously waiting
+ * for all the children managed by this <ACE_Process_Manager> to
+ * exit. Note that this does not return any status information
+ * about the success or failure of exiting child processes, although
+ * any registered exit_handlers are called. Returns 0 on success
+ * (and <remove>s the corresponding <ACE_Process_Descriptor> entries
+ * from the <Process_Manager>; otherwise, returns -1 on failure.
+ */
+ int wait (const ACE_Time_Value &timeout = ACE_Time_Value::max_time);
+
+ /**
+ * Wait up to <timeout> for a single process to terminate. If
+ * pid==0, waits for any of the managed <Process>es (but see the
+ * note in the class documentation above for caveats about this --
+ * "sloppy process cleanup on unix") If pid != 0, waits for that <Process>
+ * only. Returns the pid of the Process whose exit was handled, 0
+ * if a timeout occurred, or ACE_INVALID_PID on error.
+ */
+ pid_t wait (pid_t pid,
+ const ACE_Time_Value &timeout,
+ ACE_exitcode *status = 0);
+
+ /**
+ * Wait indefinitely for a single process to terminate. If pid==0,
+ * waits for any of the managed <Process>es (but see the note in
+ * the class documentation for caveats about this -- "sloppy Process
+ * cleanup on unix") If pid != 0, waits for that <Process> only.
+ * Returns the pid of the process whose exit was handled, or
+ * ACE_INVALID_PID on error.
+ */
+ pid_t wait (pid_t pid,
+ ACE_exitcode *status = 0);
+
+ /**
+ * Reap the result of a single process by calling <ACE_OS::waitpid>,
+ * therefore, this method is not portable to Win32. If the child is
+ * successfully reaped, <remove> is called automatically. This
+ * method does the same thing that the <wait> method directly above
+ * it does -- It's just here for backwards compatibility.
+ */
+ int reap (pid_t pid = -1,
+ ACE_exitcode *stat_loc = 0,
+ int options = WNOHANG);
+
+ // = Utility methods.
+ /**
+ * Register an Event_Handler to be called back when the specified
+ * process exits. If pid == ACE_INVALID_PID this handler is called
+ * when any process with no specific handler exits.
+ */
+ int register_handler (ACE_Event_Handler *event_handler,
+ pid_t pid = ACE_INVALID_PID);
+
+ /**
+ * Remove process <pid> from the table. This is called
+ * automatically by the <reap> method after it successfully reaped a
+ * <SIGCHLD> signal. It's also possible to call this method
+ * directly from a signal handler, but don't call both <reap> and
+ * <remove>!
+ */
+ int remove (pid_t pid);
+
+ /**
+ * Abruptly terminate a single process with id <pid> using the
+ * <ACE::terminate_process> method. Note that this call is
+ * potentially dangerous to use since the process being terminated
+ * may not have a chance to cleanup before it shuts down. Returns 0
+ * on success and -1 on failure.
+ */
+ int terminate (pid_t pid);
+
+ /// On OSs that support signals, send the signal to the specified
+ /// process. Returns 0 on success and -1 on failure.
+ int terminate (pid_t pid,
+ int sig);
+
+ /// Return the number of managed Processes.
+ size_t managed (void) const;
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+protected:
+ // = These methods allow a <Process_Manager> to be an <Event_Handler>.
+
+ // As an <Event_Handler>, the <Process_Manager> automagically
+ // detects child Processes exiting and calls notify_proc_handler()
+ // and remove(). This means that you don't have to (shouldn't!)
+ // call the wait(...) methods yourself.
+
+ // On Unix, we can't detect individual process termination very
+ // well; the best method is to catch SIGCHLD and then call the
+ // polling wait() function to collect any available exit statuses.
+ // However, we don't want to do this from within a signal handler
+ // because of the restrictions associated. Therefore (following the
+ // lead in examples/mumble) we open a bogus handle (to ACE_DEV_NULL)
+ // and register that handle with our Reactor. Then, when our
+ // SIGCHLD handler gets invoked, we tell the Reactor that the bogus
+ // handle is readable. That will cause the handle_input() function
+ // to be called once we're out of the interrupt context, and
+ // handle_input() collects exit statuses.
+
+ // On Win32, we simply register ourself with the Reactor to deal
+ // with the Process handle becoming signaled. No muss, no fuss, no
+ // signal handler, and no dummy handle.
+
+#if !defined(ACE_WIN32)
+ /// Collect one (or more, on unix) process exit status.
+ virtual int handle_input (ACE_HANDLE proc);
+#endif // !defined(ACE_WIN32)
+
+ /**
+ * On Unix, this routine is called asynchronously when a SIGCHLD is
+ * received. We just tweak the reactor so that it'll call back our
+ * <handle_input> function, which allows us to handle Process exits
+ * synchronously.
+ *
+ * On Win32, this routine is called synchronously, and is passed the
+ * HANDLE of the Process that exited, so we can do all our work here
+ */
+ virtual int handle_signal (int signum,
+ siginfo_t * = 0,
+ ucontext_t * = 0);
+
+private:
+ /// Resize the pool of Process_Descriptors.
+ int resize (size_t);
+
+ /// Locate the index of the table slot occupied by <process_id>.
+ /// Returns -1 if <process_id> is not in the <process_table_>
+ ssize_t find_proc (pid_t process_id);
+
+#if defined (ACE_WIN32)
+ /// Locate the index of the table slot occupied by <process_handle>.
+ /// Returns ~0 if <process_handle> is not in the <process_table_>
+ ssize_t find_proc (ACE_HANDLE process_handle);
+#endif /* ACE_WIN32 */
+
+ /// Insert a process in the table (checks for duplicates). Omitting
+ /// the process handle won't work on Win32...
+ int insert_proc (ACE_Process *process);
+
+ /**
+ * Append information about a process, i.e., its <process_id> in the
+ * <process_table_>. Each entry is added at the end, growing the
+ * table if necessary.
+ */
+ int append_proc (ACE_Process *process);
+
+ /// Actually removes the process at index <n> from the table. This method
+ /// must be called with locks held.
+ int remove_proc (size_t n);
+
+ /// If there's a specific handler for the Process at index <n> in the
+ /// table, or there's a default handler, call it.
+ int notify_proc_handler (size_t n,
+ ACE_exitcode status);
+
+ /// Vector that describes process state within the Process_Manager.
+ ACE_Process_Descriptor *process_table_;
+
+ /// Maximum number of processes we can manage (should be dynamically
+ /// allocated).
+ size_t max_process_table_size_;
+
+ /// Current number of processes we are managing.
+ size_t current_count_;
+
+ /// This event handler is used to notify when a process we control
+ /// exits.
+ ACE_Event_Handler *default_exit_handler_;
+
+ /// Singleton pointer.
+ static ACE_Process_Manager *instance_;
+
+ /// Controls whether the <Process_Manager> is deleted when we shut
+ /// down (we can only delete it safely if we created it!)
+ static int delete_instance_;
+
+#if defined (ACE_HAS_THREADS)
+ /// This lock protects access/ops on <process_table_>.
+ ACE_Recursive_Thread_Mutex lock_;
+#endif /* ACE_HAS_THREADS */
+};
+
+#if defined (__ACE_INLINE__)
+#include "ace/Process_Manager.i"
+#endif /* __ACE_INLINE__ */
+
+#include "ace/post.h"
+#endif /* ACE_PROCESS_MANAGER_H */
diff --git a/ace/Threads/Process_Manager.i b/ace/Threads/Process_Manager.i
new file mode 100644
index 00000000000..c6ee1f25260
--- /dev/null
+++ b/ace/Threads/Process_Manager.i
@@ -0,0 +1,8 @@
+/* -*- C++ -*- */
+// $Id$
+
+ACE_INLINE size_t
+ACE_Process_Manager::managed (void) const
+{
+ return current_count_;
+}
diff --git a/ace/Threads/Process_Mutex.cpp b/ace/Threads/Process_Mutex.cpp
new file mode 100644
index 00000000000..3930903967c
--- /dev/null
+++ b/ace/Threads/Process_Mutex.cpp
@@ -0,0 +1,76 @@
+// $Id$
+
+#include "ace/Process_Mutex.h"
+#include "ace/Synch.h"
+#include "ace/Log_Msg.h"
+
+#if !defined (__ACE_INLINE__)
+#include "ace/Process_Mutex.inl"
+#endif /* __ACE_INLINE__ */
+
+ACE_RCSID(ace, Process_Mutex, "$Id$")
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Process_Mutex)
+
+void
+ACE_Process_Mutex::dump (void) const
+{
+// ACE_TRACE ("ACE_Process_Mutex::dump");
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+ this->lock_.dump ();
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+#if defined (_ACE_USE_SV_SEM)
+const ACE_TCHAR *
+ACE_Process_Mutex::unique_name (void)
+{
+ // For all platforms other than Win32, we are going to create a
+ // machine-wide unique name if one is not provided by the user. On
+ // Win32, unnamed synchronization objects are acceptable.
+ ACE::unique_name (this, this->name_, ACE_UNIQUE_NAME_LEN);
+ return this->name_;
+}
+#endif /* _ACE_USE_SV_SEM */
+
+ACE_Process_Mutex::ACE_Process_Mutex (const char *name, void *arg)
+#if defined (_ACE_USE_SV_SEM)
+ : lock_ (name ? ACE_TEXT_CHAR_TO_TCHAR (name) :this->unique_name ())
+#else
+ : lock_ (USYNC_PROCESS, ACE_TEXT_CHAR_TO_TCHAR (name), (ACE_mutexattr_t *) arg)
+#endif /* _ACE_USE_SV_SEM */
+{
+#if defined (_ACE_USE_SV_SEM)
+ ACE_UNUSED_ARG (arg);
+#endif /* !_ACE_USE_SV_SEM */
+}
+
+#if defined (ACE_HAS_WCHAR)
+ACE_Process_Mutex::ACE_Process_Mutex (const wchar_t *name, void *arg)
+#if defined (_ACE_USE_SV_SEM)
+ : lock_ (name ? ACE_TEXT_WCHAR_TO_TCHAR (name): this->unique_name ())
+#else
+ : lock_ (USYNC_PROCESS, ACE_TEXT_WCHAR_TO_TCHAR (name), (ACE_mutexattr_t *) arg)
+#endif /* _ACE_USE_SV_SEM */
+{
+#if defined (_ACE_USE_SV_SEM)
+ ACE_UNUSED_ARG (arg);
+#endif /* _ACE_USE_SV_SEM */
+}
+#endif /* ACE_HAS_WCHAR */
+ACE_Process_Mutex::~ACE_Process_Mutex (void)
+{
+}
+
+//
+// These are instantiated both with and without ACE_HAS_THREADS.
+//
+#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION)
+
+template class ACE_Guard<ACE_Process_Mutex>;
+
+#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA)
+
+#pragma instantiate ACE_Guard<ACE_Process_Mutex>
+
+#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */
diff --git a/ace/Threads/Process_Mutex.h b/ace/Threads/Process_Mutex.h
new file mode 100644
index 00000000000..8167570f0aa
--- /dev/null
+++ b/ace/Threads/Process_Mutex.h
@@ -0,0 +1,195 @@
+// -*- C++ -*-
+
+//=============================================================================
+/**
+ * @file Process_Mutex.h
+ *
+ * $Id$
+ *
+ * A wrapper for mutexes that can be used across processes on the
+ * same host machine, as well as within a process, of course.
+ *
+ * @author Douglas C. Schmidt <schmidt@uci.edu>
+ */
+//=============================================================================
+
+#ifndef ACE_PROCESS_MUTEX_H
+#define ACE_PROCESS_MUTEX_H
+
+#include "ace/pre.h"
+
+#include "ace/config-all.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+// To make it easier to carry the setting though this file as well as
+// Process_Mutex.{cpp inl}, set a private macro here.
+#ifdef _ACE_USE_SV_SEM
+# undef _ACE_USE_SV_SEM
+#endif /* _ACE_USE_SV_SEM */
+#if defined (ACE_HAS_SYSV_IPC) && !defined (ACE_USES_MUTEX_FOR_PROCESS_MUTEX)
+# include "ace/SV_Semaphore_Complex.h"
+# define _ACE_USE_SV_SEM
+#else
+# include "ace/Synch.h"
+#endif /* ACE_HAS_SYSV_IPC && !ACE_USES_MUTEX_FOR_PROCESS_MUTEX */
+
+/**
+ * @class ACE_Process_Mutex
+ *
+ * @brief A wrapper for mutexes that can be used across processes on
+ * the same host machine, as well as within a process, of
+ * course.
+ *
+ * @attention The mechanism upon which @c ACE_Process_Mutex is based
+ * can be configured at build time to be either @c ACE_SV_Semaphore_Complex
+ * (on platforms that support it) or @c ACE_Mutex. On platforms that
+ * require interprocess mutexes be allocated from shared memory (Pthreads
+ * and UI Threads are examples), @c ACE_SV_Semaphore_Complex provides a
+ * more reliable mechanism for implementing inter-process mutex than
+ * @c ACE_Mutex. However, at least on some platforms,
+ * @c ACE_SV_Semaphore_Complex is limited to a small number of
+ * objects by the underlying System V IPC kernel parameters. If you
+ * want to force use of @c ACE_Mutex as the underlying mechanism, set
+ * @c ACE_USES_MUTEX_FOR_PROCESS_MUTEX in your @c config.h file.
+ * Also, if you require the ability to do a timed @c acquire(), you must
+ * set @c ACE_USES_MUTEX_FOR_PROCESS_MUTEX, as timed acquire does not
+ * work with System V semaphores.
+ */
+class ACE_Export ACE_Process_Mutex
+{
+public:
+ /**
+ * Create a Process_Mutex, passing in the optional @c name.
+ *
+ * @param name optional, null-terminated string containing the name of
+ * the object. Multiple users of the same @c ACE_Process_Mutex must use
+ * the same name to access the same object. If not specified, a name
+ * is generated.
+ * @param arg optional, attributes to be used to initialize the mutex.
+ * If using @c ACE_SV_Semaphore_Complex as the underlying mechanism,
+ * this argument is ignored.
+ */
+ ACE_Process_Mutex (const char *name = 0,
+ void *arg = 0);
+
+#if defined (ACE_HAS_WCHAR)
+ /**
+ * Create a Process_Mutex, passing in the optional @c name. (@c wchar_t
+ * version)
+ *
+ * @param name optional, null-terminated string containing the name of
+ * the object. Multiple users of the same @c ACE_Process_Mutex must use
+ * the same name to access the same object. If not specified, a name
+ * is generated.
+ * @param arg optional, attributes to be used to initialize the mutex.
+ * If using @c ACE_SV_Semaphore_Complex as the underlying mechanism,
+ * this argument is ignored.
+ */
+ ACE_Process_Mutex (const wchar_t *name,
+ void *arg = 0);
+#endif /* ACE_HAS_WCHAR */
+
+ ~ACE_Process_Mutex (void);
+
+ /**
+ * Explicitly destroy the mutex. Note that only one thread should
+ * call this method since it doesn't protect against race
+ * conditions.
+ *
+ * @return 0 on success; -1 on failure.
+ */
+ int remove (void);
+
+ /**
+ * Acquire lock ownership (wait on queue if necessary).
+ *
+ * @return 0 on success; -1 on failure.
+ */
+ int acquire (void);
+
+ /**
+ * Acquire lock ownership, but timeout if lock if hasn't been
+ * acquired by given time.
+ *
+ * @param tv the absolute time until which the caller is willing to
+ * wait to acquire the lock.
+ *
+ * @return 0 on success; -1 on failure.
+ */
+ int acquire (ACE_Time_Value &tv);
+
+ /**
+ * Conditionally acquire lock (i.e., don't wait on queue).
+ *
+ * @return 0 on success; -1 on failure. If the lock could not be acquired
+ * because someone else already had the lock, @c errno is set to @c EBUSY.
+ */
+ int tryacquire (void);
+
+ /// Release lock and unblock a thread at head of queue.
+ int release (void);
+
+ /// Acquire lock ownership (wait on queue if necessary).
+ int acquire_read (void);
+
+ /// Acquire lock ownership (wait on queue if necessary).
+ int acquire_write (void);
+
+ /**
+ * Conditionally acquire a lock (i.e., won't block). Returns -1 on
+ * failure. If we "failed" because someone else already had the
+ * lock, <errno> is set to <EBUSY>.
+ */
+ int tryacquire_read (void);
+
+ /**
+ * Conditionally acquire a lock (i.e., won't block). Returns -1 on
+ * failure. If we "failed" because someone else already had the
+ * lock, <errno> is set to <EBUSY>.
+ */
+ int tryacquire_write (void);
+
+ /**
+ * This is only here for consistency with the other synchronization
+ * APIs and usability with Lock adapters. Assumes the caller already has
+ * acquired the mutex and returns 0 in all cases.
+ */
+ int tryacquire_write_upgrade (void);
+
+#if !defined (_ACE_USE_SV_SEM)
+ /// Return the underlying mutex.
+ const ACE_mutex_t &lock (void) const;
+#endif /* !_ACE_USE_SV_SEM */
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+private:
+#if defined (_ACE_USE_SV_SEM)
+ /// If the user does not provide a name we generate a unique name in
+ /// this buffer.
+ ACE_TCHAR name_[ACE_UNIQUE_NAME_LEN];
+
+ /// Create and return the unique name.
+ const ACE_TCHAR *unique_name (void);
+
+ /// We need this to get the right semantics...
+ ACE_SV_Semaphore_Complex lock_;
+#else
+ ACE_Mutex lock_;
+#endif /* _ACE_USE_SV_SEM */
+};
+
+#if defined (__ACE_INLINE__)
+#include "ace/Process_Mutex.inl"
+#endif /* __ACE_INLINE__ */
+
+#include "ace/post.h"
+
+#endif /* ACE_PROCESS_MUTEX_H */
diff --git a/ace/Threads/Process_Mutex.inl b/ace/Threads/Process_Mutex.inl
new file mode 100644
index 00000000000..14c0af99e42
--- /dev/null
+++ b/ace/Threads/Process_Mutex.inl
@@ -0,0 +1,85 @@
+/* -*- C++ -*- */
+// $Id$
+
+#if !defined (_ACE_USE_SV_SEM)
+ACE_INLINE const ACE_mutex_t &
+ACE_Process_Mutex::lock (void) const
+{
+// ACE_TRACE ("ACE_Process_Mutex::lock");
+ return this->lock_.lock ();
+}
+#endif /* !_ACE_USE_SV_SEM */
+
+// Explicitly destroy the mutex.
+ACE_INLINE int
+ACE_Process_Mutex::remove (void)
+{
+ return this->lock_.remove ();
+}
+
+// Acquire lock ownership (wait on priority queue if necessary).
+ACE_INLINE int
+ACE_Process_Mutex::acquire (void)
+{
+ return this->lock_.acquire ();
+}
+
+// Acquire lock ownership (wait on priority queue if necessary).
+ACE_INLINE int
+ACE_Process_Mutex::acquire (ACE_Time_Value &tv)
+{
+#if !defined (_ACE_USE_SV_SEM)
+ return this->lock_.acquire (tv);
+#else
+ ACE_UNUSED_ARG (tv);
+ ACE_NOTSUP_RETURN (-1);
+#endif /* !_ACE_USE_SV_SEM */
+}
+
+// Conditionally acquire lock (i.e., don't wait on queue).
+ACE_INLINE int
+ACE_Process_Mutex::tryacquire (void)
+{
+ return this->lock_.tryacquire ();
+}
+
+// Release lock and unblock a thread at head of priority queue.
+ACE_INLINE int
+ACE_Process_Mutex::release (void)
+{
+ return this->lock_.release ();
+}
+
+// Acquire lock ownership (wait on priority queue if necessary).
+ACE_INLINE int
+ACE_Process_Mutex::acquire_read (void)
+{
+ return this->lock_.acquire_read ();
+}
+
+// Acquire lock ownership (wait on priority queue if necessary).
+ACE_INLINE int
+ACE_Process_Mutex::acquire_write (void)
+{
+ return this->lock_.acquire_write ();
+}
+
+// Conditionally acquire a lock (i.e., won't block).
+ACE_INLINE int
+ACE_Process_Mutex::tryacquire_read (void)
+{
+ return this->lock_.tryacquire_read ();
+}
+
+// Conditionally acquire a lock (i.e., won't block).
+ACE_INLINE int
+ACE_Process_Mutex::tryacquire_write (void)
+{
+ return this->lock_.tryacquire_write ();
+}
+
+ACE_INLINE int
+ACE_Process_Mutex::tryacquire_write_upgrade (void)
+{
+ return 0;
+}
diff --git a/ace/Threads/Process_Semaphore.cpp b/ace/Threads/Process_Semaphore.cpp
new file mode 100644
index 00000000000..ebc036b509b
--- /dev/null
+++ b/ace/Threads/Process_Semaphore.cpp
@@ -0,0 +1,91 @@
+// $Id$
+
+#include "ace/Process_Semaphore.h"
+#include "ace/Log_Msg.h"
+
+#if !defined (__ACE_INLINE__)
+#include "ace/Process_Semaphore.inl"
+#endif /* __ACE_INLINE__ */
+
+ACE_RCSID(ace, Process_Semaphore, "$Id$")
+
+void
+ACE_Process_Semaphore::dump (void) const
+{
+// ACE_TRACE ("ACE_Process_Semaphore::dump");
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+ this->lock_.dump ();
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+ACE_Process_Semaphore::ACE_Process_Semaphore (u_int count,
+ const ACE_TCHAR *name,
+ void *arg,
+ int max)
+#if defined (ACE_WIN32) || defined (ACE_HAS_POSIX_SEM) || defined (ACE_PSOS)
+ : lock_ (count, USYNC_PROCESS, name, arg, max)
+#else
+ : lock_ (name, ACE_SV_Semaphore_Complex::ACE_CREATE, count)
+#endif /* ACE_WIN32 || ACE_HAS_POSIX_SEM || ACE_PSOS */
+{
+ arg = arg;
+ max = max;
+// ACE_TRACE ("ACE_Process_Semaphore::ACE_Process_Semaphore");
+}
+
+ACE_Process_Semaphore::~ACE_Process_Semaphore (void)
+{
+ // ACE_TRACE ("ACE_Process_Semaphore::~ACE_Process_Semaphore");
+}
+
+// Explicitly destroy the semaphore.
+
+int
+ACE_Process_Semaphore::remove (void)
+{
+// ACE_TRACE ("ACE_Process_Semaphore::remove");
+ return this->lock_.remove ();
+}
+
+// Block the thread until the semaphore count becomes
+// greater than 0, then decrement it.
+
+int
+ACE_Process_Semaphore::acquire (void)
+{
+// ACE_TRACE ("ACE_Process_Semaphore::acquire");
+ return this->lock_.acquire ();
+}
+
+// Conditionally decrement the semaphore if count is greater
+// than 0 (i.e., won't block).
+
+int
+ACE_Process_Semaphore::tryacquire (void)
+{
+// ACE_TRACE ("ACE_Process_Semaphore::tryacquire");
+ return this->lock_.tryacquire ();
+}
+
+// Increment the semaphore, potentially unblocking
+// a waiting thread.
+
+int
+ACE_Process_Semaphore::release (void)
+{
+// ACE_TRACE ("ACE_Process_Semaphore::release");
+ return this->lock_.release ();
+}
+
+//
+// These are instantiated both with and without ACE_HAS_THREADS.
+//
+#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION)
+
+// template class ACE_Guard<ACE_Process_Semaphore>;
+
+#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA)
+
+// #pragma instantiate ACE_Guard<ACE_Process_Semaphore>
+
+#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */
diff --git a/ace/Threads/Process_Semaphore.h b/ace/Threads/Process_Semaphore.h
new file mode 100644
index 00000000000..208bafe8dc1
--- /dev/null
+++ b/ace/Threads/Process_Semaphore.h
@@ -0,0 +1,142 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Process_Semaphore.h
+ *
+ * $Id$
+ *
+ * Wrapper for Dijkstra style general semaphores that work
+ * across processes.
+ *
+ *
+ * @author Doug Schmidt
+ */
+//=============================================================================
+
+
+#ifndef ACE_PROCESS_SEMAPHORE_H
+#define ACE_PROCESS_SEMAPHORE_H
+#include "ace/pre.h"
+
+#include "ace/Synch.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#if !(defined (ACE_WIN32) || defined (ACE_HAS_POSIX_SEM) || defined (ACE_PSOS))
+#include "ace/SV_Semaphore_Complex.h"
+#endif /* !(ACE_WIN32 || ACE_HAS_POSIX_SEM || ACE_PSOS) */
+
+/**
+ * @class ACE_Process_Semaphore
+ *
+ * @brief Wrapper for Dijkstra style general semaphores that work
+ * across processes.
+ */
+class ACE_Export ACE_Process_Semaphore
+{
+public:
+ /// Initialize the semaphore, with an initial value of <count> and a
+ /// maximum value of <max>.
+ ACE_Process_Semaphore (u_int count = 1, // By default make this unlocked.
+ const ACE_TCHAR *name = 0,
+ void * = 0,
+ int max = 0x7FFFFFFF);
+
+ /**
+ * This method is a no-op, i.e., it doesn't remove the semaphore.
+ * If you want to remove the semaphore, you must call the <remove>
+ * method explicitly.
+ */
+ ~ACE_Process_Semaphore (void);
+
+ /**
+ * Explicitly destroy the semaphore. Note that only one thread
+ * should call this method since it doesn't protect against race
+ * conditions.
+ */
+ int remove (void);
+
+ /// Block the thread until the semaphore count becomes greater than
+ /// 0, then decrement it.
+ int acquire (void);
+
+ /**
+ * Conditionally decrement the semaphore if count is greater than 0
+ * (i.e., won't block). Returns -1 on failure. If we "failed"
+ * because someone else already had the lock, <errno> is set to
+ * <EBUSY>.
+ */
+ int tryacquire (void);
+
+ /// Increment the semaphore, potentially unblocking a waiting thread.
+ int release (void);
+
+ /**
+ * Acquire semaphore ownership. This calls <acquire> and is only
+ * here to make the <ACE_Process_Semaphore> interface consistent
+ * with the other synchronization APIs.
+ */
+ int acquire_read (void);
+
+ /**
+ * Acquire semaphore ownership. This calls <acquire> and is only
+ * here to make the <ACE_Process_Semaphore> interface consistent
+ * with the other synchronization APIs.
+ */
+ int acquire_write (void);
+
+ /**
+ * Conditionally acquire semaphore (i.e., won't block). This calls
+ * <tryacquire> and is only here to make the <ACE_Process_Semaphore>
+ * interface consistent with the other synchronization APIs.
+ * Returns -1 on failure. If we "failed" because someone else
+ * already had the lock, <errno> is set to <EBUSY>.
+ */
+ int tryacquire_read (void);
+
+ /**
+ * Conditionally acquire semaphore (i.e., won't block). This calls
+ * <tryacquire> and is only here to make the <ACE_Process_Semaphore>
+ * interface consistent with the other synchronization APIs.
+ * Returns -1 on failure. If we "failed" because someone else
+ * already had the lock, <errno> is set to <EBUSY>.
+ */
+ int tryacquire_write (void);
+
+ /**
+ * This is only here to make the <ACE_Process_Semaphore>
+ * interface consistent with the other synchronization APIs.
+ * Assumes the caller has already acquired the semaphore using one of
+ * the above calls, and returns 0 (success) always.
+ */
+ int tryacquire_write_upgrade (void);
+
+#if defined (ACE_WIN32) || defined (ACE_HAS_POSIX_SEM) || defined (ACE_PSOS)
+ /// Return the underlying lock.
+ const ACE_sema_t &lock (void) const;
+#endif /* ACE_WIN32 || ACE_HAS_POSIX_SEM || ACE_PSOS */
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+protected:
+#if defined (ACE_WIN32) || defined (ACE_HAS_POSIX_SEM) || defined (ACE_PSOS)
+ ACE_Semaphore lock_;
+#else
+ /// We need this to get the right semantics...
+ ACE_SV_Semaphore_Complex lock_;
+#endif /* ACE_WIN32 || ACE_HAS_POSIX_SEM || ACE_PSOS */
+};
+
+#if defined (__ACE_INLINE__)
+#include "ace/Process_Semaphore.inl"
+#endif /* __ACE_INLINE__ */
+
+#include "ace/post.h"
+#endif /* ACE_PROCESS_SEMAPHORE_H */
diff --git a/ace/Threads/Process_Semaphore.inl b/ace/Threads/Process_Semaphore.inl
new file mode 100644
index 00000000000..8470291233c
--- /dev/null
+++ b/ace/Threads/Process_Semaphore.inl
@@ -0,0 +1,61 @@
+/* -*- C++ -*- */
+// $Id$
+
+#if defined (ACE_WIN32) || defined (ACE_HAS_POSIX_SEM) || defined (ACE_PSOS)
+ACE_INLINE const ACE_sema_t &
+ACE_Process_Semaphore::lock (void) const
+{
+// ACE_TRACE ("ACE_Process_Semaphore::lock");
+ return this->lock_.lock ();
+}
+#endif /* ACE_WIN32 || ACE_HAS_POSIX_SEM || ACE_PSOS */
+
+// Acquire semaphore ownership. This calls <acquire> and is only here
+// to make the <ACE_Process_Semaphore> interface consistent with the
+// other synchronization APIs.
+
+ACE_INLINE int
+ACE_Process_Semaphore::acquire_read (void)
+{
+ return this->acquire ();
+}
+
+// Acquire semaphore ownership. This calls <acquire> and is only here
+// to make the <ACE_Process_Semaphore> interface consistent with the
+// other synchronization APIs.
+
+ACE_INLINE int
+ACE_Process_Semaphore::acquire_write (void)
+{
+ return this->acquire ();
+}
+
+// Conditionally acquire semaphore (i.e., won't block). This calls
+// <tryacquire> and is only here to make the <ACE_Process_Semaphore>
+// interface consistent with the other synchronization APIs.
+
+ACE_INLINE int
+ACE_Process_Semaphore::tryacquire_read (void)
+{
+ return this->tryacquire ();
+}
+
+// Conditionally acquire semaphore (i.e., won't block). This calls
+// <tryacquire> and is only here to make the <ACE_Process_Semaphore>
+// interface consistent with the other synchronization APIs.
+
+ACE_INLINE int
+ACE_Process_Semaphore::tryacquire_write (void)
+{
+ return this->tryacquire ();
+}
+
+// This is only here to make the <ACE_Process_Semaphore>
+// interface consistent with the other synchronization APIs.
+// Assumes the caller has already acquired the semaphore using one of
+// the above calls, and returns 0 (success) always.
+ACE_INLINE int
+ACE_Process_Semaphore::tryacquire_write_upgrade (void)
+{
+ return 0;
+}
diff --git a/ace/Threads/RW_Process_Mutex.cpp b/ace/Threads/RW_Process_Mutex.cpp
new file mode 100644
index 00000000000..1b0aee4eb28
--- /dev/null
+++ b/ace/Threads/RW_Process_Mutex.cpp
@@ -0,0 +1,59 @@
+// $Id$
+
+#include "ace/RW_Process_Mutex.h"
+#include "ace/Log_Msg.h"
+#include "ace/ACE.h"
+
+ACE_RCSID(ace, RW_Process_Mutex, "$Id$")
+
+#if !defined (__ACE_INLINE__)
+#include "ace/RW_Process_Mutex.inl"
+#endif /* __ACE_INLINE__ */
+
+ACE_ALLOC_HOOK_DEFINE(ACE_RW_Process_Mutex)
+
+const ACE_TCHAR *
+ACE_RW_Process_Mutex::unique_name (void)
+{
+ ACE::unique_name (this, this->name_, ACE_UNIQUE_NAME_LEN);
+ return this->name_;
+}
+
+ACE_RW_Process_Mutex::ACE_RW_Process_Mutex (const ACE_TCHAR *name,
+ int flags)
+ : lock_ (name ? name : this->unique_name (), flags
+#if defined (ACE_WIN32)
+ , ACE_DEFAULT_OPEN_PERMS)
+#else
+ , S_IRUSR | S_IWUSR)
+#endif /* ACE_WIN32 */
+{
+// ACE_TRACE ("ACE_RW_Process_Mutex::ACE_RW_Process_Mutex");
+}
+
+ACE_RW_Process_Mutex::~ACE_RW_Process_Mutex (void)
+{
+// ACE_TRACE ("ACE_RW_Process_Mutex::~ACE_RW_Process_Mutex");
+}
+
+void
+ACE_RW_Process_Mutex::dump (void) const
+{
+// ACE_TRACE ("ACE_RW_Process_Mutex::dump");
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+ this->lock_.dump ();
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+//
+// These are instantiated both with and without ACE_HAS_THREADS.
+//
+#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION)
+
+// template class ACE_Guard<ACE_RW_Process_Mutex>;
+
+#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA)
+
+// #pragma instantiate ACE_Guard<ACE_RW_Process_Mutex>
+
+#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */
diff --git a/ace/Threads/RW_Process_Mutex.h b/ace/Threads/RW_Process_Mutex.h
new file mode 100644
index 00000000000..77500d19aa3
--- /dev/null
+++ b/ace/Threads/RW_Process_Mutex.h
@@ -0,0 +1,114 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file RW_Process_Mutex.h
+ *
+ * $Id$
+ *
+ * @author Douglas C. Schmidt <schmidt@cs.wustl.edu>
+ */
+//=============================================================================
+
+#ifndef ACE_RW_PROCESS_MUTEX_H
+#define ACE_RW_PROCESS_MUTEX_H
+#include "ace/pre.h"
+
+#include "ace/File_Lock.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+/**
+ * @class ACE_RW_Process_Mutex
+ *
+ * @brief Wrapper for readers/writer locks that exist across processes.
+ *
+ * Note that because this class uses the
+ * <ACE_File_Lock> as its implementation it only can be reliably
+ * used between separate processes, rather than threads in the
+ * same process. This isn't a limitation of ACE, it's simply
+ * the file lock semantics on UNIX and Win32.
+ */
+class ACE_Export ACE_RW_Process_Mutex
+{
+public:
+ /// Create a readers/writer <Process_Mutex>, passing in the optional
+ /// <name>. If not specified, a name is generated.
+ ACE_RW_Process_Mutex (const ACE_TCHAR *name = 0,
+ int flags = O_CREAT|O_RDWR);
+
+ ~ACE_RW_Process_Mutex (void);
+
+ /**
+ * Explicitly destroy the mutex. Note that only one thread should
+ * call this method since it doesn't protect against race
+ * conditions.
+ */
+ int remove (void);
+
+ /// Acquire lock ownership (wait on queue if necessary).
+ int acquire (void);
+
+ /**
+ * Conditionally acquire lock (i.e., don't wait on queue). Returns
+ * -1 on failure. If we "failed" because someone else already had
+ * the lock, <errno> is set to <EBUSY>.
+ */
+ int tryacquire (void);
+
+ /// Release lock and unblock a thread at head of queue.
+ int release (void);
+
+ /// Acquire lock ownership (wait on queue if necessary).
+ int acquire_read (void);
+
+ /// Acquire lock ownership (wait on queue if necessary).
+ int acquire_write (void);
+
+ /**
+ * Conditionally acquire a lock (i.e., won't block). Returns -1 on
+ * failure. If we "failed" because someone else already had the
+ * lock, <errno> is set to <EBUSY>.
+ */
+ int tryacquire_read (void);
+
+ /**
+ * Conditionally acquire a lock (i.e., won't block). Returns -1 on
+ * failure. If we "failed" because someone else already had the
+ * lock, <errno> is set to <EBUSY>.
+ */
+ int tryacquire_write (void);
+
+ /// Attempt to upgrade a read lock to a write lock. Returns 0 on
+ /// success, -1 on failure.
+ int tryacquire_write_upgrade (void);
+
+ /// Return the underlying lock.
+ const ACE_File_Lock &lock (void) const;
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+private:
+ /// If the user does not provide a name we generate a unique name in
+ /// this buffer.
+ ACE_TCHAR name_[ACE_UNIQUE_NAME_LEN];
+
+ /// Create and return the unique name.
+ const ACE_TCHAR *unique_name (void);
+
+ /// We need this to get the readers/writer semantics...
+ ACE_File_Lock lock_;
+};
+
+#if defined (__ACE_INLINE__)
+#include "ace/RW_Process_Mutex.inl"
+#endif /* __ACE_INLINE__ */
+
+#include "ace/post.h"
+#endif /* ACE_RW_PROCESS_MUTEX_H */
diff --git a/ace/Threads/RW_Process_Mutex.inl b/ace/Threads/RW_Process_Mutex.inl
new file mode 100644
index 00000000000..cc59bb9fc17
--- /dev/null
+++ b/ace/Threads/RW_Process_Mutex.inl
@@ -0,0 +1,72 @@
+/* -*- C++ -*- */
+// $Id$
+
+// Explicitly destroy the mutex.
+ACE_INLINE int
+ACE_RW_Process_Mutex::remove (void)
+{
+ return this->lock_.remove ();
+}
+
+// Acquire lock ownership (wait on priority queue if necessary).
+ACE_INLINE int
+ACE_RW_Process_Mutex::acquire (void)
+{
+ return this->lock_.acquire ();
+}
+
+// Conditionally acquire lock (i.e., don't wait on queue).
+ACE_INLINE int
+ACE_RW_Process_Mutex::tryacquire (void)
+{
+ return this->lock_.tryacquire ();
+}
+
+// Release lock and unblock a thread at head of priority queue.
+ACE_INLINE int
+ACE_RW_Process_Mutex::release (void)
+{
+ return this->lock_.release ();
+}
+
+// Acquire lock ownership (wait on priority queue if necessary).
+ACE_INLINE int
+ACE_RW_Process_Mutex::acquire_read (void)
+{
+ return this->lock_.acquire_read ();
+}
+
+// Acquire lock ownership (wait on priority queue if necessary).
+ACE_INLINE int
+ACE_RW_Process_Mutex::acquire_write (void)
+{
+ return this->lock_.acquire_write ();
+}
+
+// Conditionally acquire a lock (i.e., won't block).
+ACE_INLINE int
+ACE_RW_Process_Mutex::tryacquire_read (void)
+{
+ return this->lock_.tryacquire_read ();
+}
+
+// Conditionally acquire a lock (i.e., won't block).
+ACE_INLINE int
+ACE_RW_Process_Mutex::tryacquire_write (void)
+{
+ return this->lock_.tryacquire_write ();
+}
+
+// Conditionally upgrade a lock (i.e., won't block).
+ACE_INLINE int
+ACE_RW_Process_Mutex::tryacquire_write_upgrade (void)
+{
+ return this->lock_.tryacquire_write_upgrade ();
+}
+
+ACE_INLINE const ACE_File_Lock &
+ACE_RW_Process_Mutex::lock (void) const
+{
+// ACE_TRACE ("ACE_RW_Process_Mutex::lock");
+ return this->lock_;
+}
diff --git a/ace/Threads/Synch.cpp b/ace/Threads/Synch.cpp
new file mode 100644
index 00000000000..6b81248db41
--- /dev/null
+++ b/ace/Threads/Synch.cpp
@@ -0,0 +1,902 @@
+// $Id$
+
+#ifndef ACE_SYNCH_C
+#define ACE_SYNCH_C
+
+#include "ace/Thread.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "ace/Synch_T.h"
+#include "ace/Synch.h"
+#include "ace/Log_Msg.h"
+
+ACE_RCSID(ace, Synch, "$Id$")
+
+#if !defined (__ACE_INLINE__)
+#include "ace/Synch.i"
+#endif /* __ACE_INLINE__ */
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Null_Mutex)
+
+ACE_Lock::~ACE_Lock (void)
+{
+}
+
+ACE_Adaptive_Lock::ACE_Adaptive_Lock (void)
+ : lock_ (0)
+{
+}
+
+ACE_Adaptive_Lock::~ACE_Adaptive_Lock (void)
+{
+}
+
+int
+ACE_Adaptive_Lock::remove (void)
+{
+ return this->lock_->remove ();
+}
+
+int
+ACE_Adaptive_Lock::acquire (void)
+{
+ return this->lock_->acquire ();
+}
+
+int
+ACE_Adaptive_Lock::tryacquire (void)
+{
+ return this->lock_->tryacquire ();
+}
+
+int
+ACE_Adaptive_Lock::release (void)
+{
+ return this->lock_->release ();
+}
+
+int
+ACE_Adaptive_Lock::acquire_read (void)
+{
+ return this->lock_->acquire_read ();
+}
+
+int
+ACE_Adaptive_Lock::acquire_write (void)
+{
+ return this->lock_->acquire_write ();
+}
+
+int
+ACE_Adaptive_Lock::tryacquire_read (void)
+{
+ return this->lock_->tryacquire_read ();
+}
+
+int
+ACE_Adaptive_Lock::tryacquire_write (void)
+{
+ return this->lock_->tryacquire_write ();
+}
+
+int
+ACE_Adaptive_Lock::tryacquire_write_upgrade (void)
+{
+ return this->lock_->tryacquire_write_upgrade ();
+}
+
+void
+ACE_Adaptive_Lock::dump (void) const
+{
+ // return this->lock_->dump ();
+}
+
+ACE_TSS_Adapter::ACE_TSS_Adapter (void *object, ACE_THR_DEST f)
+ : ts_obj_ (object),
+ func_ (f)
+{
+ // ACE_TRACE ("ACE_TSS_Adapter::ACE_TSS_Adapter");
+}
+
+void
+ACE_TSS_Adapter::cleanup (void)
+{
+ // ACE_TRACE ("ACE_TSS_Adapter::cleanup");
+ (*this->func_)(this->ts_obj_); // call cleanup routine for ts_obj_
+}
+
+extern "C" void
+ACE_TSS_C_cleanup (void *object)
+{
+ // ACE_TRACE ("ACE_TSS_C_cleanup");
+ if (object != 0)
+ {
+ ACE_TSS_Adapter *tss_adapter = (ACE_TSS_Adapter *) object;
+ // Perform cleanup on the real TS object.
+ tss_adapter->cleanup ();
+ // Delete the adapter object.
+ delete tss_adapter;
+ }
+}
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Semaphore)
+
+void
+ACE_Semaphore::dump (void) const
+{
+// ACE_TRACE ("ACE_Semaphore::dump");
+
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\n")));
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+ACE_Semaphore::ACE_Semaphore (u_int count,
+ int type,
+ const ACE_TCHAR *name,
+ void *arg,
+ int max)
+ : removed_ (0)
+{
+// ACE_TRACE ("ACE_Semaphore::ACE_Semaphore");
+ if (ACE_OS::sema_init (&this->semaphore_, count, type,
+ name, arg, max) != 0)
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("%p\n"),
+ ACE_LIB_TEXT ("ACE_Semaphore::ACE_Semaphore")));
+}
+
+ACE_Semaphore::~ACE_Semaphore (void)
+{
+// ACE_TRACE ("ACE_Semaphore::~ACE_Semaphore");
+
+ this->remove ();
+}
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Mutex)
+
+void
+ACE_Mutex::dump (void) const
+{
+// ACE_TRACE ("ACE_Mutex::dump");
+
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+#if defined (CHORUS)
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("lockname_ = %s\n"), this->lockname_));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("process_lock_ = %x\n"), this->process_lock_));
+#endif /* CHORUS */
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\n")));
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+ACE_Mutex::ACE_Mutex (int type, const ACE_TCHAR *name, ACE_mutexattr_t *arg)
+ :
+#if defined (CHORUS) || defined(ACE_HAS_PTHREADS) || defined(ACE_HAS_STHREADS)
+ process_lock_ (0),
+ lockname_ (0),
+#endif /* CHORUS */
+ removed_ (0)
+{
+ // ACE_TRACE ("ACE_Mutex::ACE_Mutex");
+
+ // These platforms need process-wide mutex to be in shared memory.
+#if defined(CHORUS) || defined (ACE_HAS_PTHREADS) || defined (ACE_HAS_STHREADS)
+ if (type == USYNC_PROCESS)
+ {
+ // Let's see if the shared memory entity already exists.
+ ACE_HANDLE fd = ACE_OS::shm_open (name,
+ O_RDWR | O_CREAT | O_EXCL,
+ ACE_DEFAULT_FILE_PERMS);
+ if (fd == ACE_INVALID_HANDLE)
+ {
+ if (errno == EEXIST)
+ fd = ACE_OS::shm_open (name,
+ O_RDWR | O_CREAT,
+ ACE_DEFAULT_FILE_PERMS);
+ else
+ return;
+ }
+ else
+ {
+ // We own this shared memory object! Let's set its size.
+ if (ACE_OS::ftruncate (fd,
+ sizeof (ACE_mutex_t)) == -1)
+ {
+ ACE_OS::close (fd);
+ return;
+ }
+ this->lockname_ = ACE_OS::strdup (name);
+ if (this->lockname_ == 0)
+ {
+ ACE_OS::close (fd);
+ return;
+ }
+ }
+
+ this->process_lock_ =
+ (ACE_mutex_t *) ACE_OS::mmap (0,
+ sizeof (ACE_mutex_t),
+ PROT_RDWR,
+ MAP_SHARED,
+ fd,
+ 0);
+ ACE_OS::close (fd);
+ if (this->process_lock_ == MAP_FAILED)
+ return;
+
+ if (this->lockname_
+ && ACE_OS::mutex_init (this->process_lock_,
+ type,
+ name,
+ arg) != 0)
+ return;
+ }
+ // It is ok to fall through into the <mutex_init> below if the
+ // USYNC_PROCESS flag is not enabled.
+#endif /* CHORUS */
+ if (ACE_OS::mutex_init (&this->lock_,
+ type,
+ name,
+ arg) != 0)
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("%p\n"),
+ ACE_LIB_TEXT ("ACE_Mutex::ACE_Mutex")));
+}
+
+ACE_Mutex::~ACE_Mutex (void)
+{
+// ACE_TRACE ("ACE_Mutex::~ACE_Mutex");
+ this->remove ();
+}
+
+ACE_Event::ACE_Event (int manual_reset,
+ int initial_state,
+ int type,
+ const ACE_TCHAR *name,
+ void *arg)
+ : removed_ (0)
+{
+ if (ACE_OS::event_init (&this->handle_,
+ manual_reset,
+ initial_state,
+ type,
+ name,
+ arg) != 0)
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("%p\n"),
+ ACE_LIB_TEXT ("ACE_Event::ACE_Event")));
+}
+
+ACE_Event::~ACE_Event (void)
+{
+ this->remove ();
+}
+
+int
+ACE_Event::remove (void)
+{
+ int result = 0;
+ if (this->removed_ == 0)
+ {
+ this->removed_ = 1;
+ result = ACE_OS::event_destroy (&this->handle_);
+ }
+ return result;
+}
+
+ACE_event_t
+ACE_Event::handle (void) const
+{
+ return this->handle_;
+}
+
+void
+ACE_Event::handle (ACE_event_t new_handle)
+{
+ this->handle_ = new_handle;
+}
+
+int
+ACE_Event::wait (void)
+{
+ return ACE_OS::event_wait (&this->handle_);
+}
+
+int
+ACE_Event::wait (const ACE_Time_Value *abstime, int use_absolute_time)
+{
+ return ACE_OS::event_timedwait (&this->handle_,
+ (ACE_Time_Value *) abstime,
+ use_absolute_time);
+}
+
+int
+ACE_Event::signal (void)
+{
+ return ACE_OS::event_signal (&this->handle_);
+}
+
+int
+ACE_Event::pulse (void)
+{
+ return ACE_OS::event_pulse (&this->handle_);
+}
+
+int
+ACE_Event::reset (void)
+{
+ return ACE_OS::event_reset (&this->handle_);
+}
+
+void
+ACE_Event::dump (void) const
+{
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+ACE_Manual_Event::ACE_Manual_Event (int initial_state,
+ int type,
+ const char *name,
+ void *arg)
+ : ACE_Event (1,
+ initial_state,
+ type,
+ ACE_TEXT_CHAR_TO_TCHAR (name),
+ arg)
+{
+}
+
+#if defined (ACE_HAS_WCHAR)
+ACE_Manual_Event::ACE_Manual_Event (int initial_state,
+ int type,
+ const wchar_t *name,
+ void *arg)
+ : ACE_Event (1,
+ initial_state,
+ type,
+ ACE_TEXT_WCHAR_TO_TCHAR (name),
+ arg)
+{
+}
+#endif /* ACE_HAS_WCHAR */
+
+void
+ACE_Manual_Event::dump (void) const
+{
+ ACE_Event::dump ();
+}
+
+ACE_Auto_Event::ACE_Auto_Event (int initial_state,
+ int type,
+ const char *name,
+ void *arg)
+ : ACE_Event (0,
+ initial_state,
+ type,
+ ACE_TEXT_CHAR_TO_TCHAR (name),
+ arg)
+{
+}
+
+#if defined (ACE_HAS_WCHAR)
+ACE_Auto_Event::ACE_Auto_Event (int initial_state,
+ int type,
+ const wchar_t *name,
+ void *arg)
+ : ACE_Event (0,
+ initial_state,
+ type,
+ ACE_TEXT_WCHAR_TO_TCHAR (name),
+ arg)
+{
+}
+#endif /* ACE_HAS_WCHAR */
+
+void
+ACE_Auto_Event::dump (void) const
+{
+ ACE_Event::dump ();
+}
+
+#if defined (ACE_HAS_THREADS)
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Thread_Mutex_Guard)
+
+void
+ACE_Thread_Semaphore::dump (void) const
+{
+// ACE_TRACE ("ACE_Thread_Semaphore::dump");
+
+ ACE_Semaphore::dump ();
+}
+
+ACE_Thread_Semaphore::ACE_Thread_Semaphore (u_int count,
+ const ACE_TCHAR *name,
+ void *arg,
+ int max)
+ : ACE_Semaphore (count, USYNC_THREAD, name, arg, max)
+{
+// ACE_TRACE ("ACE_Thread_Semaphore::ACE_Thread_Semaphore");
+}
+
+#if defined (ACE_USES_OBSOLETE_GUARD_CLASSES)
+void
+ACE_Thread_Mutex_Guard::dump (void) const
+{
+// ACE_TRACE ("ACE_Thread_Mutex_Guard::dump");
+
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\n")));
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+#endif /* ACE_USES_OBSOLETE_GUARD_CLASSES */
+
+ACE_Recursive_Thread_Mutex::ACE_Recursive_Thread_Mutex (const ACE_TCHAR *name,
+ ACE_mutexattr_t *arg)
+ : removed_ (0)
+{
+ // ACE_TRACE ("ACE_Recursive_Thread_Mutex::ACE_Recursive_Thread_Mutex");
+#if defined (ACE_HAS_FSU_PTHREADS) && ! defined (ACE_WIN32)
+ // Initialize FSU pthreads package. If called more than once,
+ // pthread_init does nothing and so does no harm.
+ pthread_init ();
+#endif /* ACE_HAS_FSU_PTHREADS && ! ACE_WIN32 */
+ if (ACE_OS::recursive_mutex_init (&this->recursive_mutex_,
+ name,
+ arg) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("%p\n"),
+ ACE_LIB_TEXT ("recursive_mutex_init")));
+}
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Recursive_Thread_Mutex)
+
+ACE_Recursive_Thread_Mutex::~ACE_Recursive_Thread_Mutex (void)
+{
+ // ACE_TRACE ("ACE_Recursive_Thread_Mutex::~ACE_Recursive_Thread_Mutex");
+ this->remove ();
+}
+
+int
+ACE_Recursive_Thread_Mutex::remove (void)
+{
+// ACE_TRACE ("ACE_Recursive_Thread_Mutex::remove");
+ int result = 0;
+ if (this->removed_ == 0)
+ {
+ this->removed_ = 1;
+ result = ACE_OS::recursive_mutex_destroy (&this->recursive_mutex_);
+ }
+ return result;
+}
+
+// The counter part of the following two functions for Win32 are
+// located in file Synch.i
+ACE_thread_t
+ACE_Recursive_Thread_Mutex::get_thread_id (void)
+{
+ // ACE_TRACE ("ACE_Recursive_Thread_Mutex::get_thread_id");
+#if defined (ACE_HAS_RECURSIVE_MUTEXES)
+ // @@ The structure CriticalSection in Win32 doesn't hold the thread
+ // handle of the thread that owns the lock. However it is still not
+ // clear at this point how to translate a thread handle to its
+ // corresponding thread id.
+ errno = ENOTSUP;
+ return ACE_OS::NULL_thread;
+#else
+ ACE_thread_t owner_id;
+ ACE_OS::mutex_lock (&this->recursive_mutex_.nesting_mutex_);
+ owner_id = this->recursive_mutex_.owner_id_;
+ ACE_OS::mutex_unlock (&this->recursive_mutex_.nesting_mutex_);
+ return owner_id;
+#endif /* ACE_WIN32 */
+}
+
+int
+ACE_Recursive_Thread_Mutex::get_nesting_level (void)
+{
+ // ACE_TRACE ("ACE_Recursive_Thread_Mutex::get_nesting_level");
+#if defined (ACE_HAS_WINCE) || defined (VXWORKS) || defined (ACE_PSOS)
+ ACE_NOTSUP_RETURN (-1);
+#elif defined (ACE_HAS_RECURSIVE_MUTEXES)
+# if defined (ACE_WIN32)
+ // This is really a Win32-ism...
+ return this->recursive_mutex_.RecursionCount;
+# else
+ ACE_NOTSUP_RETURN (-1);
+# endif /* ACE_HAS_RECURSIVE_MUTEXES */
+#else
+ int nesting_level = 0;
+ ACE_OS::mutex_lock (&this->recursive_mutex_.nesting_mutex_);
+ nesting_level = this->recursive_mutex_.nesting_level_;
+ ACE_OS::mutex_unlock (&this->recursive_mutex_.nesting_mutex_);
+ return nesting_level;
+#endif /* !ACE_HAS_WINCE */
+}
+
+ACE_Recursive_Thread_Mutex::ACE_Recursive_Thread_Mutex (const ACE_Recursive_Thread_Mutex &)
+{
+}
+
+int
+ACE_Recursive_Thread_Mutex::acquire (void)
+{
+ return ACE_OS::recursive_mutex_lock (&this->recursive_mutex_);
+}
+
+int
+ACE_Recursive_Thread_Mutex::release (void)
+{
+ return ACE_OS::recursive_mutex_unlock (&this->recursive_mutex_);
+}
+
+int
+ACE_Recursive_Thread_Mutex::tryacquire (void)
+{
+ return ACE_OS::recursive_mutex_trylock (&this->recursive_mutex_);
+}
+
+void
+ACE_Recursive_Thread_Mutex::dump (void) const
+{
+// ACE_TRACE ("ACE_Recursive_Thread_Mutex::dump");
+
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Condition_Thread_Mutex)
+
+void
+ACE_Condition_Thread_Mutex::dump (void) const
+{
+// ACE_TRACE ("ACE_Condition_Thread_Mutex::dump");
+
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\n")));
+#if defined (ACE_WIN32)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_LIB_TEXT ("waiters = %d\n"),
+ this->cond_.waiters ()));
+#endif /* ACE_WIN32 */
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+ACE_Condition_Thread_Mutex::ACE_Condition_Thread_Mutex (const ACE_Thread_Mutex &m,
+ const ACE_TCHAR *name,
+ void *arg)
+ : mutex_ ((ACE_Thread_Mutex &) m),
+ removed_ (0)
+{
+#if defined (ACE_HAS_FSU_PTHREADS)
+// Initialize FSU pthreads package.
+// If called more than once, pthread_init does nothing
+// and so does no harm.
+ pthread_init ();
+#endif /* ACE_HAS_FSU_PTHREADS */
+
+// ACE_TRACE ("ACE_Condition_Thread_Mutex::ACE_Condition_Thread_Mutex");
+ if (ACE_OS::cond_init (&this->cond_,
+ (short) USYNC_THREAD,
+ name,
+ arg) != 0)
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("%p\n"),
+ ACE_LIB_TEXT ("ACE_Condition_Thread_Mutex::ACE_Condition_Thread_Mutex")));
+}
+
+ACE_Condition_Thread_Mutex::
+ACE_Condition_Thread_Mutex (const ACE_Thread_Mutex &m,
+ ACE_Condition_Attributes &attributes,
+ const ACE_TCHAR *name,
+ void *arg)
+ : mutex_ ((ACE_Thread_Mutex &) m),
+ removed_ (0)
+{
+#if defined (ACE_HAS_FSU_PTHREADS)
+// Initialize FSU pthreads package.
+// If called more than once, pthread_init does nothing
+// and so does no harm.
+ pthread_init ();
+#endif /* ACE_HAS_FSU_PTHREADS */
+
+// ACE_TRACE ("ACE_Condition_Thread_Mutex::ACE_Condition_Thread_Mutex");
+ if (ACE_OS::cond_init (&this->cond_, attributes.attributes_,
+ name, arg) != 0)
+ ACE_ERROR ((LM_ERROR, ACE_LIB_TEXT ("%p\n"),
+ ACE_LIB_TEXT ("ACE_Condition_Thread_Mutex::ACE_Condition_Thread_Mutex")));
+}
+
+ACE_Condition_Thread_Mutex::~ACE_Condition_Thread_Mutex (void)
+{
+// ACE_TRACE ("ACE_Condition_Thread_Mutex::~ACE_Condition_Thread_Mutex");
+ this->remove ();
+}
+
+// Peform an "alertable" timed wait. If the argument <abstime> == 0
+// then we do a regular <cond_wait>, else we do a timed wait for up to
+// <abstime> using the <cond_timedwait> function.
+
+int
+ACE_Condition_Thread_Mutex::wait (void)
+{
+// ACE_TRACE ("ACE_Condition_Thread_Mutex::wait");
+ return ACE_OS::cond_wait (&this->cond_, &this->mutex_.lock_);
+}
+
+int
+ACE_Condition_Thread_Mutex::wait (ACE_Thread_Mutex &mutex,
+ const ACE_Time_Value *abstime)
+{
+// ACE_TRACE ("ACE_Condition_Thread_Mutex::wait");
+ return ACE_OS::cond_timedwait (&this->cond_,
+ &mutex.lock_,
+ (ACE_Time_Value *) abstime);
+}
+
+int
+ACE_Condition_Thread_Mutex::wait (const ACE_Time_Value *abstime)
+{
+// ACE_TRACE ("ACE_Condition_Thread_Mutex::wait");
+ return this->wait (this->mutex_, abstime);
+}
+
+int
+ACE_Condition_Thread_Mutex::signal (void)
+{
+// ACE_TRACE ("ACE_Condition_Thread_Mutex::signal");
+ return ACE_OS::cond_signal (&this->cond_);
+}
+
+int
+ACE_Condition_Thread_Mutex::broadcast (void)
+{
+// ACE_TRACE ("ACE_Condition_Thread_Mutex::broadcast");
+ return ACE_OS::cond_broadcast (&this->cond_);
+}
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Sub_Barrier)
+
+void
+ACE_Sub_Barrier::dump (void) const
+{
+// ACE_TRACE ("ACE_Sub_Barrier::dump");
+
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+ this->barrier_finished_.dump ();
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("running_threads_ = %d"), this->running_threads_));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\n")));
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+ACE_Sub_Barrier::ACE_Sub_Barrier (u_int count,
+ ACE_Thread_Mutex &lock,
+ const ACE_TCHAR *name,
+ void *arg)
+ : barrier_finished_ (lock, name, arg),
+ running_threads_ (count)
+{
+// ACE_TRACE ("ACE_Sub_Barrier::ACE_Sub_Barrier");
+}
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Barrier)
+ACE_ALLOC_HOOK_DEFINE(ACE_Thread_Barrier)
+ACE_ALLOC_HOOK_DEFINE(ACE_Process_Barrier)
+
+void
+ACE_Barrier::dump (void) const
+{
+// ACE_TRACE ("ACE_Barrier::dump");
+
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+ this->lock_.dump ();
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("current_generation_ = %d"), this->current_generation_));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\ncount_ = %d"), this->count_));
+ this->sub_barrier_1_.dump ();
+ this->sub_barrier_2_.dump ();
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+ACE_Barrier::ACE_Barrier (u_int count,
+ const ACE_TCHAR *name,
+ void *arg)
+ : lock_ (name, (ACE_mutexattr_t *) arg),
+ current_generation_ (0),
+ count_ (count),
+ sub_barrier_1_ (count, lock_, name, arg),
+ sub_barrier_2_ (count, lock_, name, arg)
+{
+// ACE_TRACE ("ACE_Barrier::ACE_Barrier");
+ this->sub_barrier_[0] = &this->sub_barrier_1_;
+ this->sub_barrier_[1] = &this->sub_barrier_2_;
+}
+
+int
+ACE_Barrier::wait (void)
+{
+// ACE_TRACE ("ACE_Barrier::wait");
+ ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1);
+
+ ACE_Sub_Barrier *sbp =
+ this->sub_barrier_[this->current_generation_];
+
+ // Check for shutdown...
+ if (sbp == 0)
+ return -1;
+
+ if (sbp->running_threads_ == 1)
+ {
+ // We're the last running thread, so swap generations and tell
+ // all the threads waiting on the barrier to continue on their
+ // way.
+
+ sbp->running_threads_ = this->count_;
+ // Swap generations.
+ this->current_generation_ = 1 - this->current_generation_;
+ sbp->barrier_finished_.broadcast ();
+ }
+ else
+ {
+ --sbp->running_threads_;
+
+ // Block until all the other threads wait().
+ while (sbp->running_threads_ != this->count_)
+ sbp->barrier_finished_.wait ();
+ }
+
+ return 0;
+}
+
+ACE_Thread_Barrier::ACE_Thread_Barrier (u_int count, const ACE_TCHAR *name)
+ : ACE_Barrier (count, name)
+{
+// ACE_TRACE ("ACE_Thread_Barrier::ACE_Thread_Barrier");
+}
+
+void
+ACE_Thread_Barrier::dump (void) const
+{
+// ACE_TRACE ("ACE_Thread_Barrier::dump");
+ ACE_Barrier::dump ();
+}
+
+#if 0
+ACE_Process_Barrier::ACE_Process_Barrier (u_int count, const ACE_TCHAR *name)
+ : ACE_Barrier (count, USYNC_PROCESS, name)
+{
+// ACE_TRACE ("ACE_Process_Barrier::ACE_Process_Barrier");
+}
+
+void
+ACE_Process_Barrier::dump (void) const
+{
+// ACE_TRACE ("ACE_Process_Barrier::dump");
+ ACE_Barrier::dump ();
+}
+
+template <class MUTEX> void
+ACE_Process_Condition<MUTEX>::dump (void) const
+{
+// ACE_TRACE ("ACE_Process_Condition<MUTEX>::dump");
+
+ ACE_Condition<MUTEX>::dump ();
+}
+
+template <class MUTEX>
+ACE_Process_Condition<MUTEX>::ACE_Process_Condition (MUTEX &m,
+ const ACE_TCHAR *name,
+ void *arg)
+ : ACE_Condition<MUTEX> (m, USYNC_PROCESS, name, arg)
+{
+// ACE_TRACE ("ACE_Process_Condition<MUTEX>::ACE_Process_Condition");
+}
+#endif /* 0 */
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Thread_Mutex)
+
+void
+ACE_Thread_Mutex::dump (void) const
+{
+// ACE_TRACE ("ACE_Thread_Mutex::dump");
+
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\n")));
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+ACE_Thread_Mutex::~ACE_Thread_Mutex (void)
+{
+// ACE_TRACE ("ACE_Thread_Mutex::~ACE_Thread_Mutex");
+ this->remove ();
+}
+
+ACE_Thread_Mutex::ACE_Thread_Mutex (const ACE_TCHAR *name, ACE_mutexattr_t *arg)
+ : removed_ (0)
+{
+// ACE_TRACE ("ACE_Thread_Mutex::ACE_Thread_Mutex");
+
+ if (ACE_OS::thread_mutex_init (&this->lock_,
+ USYNC_THREAD,
+ name,
+ arg) != 0)
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("%p\n"),
+ ACE_LIB_TEXT ("ACE_Thread_Mutex::ACE_Thread_Mutex")));
+}
+
+void
+ACE_RW_Mutex::dump (void) const
+{
+// ACE_TRACE ("ACE_RW_Mutex::dump");
+
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\n")));
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+ACE_RW_Mutex::ACE_RW_Mutex (int type, const ACE_TCHAR *name, void *arg)
+ : removed_ (0)
+{
+// ACE_TRACE ("ACE_RW_Mutex::ACE_RW_Mutex");
+ if (ACE_OS::rwlock_init (&this->lock_, type, name, arg) != 0)
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("%p\n"),
+ ACE_LIB_TEXT ("ACE_RW_Mutex::ACE_RW_Mutex")));
+}
+
+ACE_RW_Mutex::~ACE_RW_Mutex (void)
+{
+// ACE_TRACE ("ACE_RW_Mutex::~ACE_RW_Mutex");
+ this->remove ();
+}
+
+ACE_ALLOC_HOOK_DEFINE(ACE_RW_Thread_Mutex)
+
+ACE_RW_Thread_Mutex::ACE_RW_Thread_Mutex (const ACE_TCHAR *name,
+ void *arg)
+ : ACE_RW_Mutex (USYNC_THREAD, name, arg)
+{
+// ACE_TRACE ("ACE_RW_Thread_Mutex::ACE_RW_Thread_Mutex");
+}
+
+void
+ACE_RW_Thread_Mutex::dump (void) const
+{
+// ACE_TRACE ("ACE_RW_Thread_Mutex::dump");
+ ACE_RW_Mutex::dump ();
+}
+
+#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION)
+// These are only instantiated with ACE_HAS_THREADS.
+template class ACE_Guard<ACE_Thread_Mutex>;
+template class ACE_Guard<ACE_RW_Thread_Mutex>;
+template class ACE_Read_Guard<ACE_RW_Thread_Mutex>;
+template class ACE_Read_Guard<ACE_Thread_Mutex>;
+template class ACE_Write_Guard<ACE_RW_Thread_Mutex>;
+template class ACE_Write_Guard<ACE_Thread_Mutex>;
+#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA)
+// These are only instantiated with ACE_HAS_THREADS.
+#pragma instantiate ACE_Guard<ACE_Thread_Mutex>
+#pragma instantiate ACE_Guard<ACE_RW_Thread_Mutex>
+#pragma instantiate ACE_Read_Guard<ACE_RW_Thread_Mutex>
+#pragma instantiate ACE_Read_Guard<ACE_Thread_Mutex>
+#pragma instantiate ACE_Write_Guard<ACE_RW_Thread_Mutex>
+#pragma instantiate ACE_Write_Guard<ACE_Thread_Mutex>
+#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */
+
+#endif /* ACE_HAS_THREADS */
+
+//
+// These are instantiated both with and without ACE_HAS_THREADS.
+//
+#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION)
+
+#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA)
+
+#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */
+
+#endif /* ACE_SYNCH_C */
diff --git a/ace/Threads/Synch.h b/ace/Threads/Synch.h
new file mode 100644
index 00000000000..10248793f6c
--- /dev/null
+++ b/ace/Threads/Synch.h
@@ -0,0 +1,1753 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Synch.h
+ *
+ * $Id$
+ *
+ * Wrapper Facades for various synchronization mechanisms.
+ *
+ * @author Douglas C. Schmidt <schmidt@cs.wustl.edu>
+ */
+//=============================================================================
+
+#ifndef ACE_SYNCH_H
+#define ACE_SYNCH_H
+#include "ace/pre.h"
+
+#include "ace/ACE.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+// Forward declarations.
+/**
+ * @class ACE_Time_Value;
+ template <class ACE_COND_MUTEX> class ACE_Condition;
+ */
+class ACE_Time_Value;
+
+/**
+ * @class ACE_Lock
+ *
+ * @brief This is the abstract base class that contains the uniform
+ * locking API that is supported by all the ACE synchronization
+ * mechanisms.
+ *
+ * This class is typically used in conjunction with the
+ * <ACE_Lock_Adapter> in order to provide a polymorphic
+ * interface to the ACE synchronization mechanisms (e.g.,
+ * <ACE_Mutex>, <ACE_Semaphore>, <ACE_RW_Mutex>, etc). Note that
+ * the reason that all of ACE doesn't use polymorphic locks is
+ * that (1) they add ~20% extra overhead for virtual function
+ * calls and (2) objects with virtual functions can't be placed
+ * into shared memory.
+ */
+class ACE_Export ACE_Lock
+{
+public:
+ /// CE needs a default ctor here.
+ ACE_Lock (void);
+
+ /// Noop virtual destructor
+ virtual ~ACE_Lock (void);
+
+ /**
+ * Explicitly destroy the lock. Note that only one thread should
+ * call this method since it doesn't protect against race
+ * conditions.
+ */
+ virtual int remove (void) = 0;
+
+ /// Block the thread until the lock is acquired. Returns -1 on
+ /// failure.
+ virtual int acquire (void) = 0;
+
+ /**
+ * Conditionally acquire the lock (i.e., won't block). Returns -1
+ * on failure. If we "failed" because someone else already had the
+ * lock, <errno> is set to <EBUSY>.
+ */
+ virtual int tryacquire (void) = 0;
+
+ /// Release the lock. Returns -1 on failure.
+ virtual int release (void) = 0;
+
+ /**
+ * Block until the thread acquires a read lock. If the locking
+ * mechanism doesn't support read locks then this just calls
+ * <acquire>. Returns -1 on failure.
+ */
+ virtual int acquire_read (void) = 0;
+
+ /**
+ * Block until the thread acquires a write lock. If the locking
+ * mechanism doesn't support read locks then this just calls
+ * <acquire>. Returns -1 on failure.
+ */
+ virtual int acquire_write (void) = 0;
+
+ /**
+ * Conditionally acquire a read lock. If the locking mechanism
+ * doesn't support read locks then this just calls <acquire>.
+ * Returns -1 on failure. If we "failed" because someone else
+ * already had the lock, <errno> is set to <EBUSY>.
+ */
+ virtual int tryacquire_read (void) = 0;
+
+ /**
+ * Conditionally acquire a write lock. If the locking mechanism
+ * doesn't support read locks then this just calls <acquire>.
+ * Returns -1 on failure. If we "failed" because someone else
+ * already had the lock, <errno> is set to <EBUSY>.
+ */
+ virtual int tryacquire_write (void) = 0;
+
+ /**
+ * Conditionally try to upgrade a lock held for read to a write lock.
+ * If the locking mechanism doesn't support read locks then this just
+ * calls <acquire>. Returns 0 on success, -1 on failure.
+ */
+ virtual int tryacquire_write_upgrade (void) = 0;
+};
+
+/**
+ * @class ACE_Adaptive_Lock
+ *
+ * @brief An adaptive general locking class that defers the decision of
+ * lock type to run time.
+ *
+ * This class, as ACE_Lock, provide a set of general locking APIs.
+ * However, it defers our decision of what kind of lock to use
+ * to the run time and delegates all locking operations to the actual
+ * lock. Users must define a constructor in their subclass to
+ * initialize <lock_>.
+ */
+class ACE_Export ACE_Adaptive_Lock : public ACE_Lock
+{
+public:
+ /// You must also override the destructor function to match with how
+ /// you construct the underneath <lock_>.
+ virtual ~ACE_Adaptive_Lock (void);
+
+ // = Lock/unlock operations.
+
+ virtual int remove (void);
+ virtual int acquire (void);
+ virtual int tryacquire (void);
+ virtual int release (void);
+ virtual int acquire_read (void);
+ virtual int acquire_write (void);
+ virtual int tryacquire_read (void);
+ virtual int tryacquire_write (void);
+ virtual int tryacquire_write_upgrade (void);
+ void dump (void) const;
+
+protected:
+ /**
+ * Create and initialize create the actual lcok used in the class.
+ * The default constructor simply set the <lock_> to 0 (null). You
+ * must overwrite this method for this class to work.
+ */
+ ACE_Adaptive_Lock (void);
+
+ ACE_Lock *lock_;
+};
+
+/**
+ * @class ACE_Semaphore
+ *
+ * @brief Wrapper for Dijkstra style general semaphores.
+ */
+class ACE_Export ACE_Semaphore
+{
+public:
+ // = Initialization and termination.
+ /// Initialize the semaphore, with initial value of "count".
+ ACE_Semaphore (u_int count = 1, // By default make this unlocked.
+ int type = USYNC_THREAD,
+ const ACE_TCHAR *name = 0,
+ void * = 0,
+ int max = 0x7fffffff);
+
+ /// Implicitly destroy the semaphore.
+ ~ACE_Semaphore (void);
+
+ /**
+ * Explicitly destroy the semaphore. Note that only one thread
+ * should call this method since it doesn't protect against race
+ * conditions.
+ */
+ int remove (void);
+
+ /// Block the thread until the semaphore count becomes
+ /// greater than 0, then decrement it.
+ int acquire (void);
+
+ /**
+ * Block the thread until the semaphore count becomes greater than 0
+ * (at which point it is decremented) or until <tv> times out (in
+ * which case -1 is returned and <errno> == <ETIME>). Note that <tv>
+ * is assumed to be in "absolute" rather than "relative" time. The
+ * value of <tv> is updated upon return to show the actual
+ * (absolute) acquisition time.
+ *
+ * NOTE: Solaris threads do not support timed semaphores.
+ * Therefore, if you're running on Solaris you might want to
+ * consider using the ACE POSIX pthreads implementation instead,
+ * which can be enabled by compiling ACE with
+ * -DACE_HAS_PTHREADS, rather than -DACE_HAS_STHREADS or
+ * -DACE_HAS_POSIX_SEM. */
+ int acquire (ACE_Time_Value &tv);
+
+ /**
+ * If <tv> == 0 then call <acquire()> directly. Otherwise, Block
+ * the thread until the semaphore count becomes greater than 0
+ * (at which point it is decremented) or until <tv> times out (in
+ * which case -1 is returned and <errno> == <ETIME>). Note that
+ * <*tv> is assumed to be in "absolute" rather than "relative" time.
+ * The value of <*tv> is updated upon return to show the actual
+ * (absolute) acquisition time.
+ *
+ * NOTE: Solaris threads do not support timed semaphores.
+ * Therefore, if you're running on Solaris you might want to
+ * consider using the ACE POSIX pthreads implementation instead,
+ * which can be enabled by compiling ACE with
+ * -DACE_HAS_PTHREADS, rather than -DACE_HAS_STHREADS or
+ * -DACE_HAS_POSIX_SEM. */
+ int acquire (ACE_Time_Value *tv);
+
+ /**
+ * Conditionally decrement the semaphore if count is greater than 0
+ * (i.e., won't block). Returns -1 on failure. If we "failed"
+ * because someone else already had the lock, <errno> is set to
+ * <EBUSY>.
+ */
+ int tryacquire (void);
+
+ /// Increment the semaphore by 1, potentially unblocking a waiting
+ /// thread.
+ int release (void);
+
+ /// Increment the semaphore by <release_count>, potentially
+ /// unblocking waiting threads.
+ int release (size_t release_count);
+
+ /**
+ * Acquire semaphore ownership. This calls <acquire> and is only
+ * here to make the <ACE_Semaphore> interface consistent with the
+ * other synchronization APIs.
+ */
+ int acquire_read (void);
+
+ /**
+ * Acquire semaphore ownership. This calls <acquire> and is only
+ * here to make the <ACE_Semaphore> interface consistent with the
+ * other synchronization APIs.
+ */
+ int acquire_write (void);
+
+ /**
+ * Conditionally acquire semaphore (i.e., won't block). This calls
+ * <tryacquire> and is only here to make the <ACE_Semaphore>
+ * interface consistent with the other synchronization APIs.
+ * Returns -1 on failure. If we "failed" because someone else
+ * already had the lock, <errno> is set to <EBUSY>.
+ */
+ int tryacquire_read (void);
+
+ /**
+ * Conditionally acquire semaphore (i.e., won't block). This calls
+ * <tryacquire> and is only here to make the <ACE_Semaphore>
+ * interface consistent with the other synchronization APIs.
+ * Returns -1 on failure. If we "failed" because someone else
+ * already had the lock, <errno> is set to <EBUSY>.
+ */
+ int tryacquire_write (void);
+
+ /**
+ * This is only here to make the <ACE_Semaphore>
+ * interface consistent with the other synchronization APIs.
+ * Assumes the caller has already acquired the semaphore using one of
+ * the above calls, and returns 0 (success) always.
+ */
+ int tryacquire_write_upgrade (void);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+ /// Return the underlying lock.
+ const ACE_sema_t &lock (void) const;
+
+protected:
+ ACE_sema_t semaphore_;
+
+ /// Keeps track of whether <remove> has been called yet to avoid
+ /// multiple <remove> calls, e.g., explicitly and implicitly in the
+ /// destructor. This flag isn't protected by a lock, so make sure
+ /// that you don't have multiple threads simultaneously calling
+ /// <remove> on the same object, which is a bad idea anyway...
+ int removed_;
+
+private:
+ // = Prevent assignment and initialization.
+ void operator= (const ACE_Semaphore &);
+ ACE_Semaphore (const ACE_Semaphore &);
+};
+
+/**
+ * @class ACE_Null_Semaphore
+ *
+ * @brief Implement a do nothing <ACE_Semaphore>, i.e., all the methods are
+ * no ops.
+ *
+ * Although the methods are no-ops, the return values are different for
+ * the blocking as opposed to timed acquires. The blocking version of
+ * acquire() is often used to serialize access to a critical section,
+ * whereas the timed version is often used to wait for another thread
+ * to update some condition or change some shared state. When using an
+ * ACE_Null_Semaphore, however, there's no other thread involved to
+ * change a state or condition (otherwise, a null semaphore would be
+ * inappropriate). Returning an error value signifies that the
+ * state or condition has not been (and can't be) changed, which is
+ * consistent with the behavior of the threaded case where a timeout
+ * occurs before the state or condition is changed.
+ */
+class ACE_Export ACE_Null_Semaphore
+{
+public:
+ ACE_Null_Semaphore (u_int count = 1, // By default make this unlocked.
+ int type = USYNC_THREAD,
+ const ACE_TCHAR *name = 0,
+ void * = 0,
+ int max = 0x7fffffff);
+ ~ACE_Null_Semaphore (void);
+ /// Return 0.
+ int remove (void);
+
+ /// Return 0.
+ int acquire (void);
+
+ /// Return -1 with <errno> == <ETIME>.
+ int acquire (ACE_Time_Value &);
+
+ /// Return -1 with <errno> == <ETIME>.
+ int acquire (ACE_Time_Value *);
+
+ /// Return 0.
+ int tryacquire (void);
+
+ /// Return 0.
+ int release (void);
+
+ /// Return 0.
+ int release (size_t);
+
+ /// Return 0.
+ int acquire_write (void);
+
+ /// Return 0.
+ int tryacquire_write (void);
+
+ /// Return 0.
+ int tryacquire_write_upgrade (void);
+
+ /// Return 0.
+ int acquire_read (void);
+
+ /// Return 0.
+ int tryacquire_read (void);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+};
+
+/**
+ * @class ACE_RW_Mutex
+ *
+ * @brief Wrapper for readers/writer locks.
+ *
+ * These are most useful for applications that have many more
+ * parallel readers than writers...
+ */
+class ACE_Export ACE_RW_Mutex
+{
+public:
+ /// Initialize a readers/writer lock.
+ ACE_RW_Mutex (int type = USYNC_THREAD,
+ const ACE_TCHAR *name = 0,
+ void *arg = 0);
+
+ /// Implicitly destroy a readers/writer lock
+ ~ACE_RW_Mutex (void);
+
+ /**
+ * Explicitly destroy a readers/writer lock. Note that only one
+ * thread should call this method since it doesn't protect against
+ * race conditions.
+ */
+ int remove (void);
+
+ /// Acquire a read lock, but block if a writer hold the lock.
+ int acquire_read (void);
+
+ /// Acquire a write lock, but block if any readers or a
+ /// writer hold the lock.
+ int acquire_write (void);
+
+ /**
+ * Conditionally acquire a read lock (i.e., won't block). Returns
+ * -1 on failure. If we "failed" because someone else already had
+ * the lock, <errno> is set to <EBUSY>.
+ */
+ int tryacquire_read (void);
+
+ /// Conditionally acquire a write lock (i.e., won't block).
+ int tryacquire_write (void);
+
+ /**
+ * Conditionally upgrade a read lock to a write lock. This only
+ * works if there are no other readers present, in which case the
+ * method returns 0. Otherwise, the method returns -1 and sets
+ * <errno> to <EBUSY>. Note that the caller of this method *must*
+ * already possess this lock as a read lock (but this condition is
+ * not checked by the current implementation).
+ */
+ int tryacquire_write_upgrade (void);
+
+ /**
+ * Note, for interface uniformity with other synchronization
+ * wrappers we include the <acquire> method. This is implemented as
+ * a write-lock to safe...
+ */
+ int acquire (void);
+
+ /**
+ * Note, for interface uniformity with other synchronization
+ * wrappers we include the <tryacquire> method. This is implemented
+ * as a write-lock to be safe... Returns -1 on failure. If we
+ * "failed" because someone else already had the lock, <errno> is
+ * set to <EBUSY>.
+ */
+ int tryacquire (void);
+
+ /// Unlock a readers/writer lock.
+ int release (void);
+
+ /// Return the underlying lock.
+ const ACE_rwlock_t &lock (void) const;
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+protected:
+ /// Readers/writer lock.
+ ACE_rwlock_t lock_;
+
+ /// Keeps track of whether <remove> has been called yet to avoid
+ /// multiple <remove> calls, e.g., explicitly and implicitly in the
+ /// destructor. This flag isn't protected by a lock, so make sure
+ /// that you don't have multiple threads simultaneously calling
+ /// <remove> on the same object, which is a bad idea anyway...
+ int removed_;
+
+private:
+ // = Prevent assignment and initialization.
+ void operator= (const ACE_RW_Mutex &);
+ ACE_RW_Mutex (const ACE_RW_Mutex &);
+};
+
+/**
+ * @class ACE_Mutex
+ *
+ * @brief <ACE_Mutex> wrapper (valid in same process or across
+ * processes (depending on TYPE flag)).
+ */
+class ACE_Export ACE_Mutex
+{
+public:
+ /// Initialize the mutex.
+ ACE_Mutex (int type = USYNC_THREAD,
+ const ACE_TCHAR *name = 0,
+ ACE_mutexattr_t *arg = 0);
+
+ /// Implicitly destroy the mutex.
+ ~ACE_Mutex (void);
+
+ /**
+ * Explicitly destroy the mutex. Note that only one thread should
+ * call this method since it doesn't protect against race
+ * conditions.
+ */
+ int remove (void);
+
+ /// Acquire lock ownership (wait on queue if necessary).
+ int acquire (void);
+
+ /**
+ * Block the thread until the mutex is acquired or <tv> times out,
+ * in which case -1 is returned and <errno> == <ETIME>. Note that
+ * <tv> is assumed to be in "absolute" rather than "relative" time.
+ * The value of <tv> is updated upon return to show the actual
+ * (absolute) acquisition time.
+ */
+ int acquire (ACE_Time_Value &tv);
+
+ /**
+ * If <tv> == 0 then call <acquire()> directly. Otherwise, block
+ * the thread until the mutex is acquired or <tv> times out, in
+ * which case -1 is returned and <errno> == <ETIME>. Note that
+ * <*tv> is assumed to be in "absolute" rather than "relative" time.
+ * The value of <*tv> is updated upon return to show the actual
+ * (absolute) acquisition time. */
+ int acquire (ACE_Time_Value *tv);
+
+ /**
+ * Conditionally acquire lock (i.e., don't wait on queue). Returns
+ * -1 on failure. If we "failed" because someone else already had
+ * the lock, <errno> is set to <EBUSY>.
+ */
+ int tryacquire (void);
+
+ /// Release lock and unblock a thread at head of queue.
+ int release (void);
+
+ /**
+ * Acquire mutex ownership. This calls <acquire> and is only
+ * here to make the <ACE_Mutex> interface consistent with the
+ * other synchronization APIs.
+ */
+ int acquire_read (void);
+
+ /**
+ * Acquire mutex ownership. This calls <acquire> and is only
+ * here to make the <ACE_Mutex> interface consistent with the
+ * other synchronization APIs.
+ */
+ int acquire_write (void);
+
+ /**
+ * Conditionally acquire mutex (i.e., won't block). This calls
+ * <tryacquire> and is only here to make the <ACE_Mutex> interface
+ * consistent with the other synchronization APIs. Returns -1 on
+ * failure. If we "failed" because someone else already had the
+ * lock, <errno> is set to <EBUSY>.
+ */
+ int tryacquire_read (void);
+
+ /**
+ * Conditionally acquire mutex (i.e., won't block). This calls
+ * <tryacquire> and is only here to make the <ACE_Mutex> interface
+ * consistent with the other synchronization APIs. Returns -1 on
+ * failure. If we "failed" because someone else already had the
+ * lock, <errno> is set to <EBUSY>.
+ */
+ int tryacquire_write (void);
+
+ /**
+ * This is only here for consistency with the other synchronization
+ * APIs and usability with Lock adapters. Assumes the caller already has
+ * acquired the mutex and returns 0 in all cases.
+ */
+ int tryacquire_write_upgrade (void);
+
+ /// Return the underlying mutex.
+ const ACE_mutex_t &lock (void) const;
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+ // = This should be protected but some C++ compilers complain...
+public:
+#if defined (CHORUS) || defined(ACE_HAS_PTHREADS) || defined(ACE_HAS_STHREADS)
+ /// This lock resides in shared memory.
+ ACE_mutex_t *process_lock_;
+
+ /**
+ * Remember the name of the mutex if we created it so we can unlink
+ * it when we go away (only the actor that initialized the memory
+ * can destroy it).
+ */
+ const ACE_TCHAR *lockname_;
+#endif /* CHORUS || ACE_HAS_PTHREADS */
+
+ /// Mutex type supported by the OS.
+ ACE_mutex_t lock_;
+
+ /// Keeps track of whether <remove> has been called yet to avoid
+ /// multiple <remove> calls, e.g., explicitly and implicitly in the
+ /// destructor. This flag isn't protected by a lock, so make sure
+ /// that you don't have multiple threads simultaneously calling
+ /// <remove> on the same object, which is a bad idea anyway...
+ int removed_;
+
+private:
+ // = Prevent assignment and initialization.
+ void operator= (const ACE_Mutex &);
+ ACE_Mutex (const ACE_Mutex &);
+};
+
+/**
+ * @class ACE_Null_Barrier
+ *
+ * @brief Implements "NULL barrier synchronization".
+ */
+class ACE_Export ACE_Null_Barrier
+{
+public:
+ /// Initialize the barrier to synchronize <count> threads.
+ ACE_Null_Barrier (u_int,
+ const char * = 0,
+ void * = 0);
+
+ /// Default dtor.
+ ~ACE_Null_Barrier (void);
+
+ /// Block the caller until all <count> threads have called <wait> and
+ /// then allow all the caller threads to continue in parallel.
+ int wait (void);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+private:
+ // = Prevent assignment and initialization.
+ void operator= (const ACE_Null_Barrier &);
+ ACE_Null_Barrier (const ACE_Null_Barrier &);
+};
+
+/**
+ * @class ACE_Null_Mutex
+ *
+ * @brief Implement a do nothing <ACE_Mutex>, i.e., all the methods are
+ * no ops.
+ */
+class ACE_Export ACE_Null_Mutex
+{
+public:
+ ACE_Null_Mutex (const ACE_TCHAR * = 0);
+ ~ACE_Null_Mutex (void);
+ /// Return 0.
+ int remove (void);
+
+ /// Return 0.
+ int acquire (void);
+
+ /// Return -1 with <errno> == <ETIME>.
+ int acquire (ACE_Time_Value &timeout);
+
+ /// Return -1 with <errno> == <ETIME>.
+ int acquire (ACE_Time_Value *timeout);
+
+ /// Return 0.
+ int tryacquire (void);
+
+ /// Return 0.
+ int release (void);
+
+ /// Return 0.
+ int acquire_write (void);
+
+ /// Return 0.
+ int tryacquire_write (void);
+
+ /// Return 0.
+ int tryacquire_write_upgrade (void);
+
+ /// Return 0.
+ int acquire_read (void);
+
+ /// Return 0.
+ int tryacquire_read (void);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+};
+
+class ACE_Export ACE_Noop_Token : public ACE_Null_Mutex
+{
+public:
+ int renew (int = 0, ACE_Time_Value * =0);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+};
+
+/**
+ * @class ACE_Null_Condition
+ *
+ * @brief Implement a do nothing <ACE_Condition> variable wrapper,
+ * i.e., all methods are no ops. This class is necessary since
+ * some C++ compilers are *very* lame...
+ */
+class ACE_Export ACE_Null_Condition
+{
+public:
+ ACE_Null_Condition (const ACE_Null_Mutex &m,
+ const ACE_TCHAR * = 0,
+ void * = 0);
+ ~ACE_Null_Condition (void);
+
+ /// Returns 0.
+ int remove (void);
+
+ /// Returns -1 with <errno> == <ETIME>.
+ int wait (ACE_Time_Value * = 0);
+
+ /// Returns 0.
+ int signal (void);
+
+ /// Returns 0.
+ int broadcast (void);
+ ACE_Null_Mutex &mutex (void);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ // ACE_ALLOC_HOOK_DECLARE;
+ // Declare the dynamic allocation hooks.
+
+protected:
+ ACE_Null_Mutex &mutex_; // Reference to mutex lock.
+
+private:
+ // = Prevent assignment and initialization.
+ void operator= (const ACE_Null_Condition &);
+ ACE_Null_Condition (const ACE_Null_Condition &);
+};
+
+#if defined (ACE_USES_OBSOLETE_GUARD_CLASSES)
+/**
+ * @class ACE_Null_Mutex_Guard
+ *
+ * @brief This data structure is meant to be used within a method or
+ * function... It performs automatic aquisition and release of
+ * an ACE_Null_Mutex.
+ *
+ * This class is obsolete and should be replaced by
+ * ACE_Guard<ACE_Null_Mutex>.
+ */
+class ACE_Export ACE_Null_Mutex_Guard
+{
+public:
+ ACE_Null_Mutex_Guard (ACE_Null_Mutex &);
+ ~ACE_Null_Mutex_Guard (void);
+ int remove (void);
+ int locked (void);
+ int acquire (void);
+ int tryacquire (void);
+ int release (void);
+ void dump (void) const;
+
+private:
+ // = Prevent assignment and initialization.
+ void operator= (const ACE_Null_Mutex_Guard &);
+ ACE_Null_Mutex_Guard (const ACE_Null_Mutex_Guard &);
+};
+#endif /* ACE_USES_OBSOLETE_GUARD_CLASSES */
+
+/**
+ * @class ACE_TSS_Adapter
+ *
+ * @brief This class encapsulates a TSS object and its associated
+ * C++ destructor function. It is used by the ACE_TSS...
+ * methods (in Synch_T.cpp) in order to allow an extern
+ * "C" cleanup routine to be used. Needed by the "frigging"
+ * MVS C++ compiler.
+ *
+ * Objects of this class are stored in thread specific
+ * storage. ts_obj_ points to the "real" object and
+ * func_ is a pointer to the C++ cleanup function for ts_obj_.
+ */
+class ACE_Export ACE_TSS_Adapter
+{
+public:
+ /// Initialize the adapter.
+ ACE_TSS_Adapter (void *object, ACE_THR_DEST f);
+
+ /// Default dtor.
+ ~ACE_TSS_Adapter (void);
+
+ /// Perform the cleanup operation.
+ void cleanup (void);
+
+//private:
+
+ /// The real TS object.
+ void *ts_obj_;
+
+ /// The real cleanup routine for ts_obj;
+ ACE_THR_DEST func_;
+};
+
+/**
+ * @class ACE_Event
+ *
+ * @brief A wrapper around the Win32 event locking mechanism.
+ *
+ * Portable implementation of an Event mechanism, which is
+ * native to Win32, but must be emulated on UNIX. Note that
+ * this only provides global naming and system-scope locking support
+ * on Win32 platforms.
+ */
+class ACE_Export ACE_Event
+{
+public:
+ /// Constructor that creates event.
+ ACE_Event (int manual_reset = 0,
+ int initial_state = 0,
+ int type = USYNC_THREAD,
+ const ACE_TCHAR *name = 0,
+ void *arg = 0);
+
+ /// Implicitly destroy the event variable.
+ ~ACE_Event (void);
+
+ /**
+ * Explicitly destroy the event variable. Note that only one thread
+ * should call this method since it doesn't protect against race
+ * conditions.
+ */
+ int remove (void);
+
+ /// Underlying handle to event.
+ ACE_event_t handle (void) const;
+
+ /**
+ * Set the underlying handle to event. Note that this method assumes
+ * ownership of the <handle> and will close it down in <remove>. If
+ * you want the <handle> to stay open when <remove> is called make
+ * sure to call <dup> on the <handle> before closing it. You are
+ * responsible for the closing the existing <handle> before
+ * overwriting it.
+ */
+ void handle (ACE_event_t new_handle);
+
+ /**
+ * if MANUAL reset
+ * sleep till the event becomes signaled
+ * event remains signaled after wait() completes.
+ * else AUTO reset
+ * sleep till the event becomes signaled
+ * event resets wait() completes.
+ */
+ int wait (void);
+
+ /// Same as wait() above, but this one can be timed
+ /// <abstime> is absolute time-of-day if if <use_absolute_time>
+ /// is non-0, else it is relative time.
+ int wait (const ACE_Time_Value *abstime,
+ int use_absolute_time = 1);
+
+ /**
+ * if MANUAL reset
+ * wake up all waiting threads
+ * set to signaled state
+ * else AUTO reset
+ * if no thread is waiting, set to signaled state
+ * if thread(s) are waiting, wake up one waiting thread and
+ * reset event
+ */
+ int signal (void);
+
+ /**
+ * if MANUAL reset
+ * wakeup all waiting threads and
+ * reset event
+ * else AUTO reset
+ * wakeup one waiting thread (if present) and
+ * reset event
+ */
+ int pulse (void);
+
+ /// Set to nonsignaled state.
+ int reset (void);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks
+ ACE_ALLOC_HOOK_DECLARE;
+
+protected:
+ /// The underlying handle.
+ ACE_event_t handle_;
+
+ /// Keeps track of whether <remove> has been called yet to avoid
+ /// multiple <remove> calls, e.g., explicitly and implicitly in the
+ /// destructor. This flag isn't protected by a lock, so make sure
+ /// that you don't have multiple threads simultaneously calling
+ /// <remove> on the same object, which is a bad idea anyway...
+ int removed_;
+
+private:
+ // = Prevent copying.
+ ACE_Event (const ACE_Event& event);
+ const ACE_Event &operator= (const ACE_Event &rhs);
+};
+
+/**
+ * @class ACE_Manual_Event
+ *
+ * @brief Manual Events.
+ *
+ * Specialization of Event mechanism which wakes up all waiting
+ * threads on <signal>. Note that this only provides
+ * global naming and system-scope locking support on Win32 platforms.
+ */
+class ACE_Export ACE_Manual_Event : public ACE_Event
+{
+public:
+ /// constructor which will create manual event
+ ACE_Manual_Event (int initial_state = 0,
+ int type = USYNC_THREAD,
+ const char *name = 0,
+ void *arg = 0);
+
+#if defined (ACE_HAS_WCHAR)
+ /// constructor which will create manual event (wchar_t version)
+ ACE_Manual_Event (int initial_state,
+ int type,
+ const wchar_t *name,
+ void *arg = 0);
+#endif /* ACE_HAS_WCHAR */
+
+ /// Default dtor.
+ ~ACE_Manual_Event (void);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks
+ ACE_ALLOC_HOOK_DECLARE;
+};
+
+/**
+ * @class ACE_Auto_Event
+ *
+ * @brief Auto Events.
+ *
+ * Specialization of Event mechanism which wakes up one waiting
+ * thread on <signal>. Note that this only provides
+ * global naming and system-scope locking support on Win32 platforms.
+ */
+class ACE_Export ACE_Auto_Event : public ACE_Event
+{
+public:
+ /// constructor which will create auto event
+ ACE_Auto_Event (int initial_state = 0,
+ int type = USYNC_THREAD,
+ const char *name = 0,
+ void *arg = 0);
+
+#if defined (ACE_HAS_WCHAR)
+ /// constructor which will create auto event (wchar_t version)
+ ACE_Auto_Event (int initial_state,
+ int type,
+ const wchar_t *name,
+ void *arg = 0);
+#endif /* ACE_HAS_WCHAR */
+
+ /// Default dtor.
+ ~ACE_Auto_Event (void);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks
+ ACE_ALLOC_HOOK_DECLARE;
+};
+
+// ACE platform supports some form of threading.
+#if !defined (ACE_HAS_THREADS)
+/**
+ * @class ACE_Barrier
+ *
+ * @brief This is a no-op to make ACE "syntactically consistent."
+ */
+class ACE_Barrier
+{
+public:
+ ACE_Barrier (u_int, const ACE_TCHAR * = 0, void * = 0) {}
+ ~ACE_Barrier (void) {}
+ int wait (void) { ACE_NOTSUP_RETURN (-1); }
+ void dump (void) const {}
+};
+#else
+ /**
+ * @class ACE_Thread_Mutex
+ *
+ * @brief ACE_Thread_Mutex wrapper (only valid for threads in the same
+ * process).
+ *
+ * This implementation is optimized for locking threads that are
+ * in the same process. It maps to <CRITICAL_SECTION>s on NT
+ * and <ACE_mutex_t> with <type> set to <USYNC_THREAD> on UNIX.
+ * ACE_Thread_Mutex is recursive on some platforms (like
+ * Win32). However, on most platforms (like Solaris) it is not
+ * recursive. To be totally safe and portable, developers
+ * should use <ACE_Recursive_Thread_Mutex> when they need a
+ * recursive mutex.
+ */
+class ACE_Export ACE_Thread_Mutex
+{
+ friend class ACE_Condition_Thread_Mutex;
+public:
+ /// Constructor.
+ ACE_Thread_Mutex (const ACE_TCHAR *name = 0,
+ ACE_mutexattr_t *attributes = 0);
+
+ /// Implicitly destroy the mutex.
+ ~ACE_Thread_Mutex (void);
+
+ /**
+ * Explicitly destroy the mutex. Note that only one thread should
+ * call this method since it doesn't protect against race
+ * conditions.
+ */
+ int remove (void);
+
+ /// Acquire lock ownership (wait on queue if necessary).
+ int acquire (void);
+
+ /**
+ * Block the thread until we acquire the mutex or until <tv> times
+ * out, in which case -1 is returned with <errno> == <ETIME>. Note
+ * that <tv> is assumed to be in "absolute" rather than "relative"
+ * time. The value of <tv> is updated upon return to show the
+ * actual (absolute) acquisition time.
+ */
+ int acquire (ACE_Time_Value &tv);
+
+ /**
+ * If <tv> == 0 the call <acquire()> directly. Otherwise, Block the
+ * thread until we acquire the mutex or until <tv> times out, in
+ * which case -1 is returned with <errno> == <ETIME>. Note that
+ * <*tv> is assumed to be in "absolute" rather than "relative" time.
+ * The value of <*tv> is updated upon return to show the actual
+ * (absolute) acquisition time.
+ */
+ int acquire (ACE_Time_Value *tv);
+
+ /**
+ * Conditionally acquire lock (i.e., don't wait on queue). Returns
+ * -1 on failure. If we "failed" because someone else already had
+ * the lock, <errno> is set to <EBUSY>.
+ */
+ int tryacquire (void);
+
+ /// Release lock and unblock a thread at head of queue.
+ int release (void);
+
+ /**
+ * Acquire mutex ownership. This calls <acquire> and is only here
+ * to make the <ACE_Thread_Mutex> interface consistent with the
+ * other synchronization APIs.
+ */
+ int acquire_read (void);
+
+ /**
+ * Acquire mutex ownership. This calls <acquire> and is only here
+ * to make the <ACE_Thread_Mutex> interface consistent with the
+ * other synchronization APIs.
+ */
+ int acquire_write (void);
+
+ /**
+ * Conditionally acquire mutex (i.e., won't block). This calls
+ * <tryacquire> and is only here to make the <ACE_Thread_Mutex>
+ * interface consistent with the other synchronization APIs.
+ * Returns -1 on failure. If we "failed" because someone else
+ * already had the lock, <errno> is set to <EBUSY>.
+ */
+ int tryacquire_read (void);
+
+ /**
+ * Conditionally acquire mutex (i.e., won't block). This calls
+ * <tryacquire> and is only here to make the <ACE_Thread_Mutex>
+ * interface consistent with the other synchronization APIs.
+ * Returns -1 on failure. If we "failed" because someone else
+ * already had the lock, <errno> is set to <EBUSY>.
+ */
+ int tryacquire_write (void);
+
+ /**
+ * This is only here to make the <ACE_Thread_Mutex>
+ * interface consistent with the other synchronization APIs.
+ * Assumes the caller has already acquired the mutex using one of
+ * the above calls, and returns 0 (success) always.
+ */
+ int tryacquire_write_upgrade (void);
+
+ /// Return the underlying mutex.
+ const ACE_thread_mutex_t &lock (void) const;
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+ // protected:
+ /// Mutex type that supports single-process locking efficiently.
+ ACE_thread_mutex_t lock_;
+
+ /// Keeps track of whether <remove> has been called yet to avoid
+ /// multiple <remove> calls, e.g., explicitly and implicitly in the
+ /// destructor. This flag isn't protected by a lock, so make sure
+ /// that you don't have multiple threads simultaneously calling
+ /// <remove> on the same object, which is a bad idea anyway...
+ int removed_;
+
+private:
+ // = Prevent assignment and initialization.
+ void operator= (const ACE_Thread_Mutex &);
+ ACE_Thread_Mutex (const ACE_Thread_Mutex &);
+};
+
+#if defined (ACE_USES_OBSOLETE_GUARD_CLASSES)
+/**
+ * @class ACE_Thread_Mutex_Guard
+ *
+ * @brief This data structure is meant to be used within a method or
+ * function... It performs automatic aquisition and release of
+ * an <ACE_Thread_Mutex>.
+ *
+ * This class is obsolete and should be replaced by
+ * ACE_Guard<ACE_Thread_Mutex>.
+ */
+class ACE_Export ACE_Thread_Mutex_Guard
+{
+public:
+ /// Implicitly and automatically acquire the lock.
+ ACE_Thread_Mutex_Guard (ACE_Thread_Mutex &m, int block = 1);
+
+ /// Implicitly release the lock.
+ ~ACE_Thread_Mutex_Guard (void);
+
+ /// 1 if locked, 0 if couldn't acquire the lock (errno will contain
+ /// the reason for this).
+ int locked (void);
+
+ /**
+ * Explicitly release the lock. Note that only one thread should
+ * call this method since it doesn't protect against race
+ * conditions.
+ */
+ int remove (void);
+
+ /// Explicitly acquire the lock.
+ int acquire (void);
+
+ /**
+ * Conditionally acquire the lock (i.e., won't block). Returns -1
+ * on failure. If we "failed" because someone else already had the
+ * lock, <errno> is set to <EBUSY>.
+ */
+ int tryacquire (void);
+
+ /// Explicitly release the lock.
+ int release (void);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+protected:
+ /// Reference to the mutex.
+ ACE_Thread_Mutex &lock_;
+
+ /// Keeps track of whether we acquired the lock or failed.
+ int owner_;
+
+private:
+ // = Prevent assignment and initialization.
+ void operator= (const ACE_Thread_Mutex_Guard &);
+ ACE_Thread_Mutex_Guard (const ACE_Thread_Mutex_Guard &);
+};
+#endif /* ACE_USES_OBSOLETE_GUARD_CLASSES */
+
+class ACE_Export ACE_Condition_Attributes
+{
+public:
+ /// Constructor
+ ACE_Condition_Attributes (int type = ACE_DEFAULT_SYNCH_TYPE);
+
+ /// Destructor
+ ~ACE_Condition_Attributes (void);
+
+private:
+ friend class ACE_Condition_Thread_Mutex;
+
+ /// The attributes
+ ACE_condattr_t attributes_;
+
+private:
+ // = Prevent assignment and initialization.
+ void operator= (const ACE_Condition_Attributes &);
+ ACE_Condition_Attributes (const ACE_Condition_Attributes &);
+};
+
+/**
+ * @class ACE_Condition_Thread_Mutex
+ *
+ * @brief ACE_Condition variable wrapper written using ACE_Mutexes This
+ * allows threads to block until shared data changes state.
+ * A condition variable enables threads to atomically block and
+ * test the condition under the protection of a mutual exclu-
+ * sion lock (mutex) until the condition is satisfied. That is,
+ * the mutex must have been held by the thread before calling
+ * wait or signal on the condition. If the condition is false,
+ * a thread blocks on a condition variable and atomically
+ * releases the mutex that is waiting for the condition to
+ * change. If another thread changes the condition, it may wake
+ * up waiting threads by signaling the associated condition
+ * variable. The waiting threads, upon awakening, reacquire the
+ * mutex and re-evaluate the condition.
+ *
+ * This should be an instantiation of ACE_Condition but problems
+ * with compilers precludes this...
+ */
+class ACE_Export ACE_Condition_Thread_Mutex
+{
+public:
+ /// Initialize the condition variable.
+ ACE_Condition_Thread_Mutex (const ACE_Thread_Mutex &m,
+ const ACE_TCHAR *name = 0,
+ void *arg = 0);
+
+ /// Initialize the condition variable.
+ ACE_Condition_Thread_Mutex (const ACE_Thread_Mutex &m,
+ ACE_Condition_Attributes &attributes,
+ const ACE_TCHAR *name = 0,
+ void *arg = 0);
+
+ /// Implicitly destroy the condition variable.
+ ~ACE_Condition_Thread_Mutex (void);
+
+ /**
+ * Explicitly destroy the condition variable. Note that only one
+ * thread should call this method since it doesn't protect against
+ * race conditions.
+ */
+ int remove (void);
+
+ /**
+ * Block on condition, or until absolute time-of-day has passed. If
+ * abstime == 0 use "blocking" <wait> semantics. Else, if <abstime>
+ * != 0 and the call times out before the condition is signaled
+ * <wait> returns -1 and sets errno to ETIME.
+ */
+ int wait (const ACE_Time_Value *abstime);
+
+ /// Block on condition.
+ int wait (void);
+
+ /**
+ * Block on condition or until absolute time-of-day has passed. If
+ * abstime == 0 use "blocking" wait() semantics on the <mutex>
+ * passed as a parameter (this is useful if you need to store the
+ * <Condition> in shared memory). Else, if <abstime> != 0 and the
+ * call times out before the condition is signaled <wait> returns -1
+ * and sets errno to ETIME.
+ */
+ int wait (ACE_Thread_Mutex &mutex, const ACE_Time_Value *abstime = 0);
+
+ /// Signal one waiting thread.
+ int signal (void);
+
+ /// Signal *all* waiting threads.
+ int broadcast (void);
+
+ /// Returns a reference to the underlying mutex_;
+ ACE_Thread_Mutex &mutex (void);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+protected:
+ /// Condition variable.
+ ACE_cond_t cond_;
+
+ /// Reference to mutex lock.
+ ACE_Thread_Mutex &mutex_;
+
+ /// Keeps track of whether <remove> has been called yet to avoid
+ /// multiple <remove> calls, e.g., explicitly and implicitly in the
+ /// destructor. This flag isn't protected by a lock, so make sure
+ /// that you don't have multiple threads simultaneously calling
+ /// <remove> on the same object, which is a bad idea anyway...
+ int removed_;
+
+private:
+ // = Prevent assignment and initialization.
+ void operator= (const ACE_Condition_Thread_Mutex &);
+ ACE_Condition_Thread_Mutex (const ACE_Condition_Thread_Mutex &);
+};
+
+/**
+ * @class ACE_Recursive_Thread_Mutex
+ *
+ * @brief Implement a C++ wrapper that allows nested acquisition and
+ * release of a mutex that occurs in the same thread.
+ */
+class ACE_Export ACE_Recursive_Thread_Mutex
+{
+public:
+ /// Initialize a recursive mutex.
+ ACE_Recursive_Thread_Mutex (const ACE_TCHAR *name = 0,
+ ACE_mutexattr_t *arg = 0);
+
+ /// Implicitly release a recursive mutex.
+ ~ACE_Recursive_Thread_Mutex (void);
+
+ /**
+ * Implicitly release a recursive mutex. Note that only one thread
+ * should call this method since it doesn't protect against race
+ * conditions.
+ */
+ int remove (void);
+
+ /**
+ * Acquire a recursive mutex (will increment the nesting level and
+ * not deadmutex if the owner of the mutex calls this method more
+ * than once).
+ */
+ int acquire (void);
+
+ /**
+ * Conditionally acquire a recursive mutex (i.e., won't block).
+ * Returns -1 on failure. If we "failed" because someone else
+ * already had the lock, <errno> is set to <EBUSY>.
+ */
+ int tryacquire (void);
+
+ /**
+ * Acquire mutex ownership. This calls <acquire> and is only
+ * here to make the <ACE_Recusive_Thread_Mutex> interface consistent
+ * with the other synchronization APIs.
+ */
+ int acquire_read (void);
+
+ /**
+ * Acquire mutex ownership. This calls <acquire> and is only
+ * here to make the <ACE_Recusive_Thread_Mutex> interface consistent
+ * with the other synchronization APIs.
+ */
+ int acquire_write (void);
+
+ /**
+ * Conditionally acquire mutex (i.e., won't block). This calls
+ * <tryacquire> and is only here to make the
+ * <ACE_Recusive_Thread_Mutex> interface consistent with the other
+ * synchronization APIs. Returns -1 on failure. If we "failed"
+ * because someone else already had the lock, <errno> is set to
+ * <EBUSY>.
+ */
+ int tryacquire_read (void);
+
+ /**
+ * Conditionally acquire mutex (i.e., won't block). This calls
+ * <tryacquire> and is only here to make the
+ * <ACE_Recusive_Thread_Mutex> interface consistent with the other
+ * synchronization APIs. Returns -1 on failure. If we "failed"
+ * because someone else already had the lock, <errno> is set to
+ * <EBUSY>.
+ */
+ int tryacquire_write (void);
+
+ /**
+ * This is only here to make the <ACE_Recursive_Thread_Mutex>
+ * interface consistent with the other synchronization APIs.
+ * Assumes the caller has already acquired the mutex using one of
+ * the above calls, and returns 0 (success) always.
+ */
+ int tryacquire_write_upgrade (void);
+
+ /**
+ * Releases a recursive mutex (will not release mutex until all the
+ * nesting level drops to 0, which means the mutex is no longer
+ * held).
+ */
+ int release (void);
+
+ /// Return the id of the thread that currently owns the mutex.
+ ACE_thread_t get_thread_id (void);
+
+ /**
+ * Return the nesting level of the recursion. When a thread has
+ * acquired the mutex for the first time, the nesting level == 1.
+ * The nesting level is incremented every time the thread acquires
+ * the mutex recursively.
+ */
+ int get_nesting_level (void);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+protected:
+ // = This method should *not* be public (they hold no locks...)
+ void set_thread_id (ACE_thread_t t);
+
+ /// Recursive mutex.
+ ACE_recursive_thread_mutex_t recursive_mutex_;
+
+ /// Keeps track of whether <remove> has been called yet to avoid
+ /// multiple <remove> calls, e.g., explicitly and implicitly in the
+ /// destructor. This flag isn't protected by a lock, so make sure
+ /// that you don't have multiple threads simultaneously calling
+ /// <remove> on the same object, which is a bad idea anyway...
+ int removed_;
+
+private:
+ // = Prevent assignment and initialization.
+ void operator= (const ACE_Recursive_Thread_Mutex &);
+ ACE_Recursive_Thread_Mutex (const ACE_Recursive_Thread_Mutex &);
+};
+
+/**
+ * @class ACE_RW_Thread_Mutex
+ *
+ * @brief Wrapper for readers/writer locks that exist within a process.
+ */
+class ACE_Export ACE_RW_Thread_Mutex : public ACE_RW_Mutex
+{
+public:
+ ACE_RW_Thread_Mutex (const ACE_TCHAR *name = 0,
+ void *arg = 0);
+
+ /// Default dtor.
+ ~ACE_RW_Thread_Mutex (void);
+
+ /**
+ * Conditionally upgrade a read lock to a write lock. This only
+ * works if there are no other readers present, in which case the
+ * method returns 0. Otherwise, the method returns -1 and sets
+ * <errno> to <EBUSY>. Note that the caller of this method *must*
+ * already possess this lock as a read lock (but this condition is
+ * not checked by the current implementation).
+ */
+ int tryacquire_write_upgrade (void);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+};
+
+/**
+ * @class ACE_Thread_Semaphore
+ *
+ * @brief Wrapper for Dijkstra style general semaphores that work
+ * only within one process.
+ */
+class ACE_Export ACE_Thread_Semaphore : public ACE_Semaphore
+{
+public:
+ /// Initialize the semaphore, with an initial value of <count>,
+ /// maximum value of <max>, and unlocked by default.
+ ACE_Thread_Semaphore (u_int count = 1, // By default make this unlocked.
+ const ACE_TCHAR *name = 0,
+ void * = 0,
+ int max = 0x7FFFFFFF);
+
+ /// Default dtor.
+ ~ACE_Thread_Semaphore (void);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+};
+
+struct ACE_Export ACE_Sub_Barrier
+{
+ // = Initialization.
+ ACE_Sub_Barrier (u_int count,
+ ACE_Thread_Mutex &lock,
+ const ACE_TCHAR *name = 0,
+ void *arg = 0);
+
+ ~ACE_Sub_Barrier (void);
+
+ ACE_Condition_Thread_Mutex barrier_finished_;
+ // True if this generation of the barrier is done.
+
+ int running_threads_;
+ // Number of threads that are still running.
+
+ void dump (void) const;
+ // Dump the state of an object.
+
+ ACE_ALLOC_HOOK_DECLARE;
+ // Declare the dynamic allocation hooks.
+};
+
+/**
+ * @class ACE_Barrier
+ *
+ * @brief Implements "barrier synchronization".
+ *
+ * This class allows <count> number of threads to synchronize
+ * their completion of (one round of) a task, which is known as
+ * "barrier synchronization". The implementation uses a
+ * "sub-barrier generation numbering" scheme to avoid overhead
+ * and to ensure that all threads wait to leave the barrier
+ * correct. This code is based on an article from SunOpsis
+ * Vol. 4, No. 1 by Richard Marejka
+ * (Richard.Marejka@canada.sun.com).
+ */
+class ACE_Export ACE_Barrier
+{
+public:
+ /// Initialize the barrier to synchronize <count> threads.
+ ACE_Barrier (u_int count,
+ const ACE_TCHAR *name = 0,
+ void *arg = 0);
+
+ /// Default dtor.
+ ~ACE_Barrier (void);
+
+ /// Block the caller until all <count> threads have called <wait> and
+ /// then allow all the caller threads to continue in parallel.
+ int wait (void);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+protected:
+ /// Serialize access to the barrier state.
+ ACE_Thread_Mutex lock_;
+
+ /// Either 0 or 1, depending on whether we are the first generation
+ /// of waiters or the next generation of waiters.
+ int current_generation_;
+
+ /// Total number of threads that can be waiting at any one time.
+ int count_;
+
+ /**
+ * We keep two <sub_barriers>, one for the first "generation" of
+ * waiters, and one for the next "generation" of waiters. This
+ * efficiently solves the problem of what to do if all the first
+ * generation waiters don't leave the barrier before one of the
+ * threads calls wait() again (i.e., starts up the next generation
+ * barrier).
+ */
+ ACE_Sub_Barrier sub_barrier_1_;
+ ACE_Sub_Barrier sub_barrier_2_;
+ ACE_Sub_Barrier *sub_barrier_[2];
+
+private:
+ // = Prevent assignment and initialization.
+ void operator= (const ACE_Barrier &);
+ ACE_Barrier (const ACE_Barrier &);
+};
+
+#if 0
+// The following two classes are commented out since there doesn't
+// appear to be a portable and robust means of implementing this
+// functionality across platforms. If you know of a portable and
+// robust way to implement this functionality please let us know.
+
+/**
+ * @class ACE_Process_Condition
+ *
+ * @brief ACE_Condition variable wrapper that works across processes.
+ */
+class ACE_Export ACE_Process_Condition
+{
+public:
+ ACE_Process_Condition (MUTEX &m, const ACE_TCHAR *name = 0, void *arg = 0);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ // ACE_ALLOC_HOOK_DECLARE;
+ // Declare the dynamic allocation hooks.
+};
+#endif /* 0 */
+
+#if 0
+/**
+ * @class ACE_Process_Barrier
+ *
+ * @brief Implements "barrier synchronization" using ACE_Process_Mutexes!
+ *
+ * This class is just a simple wrapper for ACE_Barrier that
+ * selects the USYNC_PROCESS variant for the locks.
+ */
+class ACE_Export ACE_Process_Barrier : public ACE_Barrier
+{
+public:
+ /// Create a Process_Barrier, passing in the optional <name>.
+ ACE_Process_Barrier (u_int count, const ACE_TCHAR *name = 0);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+};
+#endif /* 0 */
+
+/**
+ * @class ACE_Thread_Barrier
+ *
+ * @brief Implements "barrier synchronization" using ACE_Thread_Mutexes!
+ *
+ * This class is just a simple wrapper for ACE_Barrier that
+ * selects the USYNC_THREAD variant for the locks.
+ */
+class ACE_Export ACE_Thread_Barrier : public ACE_Barrier
+{
+public:
+ /// Create a Thread_Barrier, passing in the optional <name>.
+ ACE_Thread_Barrier (u_int count, const ACE_TCHAR *name = 0);
+
+ /// Default dtor.
+ ~ACE_Thread_Barrier (void);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+};
+#endif /* ACE_HAS_THREADS */
+
+#if defined (__ACE_INLINE__)
+#include "ace/Threads/Synch.i"
+#endif /* __ACE_INLINE__ */
+
+// Include the templates here.
+#include "ace/Threads/Synch_T.h"
+
+template <class ACE_LOCK>
+class ACE_Guard;
+
+ACE_TEMPLATE_SPECIALIZATION
+/**
+ * @class ACE_Guard<ACE_Null_Mutex>
+ *
+ * @brief Template specialization of <ACE_Guard> for the
+ * <ACE_Null_Mutex>.
+ *
+ * This specialization is useful since it helps to speedup
+ * performance of the "Null_Mutex" considerably.
+ */
+class ACE_Export ACE_Guard<ACE_Null_Mutex>
+{
+public:
+ // = Initialization and termination methods.
+ ACE_Guard (ACE_Null_Mutex &) {}
+ ACE_Guard (ACE_Null_Mutex &, int) {}
+#if defined (ACE_WIN32)
+ ~ACE_Guard (void) {}
+#endif /* ACE_WIN32 */
+
+ int acquire (void) { return 0; }
+ int tryacquire (void) { return 0; }
+ int release (void) { return 0; }
+ int locked (void) { return 1; }
+ int remove (void) { return 0; }
+ void dump (void) const {}
+
+private:
+ // = Prevent assignment and initialization.
+ ACE_UNIMPLEMENTED_FUNC (void operator= (const ACE_Guard<ACE_Null_Mutex> &))
+ ACE_UNIMPLEMENTED_FUNC (ACE_Guard (const ACE_Guard<ACE_Null_Mutex> &))
+};
+
+template <class ACE_LOCK>
+class ACE_Write_Guard;
+
+ACE_TEMPLATE_SPECIALIZATION
+/**
+ * @class ACE_Write_Guard<ACE_Null_Mutex>
+ *
+ */
+class ACE_Export ACE_Write_Guard<ACE_Null_Mutex> : public ACE_Guard<ACE_Null_Mutex>
+{
+public:
+ ACE_Write_Guard (ACE_Null_Mutex &m)
+ : ACE_Guard<ACE_Null_Mutex> (m) {}
+ ACE_Write_Guard (ACE_Null_Mutex &m, int blocked)
+ : ACE_Guard<ACE_Null_Mutex> (m, blocked) {}
+
+ int acquire_write (void) { return 0; }
+ int acquire (void) { return 0; }
+ int tryacquire_write (void) { return 0; }
+ int tryacquire (void) { return 0; }
+ void dump (void) const {}
+};
+
+template <class ACE_LOCK>
+class ACE_Read_Guard;
+
+ACE_TEMPLATE_SPECIALIZATION
+/**
+ * @class ACE_Read_Guard<ACE_Null_Mutex>
+ *
+ */
+class ACE_Export ACE_Read_Guard<ACE_Null_Mutex> : public ACE_Guard<ACE_Null_Mutex>
+{
+public:
+ ACE_Read_Guard (ACE_Null_Mutex &m)
+ : ACE_Guard<ACE_Null_Mutex> (m) {}
+ ACE_Read_Guard (ACE_Null_Mutex &m, int blocked)
+ : ACE_Guard<ACE_Null_Mutex> (m, blocked) {}
+
+ int acquire_read (void) { return 0; }
+ int acquire (void) { return 0; }
+ int tryacquire_read (void) { return 0; }
+ int tryacquire (void) { return 0; }
+ void dump (void) const {}
+};
+
+#if defined (ACE_LEGACY_MODE)
+# include "ace/File_Lock.h"
+# include "ace/Process_Semaphore.h"
+# include "ace/Process_Mutex.h"
+# include "ace/RW_Process_Mutex.h"
+# include "ace/Test_and_Set.h"
+#endif /* ACE_LEGACY_MODE */
+
+#include "ace/post.h"
+#endif /* ACE_SYNCH_H */
diff --git a/ace/Threads/Synch.h~ b/ace/Threads/Synch.h~
new file mode 100644
index 00000000000..f46053bef2b
--- /dev/null
+++ b/ace/Threads/Synch.h~
@@ -0,0 +1,1753 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Synch.h
+ *
+ * $Id$
+ *
+ * Wrapper Facades for various synchronization mechanisms.
+ *
+ * @author Douglas C. Schmidt <schmidt@cs.wustl.edu>
+ */
+//=============================================================================
+
+#ifndef ACE_SYNCH_H
+#define ACE_SYNCH_H
+#include "ace/pre.h"
+
+#include "ace/ACE.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+// Forward declarations.
+/**
+ * @class ACE_Time_Value;
+ template <class ACE_COND_MUTEX> class ACE_Condition;
+ */
+class ACE_Time_Value;
+
+/**
+ * @class ACE_Lock
+ *
+ * @brief This is the abstract base class that contains the uniform
+ * locking API that is supported by all the ACE synchronization
+ * mechanisms.
+ *
+ * This class is typically used in conjunction with the
+ * <ACE_Lock_Adapter> in order to provide a polymorphic
+ * interface to the ACE synchronization mechanisms (e.g.,
+ * <ACE_Mutex>, <ACE_Semaphore>, <ACE_RW_Mutex>, etc). Note that
+ * the reason that all of ACE doesn't use polymorphic locks is
+ * that (1) they add ~20% extra overhead for virtual function
+ * calls and (2) objects with virtual functions can't be placed
+ * into shared memory.
+ */
+class ACE_Export ACE_Lock
+{
+public:
+ /// CE needs a default ctor here.
+ ACE_Lock (void);
+
+ /// Noop virtual destructor
+ virtual ~ACE_Lock (void);
+
+ /**
+ * Explicitly destroy the lock. Note that only one thread should
+ * call this method since it doesn't protect against race
+ * conditions.
+ */
+ virtual int remove (void) = 0;
+
+ /// Block the thread until the lock is acquired. Returns -1 on
+ /// failure.
+ virtual int acquire (void) = 0;
+
+ /**
+ * Conditionally acquire the lock (i.e., won't block). Returns -1
+ * on failure. If we "failed" because someone else already had the
+ * lock, <errno> is set to <EBUSY>.
+ */
+ virtual int tryacquire (void) = 0;
+
+ /// Release the lock. Returns -1 on failure.
+ virtual int release (void) = 0;
+
+ /**
+ * Block until the thread acquires a read lock. If the locking
+ * mechanism doesn't support read locks then this just calls
+ * <acquire>. Returns -1 on failure.
+ */
+ virtual int acquire_read (void) = 0;
+
+ /**
+ * Block until the thread acquires a write lock. If the locking
+ * mechanism doesn't support read locks then this just calls
+ * <acquire>. Returns -1 on failure.
+ */
+ virtual int acquire_write (void) = 0;
+
+ /**
+ * Conditionally acquire a read lock. If the locking mechanism
+ * doesn't support read locks then this just calls <acquire>.
+ * Returns -1 on failure. If we "failed" because someone else
+ * already had the lock, <errno> is set to <EBUSY>.
+ */
+ virtual int tryacquire_read (void) = 0;
+
+ /**
+ * Conditionally acquire a write lock. If the locking mechanism
+ * doesn't support read locks then this just calls <acquire>.
+ * Returns -1 on failure. If we "failed" because someone else
+ * already had the lock, <errno> is set to <EBUSY>.
+ */
+ virtual int tryacquire_write (void) = 0;
+
+ /**
+ * Conditionally try to upgrade a lock held for read to a write lock.
+ * If the locking mechanism doesn't support read locks then this just
+ * calls <acquire>. Returns 0 on success, -1 on failure.
+ */
+ virtual int tryacquire_write_upgrade (void) = 0;
+};
+
+/**
+ * @class ACE_Adaptive_Lock
+ *
+ * @brief An adaptive general locking class that defers the decision of
+ * lock type to run time.
+ *
+ * This class, as ACE_Lock, provide a set of general locking APIs.
+ * However, it defers our decision of what kind of lock to use
+ * to the run time and delegates all locking operations to the actual
+ * lock. Users must define a constructor in their subclass to
+ * initialize <lock_>.
+ */
+class ACE_Export ACE_Adaptive_Lock : public ACE_Lock
+{
+public:
+ /// You must also override the destructor function to match with how
+ /// you construct the underneath <lock_>.
+ virtual ~ACE_Adaptive_Lock (void);
+
+ // = Lock/unlock operations.
+
+ virtual int remove (void);
+ virtual int acquire (void);
+ virtual int tryacquire (void);
+ virtual int release (void);
+ virtual int acquire_read (void);
+ virtual int acquire_write (void);
+ virtual int tryacquire_read (void);
+ virtual int tryacquire_write (void);
+ virtual int tryacquire_write_upgrade (void);
+ void dump (void) const;
+
+protected:
+ /**
+ * Create and initialize create the actual lcok used in the class.
+ * The default constructor simply set the <lock_> to 0 (null). You
+ * must overwrite this method for this class to work.
+ */
+ ACE_Adaptive_Lock (void);
+
+ ACE_Lock *lock_;
+};
+
+/**
+ * @class ACE_Semaphore
+ *
+ * @brief Wrapper for Dijkstra style general semaphores.
+ */
+class ACE_Export ACE_Semaphore
+{
+public:
+ // = Initialization and termination.
+ /// Initialize the semaphore, with initial value of "count".
+ ACE_Semaphore (u_int count = 1, // By default make this unlocked.
+ int type = USYNC_THREAD,
+ const ACE_TCHAR *name = 0,
+ void * = 0,
+ int max = 0x7fffffff);
+
+ /// Implicitly destroy the semaphore.
+ ~ACE_Semaphore (void);
+
+ /**
+ * Explicitly destroy the semaphore. Note that only one thread
+ * should call this method since it doesn't protect against race
+ * conditions.
+ */
+ int remove (void);
+
+ /// Block the thread until the semaphore count becomes
+ /// greater than 0, then decrement it.
+ int acquire (void);
+
+ /**
+ * Block the thread until the semaphore count becomes greater than 0
+ * (at which point it is decremented) or until <tv> times out (in
+ * which case -1 is returned and <errno> == <ETIME>). Note that <tv>
+ * is assumed to be in "absolute" rather than "relative" time. The
+ * value of <tv> is updated upon return to show the actual
+ * (absolute) acquisition time.
+ *
+ * NOTE: Solaris threads do not support timed semaphores.
+ * Therefore, if you're running on Solaris you might want to
+ * consider using the ACE POSIX pthreads implementation instead,
+ * which can be enabled by compiling ACE with
+ * -DACE_HAS_PTHREADS, rather than -DACE_HAS_STHREADS or
+ * -DACE_HAS_POSIX_SEM. */
+ int acquire (ACE_Time_Value &tv);
+
+ /**
+ * If <tv> == 0 then call <acquire()> directly. Otherwise, Block
+ * the thread until the semaphore count becomes greater than 0
+ * (at which point it is decremented) or until <tv> times out (in
+ * which case -1 is returned and <errno> == <ETIME>). Note that
+ * <*tv> is assumed to be in "absolute" rather than "relative" time.
+ * The value of <*tv> is updated upon return to show the actual
+ * (absolute) acquisition time.
+ *
+ * NOTE: Solaris threads do not support timed semaphores.
+ * Therefore, if you're running on Solaris you might want to
+ * consider using the ACE POSIX pthreads implementation instead,
+ * which can be enabled by compiling ACE with
+ * -DACE_HAS_PTHREADS, rather than -DACE_HAS_STHREADS or
+ * -DACE_HAS_POSIX_SEM. */
+ int acquire (ACE_Time_Value *tv);
+
+ /**
+ * Conditionally decrement the semaphore if count is greater than 0
+ * (i.e., won't block). Returns -1 on failure. If we "failed"
+ * because someone else already had the lock, <errno> is set to
+ * <EBUSY>.
+ */
+ int tryacquire (void);
+
+ /// Increment the semaphore by 1, potentially unblocking a waiting
+ /// thread.
+ int release (void);
+
+ /// Increment the semaphore by <release_count>, potentially
+ /// unblocking waiting threads.
+ int release (size_t release_count);
+
+ /**
+ * Acquire semaphore ownership. This calls <acquire> and is only
+ * here to make the <ACE_Semaphore> interface consistent with the
+ * other synchronization APIs.
+ */
+ int acquire_read (void);
+
+ /**
+ * Acquire semaphore ownership. This calls <acquire> and is only
+ * here to make the <ACE_Semaphore> interface consistent with the
+ * other synchronization APIs.
+ */
+ int acquire_write (void);
+
+ /**
+ * Conditionally acquire semaphore (i.e., won't block). This calls
+ * <tryacquire> and is only here to make the <ACE_Semaphore>
+ * interface consistent with the other synchronization APIs.
+ * Returns -1 on failure. If we "failed" because someone else
+ * already had the lock, <errno> is set to <EBUSY>.
+ */
+ int tryacquire_read (void);
+
+ /**
+ * Conditionally acquire semaphore (i.e., won't block). This calls
+ * <tryacquire> and is only here to make the <ACE_Semaphore>
+ * interface consistent with the other synchronization APIs.
+ * Returns -1 on failure. If we "failed" because someone else
+ * already had the lock, <errno> is set to <EBUSY>.
+ */
+ int tryacquire_write (void);
+
+ /**
+ * This is only here to make the <ACE_Semaphore>
+ * interface consistent with the other synchronization APIs.
+ * Assumes the caller has already acquired the semaphore using one of
+ * the above calls, and returns 0 (success) always.
+ */
+ int tryacquire_write_upgrade (void);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+ /// Return the underlying lock.
+ const ACE_sema_t &lock (void) const;
+
+protected:
+ ACE_sema_t semaphore_;
+
+ /// Keeps track of whether <remove> has been called yet to avoid
+ /// multiple <remove> calls, e.g., explicitly and implicitly in the
+ /// destructor. This flag isn't protected by a lock, so make sure
+ /// that you don't have multiple threads simultaneously calling
+ /// <remove> on the same object, which is a bad idea anyway...
+ int removed_;
+
+private:
+ // = Prevent assignment and initialization.
+ void operator= (const ACE_Semaphore &);
+ ACE_Semaphore (const ACE_Semaphore &);
+};
+
+/**
+ * @class ACE_Null_Semaphore
+ *
+ * @brief Implement a do nothing <ACE_Semaphore>, i.e., all the methods are
+ * no ops.
+ *
+ * Although the methods are no-ops, the return values are different for
+ * the blocking as opposed to timed acquires. The blocking version of
+ * acquire() is often used to serialize access to a critical section,
+ * whereas the timed version is often used to wait for another thread
+ * to update some condition or change some shared state. When using an
+ * ACE_Null_Semaphore, however, there's no other thread involved to
+ * change a state or condition (otherwise, a null semaphore would be
+ * inappropriate). Returning an error value signifies that the
+ * state or condition has not been (and can't be) changed, which is
+ * consistent with the behavior of the threaded case where a timeout
+ * occurs before the state or condition is changed.
+ */
+class ACE_Export ACE_Null_Semaphore
+{
+public:
+ ACE_Null_Semaphore (u_int count = 1, // By default make this unlocked.
+ int type = USYNC_THREAD,
+ const ACE_TCHAR *name = 0,
+ void * = 0,
+ int max = 0x7fffffff);
+ ~ACE_Null_Semaphore (void);
+ /// Return 0.
+ int remove (void);
+
+ /// Return 0.
+ int acquire (void);
+
+ /// Return -1 with <errno> == <ETIME>.
+ int acquire (ACE_Time_Value &);
+
+ /// Return -1 with <errno> == <ETIME>.
+ int acquire (ACE_Time_Value *);
+
+ /// Return 0.
+ int tryacquire (void);
+
+ /// Return 0.
+ int release (void);
+
+ /// Return 0.
+ int release (size_t);
+
+ /// Return 0.
+ int acquire_write (void);
+
+ /// Return 0.
+ int tryacquire_write (void);
+
+ /// Return 0.
+ int tryacquire_write_upgrade (void);
+
+ /// Return 0.
+ int acquire_read (void);
+
+ /// Return 0.
+ int tryacquire_read (void);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+};
+
+/**
+ * @class ACE_RW_Mutex
+ *
+ * @brief Wrapper for readers/writer locks.
+ *
+ * These are most useful for applications that have many more
+ * parallel readers than writers...
+ */
+class ACE_Export ACE_RW_Mutex
+{
+public:
+ /// Initialize a readers/writer lock.
+ ACE_RW_Mutex (int type = USYNC_THREAD,
+ const ACE_TCHAR *name = 0,
+ void *arg = 0);
+
+ /// Implicitly destroy a readers/writer lock
+ ~ACE_RW_Mutex (void);
+
+ /**
+ * Explicitly destroy a readers/writer lock. Note that only one
+ * thread should call this method since it doesn't protect against
+ * race conditions.
+ */
+ int remove (void);
+
+ /// Acquire a read lock, but block if a writer hold the lock.
+ int acquire_read (void);
+
+ /// Acquire a write lock, but block if any readers or a
+ /// writer hold the lock.
+ int acquire_write (void);
+
+ /**
+ * Conditionally acquire a read lock (i.e., won't block). Returns
+ * -1 on failure. If we "failed" because someone else already had
+ * the lock, <errno> is set to <EBUSY>.
+ */
+ int tryacquire_read (void);
+
+ /// Conditionally acquire a write lock (i.e., won't block).
+ int tryacquire_write (void);
+
+ /**
+ * Conditionally upgrade a read lock to a write lock. This only
+ * works if there are no other readers present, in which case the
+ * method returns 0. Otherwise, the method returns -1 and sets
+ * <errno> to <EBUSY>. Note that the caller of this method *must*
+ * already possess this lock as a read lock (but this condition is
+ * not checked by the current implementation).
+ */
+ int tryacquire_write_upgrade (void);
+
+ /**
+ * Note, for interface uniformity with other synchronization
+ * wrappers we include the <acquire> method. This is implemented as
+ * a write-lock to safe...
+ */
+ int acquire (void);
+
+ /**
+ * Note, for interface uniformity with other synchronization
+ * wrappers we include the <tryacquire> method. This is implemented
+ * as a write-lock to be safe... Returns -1 on failure. If we
+ * "failed" because someone else already had the lock, <errno> is
+ * set to <EBUSY>.
+ */
+ int tryacquire (void);
+
+ /// Unlock a readers/writer lock.
+ int release (void);
+
+ /// Return the underlying lock.
+ const ACE_rwlock_t &lock (void) const;
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+protected:
+ /// Readers/writer lock.
+ ACE_rwlock_t lock_;
+
+ /// Keeps track of whether <remove> has been called yet to avoid
+ /// multiple <remove> calls, e.g., explicitly and implicitly in the
+ /// destructor. This flag isn't protected by a lock, so make sure
+ /// that you don't have multiple threads simultaneously calling
+ /// <remove> on the same object, which is a bad idea anyway...
+ int removed_;
+
+private:
+ // = Prevent assignment and initialization.
+ void operator= (const ACE_RW_Mutex &);
+ ACE_RW_Mutex (const ACE_RW_Mutex &);
+};
+
+/**
+ * @class ACE_Mutex
+ *
+ * @brief <ACE_Mutex> wrapper (valid in same process or across
+ * processes (depending on TYPE flag)).
+ */
+class ACE_Export ACE_Mutex
+{
+public:
+ /// Initialize the mutex.
+ ACE_Mutex (int type = USYNC_THREAD,
+ const ACE_TCHAR *name = 0,
+ ACE_mutexattr_t *arg = 0);
+
+ /// Implicitly destroy the mutex.
+ ~ACE_Mutex (void);
+
+ /**
+ * Explicitly destroy the mutex. Note that only one thread should
+ * call this method since it doesn't protect against race
+ * conditions.
+ */
+ int remove (void);
+
+ /// Acquire lock ownership (wait on queue if necessary).
+ int acquire (void);
+
+ /**
+ * Block the thread until the mutex is acquired or <tv> times out,
+ * in which case -1 is returned and <errno> == <ETIME>. Note that
+ * <tv> is assumed to be in "absolute" rather than "relative" time.
+ * The value of <tv> is updated upon return to show the actual
+ * (absolute) acquisition time.
+ */
+ int acquire (ACE_Time_Value &tv);
+
+ /**
+ * If <tv> == 0 then call <acquire()> directly. Otherwise, block
+ * the thread until the mutex is acquired or <tv> times out, in
+ * which case -1 is returned and <errno> == <ETIME>. Note that
+ * <*tv> is assumed to be in "absolute" rather than "relative" time.
+ * The value of <*tv> is updated upon return to show the actual
+ * (absolute) acquisition time. */
+ int acquire (ACE_Time_Value *tv);
+
+ /**
+ * Conditionally acquire lock (i.e., don't wait on queue). Returns
+ * -1 on failure. If we "failed" because someone else already had
+ * the lock, <errno> is set to <EBUSY>.
+ */
+ int tryacquire (void);
+
+ /// Release lock and unblock a thread at head of queue.
+ int release (void);
+
+ /**
+ * Acquire mutex ownership. This calls <acquire> and is only
+ * here to make the <ACE_Mutex> interface consistent with the
+ * other synchronization APIs.
+ */
+ int acquire_read (void);
+
+ /**
+ * Acquire mutex ownership. This calls <acquire> and is only
+ * here to make the <ACE_Mutex> interface consistent with the
+ * other synchronization APIs.
+ */
+ int acquire_write (void);
+
+ /**
+ * Conditionally acquire mutex (i.e., won't block). This calls
+ * <tryacquire> and is only here to make the <ACE_Mutex> interface
+ * consistent with the other synchronization APIs. Returns -1 on
+ * failure. If we "failed" because someone else already had the
+ * lock, <errno> is set to <EBUSY>.
+ */
+ int tryacquire_read (void);
+
+ /**
+ * Conditionally acquire mutex (i.e., won't block). This calls
+ * <tryacquire> and is only here to make the <ACE_Mutex> interface
+ * consistent with the other synchronization APIs. Returns -1 on
+ * failure. If we "failed" because someone else already had the
+ * lock, <errno> is set to <EBUSY>.
+ */
+ int tryacquire_write (void);
+
+ /**
+ * This is only here for consistency with the other synchronization
+ * APIs and usability with Lock adapters. Assumes the caller already has
+ * acquired the mutex and returns 0 in all cases.
+ */
+ int tryacquire_write_upgrade (void);
+
+ /// Return the underlying mutex.
+ const ACE_mutex_t &lock (void) const;
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+ // = This should be protected but some C++ compilers complain...
+public:
+#if defined (CHORUS) || defined(ACE_HAS_PTHREADS) || defined(ACE_HAS_STHREADS)
+ /// This lock resides in shared memory.
+ ACE_mutex_t *process_lock_;
+
+ /**
+ * Remember the name of the mutex if we created it so we can unlink
+ * it when we go away (only the actor that initialized the memory
+ * can destroy it).
+ */
+ const ACE_TCHAR *lockname_;
+#endif /* CHORUS || ACE_HAS_PTHREADS */
+
+ /// Mutex type supported by the OS.
+ ACE_mutex_t lock_;
+
+ /// Keeps track of whether <remove> has been called yet to avoid
+ /// multiple <remove> calls, e.g., explicitly and implicitly in the
+ /// destructor. This flag isn't protected by a lock, so make sure
+ /// that you don't have multiple threads simultaneously calling
+ /// <remove> on the same object, which is a bad idea anyway...
+ int removed_;
+
+private:
+ // = Prevent assignment and initialization.
+ void operator= (const ACE_Mutex &);
+ ACE_Mutex (const ACE_Mutex &);
+};
+
+/**
+ * @class ACE_Null_Barrier
+ *
+ * @brief Implements "NULL barrier synchronization".
+ */
+class ACE_Export ACE_Null_Barrier
+{
+public:
+ /// Initialize the barrier to synchronize <count> threads.
+ ACE_Null_Barrier (u_int,
+ const char * = 0,
+ void * = 0);
+
+ /// Default dtor.
+ ~ACE_Null_Barrier (void);
+
+ /// Block the caller until all <count> threads have called <wait> and
+ /// then allow all the caller threads to continue in parallel.
+ int wait (void);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+private:
+ // = Prevent assignment and initialization.
+ void operator= (const ACE_Null_Barrier &);
+ ACE_Null_Barrier (const ACE_Null_Barrier &);
+};
+
+/**
+ * @class ACE_Null_Mutex
+ *
+ * @brief Implement a do nothing <ACE_Mutex>, i.e., all the methods are
+ * no ops.
+ */
+class ACE_Export ACE_Null_Mutex
+{
+public:
+ ACE_Null_Mutex (const ACE_TCHAR * = 0);
+ ~ACE_Null_Mutex (void);
+ /// Return 0.
+ int remove (void);
+
+ /// Return 0.
+ int acquire (void);
+
+ /// Return -1 with <errno> == <ETIME>.
+ int acquire (ACE_Time_Value &timeout);
+
+ /// Return -1 with <errno> == <ETIME>.
+ int acquire (ACE_Time_Value *timeout);
+
+ /// Return 0.
+ int tryacquire (void);
+
+ /// Return 0.
+ int release (void);
+
+ /// Return 0.
+ int acquire_write (void);
+
+ /// Return 0.
+ int tryacquire_write (void);
+
+ /// Return 0.
+ int tryacquire_write_upgrade (void);
+
+ /// Return 0.
+ int acquire_read (void);
+
+ /// Return 0.
+ int tryacquire_read (void);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+};
+
+class ACE_Export ACE_Noop_Token : public ACE_Null_Mutex
+{
+public:
+ int renew (int = 0, ACE_Time_Value * =0);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+};
+
+/**
+ * @class ACE_Null_Condition
+ *
+ * @brief Implement a do nothing <ACE_Condition> variable wrapper,
+ * i.e., all methods are no ops. This class is necessary since
+ * some C++ compilers are *very* lame...
+ */
+class ACE_Export ACE_Null_Condition
+{
+public:
+ ACE_Null_Condition (const ACE_Null_Mutex &m,
+ const ACE_TCHAR * = 0,
+ void * = 0);
+ ~ACE_Null_Condition (void);
+
+ /// Returns 0.
+ int remove (void);
+
+ /// Returns -1 with <errno> == <ETIME>.
+ int wait (ACE_Time_Value * = 0);
+
+ /// Returns 0.
+ int signal (void);
+
+ /// Returns 0.
+ int broadcast (void);
+ ACE_Null_Mutex &mutex (void);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ // ACE_ALLOC_HOOK_DECLARE;
+ // Declare the dynamic allocation hooks.
+
+protected:
+ ACE_Null_Mutex &mutex_; // Reference to mutex lock.
+
+private:
+ // = Prevent assignment and initialization.
+ void operator= (const ACE_Null_Condition &);
+ ACE_Null_Condition (const ACE_Null_Condition &);
+};
+
+#if defined (ACE_USES_OBSOLETE_GUARD_CLASSES)
+/**
+ * @class ACE_Null_Mutex_Guard
+ *
+ * @brief This data structure is meant to be used within a method or
+ * function... It performs automatic aquisition and release of
+ * an ACE_Null_Mutex.
+ *
+ * This class is obsolete and should be replaced by
+ * ACE_Guard<ACE_Null_Mutex>.
+ */
+class ACE_Export ACE_Null_Mutex_Guard
+{
+public:
+ ACE_Null_Mutex_Guard (ACE_Null_Mutex &);
+ ~ACE_Null_Mutex_Guard (void);
+ int remove (void);
+ int locked (void);
+ int acquire (void);
+ int tryacquire (void);
+ int release (void);
+ void dump (void) const;
+
+private:
+ // = Prevent assignment and initialization.
+ void operator= (const ACE_Null_Mutex_Guard &);
+ ACE_Null_Mutex_Guard (const ACE_Null_Mutex_Guard &);
+};
+#endif /* ACE_USES_OBSOLETE_GUARD_CLASSES */
+
+/**
+ * @class ACE_TSS_Adapter
+ *
+ * @brief This class encapsulates a TSS object and its associated
+ * C++ destructor function. It is used by the ACE_TSS...
+ * methods (in Synch_T.cpp) in order to allow an extern
+ * "C" cleanup routine to be used. Needed by the "frigging"
+ * MVS C++ compiler.
+ *
+ * Objects of this class are stored in thread specific
+ * storage. ts_obj_ points to the "real" object and
+ * func_ is a pointer to the C++ cleanup function for ts_obj_.
+ */
+class ACE_Export ACE_TSS_Adapter
+{
+public:
+ /// Initialize the adapter.
+ ACE_TSS_Adapter (void *object, ACE_THR_DEST f);
+
+ /// Default dtor.
+ ~ACE_TSS_Adapter (void);
+
+ /// Perform the cleanup operation.
+ void cleanup (void);
+
+//private:
+
+ /// The real TS object.
+ void *ts_obj_;
+
+ /// The real cleanup routine for ts_obj;
+ ACE_THR_DEST func_;
+};
+
+/**
+ * @class ACE_Event
+ *
+ * @brief A wrapper around the Win32 event locking mechanism.
+ *
+ * Portable implementation of an Event mechanism, which is
+ * native to Win32, but must be emulated on UNIX. Note that
+ * this only provides global naming and system-scope locking support
+ * on Win32 platforms.
+ */
+class ACE_Export ACE_Event
+{
+public:
+ /// Constructor that creates event.
+ ACE_Event (int manual_reset = 0,
+ int initial_state = 0,
+ int type = USYNC_THREAD,
+ const ACE_TCHAR *name = 0,
+ void *arg = 0);
+
+ /// Implicitly destroy the event variable.
+ ~ACE_Event (void);
+
+ /**
+ * Explicitly destroy the event variable. Note that only one thread
+ * should call this method since it doesn't protect against race
+ * conditions.
+ */
+ int remove (void);
+
+ /// Underlying handle to event.
+ ACE_event_t handle (void) const;
+
+ /**
+ * Set the underlying handle to event. Note that this method assumes
+ * ownership of the <handle> and will close it down in <remove>. If
+ * you want the <handle> to stay open when <remove> is called make
+ * sure to call <dup> on the <handle> before closing it. You are
+ * responsible for the closing the existing <handle> before
+ * overwriting it.
+ */
+ void handle (ACE_event_t new_handle);
+
+ /**
+ * if MANUAL reset
+ * sleep till the event becomes signaled
+ * event remains signaled after wait() completes.
+ * else AUTO reset
+ * sleep till the event becomes signaled
+ * event resets wait() completes.
+ */
+ int wait (void);
+
+ /// Same as wait() above, but this one can be timed
+ /// <abstime> is absolute time-of-day if if <use_absolute_time>
+ /// is non-0, else it is relative time.
+ int wait (const ACE_Time_Value *abstime,
+ int use_absolute_time = 1);
+
+ /**
+ * if MANUAL reset
+ * wake up all waiting threads
+ * set to signaled state
+ * else AUTO reset
+ * if no thread is waiting, set to signaled state
+ * if thread(s) are waiting, wake up one waiting thread and
+ * reset event
+ */
+ int signal (void);
+
+ /**
+ * if MANUAL reset
+ * wakeup all waiting threads and
+ * reset event
+ * else AUTO reset
+ * wakeup one waiting thread (if present) and
+ * reset event
+ */
+ int pulse (void);
+
+ /// Set to nonsignaled state.
+ int reset (void);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks
+ ACE_ALLOC_HOOK_DECLARE;
+
+protected:
+ /// The underlying handle.
+ ACE_event_t handle_;
+
+ /// Keeps track of whether <remove> has been called yet to avoid
+ /// multiple <remove> calls, e.g., explicitly and implicitly in the
+ /// destructor. This flag isn't protected by a lock, so make sure
+ /// that you don't have multiple threads simultaneously calling
+ /// <remove> on the same object, which is a bad idea anyway...
+ int removed_;
+
+private:
+ // = Prevent copying.
+ ACE_Event (const ACE_Event& event);
+ const ACE_Event &operator= (const ACE_Event &rhs);
+};
+
+/**
+ * @class ACE_Manual_Event
+ *
+ * @brief Manual Events.
+ *
+ * Specialization of Event mechanism which wakes up all waiting
+ * threads on <signal>. Note that this only provides
+ * global naming and system-scope locking support on Win32 platforms.
+ */
+class ACE_Export ACE_Manual_Event : public ACE_Event
+{
+public:
+ /// constructor which will create manual event
+ ACE_Manual_Event (int initial_state = 0,
+ int type = USYNC_THREAD,
+ const char *name = 0,
+ void *arg = 0);
+
+#if defined (ACE_HAS_WCHAR)
+ /// constructor which will create manual event (wchar_t version)
+ ACE_Manual_Event (int initial_state,
+ int type,
+ const wchar_t *name,
+ void *arg = 0);
+#endif /* ACE_HAS_WCHAR */
+
+ /// Default dtor.
+ ~ACE_Manual_Event (void);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks
+ ACE_ALLOC_HOOK_DECLARE;
+};
+
+/**
+ * @class ACE_Auto_Event
+ *
+ * @brief Auto Events.
+ *
+ * Specialization of Event mechanism which wakes up one waiting
+ * thread on <signal>. Note that this only provides
+ * global naming and system-scope locking support on Win32 platforms.
+ */
+class ACE_Export ACE_Auto_Event : public ACE_Event
+{
+public:
+ /// constructor which will create auto event
+ ACE_Auto_Event (int initial_state = 0,
+ int type = USYNC_THREAD,
+ const char *name = 0,
+ void *arg = 0);
+
+#if defined (ACE_HAS_WCHAR)
+ /// constructor which will create auto event (wchar_t version)
+ ACE_Auto_Event (int initial_state,
+ int type,
+ const wchar_t *name,
+ void *arg = 0);
+#endif /* ACE_HAS_WCHAR */
+
+ /// Default dtor.
+ ~ACE_Auto_Event (void);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks
+ ACE_ALLOC_HOOK_DECLARE;
+};
+
+// ACE platform supports some form of threading.
+#if !defined (ACE_HAS_THREADS)
+/**
+ * @class ACE_Barrier
+ *
+ * @brief This is a no-op to make ACE "syntactically consistent."
+ */
+class ACE_Barrier
+{
+public:
+ ACE_Barrier (u_int, const ACE_TCHAR * = 0, void * = 0) {}
+ ~ACE_Barrier (void) {}
+ int wait (void) { ACE_NOTSUP_RETURN (-1); }
+ void dump (void) const {}
+};
+#else
+ /**
+ * @class ACE_Thread_Mutex
+ *
+ * @brief ACE_Thread_Mutex wrapper (only valid for threads in the same
+ * process).
+ *
+ * This implementation is optimized for locking threads that are
+ * in the same process. It maps to <CRITICAL_SECTION>s on NT
+ * and <ACE_mutex_t> with <type> set to <USYNC_THREAD> on UNIX.
+ * ACE_Thread_Mutex is recursive on some platforms (like
+ * Win32). However, on most platforms (like Solaris) it is not
+ * recursive. To be totally safe and portable, developers
+ * should use <ACE_Recursive_Thread_Mutex> when they need a
+ * recursive mutex.
+ */
+class ACE_Export ACE_Thread_Mutex
+{
+ friend class ACE_Condition_Thread_Mutex;
+public:
+ /// Constructor.
+ ACE_Thread_Mutex (const ACE_TCHAR *name = 0,
+ ACE_mutexattr_t *attributes = 0);
+
+ /// Implicitly destroy the mutex.
+ ~ACE_Thread_Mutex (void);
+
+ /**
+ * Explicitly destroy the mutex. Note that only one thread should
+ * call this method since it doesn't protect against race
+ * conditions.
+ */
+ int remove (void);
+
+ /// Acquire lock ownership (wait on queue if necessary).
+ int acquire (void);
+
+ /**
+ * Block the thread until we acquire the mutex or until <tv> times
+ * out, in which case -1 is returned with <errno> == <ETIME>. Note
+ * that <tv> is assumed to be in "absolute" rather than "relative"
+ * time. The value of <tv> is updated upon return to show the
+ * actual (absolute) acquisition time.
+ */
+ int acquire (ACE_Time_Value &tv);
+
+ /**
+ * If <tv> == 0 the call <acquire()> directly. Otherwise, Block the
+ * thread until we acquire the mutex or until <tv> times out, in
+ * which case -1 is returned with <errno> == <ETIME>. Note that
+ * <*tv> is assumed to be in "absolute" rather than "relative" time.
+ * The value of <*tv> is updated upon return to show the actual
+ * (absolute) acquisition time.
+ */
+ int acquire (ACE_Time_Value *tv);
+
+ /**
+ * Conditionally acquire lock (i.e., don't wait on queue). Returns
+ * -1 on failure. If we "failed" because someone else already had
+ * the lock, <errno> is set to <EBUSY>.
+ */
+ int tryacquire (void);
+
+ /// Release lock and unblock a thread at head of queue.
+ int release (void);
+
+ /**
+ * Acquire mutex ownership. This calls <acquire> and is only here
+ * to make the <ACE_Thread_Mutex> interface consistent with the
+ * other synchronization APIs.
+ */
+ int acquire_read (void);
+
+ /**
+ * Acquire mutex ownership. This calls <acquire> and is only here
+ * to make the <ACE_Thread_Mutex> interface consistent with the
+ * other synchronization APIs.
+ */
+ int acquire_write (void);
+
+ /**
+ * Conditionally acquire mutex (i.e., won't block). This calls
+ * <tryacquire> and is only here to make the <ACE_Thread_Mutex>
+ * interface consistent with the other synchronization APIs.
+ * Returns -1 on failure. If we "failed" because someone else
+ * already had the lock, <errno> is set to <EBUSY>.
+ */
+ int tryacquire_read (void);
+
+ /**
+ * Conditionally acquire mutex (i.e., won't block). This calls
+ * <tryacquire> and is only here to make the <ACE_Thread_Mutex>
+ * interface consistent with the other synchronization APIs.
+ * Returns -1 on failure. If we "failed" because someone else
+ * already had the lock, <errno> is set to <EBUSY>.
+ */
+ int tryacquire_write (void);
+
+ /**
+ * This is only here to make the <ACE_Thread_Mutex>
+ * interface consistent with the other synchronization APIs.
+ * Assumes the caller has already acquired the mutex using one of
+ * the above calls, and returns 0 (success) always.
+ */
+ int tryacquire_write_upgrade (void);
+
+ /// Return the underlying mutex.
+ const ACE_thread_mutex_t &lock (void) const;
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+ // protected:
+ /// Mutex type that supports single-process locking efficiently.
+ ACE_thread_mutex_t lock_;
+
+ /// Keeps track of whether <remove> has been called yet to avoid
+ /// multiple <remove> calls, e.g., explicitly and implicitly in the
+ /// destructor. This flag isn't protected by a lock, so make sure
+ /// that you don't have multiple threads simultaneously calling
+ /// <remove> on the same object, which is a bad idea anyway...
+ int removed_;
+
+private:
+ // = Prevent assignment and initialization.
+ void operator= (const ACE_Thread_Mutex &);
+ ACE_Thread_Mutex (const ACE_Thread_Mutex &);
+};
+
+#if defined (ACE_USES_OBSOLETE_GUARD_CLASSES)
+/**
+ * @class ACE_Thread_Mutex_Guard
+ *
+ * @brief This data structure is meant to be used within a method or
+ * function... It performs automatic aquisition and release of
+ * an <ACE_Thread_Mutex>.
+ *
+ * This class is obsolete and should be replaced by
+ * ACE_Guard<ACE_Thread_Mutex>.
+ */
+class ACE_Export ACE_Thread_Mutex_Guard
+{
+public:
+ /// Implicitly and automatically acquire the lock.
+ ACE_Thread_Mutex_Guard (ACE_Thread_Mutex &m, int block = 1);
+
+ /// Implicitly release the lock.
+ ~ACE_Thread_Mutex_Guard (void);
+
+ /// 1 if locked, 0 if couldn't acquire the lock (errno will contain
+ /// the reason for this).
+ int locked (void);
+
+ /**
+ * Explicitly release the lock. Note that only one thread should
+ * call this method since it doesn't protect against race
+ * conditions.
+ */
+ int remove (void);
+
+ /// Explicitly acquire the lock.
+ int acquire (void);
+
+ /**
+ * Conditionally acquire the lock (i.e., won't block). Returns -1
+ * on failure. If we "failed" because someone else already had the
+ * lock, <errno> is set to <EBUSY>.
+ */
+ int tryacquire (void);
+
+ /// Explicitly release the lock.
+ int release (void);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+protected:
+ /// Reference to the mutex.
+ ACE_Thread_Mutex &lock_;
+
+ /// Keeps track of whether we acquired the lock or failed.
+ int owner_;
+
+private:
+ // = Prevent assignment and initialization.
+ void operator= (const ACE_Thread_Mutex_Guard &);
+ ACE_Thread_Mutex_Guard (const ACE_Thread_Mutex_Guard &);
+};
+#endif /* ACE_USES_OBSOLETE_GUARD_CLASSES */
+
+class ACE_Export ACE_Condition_Attributes
+{
+public:
+ /// Constructor
+ ACE_Condition_Attributes (int type = ACE_DEFAULT_SYNCH_TYPE);
+
+ /// Destructor
+ ~ACE_Condition_Attributes (void);
+
+private:
+ friend class ACE_Condition_Thread_Mutex;
+
+ /// The attributes
+ ACE_condattr_t attributes_;
+
+private:
+ // = Prevent assignment and initialization.
+ void operator= (const ACE_Condition_Attributes &);
+ ACE_Condition_Attributes (const ACE_Condition_Attributes &);
+};
+
+/**
+ * @class ACE_Condition_Thread_Mutex
+ *
+ * @brief ACE_Condition variable wrapper written using ACE_Mutexes This
+ * allows threads to block until shared data changes state.
+ * A condition variable enables threads to atomically block and
+ * test the condition under the protection of a mutual exclu-
+ * sion lock (mutex) until the condition is satisfied. That is,
+ * the mutex must have been held by the thread before calling
+ * wait or signal on the condition. If the condition is false,
+ * a thread blocks on a condition variable and atomically
+ * releases the mutex that is waiting for the condition to
+ * change. If another thread changes the condition, it may wake
+ * up waiting threads by signaling the associated condition
+ * variable. The waiting threads, upon awakening, reacquire the
+ * mutex and re-evaluate the condition.
+ *
+ * This should be an instantiation of ACE_Condition but problems
+ * with compilers precludes this...
+ */
+class ACE_Export ACE_Condition_Thread_Mutex
+{
+public:
+ /// Initialize the condition variable.
+ ACE_Condition_Thread_Mutex (const ACE_Thread_Mutex &m,
+ const ACE_TCHAR *name = 0,
+ void *arg = 0);
+
+ /// Initialize the condition variable.
+ ACE_Condition_Thread_Mutex (const ACE_Thread_Mutex &m,
+ ACE_Condition_Attributes &attributes,
+ const ACE_TCHAR *name = 0,
+ void *arg = 0);
+
+ /// Implicitly destroy the condition variable.
+ ~ACE_Condition_Thread_Mutex (void);
+
+ /**
+ * Explicitly destroy the condition variable. Note that only one
+ * thread should call this method since it doesn't protect against
+ * race conditions.
+ */
+ int remove (void);
+
+ /**
+ * Block on condition, or until absolute time-of-day has passed. If
+ * abstime == 0 use "blocking" <wait> semantics. Else, if <abstime>
+ * != 0 and the call times out before the condition is signaled
+ * <wait> returns -1 and sets errno to ETIME.
+ */
+ int wait (const ACE_Time_Value *abstime);
+
+ /// Block on condition.
+ int wait (void);
+
+ /**
+ * Block on condition or until absolute time-of-day has passed. If
+ * abstime == 0 use "blocking" wait() semantics on the <mutex>
+ * passed as a parameter (this is useful if you need to store the
+ * <Condition> in shared memory). Else, if <abstime> != 0 and the
+ * call times out before the condition is signaled <wait> returns -1
+ * and sets errno to ETIME.
+ */
+ int wait (ACE_Thread_Mutex &mutex, const ACE_Time_Value *abstime = 0);
+
+ /// Signal one waiting thread.
+ int signal (void);
+
+ /// Signal *all* waiting threads.
+ int broadcast (void);
+
+ /// Returns a reference to the underlying mutex_;
+ ACE_Thread_Mutex &mutex (void);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+protected:
+ /// Condition variable.
+ ACE_cond_t cond_;
+
+ /// Reference to mutex lock.
+ ACE_Thread_Mutex &mutex_;
+
+ /// Keeps track of whether <remove> has been called yet to avoid
+ /// multiple <remove> calls, e.g., explicitly and implicitly in the
+ /// destructor. This flag isn't protected by a lock, so make sure
+ /// that you don't have multiple threads simultaneously calling
+ /// <remove> on the same object, which is a bad idea anyway...
+ int removed_;
+
+private:
+ // = Prevent assignment and initialization.
+ void operator= (const ACE_Condition_Thread_Mutex &);
+ ACE_Condition_Thread_Mutex (const ACE_Condition_Thread_Mutex &);
+};
+
+/**
+ * @class ACE_Recursive_Thread_Mutex
+ *
+ * @brief Implement a C++ wrapper that allows nested acquisition and
+ * release of a mutex that occurs in the same thread.
+ */
+class ACE_Export ACE_Recursive_Thread_Mutex
+{
+public:
+ /// Initialize a recursive mutex.
+ ACE_Recursive_Thread_Mutex (const ACE_TCHAR *name = 0,
+ ACE_mutexattr_t *arg = 0);
+
+ /// Implicitly release a recursive mutex.
+ ~ACE_Recursive_Thread_Mutex (void);
+
+ /**
+ * Implicitly release a recursive mutex. Note that only one thread
+ * should call this method since it doesn't protect against race
+ * conditions.
+ */
+ int remove (void);
+
+ /**
+ * Acquire a recursive mutex (will increment the nesting level and
+ * not deadmutex if the owner of the mutex calls this method more
+ * than once).
+ */
+ int acquire (void);
+
+ /**
+ * Conditionally acquire a recursive mutex (i.e., won't block).
+ * Returns -1 on failure. If we "failed" because someone else
+ * already had the lock, <errno> is set to <EBUSY>.
+ */
+ int tryacquire (void);
+
+ /**
+ * Acquire mutex ownership. This calls <acquire> and is only
+ * here to make the <ACE_Recusive_Thread_Mutex> interface consistent
+ * with the other synchronization APIs.
+ */
+ int acquire_read (void);
+
+ /**
+ * Acquire mutex ownership. This calls <acquire> and is only
+ * here to make the <ACE_Recusive_Thread_Mutex> interface consistent
+ * with the other synchronization APIs.
+ */
+ int acquire_write (void);
+
+ /**
+ * Conditionally acquire mutex (i.e., won't block). This calls
+ * <tryacquire> and is only here to make the
+ * <ACE_Recusive_Thread_Mutex> interface consistent with the other
+ * synchronization APIs. Returns -1 on failure. If we "failed"
+ * because someone else already had the lock, <errno> is set to
+ * <EBUSY>.
+ */
+ int tryacquire_read (void);
+
+ /**
+ * Conditionally acquire mutex (i.e., won't block). This calls
+ * <tryacquire> and is only here to make the
+ * <ACE_Recusive_Thread_Mutex> interface consistent with the other
+ * synchronization APIs. Returns -1 on failure. If we "failed"
+ * because someone else already had the lock, <errno> is set to
+ * <EBUSY>.
+ */
+ int tryacquire_write (void);
+
+ /**
+ * This is only here to make the <ACE_Recursive_Thread_Mutex>
+ * interface consistent with the other synchronization APIs.
+ * Assumes the caller has already acquired the mutex using one of
+ * the above calls, and returns 0 (success) always.
+ */
+ int tryacquire_write_upgrade (void);
+
+ /**
+ * Releases a recursive mutex (will not release mutex until all the
+ * nesting level drops to 0, which means the mutex is no longer
+ * held).
+ */
+ int release (void);
+
+ /// Return the id of the thread that currently owns the mutex.
+ ACE_thread_t get_thread_id (void);
+
+ /**
+ * Return the nesting level of the recursion. When a thread has
+ * acquired the mutex for the first time, the nesting level == 1.
+ * The nesting level is incremented every time the thread acquires
+ * the mutex recursively.
+ */
+ int get_nesting_level (void);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+protected:
+ // = This method should *not* be public (they hold no locks...)
+ void set_thread_id (ACE_thread_t t);
+
+ /// Recursive mutex.
+ ACE_recursive_thread_mutex_t recursive_mutex_;
+
+ /// Keeps track of whether <remove> has been called yet to avoid
+ /// multiple <remove> calls, e.g., explicitly and implicitly in the
+ /// destructor. This flag isn't protected by a lock, so make sure
+ /// that you don't have multiple threads simultaneously calling
+ /// <remove> on the same object, which is a bad idea anyway...
+ int removed_;
+
+private:
+ // = Prevent assignment and initialization.
+ void operator= (const ACE_Recursive_Thread_Mutex &);
+ ACE_Recursive_Thread_Mutex (const ACE_Recursive_Thread_Mutex &);
+};
+
+/**
+ * @class ACE_RW_Thread_Mutex
+ *
+ * @brief Wrapper for readers/writer locks that exist within a process.
+ */
+class ACE_Export ACE_RW_Thread_Mutex : public ACE_RW_Mutex
+{
+public:
+ ACE_RW_Thread_Mutex (const ACE_TCHAR *name = 0,
+ void *arg = 0);
+
+ /// Default dtor.
+ ~ACE_RW_Thread_Mutex (void);
+
+ /**
+ * Conditionally upgrade a read lock to a write lock. This only
+ * works if there are no other readers present, in which case the
+ * method returns 0. Otherwise, the method returns -1 and sets
+ * <errno> to <EBUSY>. Note that the caller of this method *must*
+ * already possess this lock as a read lock (but this condition is
+ * not checked by the current implementation).
+ */
+ int tryacquire_write_upgrade (void);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+};
+
+/**
+ * @class ACE_Thread_Semaphore
+ *
+ * @brief Wrapper for Dijkstra style general semaphores that work
+ * only within one process.
+ */
+class ACE_Export ACE_Thread_Semaphore : public ACE_Semaphore
+{
+public:
+ /// Initialize the semaphore, with an initial value of <count>,
+ /// maximum value of <max>, and unlocked by default.
+ ACE_Thread_Semaphore (u_int count = 1, // By default make this unlocked.
+ const ACE_TCHAR *name = 0,
+ void * = 0,
+ int max = 0x7FFFFFFF);
+
+ /// Default dtor.
+ ~ACE_Thread_Semaphore (void);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+};
+
+struct ACE_Export ACE_Sub_Barrier
+{
+ // = Initialization.
+ ACE_Sub_Barrier (u_int count,
+ ACE_Thread_Mutex &lock,
+ const ACE_TCHAR *name = 0,
+ void *arg = 0);
+
+ ~ACE_Sub_Barrier (void);
+
+ ACE_Condition_Thread_Mutex barrier_finished_;
+ // True if this generation of the barrier is done.
+
+ int running_threads_;
+ // Number of threads that are still running.
+
+ void dump (void) const;
+ // Dump the state of an object.
+
+ ACE_ALLOC_HOOK_DECLARE;
+ // Declare the dynamic allocation hooks.
+};
+
+/**
+ * @class ACE_Barrier
+ *
+ * @brief Implements "barrier synchronization".
+ *
+ * This class allows <count> number of threads to synchronize
+ * their completion of (one round of) a task, which is known as
+ * "barrier synchronization". The implementation uses a
+ * "sub-barrier generation numbering" scheme to avoid overhead
+ * and to ensure that all threads wait to leave the barrier
+ * correct. This code is based on an article from SunOpsis
+ * Vol. 4, No. 1 by Richard Marejka
+ * (Richard.Marejka@canada.sun.com).
+ */
+class ACE_Export ACE_Barrier
+{
+public:
+ /// Initialize the barrier to synchronize <count> threads.
+ ACE_Barrier (u_int count,
+ const ACE_TCHAR *name = 0,
+ void *arg = 0);
+
+ /// Default dtor.
+ ~ACE_Barrier (void);
+
+ /// Block the caller until all <count> threads have called <wait> and
+ /// then allow all the caller threads to continue in parallel.
+ int wait (void);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+protected:
+ /// Serialize access to the barrier state.
+ ACE_Thread_Mutex lock_;
+
+ /// Either 0 or 1, depending on whether we are the first generation
+ /// of waiters or the next generation of waiters.
+ int current_generation_;
+
+ /// Total number of threads that can be waiting at any one time.
+ int count_;
+
+ /**
+ * We keep two <sub_barriers>, one for the first "generation" of
+ * waiters, and one for the next "generation" of waiters. This
+ * efficiently solves the problem of what to do if all the first
+ * generation waiters don't leave the barrier before one of the
+ * threads calls wait() again (i.e., starts up the next generation
+ * barrier).
+ */
+ ACE_Sub_Barrier sub_barrier_1_;
+ ACE_Sub_Barrier sub_barrier_2_;
+ ACE_Sub_Barrier *sub_barrier_[2];
+
+private:
+ // = Prevent assignment and initialization.
+ void operator= (const ACE_Barrier &);
+ ACE_Barrier (const ACE_Barrier &);
+};
+
+#if 0
+// The following two classes are commented out since there doesn't
+// appear to be a portable and robust means of implementing this
+// functionality across platforms. If you know of a portable and
+// robust way to implement this functionality please let us know.
+
+/**
+ * @class ACE_Process_Condition
+ *
+ * @brief ACE_Condition variable wrapper that works across processes.
+ */
+class ACE_Export ACE_Process_Condition
+{
+public:
+ ACE_Process_Condition (MUTEX &m, const ACE_TCHAR *name = 0, void *arg = 0);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ // ACE_ALLOC_HOOK_DECLARE;
+ // Declare the dynamic allocation hooks.
+};
+#endif /* 0 */
+
+#if 0
+/**
+ * @class ACE_Process_Barrier
+ *
+ * @brief Implements "barrier synchronization" using ACE_Process_Mutexes!
+ *
+ * This class is just a simple wrapper for ACE_Barrier that
+ * selects the USYNC_PROCESS variant for the locks.
+ */
+class ACE_Export ACE_Process_Barrier : public ACE_Barrier
+{
+public:
+ /// Create a Process_Barrier, passing in the optional <name>.
+ ACE_Process_Barrier (u_int count, const ACE_TCHAR *name = 0);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+};
+#endif /* 0 */
+
+/**
+ * @class ACE_Thread_Barrier
+ *
+ * @brief Implements "barrier synchronization" using ACE_Thread_Mutexes!
+ *
+ * This class is just a simple wrapper for ACE_Barrier that
+ * selects the USYNC_THREAD variant for the locks.
+ */
+class ACE_Export ACE_Thread_Barrier : public ACE_Barrier
+{
+public:
+ /// Create a Thread_Barrier, passing in the optional <name>.
+ ACE_Thread_Barrier (u_int count, const ACE_TCHAR *name = 0);
+
+ /// Default dtor.
+ ~ACE_Thread_Barrier (void);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+};
+#endif /* ACE_HAS_THREADS */
+
+#if defined (__ACE_INLINE__)
+#include "ace/Synch.i"
+#endif /* __ACE_INLINE__ */
+
+// Include the templates here.
+#include "ace/Synch_T.h"
+
+template <class ACE_LOCK>
+class ACE_Guard;
+
+ACE_TEMPLATE_SPECIALIZATION
+/**
+ * @class ACE_Guard<ACE_Null_Mutex>
+ *
+ * @brief Template specialization of <ACE_Guard> for the
+ * <ACE_Null_Mutex>.
+ *
+ * This specialization is useful since it helps to speedup
+ * performance of the "Null_Mutex" considerably.
+ */
+class ACE_Export ACE_Guard<ACE_Null_Mutex>
+{
+public:
+ // = Initialization and termination methods.
+ ACE_Guard (ACE_Null_Mutex &) {}
+ ACE_Guard (ACE_Null_Mutex &, int) {}
+#if defined (ACE_WIN32)
+ ~ACE_Guard (void) {}
+#endif /* ACE_WIN32 */
+
+ int acquire (void) { return 0; }
+ int tryacquire (void) { return 0; }
+ int release (void) { return 0; }
+ int locked (void) { return 1; }
+ int remove (void) { return 0; }
+ void dump (void) const {}
+
+private:
+ // = Prevent assignment and initialization.
+ ACE_UNIMPLEMENTED_FUNC (void operator= (const ACE_Guard<ACE_Null_Mutex> &))
+ ACE_UNIMPLEMENTED_FUNC (ACE_Guard (const ACE_Guard<ACE_Null_Mutex> &))
+};
+
+template <class ACE_LOCK>
+class ACE_Write_Guard;
+
+ACE_TEMPLATE_SPECIALIZATION
+/**
+ * @class ACE_Write_Guard<ACE_Null_Mutex>
+ *
+ */
+class ACE_Export ACE_Write_Guard<ACE_Null_Mutex> : public ACE_Guard<ACE_Null_Mutex>
+{
+public:
+ ACE_Write_Guard (ACE_Null_Mutex &m)
+ : ACE_Guard<ACE_Null_Mutex> (m) {}
+ ACE_Write_Guard (ACE_Null_Mutex &m, int blocked)
+ : ACE_Guard<ACE_Null_Mutex> (m, blocked) {}
+
+ int acquire_write (void) { return 0; }
+ int acquire (void) { return 0; }
+ int tryacquire_write (void) { return 0; }
+ int tryacquire (void) { return 0; }
+ void dump (void) const {}
+};
+
+template <class ACE_LOCK>
+class ACE_Read_Guard;
+
+ACE_TEMPLATE_SPECIALIZATION
+/**
+ * @class ACE_Read_Guard<ACE_Null_Mutex>
+ *
+ */
+class ACE_Export ACE_Read_Guard<ACE_Null_Mutex> : public ACE_Guard<ACE_Null_Mutex>
+{
+public:
+ ACE_Read_Guard (ACE_Null_Mutex &m)
+ : ACE_Guard<ACE_Null_Mutex> (m) {}
+ ACE_Read_Guard (ACE_Null_Mutex &m, int blocked)
+ : ACE_Guard<ACE_Null_Mutex> (m, blocked) {}
+
+ int acquire_read (void) { return 0; }
+ int acquire (void) { return 0; }
+ int tryacquire_read (void) { return 0; }
+ int tryacquire (void) { return 0; }
+ void dump (void) const {}
+};
+
+#if defined (ACE_LEGACY_MODE)
+# include "ace/File_Lock.h"
+# include "ace/Process_Semaphore.h"
+# include "ace/Process_Mutex.h"
+# include "ace/RW_Process_Mutex.h"
+# include "ace/Test_and_Set.h"
+#endif /* ACE_LEGACY_MODE */
+
+#include "ace/post.h"
+#endif /* ACE_SYNCH_H */
diff --git a/ace/Threads/Synch.i b/ace/Threads/Synch.i
new file mode 100644
index 00000000000..4bb95145df5
--- /dev/null
+++ b/ace/Threads/Synch.i
@@ -0,0 +1,965 @@
+/* -*- C++ -*- */
+// $Id$
+
+ACE_INLINE
+ACE_Lock::ACE_Lock (void)
+{
+}
+
+ACE_INLINE const ACE_rwlock_t &
+ACE_RW_Mutex::lock (void) const
+{
+// ACE_TRACE ("ACE_RW_Mutex::lock");
+ return this->lock_;
+}
+
+ACE_INLINE int
+ACE_RW_Mutex::remove (void)
+{
+// ACE_TRACE ("ACE_RW_Mutex::remove");
+ int result = 0;
+ if (this->removed_ == 0)
+ {
+ this->removed_ = 1;
+ result = ACE_OS::rwlock_destroy (&this->lock_);
+ }
+ return result;
+}
+
+ACE_INLINE int
+ACE_RW_Mutex::acquire_read (void)
+{
+// ACE_TRACE ("ACE_RW_Mutex::acquire_read");
+ return ACE_OS::rw_rdlock (&this->lock_);
+}
+
+ACE_INLINE int
+ACE_RW_Mutex::acquire_write (void)
+{
+// ACE_TRACE ("ACE_RW_Mutex::acquire_write");
+ return ACE_OS::rw_wrlock (&this->lock_);
+}
+
+ACE_INLINE int
+ACE_RW_Mutex::acquire (void)
+{
+// ACE_TRACE ("ACE_RW_Mutex::acquire");
+ return ACE_OS::rw_wrlock (&this->lock_);
+}
+
+ACE_INLINE int
+ACE_RW_Mutex::tryacquire_read (void)
+{
+// ACE_TRACE ("ACE_RW_Mutex::tryacquire_read");
+ return ACE_OS::rw_tryrdlock (&this->lock_);
+}
+
+ACE_INLINE int
+ACE_RW_Mutex::tryacquire_write (void)
+{
+// ACE_TRACE ("ACE_RW_Mutex::tryacquire_write");
+ return ACE_OS::rw_trywrlock (&this->lock_);
+}
+
+ACE_INLINE int
+ACE_RW_Mutex::tryacquire_write_upgrade (void)
+{
+// ACE_TRACE ("ACE_RW_Mutex::tryacquire_write_upgrade");
+ return ACE_OS::rw_trywrlock_upgrade (&this->lock_);
+}
+
+ACE_INLINE int
+ACE_RW_Mutex::tryacquire (void)
+{
+// ACE_TRACE ("ACE_RW_Mutex::tryacquire");
+ return this->tryacquire_write ();
+}
+
+ACE_INLINE int
+ACE_RW_Mutex::release (void)
+{
+// ACE_TRACE ("ACE_RW_Mutex::release");
+ return ACE_OS::rw_unlock (&this->lock_);
+}
+
+#if defined (ACE_HAS_THREADS)
+ACE_INLINE int
+ACE_RW_Thread_Mutex::tryacquire_write_upgrade (void)
+{
+// ACE_TRACE ("ACE_RW_Thread_Mutex::tryacquire_write_upgrade");
+ return ACE_OS::rw_trywrlock_upgrade (&this->lock_);
+}
+#endif /* ACE_HAS_THREADS */
+
+ACE_INLINE int
+ACE_Mutex::acquire_read (void)
+{
+// ACE_TRACE ("ACE_Mutex::acquire_read");
+#if defined (CHORUS)
+ if (this->process_lock_)
+ return ACE_OS::mutex_lock (this->process_lock_);
+#endif /* CHORUS */
+ return ACE_OS::mutex_lock (&this->lock_);
+}
+
+ACE_INLINE int
+ACE_Mutex::acquire_write (void)
+{
+// ACE_TRACE ("ACE_Mutex::acquire_write");
+#if defined (CHORUS)
+ if (this->process_lock_)
+ return ACE_OS::mutex_lock (this->process_lock_);
+#endif /* CHORUS */
+ return ACE_OS::mutex_lock (&this->lock_);
+}
+
+ACE_INLINE int
+ACE_Mutex::tryacquire_read (void)
+{
+// ACE_TRACE ("ACE_Mutex::tryacquire_read");
+#if defined (CHORUS)
+ if (this->process_lock_)
+ return ACE_OS::mutex_trylock (this->process_lock_);
+#endif /* CHORUS */
+ return ACE_OS::mutex_trylock (&this->lock_);
+}
+
+ACE_INLINE const ACE_mutex_t &
+ACE_Mutex::lock (void) const
+{
+// ACE_TRACE ("ACE_Mutex::lock");
+#if defined (CHORUS)
+ if (this->process_lock_)
+ return *this->process_lock_;
+#endif /* CHORUS */
+ return this->lock_;
+}
+
+ACE_INLINE int
+ACE_Mutex::tryacquire_write (void)
+{
+// ACE_TRACE ("ACE_Mutex::tryacquire_write");
+#if defined (CHORUS)
+ if (this->process_lock_)
+ return ACE_OS::mutex_trylock (this->process_lock_);
+#endif /* CHORUS */
+ return ACE_OS::mutex_trylock (&this->lock_);
+}
+
+ACE_INLINE int
+ACE_Mutex::tryacquire_write_upgrade (void)
+{
+// ACE_TRACE ("ACE_Mutex::tryacquire_write_upgrade");
+ return 0;
+}
+
+ACE_INLINE int
+ACE_Mutex::acquire (void)
+{
+// ACE_TRACE ("ACE_Mutex::acquire");
+#if defined (CHORUS)
+ if (this->process_lock_)
+ return ACE_OS::mutex_lock (this->process_lock_);
+#endif /* CHORUS */
+ return ACE_OS::mutex_lock (&this->lock_);
+}
+
+ACE_INLINE int
+ACE_Mutex::acquire (ACE_Time_Value &tv)
+{
+ // ACE_TRACE ("ACE_Mutex::acquire");
+ return ACE_OS::mutex_lock (&this->lock_, tv);
+}
+
+ACE_INLINE int
+ACE_Mutex::acquire (ACE_Time_Value *tv)
+{
+ // ACE_TRACE ("ACE_Mutex::acquire");
+ return ACE_OS::mutex_lock (&this->lock_, tv);
+}
+
+ACE_INLINE int
+ACE_Mutex::tryacquire (void)
+{
+// ACE_TRACE ("ACE_Mutex::tryacquire");
+#if defined (CHORUS)
+ if (this->process_lock_)
+ return ACE_OS::mutex_trylock (this->process_lock_);
+#endif /* CHORUS */
+ return ACE_OS::mutex_trylock (&this->lock_);
+}
+
+ACE_INLINE int
+ACE_Mutex::release (void)
+{
+// ACE_TRACE ("ACE_Mutex::release");
+#if defined (CHORUS)
+ if (this->process_lock_)
+ return ACE_OS::mutex_unlock (this->process_lock_);
+#endif /* CHORUS */
+ return ACE_OS::mutex_unlock (&this->lock_);
+}
+
+ACE_INLINE int
+ACE_Mutex::remove (void)
+{
+// ACE_TRACE ("ACE_Mutex::remove");
+#if defined (CHORUS) || defined (ACE_HAS_PTHREADS) || defined (ACE_HAS_STHREADS)
+ int result = 0;
+ // In the case of a interprocess mutex, the owner is the first
+ // process that created the shared memory object. In this case, the
+ // lockname_ pointer will be non-zero (points to allocated memory
+ // for the name). Owner or not, the memory needs to be unmapped
+ // from the process. If we are the owner, the file used for
+ // shm_open needs to be deleted as well.
+ if (this->process_lock_)
+ {
+ if (this->removed_ == 0)
+ {
+ this->removed_ = 1;
+
+ // Only destroy the lock if we're the ones who initialized
+ // it.
+ if (!this->lockname_)
+ ACE_OS::munmap ((void *) this->process_lock_,
+ sizeof (ACE_mutex_t));
+ else
+ {
+ result = ACE_OS::mutex_destroy (this->process_lock_);
+ ACE_OS::munmap ((void *) this->process_lock_,
+ sizeof (ACE_mutex_t));
+ ACE_OS::shm_unlink (this->lockname_);
+ ACE_OS::free (ACE_static_cast (void *,
+ ACE_const_cast (ACE_TCHAR *,
+ this->lockname_)));
+ }
+ }
+ }
+ return result;
+#else /* !CHORUS */
+ int result = 0;
+ if (this->removed_ == 0)
+ {
+ this->removed_ = 1;
+ result = ACE_OS::mutex_destroy (&this->lock_);
+ }
+ return result;
+#endif /* CHORUS */
+}
+
+ACE_INLINE const ACE_sema_t &
+ACE_Semaphore::lock (void) const
+{
+// ACE_TRACE ("ACE_Semaphore::lock");
+ return this->semaphore_;
+}
+
+ACE_INLINE int
+ACE_Semaphore::remove (void)
+{
+// ACE_TRACE ("ACE_Semaphore::remove");
+ int result = 0;
+ if (this->removed_ == 0)
+ {
+ this->removed_ = 1;
+ result = ACE_OS::sema_destroy (&this->semaphore_);
+ }
+ return result;
+}
+
+ACE_INLINE int
+ACE_Semaphore::acquire (void)
+{
+// ACE_TRACE ("ACE_Semaphore::acquire");
+ return ACE_OS::sema_wait (&this->semaphore_);
+}
+
+ACE_INLINE int
+ACE_Semaphore::acquire (ACE_Time_Value &tv)
+{
+// ACE_TRACE ("ACE_Semaphore::acquire");
+ return ACE_OS::sema_wait (&this->semaphore_, tv);
+}
+
+ACE_INLINE int
+ACE_Semaphore::acquire (ACE_Time_Value *tv)
+{
+// ACE_TRACE ("ACE_Semaphore::acquire");
+ return ACE_OS::sema_wait (&this->semaphore_, tv);
+}
+
+ACE_INLINE int
+ACE_Semaphore::tryacquire (void)
+{
+// ACE_TRACE ("ACE_Semaphore::tryacquire");
+ return ACE_OS::sema_trywait (&this->semaphore_);
+}
+
+ACE_INLINE int
+ACE_Semaphore::release (void)
+{
+// ACE_TRACE ("ACE_Semaphore::release");
+ return ACE_OS::sema_post (&this->semaphore_);
+}
+
+ACE_INLINE int
+ACE_Semaphore::release (size_t release_count)
+{
+// ACE_TRACE ("ACE_Semaphore::release");
+ return ACE_OS::sema_post (&this->semaphore_, release_count);
+}
+
+// Acquire semaphore ownership. This calls <acquire> and is only
+// here to make the <ACE_Semaphore> interface consistent with the
+// other synchronization APIs.
+
+ACE_INLINE int
+ACE_Semaphore::acquire_read (void)
+{
+ return this->acquire ();
+}
+
+// Acquire semaphore ownership. This calls <acquire> and is only
+// here to make the <ACE_Semaphore> interface consistent with the
+// other synchronization APIs.
+
+ACE_INLINE int
+ACE_Semaphore::acquire_write (void)
+{
+ return this->acquire ();
+}
+
+// Conditionally acquire semaphore (i.e., won't block). This calls
+// <tryacquire> and is only here to make the <ACE_Semaphore>
+// interface consistent with the other synchronization APIs.
+
+ACE_INLINE int
+ACE_Semaphore::tryacquire_read (void)
+{
+ return this->tryacquire ();
+}
+
+// Conditionally acquire semaphore (i.e., won't block). This calls
+// <tryacquire> and is only here to make the <ACE_Semaphore>
+// interface consistent with the other synchronization APIs.
+
+ACE_INLINE int
+ACE_Semaphore::tryacquire_write (void)
+{
+ return this->tryacquire ();
+}
+
+// This is only here to make the <ACE_Semaphore> interface consistent
+// with the other synchronization APIs. Assumes the caller has
+// already acquired the semaphore using one of the above calls, and
+// returns 0 (success) always.
+ACE_INLINE int
+ACE_Semaphore::tryacquire_write_upgrade (void)
+{
+ return 0;
+}
+
+// Null ACE_Semaphore implementation
+
+ACE_INLINE
+ACE_Null_Semaphore::ACE_Null_Semaphore (u_int,
+ int,
+ const ACE_TCHAR *,
+ void *,
+ int)
+{
+}
+
+ACE_INLINE
+ACE_Null_Semaphore::~ACE_Null_Semaphore (void)
+{
+}
+
+ACE_INLINE int
+ACE_Null_Semaphore::remove (void)
+{
+ return 0;
+}
+
+ACE_INLINE int
+ACE_Null_Semaphore::acquire (ACE_Time_Value &)
+{
+ errno = ETIME;
+ return -1;
+}
+
+ACE_INLINE int
+ACE_Null_Semaphore::acquire (ACE_Time_Value *)
+{
+ errno = ETIME;
+ return -1;
+}
+
+ACE_INLINE int
+ACE_Null_Semaphore::acquire (void)
+{
+ return 0;
+}
+
+ACE_INLINE int
+ACE_Null_Semaphore::tryacquire (void)
+{
+ return 0;
+}
+
+ACE_INLINE int
+ACE_Null_Semaphore::release (size_t)
+{
+ return 0;
+}
+
+ACE_INLINE int
+ACE_Null_Semaphore::release (void)
+{
+ return 0;
+}
+
+ACE_INLINE int
+ACE_Null_Semaphore::acquire_write (void)
+{
+ return 0;
+}
+
+ACE_INLINE int
+ACE_Null_Semaphore::tryacquire_write (void)
+{
+ return 0;
+}
+
+ACE_INLINE int
+ACE_Null_Semaphore::tryacquire_write_upgrade (void)
+{
+ return 0;
+}
+
+ACE_INLINE int
+ACE_Null_Semaphore::acquire_read (void)
+{
+ return 0;
+}
+
+ACE_INLINE int
+ACE_Null_Semaphore::tryacquire_read (void)
+{
+ return 0;
+}
+
+ACE_INLINE void
+ACE_Null_Semaphore::dump (void) const
+{
+}
+
+#if defined (ACE_HAS_THREADS)
+
+ACE_INLINE const ACE_thread_mutex_t &
+ACE_Thread_Mutex::lock (void) const
+{
+// ACE_TRACE ("ACE_Thread_Mutex::lock");
+ return this->lock_;
+}
+
+ACE_INLINE int
+ACE_Thread_Mutex::acquire_read (void)
+{
+// ACE_TRACE ("ACE_Thread_Mutex::acquire_read");
+ return ACE_OS::thread_mutex_lock (&this->lock_);
+}
+
+ACE_INLINE int
+ACE_Thread_Mutex::acquire_write (void)
+{
+// ACE_TRACE ("ACE_Thread_Mutex::acquire_write");
+ return ACE_OS::thread_mutex_lock (&this->lock_);
+}
+
+ACE_INLINE int
+ACE_Thread_Mutex::tryacquire_read (void)
+{
+// ACE_TRACE ("ACE_Thread_Mutex::tryacquire_read");
+ return ACE_OS::thread_mutex_trylock (&this->lock_);
+}
+
+ACE_INLINE int
+ACE_Thread_Mutex::tryacquire_write (void)
+{
+// ACE_TRACE ("ACE_Thread_Mutex::tryacquire_write");
+ return ACE_OS::thread_mutex_trylock (&this->lock_);
+}
+
+ACE_INLINE int
+ACE_Thread_Mutex::tryacquire_write_upgrade (void)
+{
+// ACE_TRACE ("ACE_Thread_Mutex::tryacquire_write_upgrade");
+ return 0;
+}
+
+ACE_INLINE int
+ACE_Thread_Mutex::acquire (void)
+{
+// ACE_TRACE ("ACE_Thread_Mutex::acquire");
+ return ACE_OS::thread_mutex_lock (&this->lock_);
+}
+
+ACE_INLINE int
+ACE_Thread_Mutex::acquire (ACE_Time_Value &tv)
+{
+ // ACE_TRACE ("ACE_Thread_Mutex::acquire");
+ return ACE_OS::thread_mutex_lock (&this->lock_, tv);
+}
+
+ACE_INLINE int
+ACE_Thread_Mutex::acquire (ACE_Time_Value *tv)
+{
+ // ACE_TRACE ("ACE_Thread_Mutex::acquire");
+ return ACE_OS::thread_mutex_lock (&this->lock_, tv);
+}
+
+ACE_INLINE int
+ACE_Thread_Mutex::tryacquire (void)
+{
+// ACE_TRACE ("ACE_Thread_Mutex::tryacquire");
+ return ACE_OS::thread_mutex_trylock (&this->lock_);
+}
+
+ACE_INLINE int
+ACE_Thread_Mutex::release (void)
+{
+// ACE_TRACE ("ACE_Thread_Mutex::release");
+ return ACE_OS::thread_mutex_unlock (&this->lock_);
+}
+
+ACE_INLINE int
+ACE_Thread_Mutex::remove (void)
+{
+// ACE_TRACE ("ACE_Thread_Mutex::remove");
+ int result = 0;
+ if (this->removed_ == 0)
+ {
+ this->removed_ = 1;
+ result = ACE_OS::thread_mutex_destroy (&this->lock_);
+ }
+ return result;
+}
+
+#if defined (ACE_USES_OBSOLETE_GUARD_CLASSES)
+ACE_INLINE int
+ACE_Thread_Mutex_Guard::locked (void)
+{
+// ACE_TRACE ("ACE_Thread_Mutex_Guard::locked");
+ return this->owner_ != -1;
+}
+
+// Explicitly acquire the lock.
+
+ACE_INLINE int
+ACE_Thread_Mutex_Guard::acquire (void)
+{
+// ACE_TRACE ("ACE_Thread_Mutex_Guard::acquire");
+ return this->owner_ = this->lock_.acquire ();
+}
+
+// Conditionally acquire the lock (i.e., won't block).
+
+ACE_INLINE int
+ACE_Thread_Mutex_Guard::tryacquire (void)
+{
+// ACE_TRACE ("ACE_Thread_Mutex_Guard::tryacquire");
+ return this->owner_ = this->lock_.tryacquire ();
+}
+
+// Implicitly and automatically acquire the lock.
+
+ACE_INLINE
+ACE_Thread_Mutex_Guard::ACE_Thread_Mutex_Guard (ACE_Thread_Mutex &m,
+ int block)
+ : lock_ (m)
+{
+// ACE_TRACE ("ACE_Thread_Mutex_Guard::ACE_Thread_Mutex_Guard");
+ if (block)
+ this->acquire ();
+ else
+ this->tryacquire ();
+}
+
+// Explicitly release the lock.
+
+ACE_INLINE int
+ACE_Thread_Mutex_Guard::release (void)
+{
+// ACE_TRACE ("ACE_Thread_Mutex_Guard::release");
+ if (this->owner_ != -1)
+ {
+ this->owner_ = -1;
+ return this->lock_.release ();
+ }
+ else
+ return 0;
+}
+
+// Implicitly release the lock.
+
+ACE_INLINE
+ACE_Thread_Mutex_Guard::~ACE_Thread_Mutex_Guard (void)
+{
+// ACE_TRACE ("ACE_Thread_Mutex_Guard::~ACE_Thread_Mutex_Guard");
+ this->release ();
+}
+
+// Explicitly release the lock.
+
+ACE_INLINE int
+ACE_Thread_Mutex_Guard::remove (void)
+{
+// ACE_TRACE ("ACE_Thread_Mutex_Guard::remove");
+ this->owner_ = -1;
+ return this->release ();
+}
+#endif /* ACE_USES_OBSOLETE_GUARD_CLASSES */
+
+ACE_INLINE
+ACE_Condition_Attributes::ACE_Condition_Attributes (int type)
+{
+ (void) ACE_OS::condattr_init (this->attributes_, type);
+}
+
+ACE_INLINE
+ACE_Condition_Attributes::~ACE_Condition_Attributes (void)
+{
+ ACE_OS::condattr_destroy (this->attributes_);
+}
+
+ACE_INLINE int
+ACE_Condition_Thread_Mutex::remove (void)
+{
+// ACE_TRACE ("ACE_Condition_Thread_Mutex::remove");
+
+ // <cond_destroy> is called in a loop if the condition variable is
+ // BUSY. This avoids a condition where a condition is signaled and
+ // because of some timing problem, the thread that is to be signaled
+ // has called the cond_wait routine after the signal call. Since
+ // the condition signal is not queued in any way, deadlock occurs.
+
+ int result = 0;
+
+ if (this->removed_ == 0)
+ {
+ this->removed_ = 1;
+
+ while ((result = ACE_OS::cond_destroy (&this->cond_)) == -1
+ && errno == EBUSY)
+ {
+ ACE_OS::cond_broadcast (&this->cond_);
+ ACE_OS::thr_yield ();
+ }
+ }
+ return result;
+}
+
+ACE_INLINE ACE_Thread_Mutex &
+ACE_Condition_Thread_Mutex::mutex (void)
+{
+// ACE_TRACE ("ACE_Condition_Thread_Mutex::mutex");
+ return this->mutex_;
+}
+
+ACE_INLINE void
+ACE_Recursive_Thread_Mutex::set_thread_id (ACE_thread_t t)
+{
+// ACE_TRACE ("ACE_Recursive_Thread_Mutex::set_thread_id");
+#if defined (ACE_HAS_RECURSIVE_MUTEXES)
+ ACE_UNUSED_ARG (t);
+#else /* ! ACE_HAS_RECURSIVE_MUTEXES */
+ this->recursive_mutex_.owner_id_ = t;
+#endif /* ! ACE_HAS_RECURSIVE_MUTEXES */
+}
+
+ACE_INLINE int
+ACE_Recursive_Thread_Mutex::acquire_read (void)
+{
+ return this->acquire ();
+}
+
+ACE_INLINE int
+ACE_Recursive_Thread_Mutex::acquire_write (void)
+{
+ return this->acquire ();
+}
+
+ACE_INLINE int
+ACE_Recursive_Thread_Mutex::tryacquire_read (void)
+{
+ return this->tryacquire ();
+}
+
+ACE_INLINE int
+ACE_Recursive_Thread_Mutex::tryacquire_write (void)
+{
+ return this->tryacquire ();
+}
+
+ACE_INLINE int
+ACE_Recursive_Thread_Mutex::tryacquire_write_upgrade (void)
+{
+ return 0;
+}
+
+#endif /* ACE_HAS_THREADS */
+
+ACE_INLINE
+ACE_Null_Barrier::ACE_Null_Barrier (u_int,
+ const char *,
+ void *)
+{
+}
+
+ACE_INLINE
+ACE_Null_Barrier::~ACE_Null_Barrier (void)
+{
+}
+
+ACE_INLINE int
+ACE_Null_Barrier::wait (void)
+{
+ return 0;
+}
+
+ACE_INLINE void
+ACE_Null_Barrier::dump (void) const
+{
+}
+
+ACE_INLINE
+ACE_Null_Mutex::ACE_Null_Mutex (const ACE_TCHAR *)
+{
+}
+
+ACE_INLINE
+ACE_Null_Mutex::~ACE_Null_Mutex (void)
+{
+}
+
+ACE_INLINE int
+ACE_Null_Mutex::remove (void)
+{
+ return 0;
+}
+
+ACE_INLINE int
+ACE_Null_Mutex::acquire (void)
+{
+ return 0;
+}
+
+ACE_INLINE int
+ACE_Null_Mutex::acquire (ACE_Time_Value &)
+{
+ errno = ETIME;
+ return -1;
+}
+
+ACE_INLINE int
+ACE_Null_Mutex::acquire (ACE_Time_Value *)
+{
+ errno = ETIME;
+ return -1;
+}
+
+ACE_INLINE int
+ACE_Null_Mutex::tryacquire (void)
+{
+ return 0;
+}
+
+ACE_INLINE int
+ACE_Null_Mutex::release (void)
+{
+ return 0;
+}
+
+ACE_INLINE int
+ACE_Null_Mutex::acquire_write (void)
+{
+ return 0;
+}
+
+ACE_INLINE int
+ACE_Null_Mutex::tryacquire_write (void)
+{
+ return 0;
+}
+
+ACE_INLINE int
+ACE_Null_Mutex::tryacquire_write_upgrade (void)
+{
+ return 0;
+}
+
+ACE_INLINE int
+ACE_Null_Mutex::acquire_read (void)
+{
+ return 0;
+}
+
+ACE_INLINE int
+ACE_Null_Mutex::tryacquire_read (void)
+{
+ return 0;
+}
+
+ACE_INLINE void
+ACE_Null_Mutex::dump (void) const
+{
+}
+
+ACE_INLINE int
+ACE_Noop_Token::renew (int, ACE_Time_Value *)
+{
+ return 0;
+}
+
+ACE_INLINE void
+ACE_Noop_Token::dump (void) const
+{
+}
+
+
+ACE_INLINE
+ACE_Null_Condition::ACE_Null_Condition (const ACE_Null_Mutex &m,
+ const ACE_TCHAR *,
+ void*)
+ : mutex_ ((ACE_Null_Mutex &) m)
+{
+}
+
+ACE_INLINE ACE_Null_Condition::~ACE_Null_Condition (void)
+{
+}
+
+ACE_INLINE int ACE_Null_Condition::remove (void)
+{
+ return 0;
+}
+
+ACE_INLINE int
+ACE_Null_Condition::wait (ACE_Time_Value *)
+{
+ errno = ETIME;
+ return -1;
+}
+
+ACE_INLINE int
+ACE_Null_Condition::signal (void)
+{
+ return 0;
+}
+
+ACE_INLINE int
+ACE_Null_Condition::broadcast (void)
+{
+ return 0;
+}
+
+ACE_INLINE ACE_Null_Mutex &
+ACE_Null_Condition::mutex (void)
+{
+ return this->mutex_;
+}
+
+ACE_INLINE void
+ACE_Null_Condition::dump (void) const
+{
+}
+
+#if defined (ACE_USES_OBSOLETE_GUARD_CLASSES)
+ACE_INLINE
+ACE_Null_Mutex_Guard::ACE_Null_Mutex_Guard (ACE_Null_Mutex &)
+{
+}
+
+ACE_INLINE
+ACE_Null_Mutex_Guard::~ACE_Null_Mutex_Guard (void)
+{
+}
+
+ACE_INLINE int
+ACE_Null_Mutex_Guard::remove (void)
+{
+ return 0;
+}
+
+ACE_INLINE int
+ACE_Null_Mutex_Guard::locked (void)
+{
+ return 1;
+}
+
+ACE_INLINE int
+ACE_Null_Mutex_Guard::acquire (void)
+{
+ return 0;
+}
+
+ACE_INLINE int
+ACE_Null_Mutex_Guard::tryacquire (void)
+{
+ return 0;
+}
+
+ACE_INLINE int
+ACE_Null_Mutex_Guard::release (void)
+{
+ return 0;
+}
+
+ACE_INLINE void
+ACE_Null_Mutex_Guard::dump (void) const
+{
+}
+#endif /* ACE_USES_OBSOLETE_GUARD_CLASSES */
+
+ACE_INLINE
+ACE_TSS_Adapter::~ACE_TSS_Adapter (void)
+{
+}
+
+ACE_INLINE
+ACE_Manual_Event::~ACE_Manual_Event (void)
+{
+}
+
+ACE_INLINE
+ACE_Auto_Event::~ACE_Auto_Event (void)
+{
+}
+
+#if defined (ACE_HAS_THREADS)
+ACE_INLINE
+ACE_RW_Thread_Mutex::~ACE_RW_Thread_Mutex (void)
+{
+}
+
+ACE_INLINE
+ACE_Thread_Semaphore::~ACE_Thread_Semaphore (void)
+{
+}
+
+ACE_INLINE
+ACE_Sub_Barrier::~ACE_Sub_Barrier (void)
+{
+}
+
+ACE_INLINE
+ACE_Barrier::~ACE_Barrier (void)
+{
+}
+
+ACE_INLINE
+ACE_Thread_Barrier::~ACE_Thread_Barrier (void)
+{
+}
+#endif /* ACE_HAS_THREADS */
diff --git a/ace/Threads/Synch_Options.cpp b/ace/Threads/Synch_Options.cpp
new file mode 100644
index 00000000000..0febeccfb29
--- /dev/null
+++ b/ace/Threads/Synch_Options.cpp
@@ -0,0 +1,105 @@
+// $Id$
+
+#include "ace/Synch_Options.h"
+
+#if !defined (__ACE_INLINE__)
+#include "ace/Synch_Options.i"
+#endif /* __ACE_INLINE__ */
+
+ACE_RCSID(ace, Synch_Options, "$Id$")
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Synch_Options)
+
+void
+ACE_Synch_Options::dump (void) const
+{
+ ACE_TRACE ("ACE_Synch_Options::dump");
+}
+
+// Static initialization.
+// Note: these three objects require static construction and destruction.
+
+/* static */
+ACE_Synch_Options ACE_Synch_Options::defaults;
+
+/* static */
+ACE_Synch_Options ACE_Synch_Options::synch;
+
+/* static */
+ACE_Synch_Options ACE_Synch_Options::asynch (ACE_Synch_Options::USE_REACTOR);
+
+ACE_Synch_Options::ACE_Synch_Options (u_long options,
+ const ACE_Time_Value &timeout,
+ const void *arg)
+{
+ // ACE_TRACE ("ACE_Synch_Options::ACE_Synch_Options");
+ this->set (options, timeout, arg);
+}
+
+void
+ACE_Synch_Options::set (u_long options,
+ const ACE_Time_Value &timeout,
+ const void *arg)
+{
+ // ACE_TRACE ("ACE_Synch_Options::set");
+ this->options_ = options;
+ this->timeout_ = (ACE_Time_Value &) timeout;
+
+ // Whoa, possible dependence on static initialization here. This
+ // function is called during initialization of the statics above.
+ // But, ACE_Time_Value::zero is a static object. Very fortunately,
+ // its bits have a value of 0.
+ if (this->timeout_ != ACE_Time_Value::zero)
+ ACE_SET_BITS (this->options_, ACE_Synch_Options::USE_TIMEOUT);
+
+ this->arg_ = arg;
+}
+
+int
+ACE_Synch_Options::operator[] (u_long option) const
+{
+ ACE_TRACE ("ACE_Synch_Options::operator[]");
+ return (this->options_ & option) != 0;
+}
+
+void
+ACE_Synch_Options::operator= (u_long option)
+{
+ ACE_TRACE ("ACE_Synch_Options::operator=");
+ this->options_ |= option;
+}
+
+const ACE_Time_Value &
+ACE_Synch_Options::timeout (void) const
+{
+ ACE_TRACE ("ACE_Synch_Options::timeout");
+ return this->timeout_;
+}
+
+void
+ACE_Synch_Options::timeout (const ACE_Time_Value &tv)
+{
+ ACE_TRACE ("ACE_Synch_Options::timeout");
+ this->timeout_ = tv;
+}
+
+const ACE_Time_Value *
+ACE_Synch_Options::time_value (void) const
+{
+ ACE_TRACE ("ACE_Synch_Options::time_value");
+ return (*this)[USE_TIMEOUT] ? &this->timeout_ : 0;
+}
+
+const void *
+ACE_Synch_Options::arg (void) const
+{
+ ACE_TRACE ("ACE_Synch_Options::arg");
+ return this->arg_;
+}
+
+void
+ACE_Synch_Options::arg (const void *a)
+{
+ ACE_TRACE ("ACE_Synch_Options::arg");
+ this->arg_ = a;
+}
diff --git a/ace/Threads/Synch_Options.h b/ace/Threads/Synch_Options.h
new file mode 100644
index 00000000000..3af324bca28
--- /dev/null
+++ b/ace/Threads/Synch_Options.h
@@ -0,0 +1,154 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Synch_Options.h
+ *
+ * $Id$
+ *
+ * @author Doug Schmidt
+ */
+//=============================================================================
+
+
+#ifndef ACE_SYNCH_OPTIONS_H
+#define ACE_SYNCH_OPTIONS_H
+#include "ace/pre.h"
+
+#include "ace/ACE.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+/**
+ * @class ACE_Synch_Options
+ *
+ * @brief Contains the values of options used to determine the
+ * synchronous and asynchronous behavior.
+ *
+ * Values support the following behavior (TV == "timeout"
+ * and UR == "use ACE_Reactor"):
+ *
+ * <CODE>
+ * | Parameters | Description
+ * |
+ * |TV | UR |
+ * |-----|----------|-------------------------------
+ * | |
+ * |NULL | yes | infinite timeout (using ACE_Reactor)
+ * | |
+ * |time | yes | try asynch transaction for
+ * | | the specified time (using ACE_Reactor)
+ * | |
+ * |0,0 | yes | poll; try, if EWOULDBLOCK,
+ * | | then return immediately
+ * | | (using ACE_Reactor)
+ * | |
+ * |NULL | no | block forever (don't use ACE_Reactor)
+ * | |
+ * |time | no | do a blocking transaction
+ * | | for the specified time
+ * | | (don't use ACE_Reactor)
+ * | |
+ * |0,0 | no | poll; but do not initiate a
+ * | | nonblocking transaction
+ * | | (don't use ACE_Reactor)
+ * </CODE>
+ */
+class ACE_Export ACE_Synch_Options
+{
+public:
+ /// Options flags for controlling synchronization.
+ /**
+ * Note that these flags can be bit-wise "or'd" together if both
+ * options are desired.
+ */
+ enum
+ {
+ /// Use the Reactor.
+ USE_REACTOR = 01,
+ /// Interprete the Time_Value.
+ USE_TIMEOUT = 02
+ };
+
+ // = Initialization methods.
+ /// Initialize the Synch_Options based on parameters.
+ ACE_Synch_Options (u_long options = 0,
+ const ACE_Time_Value &timeout = ACE_Time_Value::zero,
+ const void *arg = 0);
+
+ /// Default dtor.
+ ~ACE_Synch_Options (void);
+
+ /// Initialize the Synch_Options based on parameters.
+ void set (u_long options = 0,
+ const ACE_Time_Value &timeout = ACE_Time_Value::zero,
+ const void *arg = 0);
+
+ /// Get method for determining which options are enabled.
+ int operator[] (u_long option) const;
+
+ /// Set method for enabling certain options.
+ void operator= (u_long option);
+
+ /// Returns the "magic cookie" argument.
+ const void *arg (void) const;
+
+ /// Set the "magic cookie" argument.
+ void arg (const void *);
+
+ /// Returns a reference to the <Time_Value>. This value only makes
+ /// sense if (*this)[USE_TIMEOUT] is true.
+ const ACE_Time_Value &timeout (void) const;
+
+ /// Set the <Time_Value>.
+ void timeout (const ACE_Time_Value &tv);
+
+ /**
+ * Returns the address of the timeout <Time_Value> if
+ * (*this)[USE_TIMEOUT] is true, else 0. This should be used with
+ * care, e.g., the timeout pointer should not be stored in a manner
+ * that will lead to dangling pointers...
+ */
+ const ACE_Time_Value *time_value (void) const;
+
+ // = Static data members (singletons)
+
+ /// This is the default setting for options, which will block
+ /// synchronously.
+ static ACE_Synch_Options defaults;
+
+ /// This is the default synchronous setting.
+ static ACE_Synch_Options synch;
+
+ /// This is the default asynchronous setting.
+ static ACE_Synch_Options asynch;
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+private:
+ /// Keeps track of the enabled options.
+ u_long options_;
+
+ /// Amount of time to wait for timeouts.
+ ACE_Time_Value timeout_;
+
+ /**
+ * "Magic cookie" always passed in as an argument to the ACE_Reactor's
+ * <schedule_timer> method. Used to communicate values for
+ * asynchronous programming.
+ */
+ const void *arg_;
+};
+
+#if defined (__ACE_INLINE__)
+#include "ace/Synch_Options.i"
+#endif /* __ACE_INLINE__ */
+
+#include "ace/post.h"
+#endif /* ACE_SYNCH_OPTIONS_H */
diff --git a/ace/Threads/Synch_Options.i b/ace/Threads/Synch_Options.i
new file mode 100644
index 00000000000..3c16b199ac8
--- /dev/null
+++ b/ace/Threads/Synch_Options.i
@@ -0,0 +1,9 @@
+/* -*- C++ -*- */
+// $Id$
+
+// Synch_Options.i
+
+ACE_INLINE
+ACE_Synch_Options::~ACE_Synch_Options (void)
+{
+}
diff --git a/ace/Threads/Synch_T.cpp b/ace/Threads/Synch_T.cpp
new file mode 100644
index 00000000000..dccb94fc382
--- /dev/null
+++ b/ace/Threads/Synch_T.cpp
@@ -0,0 +1,895 @@
+// $Id$
+
+
+#ifndef ACE_SYNCH_T_C
+#define ACE_SYNCH_T_C
+
+#include "ace/Threads/Thread.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "ace/Threads/Synch_T.h"
+#include "ace/Logging/Log_Msg.h"
+
+ACE_RCSID(ace, Synch_T, "$Id$")
+
+#if !defined (__ACE_INLINE__)
+#include "ace/Threads/Synch_T.i"
+#endif /* __ACE_INLINE__ */
+
+
+
+// This constructor isn't inlined, because SunPRO C++ 4.2 + patch
+// 104631-07 has trouble compiling TAO with it inline.
+template <class ACE_LOCKING_MECHANISM>
+ACE_Lock_Adapter<ACE_LOCKING_MECHANISM>::ACE_Lock_Adapter (void)
+ : lock_ (0),
+ delete_lock_ (1)
+{
+ ACE_NEW (this->lock_,
+ ACE_LOCKING_MECHANISM);
+}
+
+template <class ACE_LOCKING_MECHANISM>
+ACE_Reverse_Lock<ACE_LOCKING_MECHANISM>::~ACE_Reverse_Lock (void)
+{
+}
+// ****************************************************************
+// ACE_ALLOC_HOOK_DEFINE(ACE_Guard)
+
+template <class ACE_LOCK> void
+ACE_Guard<ACE_LOCK>::dump (void) const
+{
+// ACE_TRACE ("ACE_Guard<ACE_LOCK>::dump");
+
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("mutex_ = %x\n"), this->lock_));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("owner_ = %d\n"), this->owner_));
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+// ACE_ALLOC_HOOK_DEFINE(ACE_Write_Guard)
+
+template <class ACE_LOCK> void
+ACE_Write_Guard<ACE_LOCK>::dump (void) const
+{
+// ACE_TRACE ("ACE_Write_Guard<ACE_LOCK>::dump");
+ ACE_Guard<ACE_LOCK>::dump ();
+}
+
+// ACE_ALLOC_HOOK_DEFINE(ACE_Read_Guard)
+
+template <class ACE_LOCK> void
+ACE_Read_Guard<ACE_LOCK>::dump (void) const
+{
+// ACE_TRACE ("ACE_Read_Guard<ACE_LOCK>::dump");
+ ACE_Guard<ACE_LOCK>::dump ();
+}
+
+#if defined (ACE_HAS_THREADS)
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Condition)
+
+template <class MUTEX> void
+ACE_Condition<MUTEX>::dump (void) const
+{
+// ACE_TRACE ("ACE_Condition<MUTEX>::dump");
+
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+#if defined (CHORUS)
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("condname_ = %s\n"), this->condname_));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("process_cond_ = %x\n"), this->process_cond_));
+#endif /* CHORUS */
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\n")));
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+template <class MUTEX>
+ACE_Thread_Condition<MUTEX>::ACE_Thread_Condition (MUTEX &m,
+ const ACE_TCHAR *name,
+ void *arg)
+ : ACE_Condition<MUTEX> (m, USYNC_THREAD, name, arg)
+{
+// ACE_TRACE ("ACE_Thread_Condition<MUTEX>::ACE_Thread_Condition");
+}
+
+template <class MUTEX> void
+ACE_Thread_Condition<MUTEX>::dump (void) const
+{
+// ACE_TRACE ("ACE_Thread_Condition<MUTEX>::dump");
+
+ ACE_Condition<MUTEX>::dump ();
+}
+
+template <class MUTEX>
+ACE_Condition<MUTEX>::ACE_Condition (MUTEX &m,
+ int type,
+ const ACE_TCHAR *name,
+ void *arg)
+ :
+#if defined (CHORUS)
+ process_cond_(0),
+ condname_ (0),
+#endif /* CHORUS */
+ mutex_ (m)
+{
+
+#if defined(CHORUS)
+ if (type == USYNC_PROCESS)
+ {
+ // Let's see if the shared memory entity already exists.
+ ACE_HANDLE fd = ACE_OS::shm_open (name,
+ O_RDWR | O_CREAT | O_EXCL,
+ ACE_DEFAULT_FILE_PERMS);
+ if (fd == ACE_INVALID_HANDLE)
+ {
+ if (errno == EEXIST)
+ fd = ACE_OS::shm_open (name,
+ O_RDWR | O_CREAT,
+ ACE_DEFAULT_FILE_PERMS);
+ else
+ return;
+ }
+ else
+ {
+ // We own this shared memory object! Let's set its size.
+ if (ACE_OS::ftruncate (fd,
+ sizeof (ACE_mutex_t)) == -1)
+ {
+ ACE_OS::close (fd);
+ return;
+ }
+ this->condname_ = ACE_OS::strdup (name);
+ if (this->condname_ == 0)
+ {
+ ACE_OS::close (fd);
+ return;
+ }
+ }
+
+ this->process_cond_ =
+ (ACE_cond_t *) ACE_OS::mmap (0,
+ sizeof (ACE_cond_t),
+ PROT_RDWR,
+ MAP_SHARED,
+ fd,
+ 0);
+ ACE_OS::close (fd);
+ if (this->process_cond_ == MAP_FAILED)
+ return;
+
+ if (this->condname_
+ && ACE_OS::cond_init (this->process_cond_,
+ type,
+ name,
+ arg) != 0)
+ return;
+ }
+ // It is ok to fall through into the <cond_init> below if the
+ // USYNC_PROCESS flag is not enabled.
+#endif /* CHORUS */
+
+ // ACE_TRACE ("ACE_Condition<MUTEX>::ACE_Condition");
+
+ if (ACE_OS::cond_init (&this->cond_,
+ (short) type,
+ name,
+ arg) != 0)
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("%p\n"),
+ ACE_LIB_TEXT ("ACE_Condition::ACE_Condition")));
+}
+
+template <class MUTEX>
+ACE_Condition<MUTEX>::~ACE_Condition (void)
+{
+ // ACE_TRACE ("ACE_Condition<MUTEX>::~ACE_Condition");
+
+ if (this->remove () == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("%p\n"),
+ ACE_LIB_TEXT ("ACE_Condition::~ACE_Condition")));
+}
+
+template <class MUTEX> int
+ACE_Condition<MUTEX>::wait (void)
+{
+ // ACE_TRACE ("ACE_Condition<MUTEX>::wait");
+#if defined (CHORUS)
+ if (this->process_cond_ != 0)
+ return ACE_OS::cond_wait (this->process_cond_,
+ &this->mutex_.lock_);
+#endif /* CHORUS */
+ return ACE_OS::cond_wait (&this->cond_,
+ &this->mutex_.lock_);
+}
+
+template <class MUTEX> int
+ACE_Condition<MUTEX>::wait (MUTEX &mutex,
+ const ACE_Time_Value *abstime)
+{
+// ACE_TRACE ("ACE_Condition<MUTEX>::wait");
+ if (abstime == 0)
+ return this->wait ();
+ else
+ {
+#if defined (CHORUS)
+ if (this->process_cond_ != 0)
+ return ACE_OS::cond_timedwait (this->process_cond_,
+ &mutex_.lock_,
+ (ACE_Time_Value *) abstime);
+#endif /* CHORUS */
+ return ACE_OS::cond_timedwait (&this->cond_,
+ &mutex.lock_,
+ (ACE_Time_Value *) abstime);
+ }
+}
+
+// Peform an "alertable" timed wait. If the argument ABSTIME == 0
+// then we do a regular cond_wait(), else we do a timed wait for up to
+// ABSTIME using the Solaris cond_timedwait() function.
+
+template <class MUTEX> int
+ACE_Condition<MUTEX>::wait (const ACE_Time_Value *abstime)
+{
+// ACE_TRACE ("ACE_Condition<MUTEX>::wait");
+ return this->wait (this->mutex_, abstime);
+}
+#endif /* ACE_HAS_THREADS */
+
+ACE_ALLOC_HOOK_DEFINE(ACE_TSS)
+
+template <class TYPE>
+ACE_TSS<TYPE>::~ACE_TSS (void)
+{
+ // We can't call <ACE_OS::thr_keyfree> until *all* of the threads
+ // that are using that key have done an <ACE_OS::thr_key_detach>.
+ // Otherwise, we'll end up with "dangling TSS pointers."
+ ACE_OS::thr_key_detach (this);
+}
+
+template <class TYPE> TYPE *
+ACE_TSS<TYPE>::operator-> () const
+{
+ return this->ts_get ();
+}
+
+template <class TYPE>
+ACE_TSS<TYPE>::operator TYPE *(void) const
+{
+ return this->ts_get ();
+}
+
+template <class TYPE> TYPE *
+ACE_TSS<TYPE>::make_TSS_TYPE (void) const
+{
+ TYPE *temp = 0;
+ ACE_NEW_RETURN (temp,
+ TYPE,
+ 0);
+ return temp;
+}
+
+template <class TYPE> void
+ACE_TSS<TYPE>::dump (void) const
+{
+// ACE_TRACE ("ACE_TSS<TYPE>::dump");
+#if defined (ACE_HAS_THREADS) && (defined (ACE_HAS_THREAD_SPECIFIC_STORAGE) || defined (ACE_HAS_TSS_EMULATION))
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+ this->keylock_.dump ();
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("key_ = %d\n"), this->key_));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\nonce_ = %d"), this->once_));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\n")));
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+#endif /* defined (ACE_HAS_THREADS) && (defined (ACE_HAS_THREAD_SPECIFIC_STORAGE) || defined (ACE_HAS_TSS_EMULATION)) */
+}
+
+#if defined (ACE_HAS_THREADS) && (defined (ACE_HAS_THREAD_SPECIFIC_STORAGE) || defined (ACE_HAS_TSS_EMULATION))
+#if defined (ACE_HAS_THR_C_DEST)
+extern "C" void ACE_TSS_C_cleanup(void *); // defined in Synch.cpp
+#endif /* ACE_HAS_THR_C_DEST */
+
+template <class TYPE> void
+ACE_TSS<TYPE>::cleanup (void *ptr)
+{
+ // Cast this to the concrete TYPE * so the destructor gets called.
+ delete (TYPE *) ptr;
+}
+
+template <class TYPE> int
+ACE_TSS<TYPE>::ts_init (void) const
+{
+ // Insure that we are serialized!
+ ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, (ACE_Thread_Mutex &) this->keylock_, 0);
+
+ // Use the Double-Check pattern to make sure we only create the key
+ // once!
+ if (this->once_ == 0)
+ {
+ if (ACE_Thread::keycreate (ACE_const_cast (ACE_thread_key_t *, &this->key_),
+#if defined (ACE_HAS_THR_C_DEST)
+ &ACE_TSS_C_cleanup,
+#else
+ &ACE_TSS<TYPE>::cleanup,
+#endif /* ACE_HAS_THR_C_DEST */
+ (void *) this) != 0)
+ return -1; // Major problems, this should *never* happen!
+ else
+ {
+ // This *must* come last to avoid race conditions! Note that
+ // we need to "cast away const..."
+ * ACE_const_cast (int*, &this->once_) = 1;
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+template <class TYPE>
+ACE_TSS<TYPE>::ACE_TSS (TYPE *ts_obj)
+ : once_ (0),
+ key_ (ACE_OS::NULL_key)
+{
+ // If caller has passed us a non-NULL TYPE *, then we'll just use
+ // this to initialize the thread-specific value. Thus, subsequent
+ // calls to operator->() will return this value. This is useful
+ // since it enables us to assign objects to thread-specific data
+ // that have arbitrarily complex constructors!
+
+ if (ts_obj != 0)
+ {
+ if (this->ts_init () == -1)
+ {
+ // Save/restore errno.
+ ACE_Errno_Guard error (errno);
+ // What should we do if this call fails?!
+#if defined (ACE_HAS_WINCE)
+ ::MessageBox (NULL,
+ L"ACE_Thread::keycreate() failed!",
+ L"ACE_TSS::ACE_TSS",
+ MB_OK);
+#else
+ ACE_OS::fprintf (stderr,
+ "ACE_Thread::keycreate() failed!");
+#endif /* ACE_HAS_WINCE */
+ return;
+ }
+
+#if defined (ACE_HAS_THR_C_DEST)
+ // Encapsulate a ts_obj and it's destructor in an
+ // ACE_TSS_Adapter.
+ ACE_TSS_Adapter *tss_adapter;
+ ACE_NEW (tss_adapter,
+ ACE_TSS_Adapter ((void *) ts_obj,
+ ACE_TSS<TYPE>::cleanup));
+
+ // Put the adapter in thread specific storage
+ if (ACE_Thread::setspecific (this->key_,
+ (void *) tss_adapter) != 0)
+ {
+ delete tss_adapter;
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("%p\n"),
+ ACE_LIB_TEXT ("ACE_Thread::setspecific() failed!")));
+ }
+#else
+ if (ACE_Thread::setspecific (this->key_,
+ (void *) ts_obj) != 0)
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("%p\n"),
+ ACE_LIB_TEXT ("ACE_Thread::setspecific() failed!")));
+#endif /* ACE_HAS_THR_C_DEST */
+ }
+}
+
+template <class TYPE> TYPE *
+ACE_TSS<TYPE>::ts_get (void) const
+{
+ if (this->once_ == 0)
+ // Create and initialize thread-specific ts_obj.
+ this->ts_init ();
+
+ TYPE *ts_obj = 0;
+
+#if defined (ACE_HAS_THR_C_DEST)
+ ACE_TSS_Adapter *tss_adapter = 0;
+
+ // Get the adapter from thread-specific storage
+ if (ACE_Thread::getspecific (this->key_,
+ (void **) &tss_adapter) == -1)
+ return 0; // This should not happen!
+
+ // Check to see if this is the first time in for this thread.
+ if (tss_adapter == 0)
+#else
+ // Get the ts_obj from thread-specific storage. Note that no locks
+ // are required here...
+ if (ACE_Thread::getspecific (this->key_,
+ (void **) &ts_obj) == -1)
+ return 0; // This should not happen!
+
+ // Check to see if this is the first time in for this thread.
+ if (ts_obj == 0)
+#endif /* ACE_HAS_THR_C_DEST */
+ {
+ // Allocate memory off the heap and store it in a pointer in
+ // thread-specific storage (on the stack...).
+
+ ts_obj = this->make_TSS_TYPE ();
+
+ if (ts_obj == 0)
+ return 0;
+
+#if defined (ACE_HAS_THR_C_DEST)
+ // Encapsulate a ts_obj and it's destructor in an
+ // ACE_TSS_Adapter.
+ ACE_NEW_RETURN (tss_adapter,
+ ACE_TSS_Adapter (ts_obj,
+ ACE_TSS<TYPE>::cleanup), 0);
+
+ // Put the adapter in thread specific storage
+ if (ACE_Thread::setspecific (this->key_,
+ (void *) tss_adapter) != 0)
+ {
+ delete tss_adapter;
+ delete ts_obj;
+ return 0; // Major problems, this should *never* happen!
+ }
+#else
+ // Store the dynamically allocated pointer in thread-specific
+ // storage.
+ if (ACE_Thread::setspecific (this->key_,
+ (void *) ts_obj) != 0)
+ {
+ delete ts_obj;
+ return 0; // Major problems, this should *never* happen!
+ }
+#endif /* ACE_HAS_THR_C_DEST */
+ }
+
+#if defined (ACE_HAS_THR_C_DEST)
+ // Return the underlying ts object.
+ return (TYPE *) tss_adapter->ts_obj_;
+#else
+ return ts_obj;
+#endif /* ACE_HAS_THR_C_DEST */
+}
+
+// Get the thread-specific object for the key associated with this
+// object. Returns 0 if the ts_obj has never been initialized,
+// otherwise returns a pointer to the ts_obj.
+
+template <class TYPE> TYPE *
+ACE_TSS<TYPE>::ts_object (void) const
+{
+ // Ensure that we are serialized!
+ ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, (ACE_Thread_Mutex &) this->keylock_, 0);
+
+ if (this->once_ == 0) // Return 0 if we've never been initialized.
+ return 0;
+
+ TYPE *ts_obj = 0;
+
+#if defined (ACE_HAS_THR_C_DEST)
+ ACE_TSS_Adapter *tss_adapter = 0;
+
+ // Get the tss adapter from thread-specific storage
+ if (ACE_Thread::getspecific (this->key_,
+ (void **) &tss_adapter) == -1)
+ return 0; // This should not happen!
+ else if (tss_adapter != 0)
+ // Extract the real TS object.
+ ts_obj = (TYPE *) tss_adapter->ts_obj_;
+#else
+ if (ACE_Thread::getspecific (this->key_,
+ (void **) &ts_obj) == -1)
+ return 0; // This should not happen!
+#endif /* ACE_HAS_THR_C_DEST */
+
+ return ts_obj;
+}
+
+template <class TYPE> TYPE *
+ACE_TSS<TYPE>::ts_object (TYPE *new_ts_obj)
+{
+ // Note, we shouldn't hold the keylock at this point because
+ // <ts_init> does it for us and we'll end up with deadlock
+ // otherwise...
+ if (this->once_ == 0)
+ // Create and initialize thread-specific ts_obj.
+ this->ts_init ();
+
+ // Ensure that we are serialized!
+ ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->keylock_, 0);
+
+ TYPE *ts_obj = 0;
+
+#if defined (ACE_HAS_THR_C_DEST)
+ ACE_TSS_Adapter *tss_adapter = 0;
+
+ if (ACE_Thread::getspecific (this->key_,
+ (void **) &tss_adapter) == -1)
+ return 0; // This should not happen!
+
+ if (tss_adapter != 0)
+ {
+ ts_obj = (TYPE *) tss_adapter->ts_obj_;
+ delete tss_adapter; // don't need this anymore
+ }
+
+ ACE_NEW_RETURN (tss_adapter,
+ ACE_TSS_Adapter ((void *) new_ts_obj,
+ ACE_TSS<TYPE>::cleanup),
+ 0);
+
+ if (ACE_Thread::setspecific (this->key_,
+ (void *) tss_adapter) == -1)
+ {
+ delete tss_adapter;
+ return ts_obj; // This should not happen!
+ }
+#else
+ if (ACE_Thread::getspecific (this->key_,
+ (void **) &ts_obj) == -1)
+ return 0; // This should not happen!
+ if (ACE_Thread::setspecific (this->key_,
+ (void *) new_ts_obj) == -1)
+ return ts_obj; // This should not happen!
+#endif /* ACE_HAS_THR_C_DEST */
+
+ return ts_obj;
+}
+
+ACE_ALLOC_HOOK_DEFINE(ACE_TSS_Guard)
+
+template <class ACE_LOCK> void
+ACE_TSS_Guard<ACE_LOCK>::dump (void) const
+{
+// ACE_TRACE ("ACE_TSS_Guard<ACE_LOCK>::dump");
+
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("key_ = %d"), this->key_));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\n")));
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+template <class ACE_LOCK> void
+ACE_TSS_Guard<ACE_LOCK>::init_key (void)
+{
+// ACE_TRACE ("ACE_TSS_Guard<ACE_LOCK>::init_key");
+
+ this->key_ = ACE_OS::NULL_key;
+ ACE_Thread::keycreate (&this->key_,
+#if defined (ACE_HAS_THR_C_DEST)
+ &ACE_TSS_C_cleanup,
+#else
+ &ACE_TSS_Guard<ACE_LOCK>::cleanup,
+#endif /* ACE_HAS_THR_C_DEST */
+ (void *) this);
+}
+
+template <class ACE_LOCK>
+ACE_TSS_Guard<ACE_LOCK>::ACE_TSS_Guard (void)
+{
+// ACE_TRACE ("ACE_TSS_Guard<ACE_LOCK>::ACE_TSS_Guard");
+ this->init_key ();
+}
+
+template <class ACE_LOCK> int
+ACE_TSS_Guard<ACE_LOCK>::release (void)
+{
+// ACE_TRACE ("ACE_TSS_Guard<ACE_LOCK>::release");
+
+ ACE_Guard<ACE_LOCK> *guard = 0;
+
+#if defined (ACE_HAS_THR_C_DEST)
+ ACE_TSS_Adapter *tss_adapter = 0;
+ ACE_Thread::getspecific (this->key_,
+ (void **) &tss_adapter);
+ guard = (ACE_Guard<ACE_LOCK> *)tss_adapter->ts_obj_;
+#else
+ ACE_Thread::getspecific (this->key_,
+ (void **) &guard);
+#endif /* ACE_HAS_THR_C_DEST */
+
+ return guard->release ();
+}
+
+template <class ACE_LOCK> int
+ACE_TSS_Guard<ACE_LOCK>::remove (void)
+{
+// ACE_TRACE ("ACE_TSS_Guard<ACE_LOCK>::remove");
+
+ ACE_Guard<ACE_LOCK> *guard = 0;
+
+#if defined (ACE_HAS_THR_C_DEST)
+ ACE_TSS_Adapter *tss_adapter = 0;
+ ACE_Thread::getspecific (this->key_,
+ (void **) &tss_adapter);
+ guard = (ACE_Guard<ACE_LOCK> *) tss_adapter->ts_obj_;
+#else
+ ACE_Thread::getspecific (this->key_,
+ (void **) &guard);
+#endif /* ACE_HAS_THR_C_DEST */
+
+ return guard->remove ();
+}
+
+template <class ACE_LOCK>
+ACE_TSS_Guard<ACE_LOCK>::~ACE_TSS_Guard (void)
+{
+// ACE_TRACE ("ACE_TSS_Guard<ACE_LOCK>::~ACE_TSS_Guard");
+
+ ACE_Guard<ACE_LOCK> *guard = 0;
+
+#if defined (ACE_HAS_THR_C_DEST)
+ ACE_TSS_Adapter *tss_adapter = 0;
+ ACE_Thread::getspecific (this->key_,
+ (void **) &tss_adapter);
+ guard = (ACE_Guard<ACE_LOCK> *) tss_adapter->ts_obj_;
+#else
+ ACE_Thread::getspecific (this->key_,
+ (void **) &guard);
+#endif /* ACE_HAS_THR_C_DEST */
+
+ // Make sure that this pointer is NULL when we shut down...
+ ACE_Thread::setspecific (this->key_, 0);
+ ACE_Thread::keyfree (this->key_);
+ // Destructor releases lock.
+ delete guard;
+}
+
+template <class ACE_LOCK> void
+ACE_TSS_Guard<ACE_LOCK>::cleanup (void *ptr)
+{
+// ACE_TRACE ("ACE_TSS_Guard<ACE_LOCK>::cleanup");
+
+ // Destructor releases lock.
+ delete (ACE_Guard<ACE_LOCK> *) ptr;
+}
+
+template <class ACE_LOCK>
+ACE_TSS_Guard<ACE_LOCK>::ACE_TSS_Guard (ACE_LOCK &lock, int block)
+{
+// ACE_TRACE ("ACE_TSS_Guard<ACE_LOCK>::ACE_TSS_Guard");
+
+ this->init_key ();
+ ACE_Guard<ACE_LOCK> *guard;
+ ACE_NEW (guard,
+ ACE_Guard<ACE_LOCK> (lock,
+ block));
+
+#if defined (ACE_HAS_THR_C_DEST)
+ ACE_TSS_Adapter *tss_adapter;
+ ACE_NEW (tss_adapter,
+ ACE_TSS_Adapter ((void *) guard,
+ ACE_TSS_Guard<ACE_LOCK>::cleanup));
+ ACE_Thread::setspecific (this->key_,
+ (void *) tss_adapter);
+#else
+ ACE_Thread::setspecific (this->key_,
+ (void *) guard);
+#endif /* ACE_HAS_THR_C_DEST */
+}
+
+template <class ACE_LOCK> int
+ACE_TSS_Guard<ACE_LOCK>::acquire (void)
+{
+// ACE_TRACE ("ACE_TSS_Guard<ACE_LOCK>::acquire");
+
+ ACE_Guard<ACE_LOCK> *guard = 0;
+
+#if defined (ACE_HAS_THR_C_DEST)
+ ACE_TSS_Adapter *tss_adapter = 0;
+ ACE_Thread::getspecific (this->key_,
+ (void **) &tss_adapter);
+ guard = (ACE_Guard<ACE_LOCK> *) tss_adapter->ts_obj_;
+#else
+ ACE_Thread::getspecific (this->key_,
+ (void **) &guard);
+#endif /* ACE_HAS_THR_C_DEST */
+
+ return guard->acquire ();
+}
+
+template <class ACE_LOCK> int
+ACE_TSS_Guard<ACE_LOCK>::tryacquire (void)
+{
+// ACE_TRACE ("ACE_TSS_Guard<ACE_LOCK>::tryacquire");
+
+ ACE_Guard<ACE_LOCK> *guard = 0;
+
+#if defined (ACE_HAS_THR_C_DEST)
+ ACE_TSS_Adapter *tss_adapter = 0;
+ ACE_Thread::getspecific (this->key_,
+ (void **) &tss_adapter);
+ guard = (ACE_Guard<ACE_LOCK> *) tss_adapter->ts_obj_;
+#else
+ ACE_Thread::getspecific (this->key_,
+ (void **) &guard);
+#endif /* ACE_HAS_THR_C_DEST */
+
+ return guard->tryacquire ();
+}
+
+template <class ACE_LOCK>
+ACE_TSS_Write_Guard<ACE_LOCK>::ACE_TSS_Write_Guard (ACE_LOCK &lock,
+ int block)
+{
+// ACE_TRACE ("ACE_TSS_Write_Guard<ACE_LOCK>::ACE_TSS_Write_Guard");
+
+ this->init_key ();
+ ACE_Guard<ACE_LOCK> *guard;
+ ACE_NEW (guard,
+ ACE_Write_Guard<ACE_LOCK> (lock,
+ block));
+
+#if defined (ACE_HAS_THR_C_DEST)
+ ACE_TSS_Adapter *tss_adapter;
+ ACE_NEW (tss_adapter,
+ ACE_TSS_Adapter ((void *) guard,
+ ACE_TSS_Guard<ACE_LOCK>::cleanup));
+ ACE_Thread::setspecific (this->key_,
+ (void *) tss_adapter);
+#else
+ ACE_Thread::setspecific (this->key_,
+ (void *) guard);
+#endif /* ACE_HAS_THR_C_DEST */
+}
+
+template <class ACE_LOCK> int
+ACE_TSS_Write_Guard<ACE_LOCK>::acquire (void)
+{
+// ACE_TRACE ("ACE_TSS_Write_Guard<ACE_LOCK>::acquire");
+
+ ACE_Write_Guard<ACE_LOCK> *guard = 0;
+
+#if defined (ACE_HAS_THR_C_DEST)
+ ACE_TSS_Adapter *tss_adapter = 0;
+ ACE_Thread::getspecific (this->key_,
+ (void **) &tss_adapter);
+ guard = (ACE_Guard<ACE_LOCK> *) tss_adapter->ts_obj_;
+#else
+ ACE_Thread::getspecific (this->key_,
+ (void **) &guard);
+#endif /* ACE_HAS_THR_C_DEST */
+
+ return guard->acquire_write ();
+}
+
+template <class ACE_LOCK> int
+ACE_TSS_Write_Guard<ACE_LOCK>::tryacquire (void)
+{
+// ACE_TRACE ("ACE_TSS_Write_Guard<ACE_LOCK>::tryacquire");
+
+ ACE_Write_Guard<ACE_LOCK> *guard = 0;
+
+#if defined (ACE_HAS_THR_C_DEST)
+ ACE_TSS_Adapter *tss_adapter = 0;
+ ACE_Thread::getspecific (this->key_,
+ (void **) &tss_adapter);
+ guard = (ACE_Guard<ACE_LOCK> *) tss_adapter->ts_obj_;
+#else
+ ACE_Thread::getspecific (this->key_,
+ (void **) &guard);
+#endif /* ACE_HAS_THR_C_DEST */
+
+ return guard->tryacquire_write ();
+}
+
+template <class ACE_LOCK> int
+ACE_TSS_Write_Guard<ACE_LOCK>::acquire_write (void)
+{
+// ACE_TRACE ("ACE_TSS_Write_Guard<ACE_LOCK>::acquire_write");
+
+ return this->acquire ();
+}
+
+template <class ACE_LOCK> int
+ACE_TSS_Write_Guard<ACE_LOCK>::tryacquire_write (void)
+{
+// ACE_TRACE ("ACE_TSS_Write_Guard<ACE_LOCK>::tryacquire_write");
+
+ return this->tryacquire ();
+}
+
+template <class ACE_LOCK> void
+ACE_TSS_Write_Guard<ACE_LOCK>::dump (void) const
+{
+// ACE_TRACE ("ACE_TSS_Write_Guard<ACE_LOCK>::dump");
+ ACE_TSS_Guard<ACE_LOCK>::dump ();
+}
+
+template <class ACE_LOCK>
+ACE_TSS_Read_Guard<ACE_LOCK>::ACE_TSS_Read_Guard (ACE_LOCK &lock, int block)
+{
+// ACE_TRACE ("ACE_TSS_Read_Guard<ACE_LOCK>::ACE_TSS_Read_Guard");
+
+ this->init_key ();
+ ACE_Guard<ACE_LOCK> *guard;
+ ACE_NEW (guard,
+ ACE_Read_Guard<ACE_LOCK> (lock,
+ block));
+#if defined (ACE_HAS_THR_C_DEST)
+ ACE_TSS_Adapter *tss_adapter;
+ ACE_NEW (tss_adapter,
+ ACE_TSS_Adapter ((void *)guard,
+ ACE_TSS_Guard<ACE_LOCK>::cleanup));
+ ACE_Thread::setspecific (this->key_,
+ (void *) tss_adapter);
+#else
+ ACE_Thread::setspecific (this->key_,
+ (void *) guard);
+#endif /* ACE_HAS_THR_C_DEST */
+}
+
+template <class ACE_LOCK> int
+ACE_TSS_Read_Guard<ACE_LOCK>::acquire (void)
+{
+// ACE_TRACE ("ACE_TSS_Read_Guard<ACE_LOCK>::acquire");
+
+ ACE_Read_Guard<ACE_LOCK> *guard = 0;
+
+#if defined (ACE_HAS_THR_C_DEST)
+ ACE_TSS_Adapter *tss_adapter = 0;
+ ACE_Thread::getspecific (this->key_,
+ (void **) &tss_adapter);
+ guard = (ACE_Guard<ACE_LOCK> *) tss_adapter->ts_obj_;
+#else
+ ACE_Thread::getspecific (this->key_,
+ (void **) &guard);
+#endif /* ACE_HAS_THR_C_DEST */
+
+ return guard->acquire_read ();
+}
+
+template <class ACE_LOCK> int
+ACE_TSS_Read_Guard<ACE_LOCK>::tryacquire (void)
+{
+// ACE_TRACE ("ACE_TSS_Read_Guard<ACE_LOCK>::tryacquire");
+
+ ACE_Read_Guard<ACE_LOCK> *guard = 0;
+
+#if defined (ACE_HAS_THR_C_DEST)
+ ACE_TSS_Adapter *tss_adapter = 0;
+ ACE_Thread::getspecific (this->key_,
+ (void **) &tss_adapter);
+ guard = (ACE_Guard<ACE_LOCK> *) tss_adapter->ts_obj_;
+#else
+ ACE_Thread::getspecific (this->key_,
+ (void **) &guard);
+#endif /* ACE_HAS_THR_C_DEST */
+
+ return guard->tryacquire_read ();
+}
+
+template <class ACE_LOCK> int
+ACE_TSS_Read_Guard<ACE_LOCK>::acquire_read (void)
+{
+// ACE_TRACE ("ACE_TSS_Read_Guard<ACE_LOCK>::acquire_read");
+
+ return this->acquire ();
+}
+
+template <class ACE_LOCK> int
+ACE_TSS_Read_Guard<ACE_LOCK>::tryacquire_read (void)
+{
+// ACE_TRACE ("ACE_TSS_Read_Guard<ACE_LOCK>::tryacquire_read");
+
+ return this->tryacquire ();
+}
+
+template <class ACE_LOCK> void
+ACE_TSS_Read_Guard<ACE_LOCK>::dump (void) const
+{
+// ACE_TRACE ("ACE_TSS_Read_Guard<ACE_LOCK>::dump");
+ ACE_TSS_Guard<ACE_LOCK>::dump ();
+}
+
+
+#endif /* defined (ACE_HAS_THREADS) && (defined (ACE_HAS_THREAD_SPECIFIC_STORAGE) || defined (ACE_HAS_TSS_EMULATION)) */
+
+#endif /* ACE_SYNCH_T_C */
diff --git a/ace/Threads/Synch_T.cpp~ b/ace/Threads/Synch_T.cpp~
new file mode 100644
index 00000000000..2ec9d59acce
--- /dev/null
+++ b/ace/Threads/Synch_T.cpp~
@@ -0,0 +1,895 @@
+// $Id$
+
+
+#ifndef ACE_SYNCH_T_C
+#define ACE_SYNCH_T_C
+
+#include "ace/Thread.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "ace/Synch_T.h"
+#include "ace/Log_Msg.h"
+
+ACE_RCSID(ace, Synch_T, "$Id$")
+
+#if !defined (__ACE_INLINE__)
+#include "ace/Synch_T.i"
+#endif /* __ACE_INLINE__ */
+
+
+
+// This constructor isn't inlined, because SunPRO C++ 4.2 + patch
+// 104631-07 has trouble compiling TAO with it inline.
+template <class ACE_LOCKING_MECHANISM>
+ACE_Lock_Adapter<ACE_LOCKING_MECHANISM>::ACE_Lock_Adapter (void)
+ : lock_ (0),
+ delete_lock_ (1)
+{
+ ACE_NEW (this->lock_,
+ ACE_LOCKING_MECHANISM);
+}
+
+template <class ACE_LOCKING_MECHANISM>
+ACE_Reverse_Lock<ACE_LOCKING_MECHANISM>::~ACE_Reverse_Lock (void)
+{
+}
+// ****************************************************************
+// ACE_ALLOC_HOOK_DEFINE(ACE_Guard)
+
+template <class ACE_LOCK> void
+ACE_Guard<ACE_LOCK>::dump (void) const
+{
+// ACE_TRACE ("ACE_Guard<ACE_LOCK>::dump");
+
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("mutex_ = %x\n"), this->lock_));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("owner_ = %d\n"), this->owner_));
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+// ACE_ALLOC_HOOK_DEFINE(ACE_Write_Guard)
+
+template <class ACE_LOCK> void
+ACE_Write_Guard<ACE_LOCK>::dump (void) const
+{
+// ACE_TRACE ("ACE_Write_Guard<ACE_LOCK>::dump");
+ ACE_Guard<ACE_LOCK>::dump ();
+}
+
+// ACE_ALLOC_HOOK_DEFINE(ACE_Read_Guard)
+
+template <class ACE_LOCK> void
+ACE_Read_Guard<ACE_LOCK>::dump (void) const
+{
+// ACE_TRACE ("ACE_Read_Guard<ACE_LOCK>::dump");
+ ACE_Guard<ACE_LOCK>::dump ();
+}
+
+#if defined (ACE_HAS_THREADS)
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Condition)
+
+template <class MUTEX> void
+ACE_Condition<MUTEX>::dump (void) const
+{
+// ACE_TRACE ("ACE_Condition<MUTEX>::dump");
+
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+#if defined (CHORUS)
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("condname_ = %s\n"), this->condname_));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("process_cond_ = %x\n"), this->process_cond_));
+#endif /* CHORUS */
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\n")));
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+template <class MUTEX>
+ACE_Thread_Condition<MUTEX>::ACE_Thread_Condition (MUTEX &m,
+ const ACE_TCHAR *name,
+ void *arg)
+ : ACE_Condition<MUTEX> (m, USYNC_THREAD, name, arg)
+{
+// ACE_TRACE ("ACE_Thread_Condition<MUTEX>::ACE_Thread_Condition");
+}
+
+template <class MUTEX> void
+ACE_Thread_Condition<MUTEX>::dump (void) const
+{
+// ACE_TRACE ("ACE_Thread_Condition<MUTEX>::dump");
+
+ ACE_Condition<MUTEX>::dump ();
+}
+
+template <class MUTEX>
+ACE_Condition<MUTEX>::ACE_Condition (MUTEX &m,
+ int type,
+ const ACE_TCHAR *name,
+ void *arg)
+ :
+#if defined (CHORUS)
+ process_cond_(0),
+ condname_ (0),
+#endif /* CHORUS */
+ mutex_ (m)
+{
+
+#if defined(CHORUS)
+ if (type == USYNC_PROCESS)
+ {
+ // Let's see if the shared memory entity already exists.
+ ACE_HANDLE fd = ACE_OS::shm_open (name,
+ O_RDWR | O_CREAT | O_EXCL,
+ ACE_DEFAULT_FILE_PERMS);
+ if (fd == ACE_INVALID_HANDLE)
+ {
+ if (errno == EEXIST)
+ fd = ACE_OS::shm_open (name,
+ O_RDWR | O_CREAT,
+ ACE_DEFAULT_FILE_PERMS);
+ else
+ return;
+ }
+ else
+ {
+ // We own this shared memory object! Let's set its size.
+ if (ACE_OS::ftruncate (fd,
+ sizeof (ACE_mutex_t)) == -1)
+ {
+ ACE_OS::close (fd);
+ return;
+ }
+ this->condname_ = ACE_OS::strdup (name);
+ if (this->condname_ == 0)
+ {
+ ACE_OS::close (fd);
+ return;
+ }
+ }
+
+ this->process_cond_ =
+ (ACE_cond_t *) ACE_OS::mmap (0,
+ sizeof (ACE_cond_t),
+ PROT_RDWR,
+ MAP_SHARED,
+ fd,
+ 0);
+ ACE_OS::close (fd);
+ if (this->process_cond_ == MAP_FAILED)
+ return;
+
+ if (this->condname_
+ && ACE_OS::cond_init (this->process_cond_,
+ type,
+ name,
+ arg) != 0)
+ return;
+ }
+ // It is ok to fall through into the <cond_init> below if the
+ // USYNC_PROCESS flag is not enabled.
+#endif /* CHORUS */
+
+ // ACE_TRACE ("ACE_Condition<MUTEX>::ACE_Condition");
+
+ if (ACE_OS::cond_init (&this->cond_,
+ (short) type,
+ name,
+ arg) != 0)
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("%p\n"),
+ ACE_LIB_TEXT ("ACE_Condition::ACE_Condition")));
+}
+
+template <class MUTEX>
+ACE_Condition<MUTEX>::~ACE_Condition (void)
+{
+ // ACE_TRACE ("ACE_Condition<MUTEX>::~ACE_Condition");
+
+ if (this->remove () == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("%p\n"),
+ ACE_LIB_TEXT ("ACE_Condition::~ACE_Condition")));
+}
+
+template <class MUTEX> int
+ACE_Condition<MUTEX>::wait (void)
+{
+ // ACE_TRACE ("ACE_Condition<MUTEX>::wait");
+#if defined (CHORUS)
+ if (this->process_cond_ != 0)
+ return ACE_OS::cond_wait (this->process_cond_,
+ &this->mutex_.lock_);
+#endif /* CHORUS */
+ return ACE_OS::cond_wait (&this->cond_,
+ &this->mutex_.lock_);
+}
+
+template <class MUTEX> int
+ACE_Condition<MUTEX>::wait (MUTEX &mutex,
+ const ACE_Time_Value *abstime)
+{
+// ACE_TRACE ("ACE_Condition<MUTEX>::wait");
+ if (abstime == 0)
+ return this->wait ();
+ else
+ {
+#if defined (CHORUS)
+ if (this->process_cond_ != 0)
+ return ACE_OS::cond_timedwait (this->process_cond_,
+ &mutex_.lock_,
+ (ACE_Time_Value *) abstime);
+#endif /* CHORUS */
+ return ACE_OS::cond_timedwait (&this->cond_,
+ &mutex.lock_,
+ (ACE_Time_Value *) abstime);
+ }
+}
+
+// Peform an "alertable" timed wait. If the argument ABSTIME == 0
+// then we do a regular cond_wait(), else we do a timed wait for up to
+// ABSTIME using the Solaris cond_timedwait() function.
+
+template <class MUTEX> int
+ACE_Condition<MUTEX>::wait (const ACE_Time_Value *abstime)
+{
+// ACE_TRACE ("ACE_Condition<MUTEX>::wait");
+ return this->wait (this->mutex_, abstime);
+}
+#endif /* ACE_HAS_THREADS */
+
+ACE_ALLOC_HOOK_DEFINE(ACE_TSS)
+
+template <class TYPE>
+ACE_TSS<TYPE>::~ACE_TSS (void)
+{
+ // We can't call <ACE_OS::thr_keyfree> until *all* of the threads
+ // that are using that key have done an <ACE_OS::thr_key_detach>.
+ // Otherwise, we'll end up with "dangling TSS pointers."
+ ACE_OS::thr_key_detach (this);
+}
+
+template <class TYPE> TYPE *
+ACE_TSS<TYPE>::operator-> () const
+{
+ return this->ts_get ();
+}
+
+template <class TYPE>
+ACE_TSS<TYPE>::operator TYPE *(void) const
+{
+ return this->ts_get ();
+}
+
+template <class TYPE> TYPE *
+ACE_TSS<TYPE>::make_TSS_TYPE (void) const
+{
+ TYPE *temp = 0;
+ ACE_NEW_RETURN (temp,
+ TYPE,
+ 0);
+ return temp;
+}
+
+template <class TYPE> void
+ACE_TSS<TYPE>::dump (void) const
+{
+// ACE_TRACE ("ACE_TSS<TYPE>::dump");
+#if defined (ACE_HAS_THREADS) && (defined (ACE_HAS_THREAD_SPECIFIC_STORAGE) || defined (ACE_HAS_TSS_EMULATION))
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+ this->keylock_.dump ();
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("key_ = %d\n"), this->key_));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\nonce_ = %d"), this->once_));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\n")));
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+#endif /* defined (ACE_HAS_THREADS) && (defined (ACE_HAS_THREAD_SPECIFIC_STORAGE) || defined (ACE_HAS_TSS_EMULATION)) */
+}
+
+#if defined (ACE_HAS_THREADS) && (defined (ACE_HAS_THREAD_SPECIFIC_STORAGE) || defined (ACE_HAS_TSS_EMULATION))
+#if defined (ACE_HAS_THR_C_DEST)
+extern "C" void ACE_TSS_C_cleanup(void *); // defined in Synch.cpp
+#endif /* ACE_HAS_THR_C_DEST */
+
+template <class TYPE> void
+ACE_TSS<TYPE>::cleanup (void *ptr)
+{
+ // Cast this to the concrete TYPE * so the destructor gets called.
+ delete (TYPE *) ptr;
+}
+
+template <class TYPE> int
+ACE_TSS<TYPE>::ts_init (void) const
+{
+ // Insure that we are serialized!
+ ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, (ACE_Thread_Mutex &) this->keylock_, 0);
+
+ // Use the Double-Check pattern to make sure we only create the key
+ // once!
+ if (this->once_ == 0)
+ {
+ if (ACE_Thread::keycreate (ACE_const_cast (ACE_thread_key_t *, &this->key_),
+#if defined (ACE_HAS_THR_C_DEST)
+ &ACE_TSS_C_cleanup,
+#else
+ &ACE_TSS<TYPE>::cleanup,
+#endif /* ACE_HAS_THR_C_DEST */
+ (void *) this) != 0)
+ return -1; // Major problems, this should *never* happen!
+ else
+ {
+ // This *must* come last to avoid race conditions! Note that
+ // we need to "cast away const..."
+ * ACE_const_cast (int*, &this->once_) = 1;
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+template <class TYPE>
+ACE_TSS<TYPE>::ACE_TSS (TYPE *ts_obj)
+ : once_ (0),
+ key_ (ACE_OS::NULL_key)
+{
+ // If caller has passed us a non-NULL TYPE *, then we'll just use
+ // this to initialize the thread-specific value. Thus, subsequent
+ // calls to operator->() will return this value. This is useful
+ // since it enables us to assign objects to thread-specific data
+ // that have arbitrarily complex constructors!
+
+ if (ts_obj != 0)
+ {
+ if (this->ts_init () == -1)
+ {
+ // Save/restore errno.
+ ACE_Errno_Guard error (errno);
+ // What should we do if this call fails?!
+#if defined (ACE_HAS_WINCE)
+ ::MessageBox (NULL,
+ L"ACE_Thread::keycreate() failed!",
+ L"ACE_TSS::ACE_TSS",
+ MB_OK);
+#else
+ ACE_OS::fprintf (stderr,
+ "ACE_Thread::keycreate() failed!");
+#endif /* ACE_HAS_WINCE */
+ return;
+ }
+
+#if defined (ACE_HAS_THR_C_DEST)
+ // Encapsulate a ts_obj and it's destructor in an
+ // ACE_TSS_Adapter.
+ ACE_TSS_Adapter *tss_adapter;
+ ACE_NEW (tss_adapter,
+ ACE_TSS_Adapter ((void *) ts_obj,
+ ACE_TSS<TYPE>::cleanup));
+
+ // Put the adapter in thread specific storage
+ if (ACE_Thread::setspecific (this->key_,
+ (void *) tss_adapter) != 0)
+ {
+ delete tss_adapter;
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("%p\n"),
+ ACE_LIB_TEXT ("ACE_Thread::setspecific() failed!")));
+ }
+#else
+ if (ACE_Thread::setspecific (this->key_,
+ (void *) ts_obj) != 0)
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("%p\n"),
+ ACE_LIB_TEXT ("ACE_Thread::setspecific() failed!")));
+#endif /* ACE_HAS_THR_C_DEST */
+ }
+}
+
+template <class TYPE> TYPE *
+ACE_TSS<TYPE>::ts_get (void) const
+{
+ if (this->once_ == 0)
+ // Create and initialize thread-specific ts_obj.
+ this->ts_init ();
+
+ TYPE *ts_obj = 0;
+
+#if defined (ACE_HAS_THR_C_DEST)
+ ACE_TSS_Adapter *tss_adapter = 0;
+
+ // Get the adapter from thread-specific storage
+ if (ACE_Thread::getspecific (this->key_,
+ (void **) &tss_adapter) == -1)
+ return 0; // This should not happen!
+
+ // Check to see if this is the first time in for this thread.
+ if (tss_adapter == 0)
+#else
+ // Get the ts_obj from thread-specific storage. Note that no locks
+ // are required here...
+ if (ACE_Thread::getspecific (this->key_,
+ (void **) &ts_obj) == -1)
+ return 0; // This should not happen!
+
+ // Check to see if this is the first time in for this thread.
+ if (ts_obj == 0)
+#endif /* ACE_HAS_THR_C_DEST */
+ {
+ // Allocate memory off the heap and store it in a pointer in
+ // thread-specific storage (on the stack...).
+
+ ts_obj = this->make_TSS_TYPE ();
+
+ if (ts_obj == 0)
+ return 0;
+
+#if defined (ACE_HAS_THR_C_DEST)
+ // Encapsulate a ts_obj and it's destructor in an
+ // ACE_TSS_Adapter.
+ ACE_NEW_RETURN (tss_adapter,
+ ACE_TSS_Adapter (ts_obj,
+ ACE_TSS<TYPE>::cleanup), 0);
+
+ // Put the adapter in thread specific storage
+ if (ACE_Thread::setspecific (this->key_,
+ (void *) tss_adapter) != 0)
+ {
+ delete tss_adapter;
+ delete ts_obj;
+ return 0; // Major problems, this should *never* happen!
+ }
+#else
+ // Store the dynamically allocated pointer in thread-specific
+ // storage.
+ if (ACE_Thread::setspecific (this->key_,
+ (void *) ts_obj) != 0)
+ {
+ delete ts_obj;
+ return 0; // Major problems, this should *never* happen!
+ }
+#endif /* ACE_HAS_THR_C_DEST */
+ }
+
+#if defined (ACE_HAS_THR_C_DEST)
+ // Return the underlying ts object.
+ return (TYPE *) tss_adapter->ts_obj_;
+#else
+ return ts_obj;
+#endif /* ACE_HAS_THR_C_DEST */
+}
+
+// Get the thread-specific object for the key associated with this
+// object. Returns 0 if the ts_obj has never been initialized,
+// otherwise returns a pointer to the ts_obj.
+
+template <class TYPE> TYPE *
+ACE_TSS<TYPE>::ts_object (void) const
+{
+ // Ensure that we are serialized!
+ ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, (ACE_Thread_Mutex &) this->keylock_, 0);
+
+ if (this->once_ == 0) // Return 0 if we've never been initialized.
+ return 0;
+
+ TYPE *ts_obj = 0;
+
+#if defined (ACE_HAS_THR_C_DEST)
+ ACE_TSS_Adapter *tss_adapter = 0;
+
+ // Get the tss adapter from thread-specific storage
+ if (ACE_Thread::getspecific (this->key_,
+ (void **) &tss_adapter) == -1)
+ return 0; // This should not happen!
+ else if (tss_adapter != 0)
+ // Extract the real TS object.
+ ts_obj = (TYPE *) tss_adapter->ts_obj_;
+#else
+ if (ACE_Thread::getspecific (this->key_,
+ (void **) &ts_obj) == -1)
+ return 0; // This should not happen!
+#endif /* ACE_HAS_THR_C_DEST */
+
+ return ts_obj;
+}
+
+template <class TYPE> TYPE *
+ACE_TSS<TYPE>::ts_object (TYPE *new_ts_obj)
+{
+ // Note, we shouldn't hold the keylock at this point because
+ // <ts_init> does it for us and we'll end up with deadlock
+ // otherwise...
+ if (this->once_ == 0)
+ // Create and initialize thread-specific ts_obj.
+ this->ts_init ();
+
+ // Ensure that we are serialized!
+ ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->keylock_, 0);
+
+ TYPE *ts_obj = 0;
+
+#if defined (ACE_HAS_THR_C_DEST)
+ ACE_TSS_Adapter *tss_adapter = 0;
+
+ if (ACE_Thread::getspecific (this->key_,
+ (void **) &tss_adapter) == -1)
+ return 0; // This should not happen!
+
+ if (tss_adapter != 0)
+ {
+ ts_obj = (TYPE *) tss_adapter->ts_obj_;
+ delete tss_adapter; // don't need this anymore
+ }
+
+ ACE_NEW_RETURN (tss_adapter,
+ ACE_TSS_Adapter ((void *) new_ts_obj,
+ ACE_TSS<TYPE>::cleanup),
+ 0);
+
+ if (ACE_Thread::setspecific (this->key_,
+ (void *) tss_adapter) == -1)
+ {
+ delete tss_adapter;
+ return ts_obj; // This should not happen!
+ }
+#else
+ if (ACE_Thread::getspecific (this->key_,
+ (void **) &ts_obj) == -1)
+ return 0; // This should not happen!
+ if (ACE_Thread::setspecific (this->key_,
+ (void *) new_ts_obj) == -1)
+ return ts_obj; // This should not happen!
+#endif /* ACE_HAS_THR_C_DEST */
+
+ return ts_obj;
+}
+
+ACE_ALLOC_HOOK_DEFINE(ACE_TSS_Guard)
+
+template <class ACE_LOCK> void
+ACE_TSS_Guard<ACE_LOCK>::dump (void) const
+{
+// ACE_TRACE ("ACE_TSS_Guard<ACE_LOCK>::dump");
+
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("key_ = %d"), this->key_));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\n")));
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+template <class ACE_LOCK> void
+ACE_TSS_Guard<ACE_LOCK>::init_key (void)
+{
+// ACE_TRACE ("ACE_TSS_Guard<ACE_LOCK>::init_key");
+
+ this->key_ = ACE_OS::NULL_key;
+ ACE_Thread::keycreate (&this->key_,
+#if defined (ACE_HAS_THR_C_DEST)
+ &ACE_TSS_C_cleanup,
+#else
+ &ACE_TSS_Guard<ACE_LOCK>::cleanup,
+#endif /* ACE_HAS_THR_C_DEST */
+ (void *) this);
+}
+
+template <class ACE_LOCK>
+ACE_TSS_Guard<ACE_LOCK>::ACE_TSS_Guard (void)
+{
+// ACE_TRACE ("ACE_TSS_Guard<ACE_LOCK>::ACE_TSS_Guard");
+ this->init_key ();
+}
+
+template <class ACE_LOCK> int
+ACE_TSS_Guard<ACE_LOCK>::release (void)
+{
+// ACE_TRACE ("ACE_TSS_Guard<ACE_LOCK>::release");
+
+ ACE_Guard<ACE_LOCK> *guard = 0;
+
+#if defined (ACE_HAS_THR_C_DEST)
+ ACE_TSS_Adapter *tss_adapter = 0;
+ ACE_Thread::getspecific (this->key_,
+ (void **) &tss_adapter);
+ guard = (ACE_Guard<ACE_LOCK> *)tss_adapter->ts_obj_;
+#else
+ ACE_Thread::getspecific (this->key_,
+ (void **) &guard);
+#endif /* ACE_HAS_THR_C_DEST */
+
+ return guard->release ();
+}
+
+template <class ACE_LOCK> int
+ACE_TSS_Guard<ACE_LOCK>::remove (void)
+{
+// ACE_TRACE ("ACE_TSS_Guard<ACE_LOCK>::remove");
+
+ ACE_Guard<ACE_LOCK> *guard = 0;
+
+#if defined (ACE_HAS_THR_C_DEST)
+ ACE_TSS_Adapter *tss_adapter = 0;
+ ACE_Thread::getspecific (this->key_,
+ (void **) &tss_adapter);
+ guard = (ACE_Guard<ACE_LOCK> *) tss_adapter->ts_obj_;
+#else
+ ACE_Thread::getspecific (this->key_,
+ (void **) &guard);
+#endif /* ACE_HAS_THR_C_DEST */
+
+ return guard->remove ();
+}
+
+template <class ACE_LOCK>
+ACE_TSS_Guard<ACE_LOCK>::~ACE_TSS_Guard (void)
+{
+// ACE_TRACE ("ACE_TSS_Guard<ACE_LOCK>::~ACE_TSS_Guard");
+
+ ACE_Guard<ACE_LOCK> *guard = 0;
+
+#if defined (ACE_HAS_THR_C_DEST)
+ ACE_TSS_Adapter *tss_adapter = 0;
+ ACE_Thread::getspecific (this->key_,
+ (void **) &tss_adapter);
+ guard = (ACE_Guard<ACE_LOCK> *) tss_adapter->ts_obj_;
+#else
+ ACE_Thread::getspecific (this->key_,
+ (void **) &guard);
+#endif /* ACE_HAS_THR_C_DEST */
+
+ // Make sure that this pointer is NULL when we shut down...
+ ACE_Thread::setspecific (this->key_, 0);
+ ACE_Thread::keyfree (this->key_);
+ // Destructor releases lock.
+ delete guard;
+}
+
+template <class ACE_LOCK> void
+ACE_TSS_Guard<ACE_LOCK>::cleanup (void *ptr)
+{
+// ACE_TRACE ("ACE_TSS_Guard<ACE_LOCK>::cleanup");
+
+ // Destructor releases lock.
+ delete (ACE_Guard<ACE_LOCK> *) ptr;
+}
+
+template <class ACE_LOCK>
+ACE_TSS_Guard<ACE_LOCK>::ACE_TSS_Guard (ACE_LOCK &lock, int block)
+{
+// ACE_TRACE ("ACE_TSS_Guard<ACE_LOCK>::ACE_TSS_Guard");
+
+ this->init_key ();
+ ACE_Guard<ACE_LOCK> *guard;
+ ACE_NEW (guard,
+ ACE_Guard<ACE_LOCK> (lock,
+ block));
+
+#if defined (ACE_HAS_THR_C_DEST)
+ ACE_TSS_Adapter *tss_adapter;
+ ACE_NEW (tss_adapter,
+ ACE_TSS_Adapter ((void *) guard,
+ ACE_TSS_Guard<ACE_LOCK>::cleanup));
+ ACE_Thread::setspecific (this->key_,
+ (void *) tss_adapter);
+#else
+ ACE_Thread::setspecific (this->key_,
+ (void *) guard);
+#endif /* ACE_HAS_THR_C_DEST */
+}
+
+template <class ACE_LOCK> int
+ACE_TSS_Guard<ACE_LOCK>::acquire (void)
+{
+// ACE_TRACE ("ACE_TSS_Guard<ACE_LOCK>::acquire");
+
+ ACE_Guard<ACE_LOCK> *guard = 0;
+
+#if defined (ACE_HAS_THR_C_DEST)
+ ACE_TSS_Adapter *tss_adapter = 0;
+ ACE_Thread::getspecific (this->key_,
+ (void **) &tss_adapter);
+ guard = (ACE_Guard<ACE_LOCK> *) tss_adapter->ts_obj_;
+#else
+ ACE_Thread::getspecific (this->key_,
+ (void **) &guard);
+#endif /* ACE_HAS_THR_C_DEST */
+
+ return guard->acquire ();
+}
+
+template <class ACE_LOCK> int
+ACE_TSS_Guard<ACE_LOCK>::tryacquire (void)
+{
+// ACE_TRACE ("ACE_TSS_Guard<ACE_LOCK>::tryacquire");
+
+ ACE_Guard<ACE_LOCK> *guard = 0;
+
+#if defined (ACE_HAS_THR_C_DEST)
+ ACE_TSS_Adapter *tss_adapter = 0;
+ ACE_Thread::getspecific (this->key_,
+ (void **) &tss_adapter);
+ guard = (ACE_Guard<ACE_LOCK> *) tss_adapter->ts_obj_;
+#else
+ ACE_Thread::getspecific (this->key_,
+ (void **) &guard);
+#endif /* ACE_HAS_THR_C_DEST */
+
+ return guard->tryacquire ();
+}
+
+template <class ACE_LOCK>
+ACE_TSS_Write_Guard<ACE_LOCK>::ACE_TSS_Write_Guard (ACE_LOCK &lock,
+ int block)
+{
+// ACE_TRACE ("ACE_TSS_Write_Guard<ACE_LOCK>::ACE_TSS_Write_Guard");
+
+ this->init_key ();
+ ACE_Guard<ACE_LOCK> *guard;
+ ACE_NEW (guard,
+ ACE_Write_Guard<ACE_LOCK> (lock,
+ block));
+
+#if defined (ACE_HAS_THR_C_DEST)
+ ACE_TSS_Adapter *tss_adapter;
+ ACE_NEW (tss_adapter,
+ ACE_TSS_Adapter ((void *) guard,
+ ACE_TSS_Guard<ACE_LOCK>::cleanup));
+ ACE_Thread::setspecific (this->key_,
+ (void *) tss_adapter);
+#else
+ ACE_Thread::setspecific (this->key_,
+ (void *) guard);
+#endif /* ACE_HAS_THR_C_DEST */
+}
+
+template <class ACE_LOCK> int
+ACE_TSS_Write_Guard<ACE_LOCK>::acquire (void)
+{
+// ACE_TRACE ("ACE_TSS_Write_Guard<ACE_LOCK>::acquire");
+
+ ACE_Write_Guard<ACE_LOCK> *guard = 0;
+
+#if defined (ACE_HAS_THR_C_DEST)
+ ACE_TSS_Adapter *tss_adapter = 0;
+ ACE_Thread::getspecific (this->key_,
+ (void **) &tss_adapter);
+ guard = (ACE_Guard<ACE_LOCK> *) tss_adapter->ts_obj_;
+#else
+ ACE_Thread::getspecific (this->key_,
+ (void **) &guard);
+#endif /* ACE_HAS_THR_C_DEST */
+
+ return guard->acquire_write ();
+}
+
+template <class ACE_LOCK> int
+ACE_TSS_Write_Guard<ACE_LOCK>::tryacquire (void)
+{
+// ACE_TRACE ("ACE_TSS_Write_Guard<ACE_LOCK>::tryacquire");
+
+ ACE_Write_Guard<ACE_LOCK> *guard = 0;
+
+#if defined (ACE_HAS_THR_C_DEST)
+ ACE_TSS_Adapter *tss_adapter = 0;
+ ACE_Thread::getspecific (this->key_,
+ (void **) &tss_adapter);
+ guard = (ACE_Guard<ACE_LOCK> *) tss_adapter->ts_obj_;
+#else
+ ACE_Thread::getspecific (this->key_,
+ (void **) &guard);
+#endif /* ACE_HAS_THR_C_DEST */
+
+ return guard->tryacquire_write ();
+}
+
+template <class ACE_LOCK> int
+ACE_TSS_Write_Guard<ACE_LOCK>::acquire_write (void)
+{
+// ACE_TRACE ("ACE_TSS_Write_Guard<ACE_LOCK>::acquire_write");
+
+ return this->acquire ();
+}
+
+template <class ACE_LOCK> int
+ACE_TSS_Write_Guard<ACE_LOCK>::tryacquire_write (void)
+{
+// ACE_TRACE ("ACE_TSS_Write_Guard<ACE_LOCK>::tryacquire_write");
+
+ return this->tryacquire ();
+}
+
+template <class ACE_LOCK> void
+ACE_TSS_Write_Guard<ACE_LOCK>::dump (void) const
+{
+// ACE_TRACE ("ACE_TSS_Write_Guard<ACE_LOCK>::dump");
+ ACE_TSS_Guard<ACE_LOCK>::dump ();
+}
+
+template <class ACE_LOCK>
+ACE_TSS_Read_Guard<ACE_LOCK>::ACE_TSS_Read_Guard (ACE_LOCK &lock, int block)
+{
+// ACE_TRACE ("ACE_TSS_Read_Guard<ACE_LOCK>::ACE_TSS_Read_Guard");
+
+ this->init_key ();
+ ACE_Guard<ACE_LOCK> *guard;
+ ACE_NEW (guard,
+ ACE_Read_Guard<ACE_LOCK> (lock,
+ block));
+#if defined (ACE_HAS_THR_C_DEST)
+ ACE_TSS_Adapter *tss_adapter;
+ ACE_NEW (tss_adapter,
+ ACE_TSS_Adapter ((void *)guard,
+ ACE_TSS_Guard<ACE_LOCK>::cleanup));
+ ACE_Thread::setspecific (this->key_,
+ (void *) tss_adapter);
+#else
+ ACE_Thread::setspecific (this->key_,
+ (void *) guard);
+#endif /* ACE_HAS_THR_C_DEST */
+}
+
+template <class ACE_LOCK> int
+ACE_TSS_Read_Guard<ACE_LOCK>::acquire (void)
+{
+// ACE_TRACE ("ACE_TSS_Read_Guard<ACE_LOCK>::acquire");
+
+ ACE_Read_Guard<ACE_LOCK> *guard = 0;
+
+#if defined (ACE_HAS_THR_C_DEST)
+ ACE_TSS_Adapter *tss_adapter = 0;
+ ACE_Thread::getspecific (this->key_,
+ (void **) &tss_adapter);
+ guard = (ACE_Guard<ACE_LOCK> *) tss_adapter->ts_obj_;
+#else
+ ACE_Thread::getspecific (this->key_,
+ (void **) &guard);
+#endif /* ACE_HAS_THR_C_DEST */
+
+ return guard->acquire_read ();
+}
+
+template <class ACE_LOCK> int
+ACE_TSS_Read_Guard<ACE_LOCK>::tryacquire (void)
+{
+// ACE_TRACE ("ACE_TSS_Read_Guard<ACE_LOCK>::tryacquire");
+
+ ACE_Read_Guard<ACE_LOCK> *guard = 0;
+
+#if defined (ACE_HAS_THR_C_DEST)
+ ACE_TSS_Adapter *tss_adapter = 0;
+ ACE_Thread::getspecific (this->key_,
+ (void **) &tss_adapter);
+ guard = (ACE_Guard<ACE_LOCK> *) tss_adapter->ts_obj_;
+#else
+ ACE_Thread::getspecific (this->key_,
+ (void **) &guard);
+#endif /* ACE_HAS_THR_C_DEST */
+
+ return guard->tryacquire_read ();
+}
+
+template <class ACE_LOCK> int
+ACE_TSS_Read_Guard<ACE_LOCK>::acquire_read (void)
+{
+// ACE_TRACE ("ACE_TSS_Read_Guard<ACE_LOCK>::acquire_read");
+
+ return this->acquire ();
+}
+
+template <class ACE_LOCK> int
+ACE_TSS_Read_Guard<ACE_LOCK>::tryacquire_read (void)
+{
+// ACE_TRACE ("ACE_TSS_Read_Guard<ACE_LOCK>::tryacquire_read");
+
+ return this->tryacquire ();
+}
+
+template <class ACE_LOCK> void
+ACE_TSS_Read_Guard<ACE_LOCK>::dump (void) const
+{
+// ACE_TRACE ("ACE_TSS_Read_Guard<ACE_LOCK>::dump");
+ ACE_TSS_Guard<ACE_LOCK>::dump ();
+}
+
+
+#endif /* defined (ACE_HAS_THREADS) && (defined (ACE_HAS_THREAD_SPECIFIC_STORAGE) || defined (ACE_HAS_TSS_EMULATION)) */
+
+#endif /* ACE_SYNCH_T_C */
diff --git a/ace/Threads/Synch_T.h b/ace/Threads/Synch_T.h
new file mode 100644
index 00000000000..e33503a9bc3
--- /dev/null
+++ b/ace/Threads/Synch_T.h
@@ -0,0 +1,903 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Synch_T.h
+ *
+ * $Id$
+ *
+ * @author Douglas C. Schmidt <schmidt@uci.edu>
+ */
+//=============================================================================
+
+#ifndef ACE_SYNCH_T_H
+#define ACE_SYNCH_T_H
+#include "ace/pre.h"
+#include "ace/Threads/Synch.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+// Forward decl
+class ACE_Time_Value;
+
+/**
+ * @class ACE_Lock_Adapter
+ *
+ * @brief This is an adapter that allows applications to transparently
+ * combine the <ACE_Lock> abstract base class (which contains
+ * pure virtual methods) with any of the other concrete ACE
+ * synchronization classes (e.g., <ACE_Mutex>, <ACE_Semaphore>,
+ * <ACE_RW_Mutex>, etc.).
+ *
+ * This class uses a form of the Adapter pattern.
+ */
+template <class ACE_LOCKING_MECHANISM>
+class ACE_Lock_Adapter : public ACE_Lock
+{
+public:
+ typedef ACE_LOCKING_MECHANISM ACE_LOCK;
+
+ // = Initialization/Finalization methods.
+
+ /// Constructor. All locking requests will be forwarded to <lock>.
+ ACE_Lock_Adapter (ACE_LOCKING_MECHANISM &lock);
+
+ /// Constructor. Since no lock is provided by the user, one will be
+ /// created internally.
+ ACE_Lock_Adapter (void);
+
+ /// Destructor. If <lock_> was not passed in by the user, it will be
+ /// deleted.
+ virtual ~ACE_Lock_Adapter (void);
+
+ // = Lock accessors.
+ /// Block the thread until the lock is acquired.
+ virtual int acquire (void);
+
+ /// Conditionally acquire the lock (i.e., won't block).
+ virtual int tryacquire (void);
+
+ /// Release the lock.
+ virtual int release (void);
+
+ /**
+ * Block until the thread acquires a read lock. If the locking
+ * mechanism doesn't support read locks then this just calls
+ * <acquire>.
+ */
+ virtual int acquire_read (void);
+
+ /**
+ * Block until the thread acquires a write lock. If the locking
+ * mechanism doesn't support read locks then this just calls
+ * <acquire>.
+ */
+ virtual int acquire_write (void);
+
+ /// Conditionally acquire a read lock. If the locking mechanism
+ /// doesn't support read locks then this just calls <acquire>.
+ virtual int tryacquire_read (void);
+
+ /// Conditionally acquire a write lock. If the locking mechanism
+ /// doesn't support read locks then this just calls <acquire>.
+ virtual int tryacquire_write (void);
+
+ /**
+ * Conditionally try to upgrade a lock held for read to a write lock.
+ * If the locking mechanism doesn't support read locks then this just
+ * calls <acquire>. Returns 0 on success, -1 on failure.
+ */
+ virtual int tryacquire_write_upgrade (void);
+
+ /// Explicitly destroy the lock.
+ virtual int remove (void);
+
+private:
+ /// The concrete locking mechanism that all the methods delegate to.
+ ACE_LOCKING_MECHANISM *lock_;
+
+ /// This flag keep track of whether we are responsible for deleting
+ /// the lock
+ int delete_lock_;
+};
+
+/**
+ * @class ACE_Acquire_Method
+ *
+ * @brief An enum class.
+ *
+ * These enums should have been inside the reverse lock class, but
+ * some lame compilers cannot handle enums inside template classes.
+ *
+ * The METHOD_TYPE is used to indicate which acquire() method will be
+ * called on the real lock when the release() method is called on the
+ * reverse lock. REGULAR indicated the acquire() method, READ
+ * indicates the acquire_read() method, and WRITE indicates the
+ * acquire_write() method. Note that the try_*() methods are not
+ * represented here because we have to make sure that the release()
+ * method on the reverse lock acquires a lock on the real lock.
+ **/
+class ACE_Acquire_Method
+{
+public:
+ enum METHOD_TYPE
+ {
+ ACE_REGULAR,
+ ACE_READ,
+ ACE_WRITE
+ };
+};
+
+/**
+ * @class ACE_Reverse_Lock
+ *
+ * @brief A reverse (or anti) lock.
+ *
+ * This is an interesting adapter class that changes a lock into
+ * a reverse lock, i.e., <acquire> on this class calls <release>
+ * on the lock, and <release> on this class calls <acquire> on
+ * the lock.
+ * One motivation for this class is when we temporarily want to
+ * release a lock (which we have already acquired) but then
+ * reacquire it soon after. An alternative design would be to
+ * add a Anti_Guard or Reverse_Guard class which would <release>
+ * on construction and <acquire> destruction. However, there
+ * are *many* varieties of the Guard class and this design
+ * choice would lead to at least 6 new classes. One new
+ * ACE_Reverse_Lock class seemed more reasonable.
+ */
+template <class ACE_LOCKING_MECHANISM>
+class ACE_Reverse_Lock : public ACE_Lock
+{
+public:
+
+ typedef ACE_LOCKING_MECHANISM ACE_LOCK;
+
+ // = Initialization/Finalization methods.
+
+ /// Constructor. All locking requests will be forwarded to <lock>.
+ ACE_Reverse_Lock (ACE_LOCKING_MECHANISM &lock,
+ ACE_Acquire_Method::METHOD_TYPE acquire_method = ACE_Acquire_Method::ACE_REGULAR);
+
+ /// Destructor. If <lock_> was not passed in by the user, it will be
+ /// deleted.
+ virtual ~ACE_Reverse_Lock (void);
+
+ // = Lock accessors.
+ /// Release the lock.
+ virtual int acquire (void);
+
+ /// Release the lock.
+ virtual int tryacquire (void);
+
+ /// Acquire the lock.
+ virtual int release (void);
+
+ /// Release the lock.
+ virtual int acquire_read (void);
+
+ /// Release the lock.
+ virtual int acquire_write (void);
+
+ /// Release the lock.
+ virtual int tryacquire_read (void);
+
+ /// Release the lock.
+ virtual int tryacquire_write (void);
+
+ /// Release the lock.
+ virtual int tryacquire_write_upgrade (void);
+
+ /// Explicitly destroy the lock.
+ virtual int remove (void);
+
+private:
+ /// The concrete locking mechanism that all the methods delegate to.
+ ACE_LOCKING_MECHANISM &lock_;
+
+ /// This indicates what kind of acquire method will be called.
+ ACE_Acquire_Method::METHOD_TYPE acquire_method_;
+};
+
+/**
+ * @class ACE_TSS
+ *
+ * @brief Allows objects that are "physically" in thread specific
+ * storage (i.e., private to a thread) to be accessed as though
+ * they were "logically" global to a program.
+ *
+ * This class is a wrapper around the OS thread library
+ * thread-specific functions. It uses the <C++ operator->> to
+ * shield applications from the details of accessing
+ * thread-specific storage.
+ *
+ * NOTE: For maximal portability, <TYPE> cannot be a built-in type,
+ * but instead should be a user-defined class (some compilers will
+ * allow a built-in type, others won't). See template class
+ * ACE_TSS_Type_Adapter, below, for adapting built-in types to work
+ * with ACE_TSS.
+ */
+template <class TYPE>
+class ACE_TSS
+{
+public:
+ // = Initialization and termination methods.
+
+ /**
+ * If caller has passed us a non-NULL ts_obj *, then we'll just use
+ * this to initialize the thread-specific value (but only for the
+ * calling thread). Thus, subsequent calls to <operator->> in this
+ * thread will return this value. This is useful since it enables
+ * us to assign objects to thread-specific data that have
+ * arbitrarily complex constructors.
+ */
+ ACE_TSS (TYPE *ts_obj = 0);
+
+ /// Deregister with thread-key administration.
+ virtual ~ACE_TSS (void);
+
+ // = Accessors.
+
+ /**
+ * Get the thread-specific object for the key associated with this
+ * object. Returns 0 if the data has never been initialized,
+ * otherwise returns a pointer to the data.
+ */
+ TYPE *ts_object (void) const;
+
+ /// Set the thread-specific object for the key associated with this
+ /// object.
+ TYPE *ts_object (TYPE *);
+
+ /// Use a "smart pointer" to get the thread-specific object
+ /// associated with the <key_>.
+ TYPE *operator-> () const;
+
+ /// Return or create and return the calling threads TYPE object.
+ operator TYPE *(void) const;
+
+ /// Hook for construction parameters.
+ virtual TYPE *make_TSS_TYPE (void) const;
+
+ // = Utility methods.
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ // ACE_ALLOC_HOOK_DECLARE;
+ // Declare the dynamic allocation hooks.
+
+protected:
+ /// Actually implements the code that retrieves the object from
+ /// thread-specific storage.
+ TYPE *ts_get (void) const;
+
+ /// Factors out common code for initializing TSS. This must NOT be
+ /// called with the lock held...
+ int ts_init (void) const;
+
+#if !(defined (ACE_HAS_THREADS) && (defined (ACE_HAS_THREAD_SPECIFIC_STORAGE) || defined (ACE_HAS_TSS_EMULATION)))
+ /// This implementation only works for non-threading systems...
+ TYPE *type_;
+#else
+ /// Avoid race conditions during initialization.
+ ACE_Thread_Mutex keylock_;
+
+ /// "First time in" flag.
+ int once_;
+
+ /// Key for the thread-specific error data.
+ ACE_thread_key_t key_;
+
+ /// "Destructor" that deletes internal TYPE * when thread exits.
+ static void cleanup (void *ptr);
+#endif /* defined (ACE_HAS_THREADS) && (defined (ACE_HAS_THREAD_SPECIFIC_STORAGE) || defined (ACE_HAS_TSS_EMULATION)) */
+ // = Disallow copying...
+ ACE_UNIMPLEMENTED_FUNC (void operator= (const ACE_TSS<TYPE> &))
+ ACE_UNIMPLEMENTED_FUNC (ACE_TSS (const ACE_TSS<TYPE> &))
+};
+
+/**
+ * @class ACE_TSS_Type_Adapter
+ *
+ * @brief Adapter that allows built-in types to be used with ACE_TSS.
+ *
+ * Wraps a value of a built-in type, providing conversions to
+ * and from the type. Example use with ACE_TSS:
+ * ACE_TSS<ACE_TSS_Type_Adapter<int> > i;
+ * *i = 37;
+ * ACE_OS::fprintf (stderr, "%d\n", *i);
+ * Unfortunately, though, some compilers have trouble with the
+ * implicit type conversions. This seems to work better:
+ * ACE_TSS<ACE_TSS_Type_Adapter<int> > i;
+ * i->operator int & () = 37;
+ * ACE_OS::fprintf (stderr, "%d\n", i->operator int ());
+ */
+template <class TYPE>
+class ACE_TSS_Type_Adapter
+{
+public:
+ /// Constructor. Inlined here so that it should _always_ be inlined.
+ ACE_TSS_Type_Adapter (const TYPE value = 0): value_ (value) {}
+
+ /// TYPE conversion. Inlined here so that it should _always_ be
+ /// inlined.
+ operator TYPE () const { return value_; };
+
+ /// TYPE & conversion. Inlined here so that it should _always_ be
+ /// inlined.
+ operator TYPE &() { return value_; };
+
+private:
+ /// The wrapped value.
+ TYPE value_;
+};
+
+/**
+ * @class ACE_Guard
+ *
+ * @brief This data structure is meant to be used within a method or
+ * function... It performs automatic aquisition and release of
+ * a parameterized synchronization object <ACE_LOCK>.
+ *
+ * The <ACE_LOCK> class given as an actual parameter must provide at
+ * the very least the <acquire>, <tryacquire>, <release>, and
+ * <remove> methods.
+ */
+template <class ACE_LOCK>
+class ACE_Guard
+{
+public:
+
+ // = Initialization and termination methods.
+ ACE_Guard (ACE_LOCK &l);
+
+ /// Implicitly and automatically acquire (or try to acquire) the
+ /// lock. If <block> is non-0 then <acquire> the <ACE_LOCK>, else
+ /// <tryacquire> it.
+ ACE_Guard (ACE_LOCK &l, int block);
+
+ /// Initialise the guard without implicitly acquiring the lock. The
+ /// <become_owner> parameter indicates whether the guard should release
+ /// the lock implicitly on destruction. The <block> parameter is
+ /// ignored and is used here to disambiguate with the preceding
+ /// constructor.
+ ACE_Guard (ACE_LOCK &l, int block, int become_owner);
+
+ /// Implicitly release the lock.
+ ~ACE_Guard (void);
+
+ // = Lock accessors.
+
+ /// Explicitly acquire the lock.
+ int acquire (void);
+
+ /// Conditionally acquire the lock (i.e., won't block).
+ int tryacquire (void);
+
+ /// Explicitly release the lock, but only if it is held!
+ int release (void);
+
+ /// Relinquish ownership of the lock so that it is not released
+ /// implicitly in the destructor.
+ void disown (void);
+
+ // = Utility methods.
+ /// 1 if locked, 0 if couldn't acquire the lock
+ /// (errno will contain the reason for this).
+ int locked (void) const;
+
+ /// Explicitly remove the lock.
+ int remove (void);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ // ACE_ALLOC_HOOK_DECLARE;
+ // Declare the dynamic allocation hooks.
+
+protected:
+
+ /// Helper, meant for subclass only.
+ ACE_Guard (ACE_LOCK *lock): lock_ (lock) {}
+
+ /// Pointer to the ACE_LOCK we're guarding.
+ ACE_LOCK *lock_;
+
+ /// Keeps track of whether we acquired the lock or failed.
+ int owner_;
+
+private:
+ // = Prevent assignment and initialization.
+ ACE_UNIMPLEMENTED_FUNC (void operator= (const ACE_Guard<ACE_LOCK> &))
+ ACE_UNIMPLEMENTED_FUNC (ACE_Guard (const ACE_Guard<ACE_LOCK> &))
+};
+
+/**
+ * @class ACE_Write_Guard
+ *
+ * @brief This class is similar to class <ACE_Guard>, though it
+ * acquires/releases a write lock automatically (naturally, the
+ * <ACE_LOCK> it is instantiated with must support the appropriate
+ * API).
+ */
+template <class ACE_LOCK>
+class ACE_Write_Guard : public ACE_Guard<ACE_LOCK>
+{
+public:
+ // = Initialization method.
+
+ /// Implicitly and automatically acquire a write lock.
+ ACE_Write_Guard (ACE_LOCK &m);
+
+ /// Implicitly and automatically acquire (or try to acquire) a write
+ /// lock.
+ ACE_Write_Guard (ACE_LOCK &m, int block);
+
+ // = Lock accessors.
+
+ /// Explicitly acquire the write lock.
+ int acquire_write (void);
+
+ /// Explicitly acquire the write lock.
+ int acquire (void);
+
+ /// Conditionally acquire the write lock (i.e., won't block).
+ int tryacquire_write (void);
+
+ /// Conditionally acquire the write lock (i.e., won't block).
+ int tryacquire (void);
+
+ // = Utility methods.
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ // ACE_ALLOC_HOOK_DECLARE;
+ // Declare the dynamic allocation hooks.
+};
+
+/**
+ * @class ACE_Read_Guard
+ *
+ * @brief This class is similar to class <ACE_Guard>, though it
+ * acquires/releases a read lock automatically (naturally, the
+ * <ACE_LOCK> it is instantiated with must support the appropriate
+ * API).
+ */
+template <class ACE_LOCK>
+class ACE_Read_Guard : public ACE_Guard<ACE_LOCK>
+{
+public:
+ // = Initialization methods.
+
+ /// Implicitly and automatically acquire a read lock.
+ ACE_Read_Guard (ACE_LOCK& m);
+
+ /// Implicitly and automatically acquire (or try to acquire) a read
+ /// lock.
+ ACE_Read_Guard (ACE_LOCK &m, int block);
+
+ // = Lock accessors.
+
+ /// Explicitly acquire the read lock.
+ int acquire_read (void);
+
+ /// Explicitly acquire the read lock.
+ int acquire (void);
+
+ /// Conditionally acquire the read lock (i.e., won't block).
+ int tryacquire_read (void);
+
+ /// Conditionally acquire the read lock (i.e., won't block).
+ int tryacquire (void);
+
+ // = Utility methods.
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ // ACE_ALLOC_HOOK_DECLARE;
+ // Declare the dynamic allocation hooks.
+};
+
+#if !(defined (ACE_HAS_THREADS) && (defined (ACE_HAS_THREAD_SPECIFIC_STORAGE) || defined (ACE_HAS_TSS_EMULATION)))
+
+#define ACE_TSS_Guard ACE_Guard
+#define ACE_TSS_Write_GUARD ACE_Write_Guard
+#define ACE_TSS_Read_GUARD ACE_Read_Guard
+
+#else
+ /* ACE platform supports some form of threading and
+ thread-specific storage. */
+
+/**
+ * @class ACE_TSS_Guard
+ *
+ * @brief This data structure is meant to be used within a method or
+ * function... It performs automatic aquisition and release of
+ * a synchronization object. Moreover, it ensures that the lock
+ * is released even if a thread exits via <thr_exit>!
+ */
+template <class ACE_LOCK>
+class ACE_TSS_Guard
+{
+public:
+ // = Initialization and termination methods.
+
+ /// Implicitly and automatically acquire the thread-specific lock.
+ ACE_TSS_Guard (ACE_LOCK &lock, int block = 1);
+
+ /// Implicitly release the thread-specific lock.
+ ~ACE_TSS_Guard (void);
+
+ // = Lock accessors.
+
+ /// Explicitly acquire the thread-specific lock.
+ int acquire (void);
+
+ /// Conditionally acquire the thread-specific lock (i.e., won't
+ /// block).
+ int tryacquire (void);
+
+ /// Explicitly release the thread-specific lock.
+ int release (void);
+
+ // = Utility methods.
+ /// Explicitly release the thread-specific lock.
+ int remove (void);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ // ACE_ALLOC_HOOK_DECLARE;
+ // Declare the dynamic allocation hooks.
+
+protected:
+ /// Helper, meant for subclass only.
+ ACE_TSS_Guard (void);
+
+ /// Initialize the key.
+ void init_key (void);
+
+ /// Called when thread exits to clean up the lock.
+ static void cleanup (void *ptr);
+
+ /// Thread-specific key...
+ ACE_thread_key_t key_;
+
+private:
+ // = Prevent assignment and initialization.
+ ACE_UNIMPLEMENTED_FUNC (void operator= (const ACE_TSS_Guard<ACE_LOCK> &))
+ ACE_UNIMPLEMENTED_FUNC (ACE_TSS_Guard (const ACE_TSS_Guard<ACE_LOCK> &))
+};
+
+/**
+ * @class ACE_TSS_Write_Guard
+ *
+ * @brief This class is similar to class ACE_TSS_Guard, though it
+ * acquires/releases a write-lock automatically (naturally, the
+ * ACE_LOCK it is instantiated with must support the appropriate
+ * API).
+ */
+template <class ACE_LOCK>
+class ACE_TSS_Write_Guard : public ACE_TSS_Guard<ACE_LOCK>
+{
+public:
+ // = Initialization method.
+
+ /// Implicitly and automatically acquire the thread-specific write lock.
+ ACE_TSS_Write_Guard (ACE_LOCK &lock, int block = 1);
+
+ // = Lock accessors.
+
+ /// Explicitly acquire the thread-specific write lock.
+ int acquire_write (void);
+
+ /// Explicitly acquire the thread-specific write lock.
+ int acquire (void);
+
+ /// Conditionally acquire the thread-specific write lock (i.e., won't block).
+ int tryacquire_write (void);
+
+ /// Conditionally acquire the thread-specific write lock (i.e., won't block).
+ int tryacquire (void);
+
+ // = Utility methods.
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ // ACE_ALLOC_HOOK_DECLARE;
+ // Declare the dynamic allocation hooks.
+};
+
+/**
+ * @class ACE_TSS_Read_Guard
+ *
+ * @brief This class is similar to class <ACE_TSS_Guard>, though it
+ * acquires/releases a read lock automatically (naturally, the
+ * <ACE_LOCK> it is instantiated with must support the
+ * appropriate API).
+ */
+template <class ACE_LOCK>
+class ACE_TSS_Read_Guard : public ACE_TSS_Guard<ACE_LOCK>
+{
+public:
+ // = Initialization method.
+ /// Implicitly and automatically acquire the thread-specific read lock.
+ ACE_TSS_Read_Guard (ACE_LOCK &lock, int block = 1);
+
+ // = Lock accessors.
+ /// Explicitly acquire the thread-specific read lock.
+ int acquire_read (void);
+
+ /// Explicitly acquire the thread-specific read lock.
+ int acquire (void);
+
+ /// Conditionally acquire the thread-specific read lock (i.e., won't
+ /// block).
+ int tryacquire_read (void);
+
+ /// Conditionally acquire the thread-specific read lock (i.e., won't
+ /// block).
+ int tryacquire (void);
+
+ // = Utility methods.
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ // ACE_ALLOC_HOOK_DECLARE;
+ // Declare the dynamic allocation hooks.
+};
+#endif /* !(defined (ACE_HAS_THREADS) && (defined (ACE_HAS_THREAD_SPECIFIC_STORAGE) || defined (ACE_HAS_TSS_EMULATION))) */
+
+#if defined (ACE_HAS_THREADS) /* ACE platform supports some form of threading. */
+
+/**
+ * @class ACE_Condition
+ *
+ * @brief ACE_Condition variable wrapper, which allows threads to block
+ * until shared data changes state.
+ *
+ * A condition variable enables threads to atomically block and
+ * test the condition under the protection of a mutual exclu-
+ * sion lock (mutex) until the condition is satisfied. That is,
+ * the mutex must have been held by the thread before calling
+ * wait or signal on the condition. If the condition is false,
+ * a thread blocks on a condition variable and atomically
+ * releases the mutex that is waiting for the condition to
+ * change. If another thread changes the condition, it may wake
+ * up waiting threads by signaling the associated condition
+ * variable. The waiting threads, upon awakening, reacquire the
+ * mutex and re-evaluate the condition.
+ * Note, you can only parameterize <ACE_Condition> with
+ * <ACE_Thread_Mutex> or <ACE_Null_Mutex>.
+ */
+template <class MUTEX>
+class ACE_Condition
+{
+public:
+ // = Initialiation and termination methods.
+ /// Initialize the condition variable.
+ ACE_Condition (MUTEX &m, int type = USYNC_THREAD,
+ const ACE_TCHAR *name = 0, void *arg = 0);
+
+ /// Implicitly destroy the condition variable.
+ ~ACE_Condition (void);
+
+ // = Lock accessors.
+ /**
+ * Block on condition, or until absolute time-of-day has passed. If
+ * abstime == 0 use "blocking" <wait> semantics. Else, if <abstime>
+ * != 0 and the call times out before the condition is signaled
+ * <wait> returns -1 and sets errno to ETIME.
+ */
+ int wait (const ACE_Time_Value *abstime);
+
+ /// Block on condition.
+ int wait (void);
+
+ /**
+ * Block on condition or until absolute time-of-day has passed. If
+ * abstime == 0 use "blocking" wait() semantics on the <mutex>
+ * passed as a parameter (this is useful if you need to store the
+ * <Condition> in shared memory). Else, if <abstime> != 0 and the
+ * call times out before the condition is signaled <wait> returns -1
+ * and sets errno to ETIME.
+ */
+ int wait (MUTEX &mutex, const ACE_Time_Value *abstime = 0);
+
+ /// Signal one waiting thread.
+ int signal (void);
+
+ /// Signal *all* waiting threads.
+ int broadcast (void);
+
+ // = Utility methods.
+ /// Explicitly destroy the condition variable.
+ int remove (void);
+
+ /// Returns a reference to the underlying mutex_;
+ MUTEX &mutex (void);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ // ACE_ALLOC_HOOK_DECLARE;
+ // Declare the dynamic allocation hooks.
+
+protected:
+#if defined (CHORUS)
+ /// This condition resides in shared memory.
+ ACE_cond_t *process_cond_;
+
+ /**
+ * Remember the name of the condition if we created it so we can
+ * unlink it when we go away (only the actor that initialized the
+ * memory can destroy it).
+ */
+ const ACE_TCHAR *condname_;
+#endif /* CHORUS */
+
+ /// Condition variable.
+ ACE_cond_t cond_;
+
+ /// Reference to mutex lock.
+ MUTEX &mutex_;
+
+private:
+ // = Prevent assignment and initialization.
+ ACE_UNIMPLEMENTED_FUNC (void operator= (const ACE_Condition<MUTEX> &))
+ ACE_UNIMPLEMENTED_FUNC (ACE_Condition (const ACE_Condition<MUTEX> &))
+};
+
+/**
+ * @class ACE_Thread_Condition
+ *
+ * @brief ACE_Condition variable wrapper that works within processes.
+ *
+ * A condition variable enables threads to atomically block and
+ * test the condition under the protection of a mutual exclu-
+ * sion lock (mutex) until the condition is satisfied. That is,
+ * the mutex must have been held by the thread before calling
+ * wait or signal on the condition. If the condition is false,
+ * a thread blocks on a condition variable and atomically
+ * releases the mutex that is waiting for the condition to
+ * change. If another thread changes the condition, it may wake
+ * up waiting threads by signaling the associated condition
+ * variable. The waiting threads, upon awakening, reacquire the
+ * mutex and re-evaluate the condition.
+ */
+template <class MUTEX>
+class ACE_Thread_Condition : public ACE_Condition<MUTEX>
+{
+public:
+ // = Initialization method.
+ ACE_Thread_Condition (MUTEX &m, const ACE_TCHAR *name = 0, void *arg = 0);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ // ACE_ALLOC_HOOK_DECLARE;
+ // Declare the dynamic allocation hooks.
+};
+
+#endif /* ACE_HAS_THREADS */
+
+#if defined (ACE_HAS_TEMPLATE_TYPEDEFS)
+
+/**
+ * @class ACE_NULL_SYNCH
+ *
+ * @brief Implement a do nothing Synchronization wrapper that
+ * typedefs the <ACE_Condition> and <ACE_Mutex> to the Null* versions.
+ */
+class ACE_Export ACE_NULL_SYNCH
+{
+public:
+ typedef ACE_Null_Mutex MUTEX;
+ typedef ACE_Null_Mutex NULL_MUTEX;
+ typedef ACE_Null_Mutex PROCESS_MUTEX;
+ typedef ACE_Null_Mutex RECURSIVE_MUTEX;
+ typedef ACE_Null_Mutex RW_MUTEX;
+ typedef ACE_Null_Condition CONDITION;
+ typedef ACE_Null_Semaphore SEMAPHORE;
+ typedef ACE_Null_Mutex NULL_SEMAPHORE;
+};
+
+#if defined (ACE_HAS_THREADS)
+
+class ACE_Process_Mutex;
+
+/**
+ * @class ACE_MT_SYNCH
+ *
+ * @brief Implement a default thread safe synchronization wrapper that
+ * typedefs the <ACE_Condition> and <ACE_Mutex> to the
+ * <ACE_Condition> and <ACE_Mutex> versions. Note that this
+ * should be a template, but SunC++ 4.0.1 complains about
+ * this...
+ */
+class ACE_Export ACE_MT_SYNCH
+{
+public:
+ typedef ACE_Thread_Mutex MUTEX;
+ typedef ACE_Null_Mutex NULL_MUTEX;
+ typedef ACE_Process_Mutex PROCESS_MUTEX;
+ typedef ACE_Recursive_Thread_Mutex RECURSIVE_MUTEX;
+ typedef ACE_RW_Thread_Mutex RW_MUTEX;
+ typedef ACE_Condition_Thread_Mutex CONDITION;
+ typedef ACE_Thread_Semaphore SEMAPHORE;
+ typedef ACE_Null_Semaphore NULL_SEMAPHORE;
+};
+
+#endif /* ACE_HAS_THREADS */
+
+#define ACE_SYNCH_MUTEX ACE_SYNCH::MUTEX
+#define ACE_SYNCH_NULL_MUTEX ACE_SYNCH::NULL_MUTEX
+#define ACE_SYNCH_RECURSIVE_MUTEX ACE_SYNCH::RECURSIVE_MUTEX
+#define ACE_SYNCH_RW_MUTEX ACE_SYNCH::RW_MUTEX
+#define ACE_SYNCH_CONDITION ACE_SYNCH::CONDITION
+#define ACE_SYNCH_NULL_SEMAPHORE ACE_SYNCH::NULL_SEMAPHORE
+#define ACE_SYNCH_SEMAPHORE ACE_SYNCH::SEMAPHORE
+
+#else /* !ACE_HAS_TEMPLATE_TYPEDEFS */
+
+#if defined (ACE_HAS_OPTIMIZED_MESSAGE_QUEUE)
+#define ACE_NULL_SYNCH ACE_Null_Mutex, ACE_Null_Condition, ACE_Null_Mutex
+#define ACE_MT_SYNCH ACE_Thread_Mutex, ACE_Condition_Thread_Mutex, ACE_Thread_Semaphore
+#else
+#define ACE_NULL_SYNCH ACE_Null_Mutex, ACE_Null_Condition
+#define ACE_MT_SYNCH ACE_Thread_Mutex, ACE_Condition_Thread_Mutex
+#endif /* ACE_HAS_OPTIMIZED_MESSAGE_QUEUE */
+
+#if defined (ACE_HAS_THREADS)
+
+#define ACE_SYNCH_MUTEX ACE_Thread_Mutex
+#define ACE_SYNCH_NULL_MUTEX ACE_Null_Mutex
+#define ACE_SYNCH_RECURSIVE_MUTEX ACE_Recursive_Thread_Mutex
+#define ACE_SYNCH_RW_MUTEX ACE_RW_Thread_Mutex
+#define ACE_SYNCH_CONDITION ACE_Condition_Thread_Mutex
+#define ACE_SYNCH_SEMAPHORE ACE_Thread_Semaphore
+#define ACE_SYNCH_NULL_SEMAPHORE ACE_Null_Semaphore
+
+#else /* ACE_HAS_THREADS */
+
+#define ACE_SYNCH_MUTEX ACE_Null_Mutex
+#define ACE_SYNCH_NULL_MUTEX ACE_Null_Mutex
+#define ACE_SYNCH_RECURSIVE_MUTEX ACE_Null_Mutex
+#define ACE_SYNCH_RW_MUTEX ACE_Null_Mutex
+#define ACE_SYNCH_CONDITION ACE_Null_Condition
+#define ACE_SYNCH_SEMAPHORE ACE_Null_Semaphore
+#define ACE_SYNCH_NULL_SEMAPHORE ACE_Null_Mutex
+
+#endif /* ACE_HAS_THREADS */
+#endif /* ACE_HAS_TEMPLATE_TYPEDEFS */
+
+// These are available on *all* platforms
+#define ACE_SYNCH_PROCESS_SEMAPHORE ACE_Process_Semaphore
+#define ACE_SYNCH_PROCESS_MUTEX ACE_Process_Mutex
+
+#if defined (ACE_HAS_THREADS)
+#define ACE_SYNCH ACE_MT_SYNCH
+#else /* ACE_HAS_THREADS */
+#define ACE_SYNCH ACE_NULL_SYNCH
+#endif /* ACE_HAS_THREADS */
+
+#if defined (__ACE_INLINE__)
+#include "ace/Threads/Synch_T.i"
+#endif /* __ACE_INLINE__ */
+
+#if defined (ACE_TEMPLATES_REQUIRE_SOURCE)
+#include "ace/Threads/Synch_T.cpp"
+#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */
+
+#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA)
+#pragma implementation ("Synch_T.cpp")
+#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */
+
+#include "ace/post.h"
+#endif /* ACE_SYNCH_T_H */
diff --git a/ace/Threads/Synch_T.h~ b/ace/Threads/Synch_T.h~
new file mode 100644
index 00000000000..74b3170f0ac
--- /dev/null
+++ b/ace/Threads/Synch_T.h~
@@ -0,0 +1,903 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Synch_T.h
+ *
+ * $Id$
+ *
+ * @author Douglas C. Schmidt <schmidt@uci.edu>
+ */
+//=============================================================================
+
+#ifndef ACE_SYNCH_T_H
+#define ACE_SYNCH_T_H
+#include "ace/pre.h"
+#include "ace/Synch.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+// Forward decl
+class ACE_Time_Value;
+
+/**
+ * @class ACE_Lock_Adapter
+ *
+ * @brief This is an adapter that allows applications to transparently
+ * combine the <ACE_Lock> abstract base class (which contains
+ * pure virtual methods) with any of the other concrete ACE
+ * synchronization classes (e.g., <ACE_Mutex>, <ACE_Semaphore>,
+ * <ACE_RW_Mutex>, etc.).
+ *
+ * This class uses a form of the Adapter pattern.
+ */
+template <class ACE_LOCKING_MECHANISM>
+class ACE_Lock_Adapter : public ACE_Lock
+{
+public:
+ typedef ACE_LOCKING_MECHANISM ACE_LOCK;
+
+ // = Initialization/Finalization methods.
+
+ /// Constructor. All locking requests will be forwarded to <lock>.
+ ACE_Lock_Adapter (ACE_LOCKING_MECHANISM &lock);
+
+ /// Constructor. Since no lock is provided by the user, one will be
+ /// created internally.
+ ACE_Lock_Adapter (void);
+
+ /// Destructor. If <lock_> was not passed in by the user, it will be
+ /// deleted.
+ virtual ~ACE_Lock_Adapter (void);
+
+ // = Lock accessors.
+ /// Block the thread until the lock is acquired.
+ virtual int acquire (void);
+
+ /// Conditionally acquire the lock (i.e., won't block).
+ virtual int tryacquire (void);
+
+ /// Release the lock.
+ virtual int release (void);
+
+ /**
+ * Block until the thread acquires a read lock. If the locking
+ * mechanism doesn't support read locks then this just calls
+ * <acquire>.
+ */
+ virtual int acquire_read (void);
+
+ /**
+ * Block until the thread acquires a write lock. If the locking
+ * mechanism doesn't support read locks then this just calls
+ * <acquire>.
+ */
+ virtual int acquire_write (void);
+
+ /// Conditionally acquire a read lock. If the locking mechanism
+ /// doesn't support read locks then this just calls <acquire>.
+ virtual int tryacquire_read (void);
+
+ /// Conditionally acquire a write lock. If the locking mechanism
+ /// doesn't support read locks then this just calls <acquire>.
+ virtual int tryacquire_write (void);
+
+ /**
+ * Conditionally try to upgrade a lock held for read to a write lock.
+ * If the locking mechanism doesn't support read locks then this just
+ * calls <acquire>. Returns 0 on success, -1 on failure.
+ */
+ virtual int tryacquire_write_upgrade (void);
+
+ /// Explicitly destroy the lock.
+ virtual int remove (void);
+
+private:
+ /// The concrete locking mechanism that all the methods delegate to.
+ ACE_LOCKING_MECHANISM *lock_;
+
+ /// This flag keep track of whether we are responsible for deleting
+ /// the lock
+ int delete_lock_;
+};
+
+/**
+ * @class ACE_Acquire_Method
+ *
+ * @brief An enum class.
+ *
+ * These enums should have been inside the reverse lock class, but
+ * some lame compilers cannot handle enums inside template classes.
+ *
+ * The METHOD_TYPE is used to indicate which acquire() method will be
+ * called on the real lock when the release() method is called on the
+ * reverse lock. REGULAR indicated the acquire() method, READ
+ * indicates the acquire_read() method, and WRITE indicates the
+ * acquire_write() method. Note that the try_*() methods are not
+ * represented here because we have to make sure that the release()
+ * method on the reverse lock acquires a lock on the real lock.
+ **/
+class ACE_Acquire_Method
+{
+public:
+ enum METHOD_TYPE
+ {
+ ACE_REGULAR,
+ ACE_READ,
+ ACE_WRITE
+ };
+};
+
+/**
+ * @class ACE_Reverse_Lock
+ *
+ * @brief A reverse (or anti) lock.
+ *
+ * This is an interesting adapter class that changes a lock into
+ * a reverse lock, i.e., <acquire> on this class calls <release>
+ * on the lock, and <release> on this class calls <acquire> on
+ * the lock.
+ * One motivation for this class is when we temporarily want to
+ * release a lock (which we have already acquired) but then
+ * reacquire it soon after. An alternative design would be to
+ * add a Anti_Guard or Reverse_Guard class which would <release>
+ * on construction and <acquire> destruction. However, there
+ * are *many* varieties of the Guard class and this design
+ * choice would lead to at least 6 new classes. One new
+ * ACE_Reverse_Lock class seemed more reasonable.
+ */
+template <class ACE_LOCKING_MECHANISM>
+class ACE_Reverse_Lock : public ACE_Lock
+{
+public:
+
+ typedef ACE_LOCKING_MECHANISM ACE_LOCK;
+
+ // = Initialization/Finalization methods.
+
+ /// Constructor. All locking requests will be forwarded to <lock>.
+ ACE_Reverse_Lock (ACE_LOCKING_MECHANISM &lock,
+ ACE_Acquire_Method::METHOD_TYPE acquire_method = ACE_Acquire_Method::ACE_REGULAR);
+
+ /// Destructor. If <lock_> was not passed in by the user, it will be
+ /// deleted.
+ virtual ~ACE_Reverse_Lock (void);
+
+ // = Lock accessors.
+ /// Release the lock.
+ virtual int acquire (void);
+
+ /// Release the lock.
+ virtual int tryacquire (void);
+
+ /// Acquire the lock.
+ virtual int release (void);
+
+ /// Release the lock.
+ virtual int acquire_read (void);
+
+ /// Release the lock.
+ virtual int acquire_write (void);
+
+ /// Release the lock.
+ virtual int tryacquire_read (void);
+
+ /// Release the lock.
+ virtual int tryacquire_write (void);
+
+ /// Release the lock.
+ virtual int tryacquire_write_upgrade (void);
+
+ /// Explicitly destroy the lock.
+ virtual int remove (void);
+
+private:
+ /// The concrete locking mechanism that all the methods delegate to.
+ ACE_LOCKING_MECHANISM &lock_;
+
+ /// This indicates what kind of acquire method will be called.
+ ACE_Acquire_Method::METHOD_TYPE acquire_method_;
+};
+
+/**
+ * @class ACE_TSS
+ *
+ * @brief Allows objects that are "physically" in thread specific
+ * storage (i.e., private to a thread) to be accessed as though
+ * they were "logically" global to a program.
+ *
+ * This class is a wrapper around the OS thread library
+ * thread-specific functions. It uses the <C++ operator->> to
+ * shield applications from the details of accessing
+ * thread-specific storage.
+ *
+ * NOTE: For maximal portability, <TYPE> cannot be a built-in type,
+ * but instead should be a user-defined class (some compilers will
+ * allow a built-in type, others won't). See template class
+ * ACE_TSS_Type_Adapter, below, for adapting built-in types to work
+ * with ACE_TSS.
+ */
+template <class TYPE>
+class ACE_TSS
+{
+public:
+ // = Initialization and termination methods.
+
+ /**
+ * If caller has passed us a non-NULL ts_obj *, then we'll just use
+ * this to initialize the thread-specific value (but only for the
+ * calling thread). Thus, subsequent calls to <operator->> in this
+ * thread will return this value. This is useful since it enables
+ * us to assign objects to thread-specific data that have
+ * arbitrarily complex constructors.
+ */
+ ACE_TSS (TYPE *ts_obj = 0);
+
+ /// Deregister with thread-key administration.
+ virtual ~ACE_TSS (void);
+
+ // = Accessors.
+
+ /**
+ * Get the thread-specific object for the key associated with this
+ * object. Returns 0 if the data has never been initialized,
+ * otherwise returns a pointer to the data.
+ */
+ TYPE *ts_object (void) const;
+
+ /// Set the thread-specific object for the key associated with this
+ /// object.
+ TYPE *ts_object (TYPE *);
+
+ /// Use a "smart pointer" to get the thread-specific object
+ /// associated with the <key_>.
+ TYPE *operator-> () const;
+
+ /// Return or create and return the calling threads TYPE object.
+ operator TYPE *(void) const;
+
+ /// Hook for construction parameters.
+ virtual TYPE *make_TSS_TYPE (void) const;
+
+ // = Utility methods.
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ // ACE_ALLOC_HOOK_DECLARE;
+ // Declare the dynamic allocation hooks.
+
+protected:
+ /// Actually implements the code that retrieves the object from
+ /// thread-specific storage.
+ TYPE *ts_get (void) const;
+
+ /// Factors out common code for initializing TSS. This must NOT be
+ /// called with the lock held...
+ int ts_init (void) const;
+
+#if !(defined (ACE_HAS_THREADS) && (defined (ACE_HAS_THREAD_SPECIFIC_STORAGE) || defined (ACE_HAS_TSS_EMULATION)))
+ /// This implementation only works for non-threading systems...
+ TYPE *type_;
+#else
+ /// Avoid race conditions during initialization.
+ ACE_Thread_Mutex keylock_;
+
+ /// "First time in" flag.
+ int once_;
+
+ /// Key for the thread-specific error data.
+ ACE_thread_key_t key_;
+
+ /// "Destructor" that deletes internal TYPE * when thread exits.
+ static void cleanup (void *ptr);
+#endif /* defined (ACE_HAS_THREADS) && (defined (ACE_HAS_THREAD_SPECIFIC_STORAGE) || defined (ACE_HAS_TSS_EMULATION)) */
+ // = Disallow copying...
+ ACE_UNIMPLEMENTED_FUNC (void operator= (const ACE_TSS<TYPE> &))
+ ACE_UNIMPLEMENTED_FUNC (ACE_TSS (const ACE_TSS<TYPE> &))
+};
+
+/**
+ * @class ACE_TSS_Type_Adapter
+ *
+ * @brief Adapter that allows built-in types to be used with ACE_TSS.
+ *
+ * Wraps a value of a built-in type, providing conversions to
+ * and from the type. Example use with ACE_TSS:
+ * ACE_TSS<ACE_TSS_Type_Adapter<int> > i;
+ * *i = 37;
+ * ACE_OS::fprintf (stderr, "%d\n", *i);
+ * Unfortunately, though, some compilers have trouble with the
+ * implicit type conversions. This seems to work better:
+ * ACE_TSS<ACE_TSS_Type_Adapter<int> > i;
+ * i->operator int & () = 37;
+ * ACE_OS::fprintf (stderr, "%d\n", i->operator int ());
+ */
+template <class TYPE>
+class ACE_TSS_Type_Adapter
+{
+public:
+ /// Constructor. Inlined here so that it should _always_ be inlined.
+ ACE_TSS_Type_Adapter (const TYPE value = 0): value_ (value) {}
+
+ /// TYPE conversion. Inlined here so that it should _always_ be
+ /// inlined.
+ operator TYPE () const { return value_; };
+
+ /// TYPE & conversion. Inlined here so that it should _always_ be
+ /// inlined.
+ operator TYPE &() { return value_; };
+
+private:
+ /// The wrapped value.
+ TYPE value_;
+};
+
+/**
+ * @class ACE_Guard
+ *
+ * @brief This data structure is meant to be used within a method or
+ * function... It performs automatic aquisition and release of
+ * a parameterized synchronization object <ACE_LOCK>.
+ *
+ * The <ACE_LOCK> class given as an actual parameter must provide at
+ * the very least the <acquire>, <tryacquire>, <release>, and
+ * <remove> methods.
+ */
+template <class ACE_LOCK>
+class ACE_Guard
+{
+public:
+
+ // = Initialization and termination methods.
+ ACE_Guard (ACE_LOCK &l);
+
+ /// Implicitly and automatically acquire (or try to acquire) the
+ /// lock. If <block> is non-0 then <acquire> the <ACE_LOCK>, else
+ /// <tryacquire> it.
+ ACE_Guard (ACE_LOCK &l, int block);
+
+ /// Initialise the guard without implicitly acquiring the lock. The
+ /// <become_owner> parameter indicates whether the guard should release
+ /// the lock implicitly on destruction. The <block> parameter is
+ /// ignored and is used here to disambiguate with the preceding
+ /// constructor.
+ ACE_Guard (ACE_LOCK &l, int block, int become_owner);
+
+ /// Implicitly release the lock.
+ ~ACE_Guard (void);
+
+ // = Lock accessors.
+
+ /// Explicitly acquire the lock.
+ int acquire (void);
+
+ /// Conditionally acquire the lock (i.e., won't block).
+ int tryacquire (void);
+
+ /// Explicitly release the lock, but only if it is held!
+ int release (void);
+
+ /// Relinquish ownership of the lock so that it is not released
+ /// implicitly in the destructor.
+ void disown (void);
+
+ // = Utility methods.
+ /// 1 if locked, 0 if couldn't acquire the lock
+ /// (errno will contain the reason for this).
+ int locked (void) const;
+
+ /// Explicitly remove the lock.
+ int remove (void);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ // ACE_ALLOC_HOOK_DECLARE;
+ // Declare the dynamic allocation hooks.
+
+protected:
+
+ /// Helper, meant for subclass only.
+ ACE_Guard (ACE_LOCK *lock): lock_ (lock) {}
+
+ /// Pointer to the ACE_LOCK we're guarding.
+ ACE_LOCK *lock_;
+
+ /// Keeps track of whether we acquired the lock or failed.
+ int owner_;
+
+private:
+ // = Prevent assignment and initialization.
+ ACE_UNIMPLEMENTED_FUNC (void operator= (const ACE_Guard<ACE_LOCK> &))
+ ACE_UNIMPLEMENTED_FUNC (ACE_Guard (const ACE_Guard<ACE_LOCK> &))
+};
+
+/**
+ * @class ACE_Write_Guard
+ *
+ * @brief This class is similar to class <ACE_Guard>, though it
+ * acquires/releases a write lock automatically (naturally, the
+ * <ACE_LOCK> it is instantiated with must support the appropriate
+ * API).
+ */
+template <class ACE_LOCK>
+class ACE_Write_Guard : public ACE_Guard<ACE_LOCK>
+{
+public:
+ // = Initialization method.
+
+ /// Implicitly and automatically acquire a write lock.
+ ACE_Write_Guard (ACE_LOCK &m);
+
+ /// Implicitly and automatically acquire (or try to acquire) a write
+ /// lock.
+ ACE_Write_Guard (ACE_LOCK &m, int block);
+
+ // = Lock accessors.
+
+ /// Explicitly acquire the write lock.
+ int acquire_write (void);
+
+ /// Explicitly acquire the write lock.
+ int acquire (void);
+
+ /// Conditionally acquire the write lock (i.e., won't block).
+ int tryacquire_write (void);
+
+ /// Conditionally acquire the write lock (i.e., won't block).
+ int tryacquire (void);
+
+ // = Utility methods.
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ // ACE_ALLOC_HOOK_DECLARE;
+ // Declare the dynamic allocation hooks.
+};
+
+/**
+ * @class ACE_Read_Guard
+ *
+ * @brief This class is similar to class <ACE_Guard>, though it
+ * acquires/releases a read lock automatically (naturally, the
+ * <ACE_LOCK> it is instantiated with must support the appropriate
+ * API).
+ */
+template <class ACE_LOCK>
+class ACE_Read_Guard : public ACE_Guard<ACE_LOCK>
+{
+public:
+ // = Initialization methods.
+
+ /// Implicitly and automatically acquire a read lock.
+ ACE_Read_Guard (ACE_LOCK& m);
+
+ /// Implicitly and automatically acquire (or try to acquire) a read
+ /// lock.
+ ACE_Read_Guard (ACE_LOCK &m, int block);
+
+ // = Lock accessors.
+
+ /// Explicitly acquire the read lock.
+ int acquire_read (void);
+
+ /// Explicitly acquire the read lock.
+ int acquire (void);
+
+ /// Conditionally acquire the read lock (i.e., won't block).
+ int tryacquire_read (void);
+
+ /// Conditionally acquire the read lock (i.e., won't block).
+ int tryacquire (void);
+
+ // = Utility methods.
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ // ACE_ALLOC_HOOK_DECLARE;
+ // Declare the dynamic allocation hooks.
+};
+
+#if !(defined (ACE_HAS_THREADS) && (defined (ACE_HAS_THREAD_SPECIFIC_STORAGE) || defined (ACE_HAS_TSS_EMULATION)))
+
+#define ACE_TSS_Guard ACE_Guard
+#define ACE_TSS_Write_GUARD ACE_Write_Guard
+#define ACE_TSS_Read_GUARD ACE_Read_Guard
+
+#else
+ /* ACE platform supports some form of threading and
+ thread-specific storage. */
+
+/**
+ * @class ACE_TSS_Guard
+ *
+ * @brief This data structure is meant to be used within a method or
+ * function... It performs automatic aquisition and release of
+ * a synchronization object. Moreover, it ensures that the lock
+ * is released even if a thread exits via <thr_exit>!
+ */
+template <class ACE_LOCK>
+class ACE_TSS_Guard
+{
+public:
+ // = Initialization and termination methods.
+
+ /// Implicitly and automatically acquire the thread-specific lock.
+ ACE_TSS_Guard (ACE_LOCK &lock, int block = 1);
+
+ /// Implicitly release the thread-specific lock.
+ ~ACE_TSS_Guard (void);
+
+ // = Lock accessors.
+
+ /// Explicitly acquire the thread-specific lock.
+ int acquire (void);
+
+ /// Conditionally acquire the thread-specific lock (i.e., won't
+ /// block).
+ int tryacquire (void);
+
+ /// Explicitly release the thread-specific lock.
+ int release (void);
+
+ // = Utility methods.
+ /// Explicitly release the thread-specific lock.
+ int remove (void);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ // ACE_ALLOC_HOOK_DECLARE;
+ // Declare the dynamic allocation hooks.
+
+protected:
+ /// Helper, meant for subclass only.
+ ACE_TSS_Guard (void);
+
+ /// Initialize the key.
+ void init_key (void);
+
+ /// Called when thread exits to clean up the lock.
+ static void cleanup (void *ptr);
+
+ /// Thread-specific key...
+ ACE_thread_key_t key_;
+
+private:
+ // = Prevent assignment and initialization.
+ ACE_UNIMPLEMENTED_FUNC (void operator= (const ACE_TSS_Guard<ACE_LOCK> &))
+ ACE_UNIMPLEMENTED_FUNC (ACE_TSS_Guard (const ACE_TSS_Guard<ACE_LOCK> &))
+};
+
+/**
+ * @class ACE_TSS_Write_Guard
+ *
+ * @brief This class is similar to class ACE_TSS_Guard, though it
+ * acquires/releases a write-lock automatically (naturally, the
+ * ACE_LOCK it is instantiated with must support the appropriate
+ * API).
+ */
+template <class ACE_LOCK>
+class ACE_TSS_Write_Guard : public ACE_TSS_Guard<ACE_LOCK>
+{
+public:
+ // = Initialization method.
+
+ /// Implicitly and automatically acquire the thread-specific write lock.
+ ACE_TSS_Write_Guard (ACE_LOCK &lock, int block = 1);
+
+ // = Lock accessors.
+
+ /// Explicitly acquire the thread-specific write lock.
+ int acquire_write (void);
+
+ /// Explicitly acquire the thread-specific write lock.
+ int acquire (void);
+
+ /// Conditionally acquire the thread-specific write lock (i.e., won't block).
+ int tryacquire_write (void);
+
+ /// Conditionally acquire the thread-specific write lock (i.e., won't block).
+ int tryacquire (void);
+
+ // = Utility methods.
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ // ACE_ALLOC_HOOK_DECLARE;
+ // Declare the dynamic allocation hooks.
+};
+
+/**
+ * @class ACE_TSS_Read_Guard
+ *
+ * @brief This class is similar to class <ACE_TSS_Guard>, though it
+ * acquires/releases a read lock automatically (naturally, the
+ * <ACE_LOCK> it is instantiated with must support the
+ * appropriate API).
+ */
+template <class ACE_LOCK>
+class ACE_TSS_Read_Guard : public ACE_TSS_Guard<ACE_LOCK>
+{
+public:
+ // = Initialization method.
+ /// Implicitly and automatically acquire the thread-specific read lock.
+ ACE_TSS_Read_Guard (ACE_LOCK &lock, int block = 1);
+
+ // = Lock accessors.
+ /// Explicitly acquire the thread-specific read lock.
+ int acquire_read (void);
+
+ /// Explicitly acquire the thread-specific read lock.
+ int acquire (void);
+
+ /// Conditionally acquire the thread-specific read lock (i.e., won't
+ /// block).
+ int tryacquire_read (void);
+
+ /// Conditionally acquire the thread-specific read lock (i.e., won't
+ /// block).
+ int tryacquire (void);
+
+ // = Utility methods.
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ // ACE_ALLOC_HOOK_DECLARE;
+ // Declare the dynamic allocation hooks.
+};
+#endif /* !(defined (ACE_HAS_THREADS) && (defined (ACE_HAS_THREAD_SPECIFIC_STORAGE) || defined (ACE_HAS_TSS_EMULATION))) */
+
+#if defined (ACE_HAS_THREADS) /* ACE platform supports some form of threading. */
+
+/**
+ * @class ACE_Condition
+ *
+ * @brief ACE_Condition variable wrapper, which allows threads to block
+ * until shared data changes state.
+ *
+ * A condition variable enables threads to atomically block and
+ * test the condition under the protection of a mutual exclu-
+ * sion lock (mutex) until the condition is satisfied. That is,
+ * the mutex must have been held by the thread before calling
+ * wait or signal on the condition. If the condition is false,
+ * a thread blocks on a condition variable and atomically
+ * releases the mutex that is waiting for the condition to
+ * change. If another thread changes the condition, it may wake
+ * up waiting threads by signaling the associated condition
+ * variable. The waiting threads, upon awakening, reacquire the
+ * mutex and re-evaluate the condition.
+ * Note, you can only parameterize <ACE_Condition> with
+ * <ACE_Thread_Mutex> or <ACE_Null_Mutex>.
+ */
+template <class MUTEX>
+class ACE_Condition
+{
+public:
+ // = Initialiation and termination methods.
+ /// Initialize the condition variable.
+ ACE_Condition (MUTEX &m, int type = USYNC_THREAD,
+ const ACE_TCHAR *name = 0, void *arg = 0);
+
+ /// Implicitly destroy the condition variable.
+ ~ACE_Condition (void);
+
+ // = Lock accessors.
+ /**
+ * Block on condition, or until absolute time-of-day has passed. If
+ * abstime == 0 use "blocking" <wait> semantics. Else, if <abstime>
+ * != 0 and the call times out before the condition is signaled
+ * <wait> returns -1 and sets errno to ETIME.
+ */
+ int wait (const ACE_Time_Value *abstime);
+
+ /// Block on condition.
+ int wait (void);
+
+ /**
+ * Block on condition or until absolute time-of-day has passed. If
+ * abstime == 0 use "blocking" wait() semantics on the <mutex>
+ * passed as a parameter (this is useful if you need to store the
+ * <Condition> in shared memory). Else, if <abstime> != 0 and the
+ * call times out before the condition is signaled <wait> returns -1
+ * and sets errno to ETIME.
+ */
+ int wait (MUTEX &mutex, const ACE_Time_Value *abstime = 0);
+
+ /// Signal one waiting thread.
+ int signal (void);
+
+ /// Signal *all* waiting threads.
+ int broadcast (void);
+
+ // = Utility methods.
+ /// Explicitly destroy the condition variable.
+ int remove (void);
+
+ /// Returns a reference to the underlying mutex_;
+ MUTEX &mutex (void);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ // ACE_ALLOC_HOOK_DECLARE;
+ // Declare the dynamic allocation hooks.
+
+protected:
+#if defined (CHORUS)
+ /// This condition resides in shared memory.
+ ACE_cond_t *process_cond_;
+
+ /**
+ * Remember the name of the condition if we created it so we can
+ * unlink it when we go away (only the actor that initialized the
+ * memory can destroy it).
+ */
+ const ACE_TCHAR *condname_;
+#endif /* CHORUS */
+
+ /// Condition variable.
+ ACE_cond_t cond_;
+
+ /// Reference to mutex lock.
+ MUTEX &mutex_;
+
+private:
+ // = Prevent assignment and initialization.
+ ACE_UNIMPLEMENTED_FUNC (void operator= (const ACE_Condition<MUTEX> &))
+ ACE_UNIMPLEMENTED_FUNC (ACE_Condition (const ACE_Condition<MUTEX> &))
+};
+
+/**
+ * @class ACE_Thread_Condition
+ *
+ * @brief ACE_Condition variable wrapper that works within processes.
+ *
+ * A condition variable enables threads to atomically block and
+ * test the condition under the protection of a mutual exclu-
+ * sion lock (mutex) until the condition is satisfied. That is,
+ * the mutex must have been held by the thread before calling
+ * wait or signal on the condition. If the condition is false,
+ * a thread blocks on a condition variable and atomically
+ * releases the mutex that is waiting for the condition to
+ * change. If another thread changes the condition, it may wake
+ * up waiting threads by signaling the associated condition
+ * variable. The waiting threads, upon awakening, reacquire the
+ * mutex and re-evaluate the condition.
+ */
+template <class MUTEX>
+class ACE_Thread_Condition : public ACE_Condition<MUTEX>
+{
+public:
+ // = Initialization method.
+ ACE_Thread_Condition (MUTEX &m, const ACE_TCHAR *name = 0, void *arg = 0);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ // ACE_ALLOC_HOOK_DECLARE;
+ // Declare the dynamic allocation hooks.
+};
+
+#endif /* ACE_HAS_THREADS */
+
+#if defined (ACE_HAS_TEMPLATE_TYPEDEFS)
+
+/**
+ * @class ACE_NULL_SYNCH
+ *
+ * @brief Implement a do nothing Synchronization wrapper that
+ * typedefs the <ACE_Condition> and <ACE_Mutex> to the Null* versions.
+ */
+class ACE_Export ACE_NULL_SYNCH
+{
+public:
+ typedef ACE_Null_Mutex MUTEX;
+ typedef ACE_Null_Mutex NULL_MUTEX;
+ typedef ACE_Null_Mutex PROCESS_MUTEX;
+ typedef ACE_Null_Mutex RECURSIVE_MUTEX;
+ typedef ACE_Null_Mutex RW_MUTEX;
+ typedef ACE_Null_Condition CONDITION;
+ typedef ACE_Null_Semaphore SEMAPHORE;
+ typedef ACE_Null_Mutex NULL_SEMAPHORE;
+};
+
+#if defined (ACE_HAS_THREADS)
+
+class ACE_Process_Mutex;
+
+/**
+ * @class ACE_MT_SYNCH
+ *
+ * @brief Implement a default thread safe synchronization wrapper that
+ * typedefs the <ACE_Condition> and <ACE_Mutex> to the
+ * <ACE_Condition> and <ACE_Mutex> versions. Note that this
+ * should be a template, but SunC++ 4.0.1 complains about
+ * this...
+ */
+class ACE_Export ACE_MT_SYNCH
+{
+public:
+ typedef ACE_Thread_Mutex MUTEX;
+ typedef ACE_Null_Mutex NULL_MUTEX;
+ typedef ACE_Process_Mutex PROCESS_MUTEX;
+ typedef ACE_Recursive_Thread_Mutex RECURSIVE_MUTEX;
+ typedef ACE_RW_Thread_Mutex RW_MUTEX;
+ typedef ACE_Condition_Thread_Mutex CONDITION;
+ typedef ACE_Thread_Semaphore SEMAPHORE;
+ typedef ACE_Null_Semaphore NULL_SEMAPHORE;
+};
+
+#endif /* ACE_HAS_THREADS */
+
+#define ACE_SYNCH_MUTEX ACE_SYNCH::MUTEX
+#define ACE_SYNCH_NULL_MUTEX ACE_SYNCH::NULL_MUTEX
+#define ACE_SYNCH_RECURSIVE_MUTEX ACE_SYNCH::RECURSIVE_MUTEX
+#define ACE_SYNCH_RW_MUTEX ACE_SYNCH::RW_MUTEX
+#define ACE_SYNCH_CONDITION ACE_SYNCH::CONDITION
+#define ACE_SYNCH_NULL_SEMAPHORE ACE_SYNCH::NULL_SEMAPHORE
+#define ACE_SYNCH_SEMAPHORE ACE_SYNCH::SEMAPHORE
+
+#else /* !ACE_HAS_TEMPLATE_TYPEDEFS */
+
+#if defined (ACE_HAS_OPTIMIZED_MESSAGE_QUEUE)
+#define ACE_NULL_SYNCH ACE_Null_Mutex, ACE_Null_Condition, ACE_Null_Mutex
+#define ACE_MT_SYNCH ACE_Thread_Mutex, ACE_Condition_Thread_Mutex, ACE_Thread_Semaphore
+#else
+#define ACE_NULL_SYNCH ACE_Null_Mutex, ACE_Null_Condition
+#define ACE_MT_SYNCH ACE_Thread_Mutex, ACE_Condition_Thread_Mutex
+#endif /* ACE_HAS_OPTIMIZED_MESSAGE_QUEUE */
+
+#if defined (ACE_HAS_THREADS)
+
+#define ACE_SYNCH_MUTEX ACE_Thread_Mutex
+#define ACE_SYNCH_NULL_MUTEX ACE_Null_Mutex
+#define ACE_SYNCH_RECURSIVE_MUTEX ACE_Recursive_Thread_Mutex
+#define ACE_SYNCH_RW_MUTEX ACE_RW_Thread_Mutex
+#define ACE_SYNCH_CONDITION ACE_Condition_Thread_Mutex
+#define ACE_SYNCH_SEMAPHORE ACE_Thread_Semaphore
+#define ACE_SYNCH_NULL_SEMAPHORE ACE_Null_Semaphore
+
+#else /* ACE_HAS_THREADS */
+
+#define ACE_SYNCH_MUTEX ACE_Null_Mutex
+#define ACE_SYNCH_NULL_MUTEX ACE_Null_Mutex
+#define ACE_SYNCH_RECURSIVE_MUTEX ACE_Null_Mutex
+#define ACE_SYNCH_RW_MUTEX ACE_Null_Mutex
+#define ACE_SYNCH_CONDITION ACE_Null_Condition
+#define ACE_SYNCH_SEMAPHORE ACE_Null_Semaphore
+#define ACE_SYNCH_NULL_SEMAPHORE ACE_Null_Mutex
+
+#endif /* ACE_HAS_THREADS */
+#endif /* ACE_HAS_TEMPLATE_TYPEDEFS */
+
+// These are available on *all* platforms
+#define ACE_SYNCH_PROCESS_SEMAPHORE ACE_Process_Semaphore
+#define ACE_SYNCH_PROCESS_MUTEX ACE_Process_Mutex
+
+#if defined (ACE_HAS_THREADS)
+#define ACE_SYNCH ACE_MT_SYNCH
+#else /* ACE_HAS_THREADS */
+#define ACE_SYNCH ACE_NULL_SYNCH
+#endif /* ACE_HAS_THREADS */
+
+#if defined (__ACE_INLINE__)
+#include "ace/Synch_T.i"
+#endif /* __ACE_INLINE__ */
+
+#if defined (ACE_TEMPLATES_REQUIRE_SOURCE)
+#include "ace/Synch_T.cpp"
+#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */
+
+#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA)
+#pragma implementation ("Synch_T.cpp")
+#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */
+
+#include "ace/post.h"
+#endif /* ACE_SYNCH_T_H */
diff --git a/ace/Threads/Synch_T.i b/ace/Threads/Synch_T.i
new file mode 100644
index 00000000000..24f0f0a1ff7
--- /dev/null
+++ b/ace/Threads/Synch_T.i
@@ -0,0 +1,452 @@
+/* -*- C++ -*- */
+// $Id$
+
+#include "ace/Threads/Thread.h"
+
+template <class ACE_LOCK> ACE_INLINE int
+ACE_Guard<ACE_LOCK>::acquire (void)
+{
+ return this->owner_ = this->lock_->acquire ();
+}
+
+template <class ACE_LOCK> ACE_INLINE int
+ACE_Guard<ACE_LOCK>::tryacquire (void)
+{
+ return this->owner_ = this->lock_->tryacquire ();
+}
+
+template <class ACE_LOCK> ACE_INLINE int
+ACE_Guard<ACE_LOCK>::release (void)
+{
+ if (this->owner_ == -1)
+ return -1;
+ else
+ {
+ this->owner_ = -1;
+ return this->lock_->release ();
+ }
+}
+
+template <class ACE_LOCK> ACE_INLINE
+ACE_Guard<ACE_LOCK>::ACE_Guard (ACE_LOCK &l)
+ : lock_ (&l),
+ owner_ (0)
+{
+ this->acquire ();
+}
+
+template <class ACE_LOCK> ACE_INLINE
+ACE_Guard<ACE_LOCK>::ACE_Guard (ACE_LOCK &l, int block)
+ : lock_ (&l),
+ owner_ (0)
+{
+ if (block)
+ this->acquire ();
+ else
+ this->tryacquire ();
+}
+
+template <class ACE_LOCK> ACE_INLINE
+ACE_Guard<ACE_LOCK>::ACE_Guard (ACE_LOCK &l, int block, int become_owner)
+ : lock_ (&l),
+ owner_ (become_owner == 0 ? -1 : 0)
+{
+ ACE_UNUSED_ARG (block);
+}
+
+// Implicitly and automatically acquire (or try to acquire) the
+// lock.
+
+template <class ACE_LOCK> ACE_INLINE
+ACE_Guard<ACE_LOCK>::~ACE_Guard (void)
+{
+ this->release ();
+}
+
+template <class ACE_LOCK> ACE_INLINE int
+ACE_Guard<ACE_LOCK>::locked (void) const
+{
+ return this->owner_ != -1;
+}
+
+template <class ACE_LOCK> ACE_INLINE int
+ACE_Guard<ACE_LOCK>::remove (void)
+{
+ return this->lock_->remove ();
+}
+
+template <class ACE_LOCK> ACE_INLINE void
+ACE_Guard<ACE_LOCK>::disown (void)
+{
+ this->owner_ = -1;
+}
+
+template <class ACE_LOCK> ACE_INLINE
+ACE_Write_Guard<ACE_LOCK>::ACE_Write_Guard (ACE_LOCK &m)
+ : ACE_Guard<ACE_LOCK> (&m)
+{
+ this->acquire_write ();
+}
+
+template <class ACE_LOCK> ACE_INLINE int
+ACE_Write_Guard<ACE_LOCK>::acquire_write (void)
+{
+ return this->owner_ = this->lock_->acquire_write ();
+}
+
+template <class ACE_LOCK> ACE_INLINE int
+ACE_Write_Guard<ACE_LOCK>::acquire (void)
+{
+ return this->owner_ = this->lock_->acquire_write ();
+}
+
+template <class ACE_LOCK> ACE_INLINE int
+ACE_Write_Guard<ACE_LOCK>::tryacquire_write (void)
+{
+ return this->owner_ = this->lock_->tryacquire_write ();
+}
+
+template <class ACE_LOCK> ACE_INLINE int
+ACE_Write_Guard<ACE_LOCK>::tryacquire (void)
+{
+ return this->owner_ = this->lock_->tryacquire_write ();
+}
+
+template <class ACE_LOCK> ACE_INLINE
+ACE_Write_Guard<ACE_LOCK>::ACE_Write_Guard (ACE_LOCK &m,
+ int block)
+ : ACE_Guard<ACE_LOCK> (&m)
+{
+ if (block)
+ this->acquire_write ();
+ else
+ this->tryacquire_write ();
+}
+
+template <class ACE_LOCK> ACE_INLINE int
+ACE_Read_Guard<ACE_LOCK>::acquire_read (void)
+{
+ return this->owner_ = this->lock_->acquire_read ();
+}
+
+template <class ACE_LOCK> ACE_INLINE int
+ACE_Read_Guard<ACE_LOCK>::acquire (void)
+{
+ return this->owner_ = this->lock_->acquire_read ();
+}
+
+template <class ACE_LOCK> ACE_INLINE int
+ACE_Read_Guard<ACE_LOCK>::tryacquire_read (void)
+{
+ return this->owner_ = this->lock_->tryacquire_read ();
+}
+
+template <class ACE_LOCK> ACE_INLINE int
+ACE_Read_Guard<ACE_LOCK>::tryacquire (void)
+{
+ return this->owner_ = this->lock_->tryacquire_read ();
+}
+
+template <class ACE_LOCK> ACE_INLINE
+ACE_Read_Guard<ACE_LOCK>::ACE_Read_Guard (ACE_LOCK &m)
+ : ACE_Guard<ACE_LOCK> (&m)
+{
+ this->acquire_read ();
+}
+
+template <class ACE_LOCK> ACE_INLINE
+ACE_Read_Guard<ACE_LOCK>::ACE_Read_Guard (ACE_LOCK &m,
+ int block)
+ : ACE_Guard<ACE_LOCK> (&m)
+{
+ if (block)
+ this->acquire_read ();
+ else
+ this->tryacquire_read ();
+}
+
+template <class ACE_LOCKING_MECHANISM> ACE_INLINE
+ACE_Lock_Adapter<ACE_LOCKING_MECHANISM>::ACE_Lock_Adapter (ACE_LOCKING_MECHANISM &lock)
+ : lock_ (&lock),
+ delete_lock_ (0)
+{
+}
+
+template <class ACE_LOCKING_MECHANISM> ACE_INLINE
+ACE_Lock_Adapter<ACE_LOCKING_MECHANISM>::~ACE_Lock_Adapter (void)
+{
+ if (this->delete_lock_)
+ delete this->lock_;
+}
+
+// Explicitly destroy the lock.
+template <class ACE_LOCKING_MECHANISM> ACE_INLINE int
+ACE_Lock_Adapter<ACE_LOCKING_MECHANISM>::remove (void)
+{
+ return this->lock_->remove ();
+}
+
+// Block the thread until the lock is acquired.
+template <class ACE_LOCKING_MECHANISM> ACE_INLINE int
+ACE_Lock_Adapter<ACE_LOCKING_MECHANISM>::acquire (void)
+{
+ return this->lock_->acquire ();
+}
+
+// Conditionally acquire the lock (i.e., won't block).
+
+template <class ACE_LOCKING_MECHANISM> ACE_INLINE int
+ACE_Lock_Adapter<ACE_LOCKING_MECHANISM>::tryacquire (void)
+{
+ return this->lock_->tryacquire ();
+}
+
+// Release the lock.
+
+template <class ACE_LOCKING_MECHANISM> ACE_INLINE int
+ACE_Lock_Adapter<ACE_LOCKING_MECHANISM>::release (void)
+{
+ return this->lock_->release ();
+}
+
+// Block until the thread acquires a read lock. If the locking
+// mechanism doesn't support read locks then this just calls
+// <acquire>.
+
+template <class ACE_LOCKING_MECHANISM> ACE_INLINE int
+ACE_Lock_Adapter<ACE_LOCKING_MECHANISM>::acquire_read (void)
+{
+ return this->lock_->acquire_read ();
+}
+
+// Block until the thread acquires a write lock. If the locking
+// mechanism doesn't support read locks then this just calls
+// <acquire>.
+
+template <class ACE_LOCKING_MECHANISM> ACE_INLINE int
+ACE_Lock_Adapter<ACE_LOCKING_MECHANISM>::acquire_write (void)
+{
+ return this->lock_->acquire_write ();
+}
+
+// Conditionally acquire a read lock. If the locking mechanism
+// doesn't support read locks then this just calls <acquire>.
+
+template <class ACE_LOCKING_MECHANISM> ACE_INLINE int
+ACE_Lock_Adapter<ACE_LOCKING_MECHANISM>::tryacquire_read (void)
+{
+ return this->lock_->tryacquire_read ();
+}
+
+// Conditionally acquire a write lock. If the locking mechanism
+// doesn't support write locks then this just calls <acquire>.
+
+template <class ACE_LOCKING_MECHANISM> ACE_INLINE int
+ACE_Lock_Adapter<ACE_LOCKING_MECHANISM>::tryacquire_write (void)
+{
+ return this->lock_->tryacquire_write ();
+}
+
+// Conditionally try to upgrade a lock held for read to a write lock.
+// If the locking mechanism doesn't support read locks then this just
+// calls <acquire>. Returns 0 on success, -1 on failure.
+
+template <class ACE_LOCKING_MECHANISM> ACE_INLINE int
+ACE_Lock_Adapter<ACE_LOCKING_MECHANISM>::tryacquire_write_upgrade (void)
+{
+ return this->lock_->tryacquire_write_upgrade ();
+}
+
+template <class ACE_LOCKING_MECHANISM> ACE_INLINE
+ACE_Reverse_Lock<ACE_LOCKING_MECHANISM>::ACE_Reverse_Lock (ACE_LOCKING_MECHANISM &lock,
+ ACE_Acquire_Method::METHOD_TYPE acquire_method)
+ : lock_ (lock),
+ acquire_method_ (acquire_method)
+{
+}
+
+// Explicitly destroy the lock.
+template <class ACE_LOCKING_MECHANISM> ACE_INLINE int
+ACE_Reverse_Lock<ACE_LOCKING_MECHANISM>::remove (void)
+{
+ return this->lock_.remove ();
+}
+
+// Release the lock.
+template <class ACE_LOCKING_MECHANISM> ACE_INLINE int
+ACE_Reverse_Lock<ACE_LOCKING_MECHANISM>::acquire (void)
+{
+ return this->lock_.release ();
+}
+
+// Release the lock.
+template <class ACE_LOCKING_MECHANISM> ACE_INLINE int
+ACE_Reverse_Lock<ACE_LOCKING_MECHANISM>::tryacquire (void)
+{
+ ACE_NOTSUP_RETURN (-1);
+}
+
+// Acquire the lock.
+template <class ACE_LOCKING_MECHANISM> ACE_INLINE int
+ACE_Reverse_Lock<ACE_LOCKING_MECHANISM>::release (void)
+{
+ if (this->acquire_method_ == ACE_Acquire_Method::ACE_READ)
+ return this->lock_.acquire_read ();
+ else if (this->acquire_method_ == ACE_Acquire_Method::ACE_WRITE)
+ return this->lock_.acquire_write ();
+ else
+ return this->lock_.acquire ();
+}
+
+// Release the lock.
+template <class ACE_LOCKING_MECHANISM> ACE_INLINE int
+ACE_Reverse_Lock<ACE_LOCKING_MECHANISM>::acquire_read (void)
+{
+ ACE_NOTSUP_RETURN (-1);
+}
+
+// Release the lock.
+template <class ACE_LOCKING_MECHANISM> ACE_INLINE int
+ACE_Reverse_Lock<ACE_LOCKING_MECHANISM>::acquire_write (void)
+{
+ ACE_NOTSUP_RETURN (-1);
+}
+
+// Release the lock.
+template <class ACE_LOCKING_MECHANISM> ACE_INLINE int
+ACE_Reverse_Lock<ACE_LOCKING_MECHANISM>::tryacquire_read (void)
+{
+ ACE_NOTSUP_RETURN (-1);
+}
+
+// Release the lock.
+template <class ACE_LOCKING_MECHANISM> ACE_INLINE int
+ACE_Reverse_Lock<ACE_LOCKING_MECHANISM>::tryacquire_write (void)
+{
+ ACE_NOTSUP_RETURN (-1);
+}
+
+// Release the lock.
+template <class ACE_LOCKING_MECHANISM> ACE_INLINE int
+ACE_Reverse_Lock<ACE_LOCKING_MECHANISM>::tryacquire_write_upgrade (void)
+{
+ ACE_NOTSUP_RETURN (-1);
+}
+
+#if defined (ACE_HAS_THREADS)
+
+template<class MUTEX> ACE_INLINE int
+ACE_Condition<MUTEX>::remove (void)
+{
+ // ACE_TRACE ("ACE_Condition<MUTEX>::remove");
+
+ // cond_destroy() is called in a loop if the condition variable is
+ // BUSY. This avoids a condition where a condition is signaled and
+ // because of some timing problem, the thread that is to be signaled
+ // has called the cond_wait routine after the signal call. Since
+ // the condition signal is not queued in any way, deadlock occurs.
+
+ int result = 0;
+
+#if defined (CHORUS)
+ // Are we the owner?
+ if (this->process_cond_ && this->condname_)
+ {
+ // Only destroy the condition if we're the ones who initialized
+ // it.
+ while ((result = ACE_OS::cond_destroy (this->process_cond_)) == -1
+ && errno == EBUSY)
+ {
+ ACE_OS::cond_broadcast (this->process_cond_);
+ ACE_OS::thr_yield ();
+ }
+ ACE_OS::munmap (this->process_cond_,
+ sizeof (ACE_cond_t));
+ ACE_OS::shm_unlink (this->condname_);
+ ACE_OS::free (ACE_static_cast (void *,
+ ACE_const_cast (ACE_TCHAR *,
+ this->condname_)));
+ }
+ else if (this->process_cond_)
+ {
+ ACE_OS::munmap (this->process_cond_,
+ sizeof (ACE_cond_t));
+ result = 0;
+ }
+ else
+#endif /* CHORUS */
+
+ while ((result = ACE_OS::cond_destroy (&this->cond_)) == -1
+ && errno == EBUSY)
+ {
+ ACE_OS::cond_broadcast (&this->cond_);
+ ACE_OS::thr_yield ();
+ }
+
+ return result;
+}
+
+template<class MUTEX> ACE_INLINE MUTEX &
+ACE_Condition<MUTEX>::mutex (void)
+{
+ // ACE_TRACE ("ACE_Condition<MUTEX>::mutex");
+ return this->mutex_;
+}
+
+template <class MUTEX> ACE_INLINE int
+ACE_Condition<MUTEX>::signal (void)
+{
+// ACE_TRACE ("ACE_Condition<MUTEX>::signal");
+#if defined (CHORUS)
+ if (this->process_cond_ != 0)
+ return ACE_OS::cond_signal (this->process_cond_);
+#endif /* CHORUS */
+ return ACE_OS::cond_signal (&this->cond_);
+}
+
+template <class MUTEX> ACE_INLINE int
+ACE_Condition<MUTEX>::broadcast (void)
+{
+// ACE_TRACE ("ACE_Condition<MUTEX>::broadcast");
+#if defined (CHORUS)
+ if (this->process_cond_ != 0)
+ return ACE_OS::cond_broadcast (this->process_cond_);
+#endif /* CHORUS */
+ return ACE_OS::cond_broadcast (&this->cond_);
+}
+
+#endif /* ACE_HAS_THREADS */
+
+#if !(defined (ACE_HAS_THREADS) && (defined (ACE_HAS_THREAD_SPECIFIC_STORAGE) || defined (ACE_HAS_TSS_EMULATION)))
+template <class TYPE> ACE_INLINE
+ACE_TSS<TYPE>::ACE_TSS (TYPE *type)
+ : type_ (type)
+{
+}
+
+template <class TYPE> ACE_INLINE int
+ACE_TSS<TYPE>::ts_init (void) const
+{
+ return 0;
+}
+
+template <class TYPE> ACE_INLINE TYPE *
+ACE_TSS<TYPE>::ts_object (void) const
+{
+ return this->type_;
+}
+
+template <class TYPE> ACE_INLINE TYPE *
+ACE_TSS<TYPE>::ts_object (TYPE *type)
+{
+ this->type_ = type;
+ return this->type_;
+}
+
+template <class TYPE> ACE_INLINE TYPE *
+ACE_TSS<TYPE>::ts_get (void) const
+{
+ return this->type_;
+}
+
+#endif /* ! (defined (ACE_HAS_THREADS) && (defined (ACE_HAS_THREAD_SPECIFIC_STORAGE) || defined (ACE_HAS_TSS_EMULATION))) */
diff --git a/ace/Threads/Synch_T.i~ b/ace/Threads/Synch_T.i~
new file mode 100644
index 00000000000..50cd0a710e9
--- /dev/null
+++ b/ace/Threads/Synch_T.i~
@@ -0,0 +1,452 @@
+/* -*- C++ -*- */
+// $Id$
+
+#include "ace/Thread.h"
+
+template <class ACE_LOCK> ACE_INLINE int
+ACE_Guard<ACE_LOCK>::acquire (void)
+{
+ return this->owner_ = this->lock_->acquire ();
+}
+
+template <class ACE_LOCK> ACE_INLINE int
+ACE_Guard<ACE_LOCK>::tryacquire (void)
+{
+ return this->owner_ = this->lock_->tryacquire ();
+}
+
+template <class ACE_LOCK> ACE_INLINE int
+ACE_Guard<ACE_LOCK>::release (void)
+{
+ if (this->owner_ == -1)
+ return -1;
+ else
+ {
+ this->owner_ = -1;
+ return this->lock_->release ();
+ }
+}
+
+template <class ACE_LOCK> ACE_INLINE
+ACE_Guard<ACE_LOCK>::ACE_Guard (ACE_LOCK &l)
+ : lock_ (&l),
+ owner_ (0)
+{
+ this->acquire ();
+}
+
+template <class ACE_LOCK> ACE_INLINE
+ACE_Guard<ACE_LOCK>::ACE_Guard (ACE_LOCK &l, int block)
+ : lock_ (&l),
+ owner_ (0)
+{
+ if (block)
+ this->acquire ();
+ else
+ this->tryacquire ();
+}
+
+template <class ACE_LOCK> ACE_INLINE
+ACE_Guard<ACE_LOCK>::ACE_Guard (ACE_LOCK &l, int block, int become_owner)
+ : lock_ (&l),
+ owner_ (become_owner == 0 ? -1 : 0)
+{
+ ACE_UNUSED_ARG (block);
+}
+
+// Implicitly and automatically acquire (or try to acquire) the
+// lock.
+
+template <class ACE_LOCK> ACE_INLINE
+ACE_Guard<ACE_LOCK>::~ACE_Guard (void)
+{
+ this->release ();
+}
+
+template <class ACE_LOCK> ACE_INLINE int
+ACE_Guard<ACE_LOCK>::locked (void) const
+{
+ return this->owner_ != -1;
+}
+
+template <class ACE_LOCK> ACE_INLINE int
+ACE_Guard<ACE_LOCK>::remove (void)
+{
+ return this->lock_->remove ();
+}
+
+template <class ACE_LOCK> ACE_INLINE void
+ACE_Guard<ACE_LOCK>::disown (void)
+{
+ this->owner_ = -1;
+}
+
+template <class ACE_LOCK> ACE_INLINE
+ACE_Write_Guard<ACE_LOCK>::ACE_Write_Guard (ACE_LOCK &m)
+ : ACE_Guard<ACE_LOCK> (&m)
+{
+ this->acquire_write ();
+}
+
+template <class ACE_LOCK> ACE_INLINE int
+ACE_Write_Guard<ACE_LOCK>::acquire_write (void)
+{
+ return this->owner_ = this->lock_->acquire_write ();
+}
+
+template <class ACE_LOCK> ACE_INLINE int
+ACE_Write_Guard<ACE_LOCK>::acquire (void)
+{
+ return this->owner_ = this->lock_->acquire_write ();
+}
+
+template <class ACE_LOCK> ACE_INLINE int
+ACE_Write_Guard<ACE_LOCK>::tryacquire_write (void)
+{
+ return this->owner_ = this->lock_->tryacquire_write ();
+}
+
+template <class ACE_LOCK> ACE_INLINE int
+ACE_Write_Guard<ACE_LOCK>::tryacquire (void)
+{
+ return this->owner_ = this->lock_->tryacquire_write ();
+}
+
+template <class ACE_LOCK> ACE_INLINE
+ACE_Write_Guard<ACE_LOCK>::ACE_Write_Guard (ACE_LOCK &m,
+ int block)
+ : ACE_Guard<ACE_LOCK> (&m)
+{
+ if (block)
+ this->acquire_write ();
+ else
+ this->tryacquire_write ();
+}
+
+template <class ACE_LOCK> ACE_INLINE int
+ACE_Read_Guard<ACE_LOCK>::acquire_read (void)
+{
+ return this->owner_ = this->lock_->acquire_read ();
+}
+
+template <class ACE_LOCK> ACE_INLINE int
+ACE_Read_Guard<ACE_LOCK>::acquire (void)
+{
+ return this->owner_ = this->lock_->acquire_read ();
+}
+
+template <class ACE_LOCK> ACE_INLINE int
+ACE_Read_Guard<ACE_LOCK>::tryacquire_read (void)
+{
+ return this->owner_ = this->lock_->tryacquire_read ();
+}
+
+template <class ACE_LOCK> ACE_INLINE int
+ACE_Read_Guard<ACE_LOCK>::tryacquire (void)
+{
+ return this->owner_ = this->lock_->tryacquire_read ();
+}
+
+template <class ACE_LOCK> ACE_INLINE
+ACE_Read_Guard<ACE_LOCK>::ACE_Read_Guard (ACE_LOCK &m)
+ : ACE_Guard<ACE_LOCK> (&m)
+{
+ this->acquire_read ();
+}
+
+template <class ACE_LOCK> ACE_INLINE
+ACE_Read_Guard<ACE_LOCK>::ACE_Read_Guard (ACE_LOCK &m,
+ int block)
+ : ACE_Guard<ACE_LOCK> (&m)
+{
+ if (block)
+ this->acquire_read ();
+ else
+ this->tryacquire_read ();
+}
+
+template <class ACE_LOCKING_MECHANISM> ACE_INLINE
+ACE_Lock_Adapter<ACE_LOCKING_MECHANISM>::ACE_Lock_Adapter (ACE_LOCKING_MECHANISM &lock)
+ : lock_ (&lock),
+ delete_lock_ (0)
+{
+}
+
+template <class ACE_LOCKING_MECHANISM> ACE_INLINE
+ACE_Lock_Adapter<ACE_LOCKING_MECHANISM>::~ACE_Lock_Adapter (void)
+{
+ if (this->delete_lock_)
+ delete this->lock_;
+}
+
+// Explicitly destroy the lock.
+template <class ACE_LOCKING_MECHANISM> ACE_INLINE int
+ACE_Lock_Adapter<ACE_LOCKING_MECHANISM>::remove (void)
+{
+ return this->lock_->remove ();
+}
+
+// Block the thread until the lock is acquired.
+template <class ACE_LOCKING_MECHANISM> ACE_INLINE int
+ACE_Lock_Adapter<ACE_LOCKING_MECHANISM>::acquire (void)
+{
+ return this->lock_->acquire ();
+}
+
+// Conditionally acquire the lock (i.e., won't block).
+
+template <class ACE_LOCKING_MECHANISM> ACE_INLINE int
+ACE_Lock_Adapter<ACE_LOCKING_MECHANISM>::tryacquire (void)
+{
+ return this->lock_->tryacquire ();
+}
+
+// Release the lock.
+
+template <class ACE_LOCKING_MECHANISM> ACE_INLINE int
+ACE_Lock_Adapter<ACE_LOCKING_MECHANISM>::release (void)
+{
+ return this->lock_->release ();
+}
+
+// Block until the thread acquires a read lock. If the locking
+// mechanism doesn't support read locks then this just calls
+// <acquire>.
+
+template <class ACE_LOCKING_MECHANISM> ACE_INLINE int
+ACE_Lock_Adapter<ACE_LOCKING_MECHANISM>::acquire_read (void)
+{
+ return this->lock_->acquire_read ();
+}
+
+// Block until the thread acquires a write lock. If the locking
+// mechanism doesn't support read locks then this just calls
+// <acquire>.
+
+template <class ACE_LOCKING_MECHANISM> ACE_INLINE int
+ACE_Lock_Adapter<ACE_LOCKING_MECHANISM>::acquire_write (void)
+{
+ return this->lock_->acquire_write ();
+}
+
+// Conditionally acquire a read lock. If the locking mechanism
+// doesn't support read locks then this just calls <acquire>.
+
+template <class ACE_LOCKING_MECHANISM> ACE_INLINE int
+ACE_Lock_Adapter<ACE_LOCKING_MECHANISM>::tryacquire_read (void)
+{
+ return this->lock_->tryacquire_read ();
+}
+
+// Conditionally acquire a write lock. If the locking mechanism
+// doesn't support write locks then this just calls <acquire>.
+
+template <class ACE_LOCKING_MECHANISM> ACE_INLINE int
+ACE_Lock_Adapter<ACE_LOCKING_MECHANISM>::tryacquire_write (void)
+{
+ return this->lock_->tryacquire_write ();
+}
+
+// Conditionally try to upgrade a lock held for read to a write lock.
+// If the locking mechanism doesn't support read locks then this just
+// calls <acquire>. Returns 0 on success, -1 on failure.
+
+template <class ACE_LOCKING_MECHANISM> ACE_INLINE int
+ACE_Lock_Adapter<ACE_LOCKING_MECHANISM>::tryacquire_write_upgrade (void)
+{
+ return this->lock_->tryacquire_write_upgrade ();
+}
+
+template <class ACE_LOCKING_MECHANISM> ACE_INLINE
+ACE_Reverse_Lock<ACE_LOCKING_MECHANISM>::ACE_Reverse_Lock (ACE_LOCKING_MECHANISM &lock,
+ ACE_Acquire_Method::METHOD_TYPE acquire_method)
+ : lock_ (lock),
+ acquire_method_ (acquire_method)
+{
+}
+
+// Explicitly destroy the lock.
+template <class ACE_LOCKING_MECHANISM> ACE_INLINE int
+ACE_Reverse_Lock<ACE_LOCKING_MECHANISM>::remove (void)
+{
+ return this->lock_.remove ();
+}
+
+// Release the lock.
+template <class ACE_LOCKING_MECHANISM> ACE_INLINE int
+ACE_Reverse_Lock<ACE_LOCKING_MECHANISM>::acquire (void)
+{
+ return this->lock_.release ();
+}
+
+// Release the lock.
+template <class ACE_LOCKING_MECHANISM> ACE_INLINE int
+ACE_Reverse_Lock<ACE_LOCKING_MECHANISM>::tryacquire (void)
+{
+ ACE_NOTSUP_RETURN (-1);
+}
+
+// Acquire the lock.
+template <class ACE_LOCKING_MECHANISM> ACE_INLINE int
+ACE_Reverse_Lock<ACE_LOCKING_MECHANISM>::release (void)
+{
+ if (this->acquire_method_ == ACE_Acquire_Method::ACE_READ)
+ return this->lock_.acquire_read ();
+ else if (this->acquire_method_ == ACE_Acquire_Method::ACE_WRITE)
+ return this->lock_.acquire_write ();
+ else
+ return this->lock_.acquire ();
+}
+
+// Release the lock.
+template <class ACE_LOCKING_MECHANISM> ACE_INLINE int
+ACE_Reverse_Lock<ACE_LOCKING_MECHANISM>::acquire_read (void)
+{
+ ACE_NOTSUP_RETURN (-1);
+}
+
+// Release the lock.
+template <class ACE_LOCKING_MECHANISM> ACE_INLINE int
+ACE_Reverse_Lock<ACE_LOCKING_MECHANISM>::acquire_write (void)
+{
+ ACE_NOTSUP_RETURN (-1);
+}
+
+// Release the lock.
+template <class ACE_LOCKING_MECHANISM> ACE_INLINE int
+ACE_Reverse_Lock<ACE_LOCKING_MECHANISM>::tryacquire_read (void)
+{
+ ACE_NOTSUP_RETURN (-1);
+}
+
+// Release the lock.
+template <class ACE_LOCKING_MECHANISM> ACE_INLINE int
+ACE_Reverse_Lock<ACE_LOCKING_MECHANISM>::tryacquire_write (void)
+{
+ ACE_NOTSUP_RETURN (-1);
+}
+
+// Release the lock.
+template <class ACE_LOCKING_MECHANISM> ACE_INLINE int
+ACE_Reverse_Lock<ACE_LOCKING_MECHANISM>::tryacquire_write_upgrade (void)
+{
+ ACE_NOTSUP_RETURN (-1);
+}
+
+#if defined (ACE_HAS_THREADS)
+
+template<class MUTEX> ACE_INLINE int
+ACE_Condition<MUTEX>::remove (void)
+{
+ // ACE_TRACE ("ACE_Condition<MUTEX>::remove");
+
+ // cond_destroy() is called in a loop if the condition variable is
+ // BUSY. This avoids a condition where a condition is signaled and
+ // because of some timing problem, the thread that is to be signaled
+ // has called the cond_wait routine after the signal call. Since
+ // the condition signal is not queued in any way, deadlock occurs.
+
+ int result = 0;
+
+#if defined (CHORUS)
+ // Are we the owner?
+ if (this->process_cond_ && this->condname_)
+ {
+ // Only destroy the condition if we're the ones who initialized
+ // it.
+ while ((result = ACE_OS::cond_destroy (this->process_cond_)) == -1
+ && errno == EBUSY)
+ {
+ ACE_OS::cond_broadcast (this->process_cond_);
+ ACE_OS::thr_yield ();
+ }
+ ACE_OS::munmap (this->process_cond_,
+ sizeof (ACE_cond_t));
+ ACE_OS::shm_unlink (this->condname_);
+ ACE_OS::free (ACE_static_cast (void *,
+ ACE_const_cast (ACE_TCHAR *,
+ this->condname_)));
+ }
+ else if (this->process_cond_)
+ {
+ ACE_OS::munmap (this->process_cond_,
+ sizeof (ACE_cond_t));
+ result = 0;
+ }
+ else
+#endif /* CHORUS */
+
+ while ((result = ACE_OS::cond_destroy (&this->cond_)) == -1
+ && errno == EBUSY)
+ {
+ ACE_OS::cond_broadcast (&this->cond_);
+ ACE_OS::thr_yield ();
+ }
+
+ return result;
+}
+
+template<class MUTEX> ACE_INLINE MUTEX &
+ACE_Condition<MUTEX>::mutex (void)
+{
+ // ACE_TRACE ("ACE_Condition<MUTEX>::mutex");
+ return this->mutex_;
+}
+
+template <class MUTEX> ACE_INLINE int
+ACE_Condition<MUTEX>::signal (void)
+{
+// ACE_TRACE ("ACE_Condition<MUTEX>::signal");
+#if defined (CHORUS)
+ if (this->process_cond_ != 0)
+ return ACE_OS::cond_signal (this->process_cond_);
+#endif /* CHORUS */
+ return ACE_OS::cond_signal (&this->cond_);
+}
+
+template <class MUTEX> ACE_INLINE int
+ACE_Condition<MUTEX>::broadcast (void)
+{
+// ACE_TRACE ("ACE_Condition<MUTEX>::broadcast");
+#if defined (CHORUS)
+ if (this->process_cond_ != 0)
+ return ACE_OS::cond_broadcast (this->process_cond_);
+#endif /* CHORUS */
+ return ACE_OS::cond_broadcast (&this->cond_);
+}
+
+#endif /* ACE_HAS_THREADS */
+
+#if !(defined (ACE_HAS_THREADS) && (defined (ACE_HAS_THREAD_SPECIFIC_STORAGE) || defined (ACE_HAS_TSS_EMULATION)))
+template <class TYPE> ACE_INLINE
+ACE_TSS<TYPE>::ACE_TSS (TYPE *type)
+ : type_ (type)
+{
+}
+
+template <class TYPE> ACE_INLINE int
+ACE_TSS<TYPE>::ts_init (void) const
+{
+ return 0;
+}
+
+template <class TYPE> ACE_INLINE TYPE *
+ACE_TSS<TYPE>::ts_object (void) const
+{
+ return this->type_;
+}
+
+template <class TYPE> ACE_INLINE TYPE *
+ACE_TSS<TYPE>::ts_object (TYPE *type)
+{
+ this->type_ = type;
+ return this->type_;
+}
+
+template <class TYPE> ACE_INLINE TYPE *
+ACE_TSS<TYPE>::ts_get (void) const
+{
+ return this->type_;
+}
+
+#endif /* ! (defined (ACE_HAS_THREADS) && (defined (ACE_HAS_THREAD_SPECIFIC_STORAGE) || defined (ACE_HAS_TSS_EMULATION))) */
diff --git a/ace/Threads/Thread.cpp b/ace/Threads/Thread.cpp
new file mode 100644
index 00000000000..7fa156c2488
--- /dev/null
+++ b/ace/Threads/Thread.cpp
@@ -0,0 +1,90 @@
+// Thread.cpp
+// $Id$
+
+#include "ace/Thread.h"
+
+#if !defined (__ACE_INLINE__)
+#include "ace/Thread.i"
+#endif /* !defined (__ACE_INLINE__) */
+
+ACE_RCSID(ace, Thread, "$Id$")
+
+#if defined (ACE_HAS_THREADS)
+
+int
+ACE_Thread::spawn_n (size_t n,
+ ACE_THR_FUNC func,
+ void *arg,
+ long flags,
+ long priority,
+ void *stack[],
+ size_t stack_size[],
+ ACE_Thread_Adapter *thread_adapter)
+{
+ ACE_TRACE ("ACE_Thread::spawn_n");
+ ACE_thread_t t_id;
+ size_t i;
+
+ for (i = 0; i < n; i++)
+ // Bail out if error occurs.
+ if (ACE_OS::thr_create (func,
+ arg,
+ flags,
+ &t_id,
+ 0,
+ priority,
+ stack == 0 ? 0 : stack[i],
+ stack_size == 0 ? 0 : stack_size[i],
+ thread_adapter) != 0)
+ break;
+
+ return i;
+}
+
+int
+ACE_Thread::spawn_n (ACE_thread_t thread_ids[],
+ size_t n,
+ ACE_THR_FUNC func,
+ void *arg,
+ long flags,
+ long priority,
+ void *stack[],
+ size_t stack_size[],
+ ACE_hthread_t thread_handles[],
+ ACE_Thread_Adapter *thread_adapter)
+{
+ ACE_TRACE ("ACE_Thread::spawn_n");
+ size_t i;
+
+ for (i = 0; i < n; i++)
+ {
+ ACE_thread_t t_id;
+ ACE_hthread_t t_handle;
+
+ int result =
+ ACE_OS::thr_create (func,
+ arg,
+ flags,
+ &t_id,
+ &t_handle,
+ priority,
+ stack == 0 ? 0 : stack[i],
+ stack_size == 0 ? 0 : stack_size[i],
+ thread_adapter);
+
+ if (result == 0)
+ {
+ if (thread_ids != 0)
+ thread_ids[i] = t_id;
+ if (thread_handles != 0)
+ thread_handles[i] = t_handle;
+ }
+ else
+ // Bail out if error occurs.
+ break;
+ }
+
+ return i;
+}
+
+#endif /* ACE_HAS_THREADS */
diff --git a/ace/Threads/Thread.h b/ace/Threads/Thread.h
new file mode 100644
index 00000000000..9de66e1d3fe
--- /dev/null
+++ b/ace/Threads/Thread.h
@@ -0,0 +1,240 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Thread.h
+ *
+ * $Id$
+ *
+ * @author Douglas Schmidt <schmidt@cs.wustl.edu>
+ */
+//=============================================================================
+
+#ifndef ACE_THREAD_H
+#define ACE_THREAD_H
+#include "ace/pre.h"
+
+#include "ace/ACE.h"
+#include "ace/Thread_Adapter.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+/**
+ * @class ACE_Thread
+ *
+ * @brief Provides a wrapper for threads.
+ *
+ * This class provides a common interface that is mapped onto
+ * POSIX Pthreads, Solaris threads, Win32 threads, VxWorks
+ * threads, or pSoS threads. Note, however, that it is
+ * generally a better idea to use the <ACE_Thread_Manager>
+ * programming API rather than the <ACE_Thread> API since the
+ * thread manager is more powerful.
+ */
+class ACE_Export ACE_Thread
+{
+public:
+ /**
+ * Creates a new thread having <flags> attributes and running <func>
+ * with <args> (if <thread_adapter> is non-0 then <func> and <args>
+ * are ignored and are obtained from <thread_adapter>). <thr_id>
+ * and <t_handle> are set to the thread's ID and handle (?),
+ * respectively. The thread runs at <priority> priority (see
+ * below).
+ *
+ * The <flags> are a bitwise-OR of the following:
+ * = BEGIN<INDENT>
+ * THR_CANCEL_DISABLE, THR_CANCEL_ENABLE, THR_CANCEL_DEFERRED,
+ * THR_CANCEL_ASYNCHRONOUS, THR_BOUND, THR_NEW_LWP, THR_DETACHED,
+ * THR_SUSPENDED, THR_DAEMON, THR_JOINABLE, THR_SCHED_FIFO,
+ * THR_SCHED_RR, THR_SCHED_DEFAULT, THR_EXPLICIT_SCHED,
+ * THR_SCOPE_SYSTEM, THR_SCOPE_PROCESS
+ * = END<INDENT>
+ *
+ * By default, or if <priority> is set to
+ * ACE_DEFAULT_THREAD_PRIORITY, an "appropriate" priority value for
+ * the given scheduling policy (specified in <flags}>, e.g.,
+ * <THR_SCHED_DEFAULT>) is used. This value is calculated
+ * dynamically, and is the median value between the minimum and
+ * maximum priority values for the given policy. If an explicit
+ * value is given, it is used. Note that actual priority values are
+ * EXTREMEMLY implementation-dependent, and are probably best
+ * avoided.
+ *
+ * Note that <thread_adapter> is always deleted when <spawn>
+ * is called, so it must be allocated with global operator new.
+ */
+ static int spawn (ACE_THR_FUNC func,
+ void *arg = 0,
+ long flags = THR_NEW_LWP | THR_JOINABLE,
+ ACE_thread_t *t_id = 0,
+ ACE_hthread_t *t_handle = 0,
+ long priority = ACE_DEFAULT_THREAD_PRIORITY,
+ void *stack = 0,
+ size_t stack_size = 0,
+ ACE_Thread_Adapter *thread_adapter = 0);
+
+ /**
+ * Spawn N new threads, which execute <func> with argument <arg> (if
+ * <thread_adapter> is non-0 then <func> and <args> are ignored and
+ * are obtained from <thread_adapter>). If <stack> != 0 it is
+ * assumed to be an array of <n> pointers to the base of the stacks
+ * to use for the threads being spawned. Likewise, if <stack_size>
+ * != 0 it is assumed to be an array of <n> values indicating how
+ * big each of the corresponding <stack>s are. Returns the number
+ * of threads actually spawned (if this doesn't equal the number
+ * requested then something has gone wrong and <errno> will
+ * explain...).
+ *
+ * See also <spawn>.
+ */
+ static int spawn_n (size_t n,
+ ACE_THR_FUNC func,
+ void *arg = 0,
+ long flags = THR_NEW_LWP | THR_JOINABLE,
+ long priority = ACE_DEFAULT_THREAD_PRIORITY,
+ void *stack[] = 0,
+ size_t stack_size[] = 0,
+ ACE_Thread_Adapter *thread_adapter = 0);
+
+ /**
+ * Spawn <n> new threads, which execute <func> with argument <arg>
+ * (if <thread_adapter> is non-0 then <func> and <args> are ignored
+ * and are obtained from <thread_adapter>). The thread_ids of
+ * successfully spawned threads will be placed into the <thread_ids>
+ * buffer (which must be the same size as <n>). If <stack> != 0 it
+ * is assumed to be an array of <n> pointers to the base of the
+ * stacks to use for the threads being spawned. If <stack_size> !=
+ * 0 it is assumed to be an array of <n> values indicating how big
+ * each of the corresponding <stack>s are. If <thread_handles> != 0
+ * it is assumed to be an array of <n> thread_handles that will be
+ * assigned the values of the thread handles being spawned. Returns
+ * the number of threads actually spawned (if this doesn't equal the
+ * number requested then something has gone wrong and <errno> will
+ * explain...).
+ *
+ * See also <spawn>.
+ */
+ static int spawn_n (ACE_thread_t thread_ids[],
+ size_t n,
+ ACE_THR_FUNC func,
+ void *arg,
+ long flags,
+ long priority = ACE_DEFAULT_THREAD_PRIORITY,
+ void *stack[] = 0,
+ size_t stack_size[] = 0,
+ ACE_hthread_t thread_handles[] = 0,
+ ACE_Thread_Adapter *thread_adapter = 0);
+
+ /// Wait for one or more threads to exit and reap their exit status.
+ static int join (ACE_thread_t,
+ ACE_thread_t *,
+ void **status);
+
+ /// Wait for one thread to exit and reap its exit status.
+ static int join (ACE_hthread_t,
+ void ** = 0);
+
+ /// Continue the execution of a previously suspended thread.
+ static int resume (ACE_hthread_t);
+
+ /// Suspend the execution of a particular thread.
+ static int suspend (ACE_hthread_t);
+
+ /// Get the priority of a particular thread.
+ static int getprio (ACE_hthread_t, int &prio);
+
+ /// Set the priority of a particular thread.
+ static int setprio (ACE_hthread_t, int prio);
+
+ /// Send a signal to the thread.
+ static int kill (ACE_thread_t, int signum);
+
+ /// Yield the thread to another.
+ static void yield (void);
+
+ /**
+ * Return the unique kernel handle of the thread. Note that on
+ * Win32 this is actually a pseudohandle, which cannot be shared
+ * with other processes or waited on by threads. To locate the real
+ * handle, please use the <ACE_Thread_Manager::thr_self> method.
+ */
+ static void self (ACE_hthread_t &t_handle);
+
+ /// Return the unique ID of the thread.
+ static ACE_thread_t self (void);
+
+ /// Exit the current thread and return "status".
+ /// Should _not_ be called by main thread.
+ static void exit (void *status = 0);
+
+ /// Get the LWP concurrency level of the process.
+ static int getconcurrency (void);
+
+ /// Set the LWP concurrency level of the process.
+ static int setconcurrency (int new_level);
+
+ /// Change and/or examine calling thread's signal mask.
+ static int sigsetmask (int how,
+ const sigset_t *sigset,
+ sigset_t *osigset = 0);
+
+ static int keycreate (ACE_thread_key_t *keyp,
+#if defined (ACE_HAS_THR_C_DEST)
+ ACE_THR_C_DEST destructor,
+#else
+ ACE_THR_DEST destructor,
+#endif /* ACE_HAS_THR_C_DEST */
+ /**
+ * Allocates a <keyp> that is used to identify data that is specific
+ * to each thread in the process. The key is global to all threads
+ * in the process.
+ */
+ void * = 0);
+
+ /// Free up the key so that other threads can reuse it.
+ static int keyfree (ACE_thread_key_t key);
+
+ /// Bind value to the thread-specific data key, <key>, for the calling
+ /// thread.
+ static int setspecific (ACE_thread_key_t key,
+ void *value);
+
+ /// Stores the current value bound to <key> for the calling thread
+ /// into the location pointed to by <valuep>.
+ static int getspecific (ACE_thread_key_t key,
+ void **valuep);
+
+ /// Disable thread cancellation.
+ static int disablecancel (struct cancel_state *old_state);
+
+ /// Enable thread cancellation.
+ static int enablecancel (struct cancel_state *old_state,
+ int flag);
+
+ /// Set the cancellation state.
+ static int setcancelstate (struct cancel_state &new_state,
+ struct cancel_state *old_state);
+
+ /**
+ * Cancel a thread. Note that this method is only portable on
+ * platforms, such as POSIX pthreads, that support thread
+ * cancellation.
+ */
+ static int cancel (ACE_thread_t t_id);
+
+ /// Test the cancel.
+ static void testcancel (void);
+
+private:
+ /// Ensure that we don't get instantiated.
+ ACE_Thread (void);
+};
+
+#if defined (__ACE_INLINE__)
+#include "ace/Thread.i"
+#endif /* __ACE_INLINE__ */
+#include "ace/post.h"
+#endif /* ACE_THREAD_H */
diff --git a/ace/Threads/Thread.i b/ace/Threads/Thread.i
new file mode 100644
index 00000000000..610b84f1ad0
--- /dev/null
+++ b/ace/Threads/Thread.i
@@ -0,0 +1,272 @@
+/* -*- C++ -*- */
+// $Id$
+
+// Thread.i
+
+// Allocates a <keyp> that is used to identify data that is specific
+// to each thread in the process. The key is global to all threads in
+// the process.
+
+ACE_INLINE int
+ACE_Thread::keycreate (ACE_thread_key_t *keyp,
+#if defined (ACE_HAS_THR_C_DEST)
+ ACE_THR_C_DEST destructor,
+#else
+ ACE_THR_DEST destructor,
+#endif /* ACE_HAS_THR_C_DEST */
+ void *inst)
+{
+ // ACE_TRACE ("ACE_Thread::keycreate");
+ return ACE_OS::thr_keycreate (keyp, destructor, inst);
+}
+
+// Free up the key so that other threads can reuse it.
+
+ACE_INLINE int
+ACE_Thread::keyfree (ACE_thread_key_t key)
+{
+ ACE_TRACE ("ACE_Thread::keyfree");
+ return ACE_OS::thr_keyfree (key);
+}
+
+// Bind value to the thread-specific data key, <key>, for the calling
+// thread.
+
+ACE_INLINE int
+ACE_Thread::setspecific (ACE_thread_key_t key, void *value)
+{
+ // ACE_TRACE ("ACE_Thread::setspecific");
+ return ACE_OS::thr_setspecific (key, value);
+}
+
+// Stores the current value bound to <key> for the calling thread
+// into the location pointed to by <valuep>.
+
+ACE_INLINE int
+ACE_Thread::getspecific (ACE_thread_key_t key, void **valuep)
+{
+ // ACE_TRACE ("ACE_Thread::getspecific");
+ return ACE_OS::thr_getspecific (key, valuep);
+}
+
+ACE_INLINE ACE_thread_t
+ACE_Thread::self (void)
+{
+// ACE_TRACE ("ACE_Thread::self");
+ return ACE_OS::thr_self ();
+}
+
+ACE_INLINE void
+ACE_Thread::exit (void *status)
+{
+ ACE_TRACE ("ACE_Thread::exit");
+ ACE_OS::thr_exit (status);
+}
+
+ACE_INLINE void
+ACE_Thread::yield (void)
+{
+ ACE_TRACE ("ACE_Thread::yield");
+ ACE_OS::thr_yield ();
+}
+
+ACE_INLINE int
+ACE_Thread::spawn (ACE_THR_FUNC func,
+ void *arg,
+ long flags,
+ ACE_thread_t *t_id,
+ ACE_hthread_t *t_handle,
+ long priority,
+ void *thr_stack,
+ size_t thr_stack_size,
+ ACE_Thread_Adapter *thread_adapter)
+{
+ ACE_TRACE ("ACE_Thread::spawn");
+
+ return ACE_OS::thr_create (func,
+ arg,
+ flags,
+ t_id,
+ t_handle,
+ priority,
+ thr_stack,
+ thr_stack_size,
+ thread_adapter);
+}
+
+ACE_INLINE int
+ACE_Thread::resume (ACE_hthread_t t_id)
+{
+ ACE_TRACE ("ACE_Thread::resume");
+ return ACE_OS::thr_continue (t_id);
+}
+
+ACE_INLINE int
+ACE_Thread::suspend (ACE_hthread_t t_id)
+{
+ ACE_TRACE ("ACE_Thread::suspend");
+ return ACE_OS::thr_suspend (t_id);
+}
+
+ACE_INLINE int
+ACE_Thread::kill (ACE_thread_t t_id, int signum)
+{
+ ACE_TRACE ("ACE_Thread::kill");
+ return ACE_OS::thr_kill (t_id, signum);
+}
+
+ACE_INLINE int
+ACE_Thread::join (ACE_thread_t wait_for,
+ ACE_thread_t *departed,
+ void **status)
+{
+ ACE_TRACE ("ACE_Thread::join");
+ return ACE_OS::thr_join (wait_for, departed, status);
+}
+
+ACE_INLINE int
+ACE_Thread::join (ACE_hthread_t wait_for,
+ void **status)
+{
+ ACE_TRACE ("ACE_Thread::join");
+ return ACE_OS::thr_join (wait_for, status);
+}
+
+ACE_INLINE int
+ACE_Thread::getconcurrency (void)
+{
+ ACE_TRACE ("ACE_Thread::getconcurrency");
+ return ACE_OS::thr_getconcurrency ();
+}
+
+ACE_INLINE int
+ACE_Thread::setconcurrency (int new_level)
+{
+ ACE_TRACE ("ACE_Thread::setconcurrency");
+ return ACE_OS::thr_setconcurrency (new_level);
+}
+
+ACE_INLINE int
+ACE_Thread::sigsetmask (int how,
+ const sigset_t *sigset,
+ sigset_t *osigset)
+{
+ ACE_TRACE ("ACE_Thread::sigsetmask");
+ return ACE_OS::thr_sigsetmask (how, sigset, osigset);
+}
+
+ACE_INLINE int
+ACE_Thread::disablecancel (struct cancel_state *old_state)
+{
+ ACE_TRACE ("ACE_Thread::disablecancel");
+ int old_cstate = 0;
+ int result = ACE_OS::thr_setcancelstate (THR_CANCEL_DISABLE,
+ &old_cstate);
+ if (result == 0 && old_state != 0)
+ {
+ ACE_OS::memset (old_state,
+ 0,
+ sizeof (old_state));
+ old_state->cancelstate = old_cstate;
+ }
+
+ return result;
+}
+
+ACE_INLINE int
+ACE_Thread::enablecancel (struct cancel_state *old_state,
+ int flag)
+{
+ ACE_TRACE ("ACE_Thread::enablecancel");
+ int old_cstate = 0;
+ int old_ctype = 0;
+ int result;
+
+ result = ACE_OS::thr_setcancelstate (THR_CANCEL_ENABLE,
+ &old_cstate);
+ if (result != 0)
+ return result;
+
+ result = ACE_OS::thr_setcanceltype (flag,
+ &old_ctype);
+ if (result != 0)
+ return result;
+
+ if (old_state != 0)
+ {
+ old_state->cancelstate = old_cstate;
+ old_state->canceltype = old_ctype;
+ }
+
+ return 0;
+}
+
+ACE_INLINE int
+ACE_Thread::setcancelstate (struct cancel_state &new_state,
+ struct cancel_state *old_state)
+{
+ ACE_TRACE ("ACE_Thread::setcancelstate");
+ int old_cstate = 0;
+ int old_ctype = 0;
+
+ if (new_state.cancelstate != 0
+ && ACE_OS::thr_setcancelstate (new_state.cancelstate,
+ &old_cstate) != 0)
+ return -1;
+
+ if (new_state.canceltype != 0
+ && ACE_OS::thr_setcanceltype (new_state.canceltype,
+ &old_ctype) != 0)
+ {
+ int o_cstate;
+
+ ACE_OS::thr_setcancelstate (old_cstate,
+ &o_cstate);
+ return -1;
+ }
+
+ if (old_state != 0)
+ {
+ old_state->cancelstate = old_cstate;
+ old_state->canceltype = old_ctype;
+ }
+
+ return 0;
+}
+
+ACE_INLINE int
+ACE_Thread::cancel (ACE_thread_t t_id)
+{
+ ACE_TRACE ("ACE_Thread::cancel");
+
+ return ACE_OS::thr_cancel (t_id);
+}
+
+ACE_INLINE void
+ACE_Thread::testcancel (void)
+{
+ ACE_TRACE ("ACE_Thread::testcancel");
+
+ ACE_OS::thr_testcancel ();
+}
+
+ACE_INLINE void
+ACE_Thread::self (ACE_hthread_t &t_id)
+{
+// ACE_TRACE ("ACE_Thread::self");
+ ACE_OS::thr_self (t_id);
+}
+
+ACE_INLINE int
+ACE_Thread::getprio (ACE_hthread_t t_id, int &prio)
+{
+ ACE_TRACE ("ACE_Thread::getprio");
+ return ACE_OS::thr_getprio (t_id, prio);
+}
+
+ACE_INLINE int
+ACE_Thread::setprio (ACE_hthread_t t_id, int prio)
+{
+ ACE_TRACE ("ACE_Thread::setprio");
+ return ACE_OS::thr_setprio (t_id, prio);
+}
diff --git a/ace/Threads/Thread_Adapter.cpp b/ace/Threads/Thread_Adapter.cpp
new file mode 100644
index 00000000000..91357bfc58f
--- /dev/null
+++ b/ace/Threads/Thread_Adapter.cpp
@@ -0,0 +1,252 @@
+// $Id$
+
+#include "ace/Thread_Adapter.h"
+#include "ace/OS.h"
+#include "ace/Thread_Manager.h"
+#include "ace/Thread_Exit.h"
+#include "ace/Thread_Hook.h"
+
+ACE_RCSID(ace, Thread_Adapter, "$Id$")
+
+#if !defined (ACE_HAS_INLINED_OSCALLS)
+# include "ace/Thread_Adapter.inl"
+#endif /* ACE_HAS_INLINED_OS_CALLS */
+
+ACE_Thread_Adapter::ACE_Thread_Adapter (ACE_THR_FUNC user_func,
+ void *arg,
+ ACE_THR_C_FUNC entry_point,
+ ACE_Thread_Manager *tm,
+ ACE_Thread_Descriptor *td
+#if defined (ACE_HAS_WIN32_STRUCTURAL_EXCEPTIONS)
+ , ACE_SEH_EXCEPT_HANDLER selector,
+ ACE_SEH_EXCEPT_HANDLER handler
+#endif /* ACE_HAS_WIN32_STRUCTURAL_EXCEPTIONS */
+ )
+ : ACE_Base_Thread_Adapter (
+ user_func
+ , arg
+ , entry_point
+ , td
+#if defined (ACE_HAS_WIN32_STRUCTURAL_EXCEPTIONS)
+ , selector
+ , handler
+#endif /* ACE_HAS_WIN32_STRUCTURAL_EXCEPTIONS */
+ )
+ , thr_mgr_ (tm)
+{
+ ACE_OS_TRACE ("ACE_Thread_Adapter::ACE_Thread_Adapter");
+}
+
+ACE_Thread_Adapter::~ACE_Thread_Adapter (void)
+{
+}
+
+void *
+ACE_Thread_Adapter::invoke (void)
+{
+ // Inherit the logging features if the parent thread has an
+ // ACE_Log_Msg instance in thread-specific storage.
+ this->inherit_log_msg ();
+
+#if !defined(ACE_USE_THREAD_MANAGER_ADAPTER)
+ // NOTE: this preprocessor directive should match the one in above
+ // ACE_Thread_Exit::instance (). With the Xavier Pthreads package,
+ // the exit_hook in TSS causes a seg fault. So, this works around
+ // that by creating exit_hook on the stack.
+# if defined (ACE_HAS_THREAD_SPECIFIC_STORAGE) || defined (ACE_HAS_TSS_EMULATION)
+ // Obtain our thread-specific exit hook and make sure that it knows
+ // how to clean us up! Note that we never use this pointer directly
+ // (it's stored in thread-specific storage), so it's ok to
+ // dereference it here and only store it as a reference.
+
+ // Except if it is null, then the thr_mgr() method crashes.
+ // -jxh
+
+ ACE_Thread_Exit *exit_hook_instance = ACE_Thread_Exit::instance ();
+ ACE_Thread_Exit_Maybe exit_hook_maybe (exit_hook_instance == 0);
+ ACE_Thread_Exit *exit_hook_ptr = exit_hook_instance
+ ? exit_hook_instance
+ : exit_hook_maybe.instance ();
+ ACE_Thread_Exit &exit_hook = *exit_hook_ptr;
+
+ if (this->thr_mgr () != 0)
+ {
+ // Keep track of the <Thread_Manager> that's associated with this
+ // <exit_hook>.
+ exit_hook.thr_mgr (this->thr_mgr ());
+ }
+# else
+ // Without TSS, create an <ACE_Thread_Exit> instance. When this
+ // function returns, its destructor will be called because the
+ // object goes out of scope. The drawback with this appraoch is
+ // that the destructor _won't_ get called if <thr_exit> is called.
+ // So, threads shouldn't exit that way. Instead, they should return
+ // from <svc>.
+ ACE_Thread_Exit exit_hook;
+ exit_hook.thr_mgr (this->thr_mgr ());
+# endif /* ACE_HAS_THREAD_SPECIFIC_STORAGE || ACE_HAS_TSS_EMULATION */
+
+#endif /* ! ACE_USE_THREAD_MANAGER_ADAPTER */
+
+ return this->invoke_i ();
+}
+
+void *
+ACE_Thread_Adapter::invoke_i (void)
+{
+ // Extract the arguments.
+ ACE_THR_FUNC_INTERNAL func = ACE_reinterpret_cast (ACE_THR_FUNC_INTERNAL,
+ this->user_func_);
+ void *arg = this->arg_;
+
+#if defined (ACE_WIN32) && defined (ACE_HAS_MFC) && (ACE_HAS_MFC != 0)
+ ACE_OS_Thread_Descriptor *thr_desc = this->thr_desc_;
+#endif /* ACE_WIN32 && ACE_HAS_MFC && (ACE_HAS_MFC != 0) */
+
+ // Delete ourselves since we don't need <this> anymore. Make sure
+ // not to access <this> anywhere below this point.
+ delete this;
+
+#if defined (ACE_NEEDS_LWP_PRIO_SET)
+ // On SunOS, the LWP priority needs to be set in order to get
+ // preemption when running in the RT class. This is the ACE way to
+ // do that . . .
+ ACE_hthread_t thr_handle;
+ ACE_OS::thr_self (thr_handle);
+ int prio;
+
+ // thr_getprio () on the current thread should never fail.
+ ACE_OS::thr_getprio (thr_handle, prio);
+
+ // ACE_OS::thr_setprio () has the special logic to set the LWP priority,
+ // if running in the RT class.
+ ACE_OS::thr_setprio (prio);
+
+#endif /* ACE_NEEDS_LWP_PRIO_SET */
+
+ void *status = 0;
+
+ ACE_SEH_TRY
+ {
+ ACE_SEH_TRY
+ {
+ ACE_Thread_Hook *hook =
+ ACE_OS_Object_Manager::thread_hook ();
+
+ if (hook)
+ // Invoke the start hook to give the user a chance to
+ // perform some initialization processing before the
+ // <func> is invoked.
+ status = hook->start (ACE_reinterpret_cast (ACE_THR_FUNC, func),
+ arg);
+ else
+ {
+ // Call thread entry point.
+#if defined (ACE_PSOS)
+ (*func) (arg);
+#else /* ! ACE_PSOS */
+ status = ACE_reinterpret_cast (void *, (*func) (arg));
+#endif /* ACE_PSOS */
+ }
+#if defined (ACE_PSOS)
+ // pSOS task functions do not return a value.
+ status = 0;
+#endif /* ACE_PSOS */
+ }
+
+#if defined (ACE_HAS_WIN32_STRUCTURAL_EXCEPTIONS)
+ ACE_SEH_EXCEPT (ACE_OS_Object_Manager::seh_except_selector ()(
+ (void *) GetExceptionInformation ()))
+ {
+ ACE_OS_Object_Manager::seh_except_handler ()(0);
+ }
+#endif /* ACE_HAS_WIN32_STRUCTURAL_EXCEPTIONS */
+ }
+
+ ACE_SEH_FINALLY
+ {
+ // If we changed this to 1, change the respective if in
+ // Task::svc_run to 0.
+#if 0
+ // Call the <Task->close> hook.
+ if (func == ACE_reinterpret_cast (ACE_THR_FUNC_INTERNAL,
+ ACE_Task_Base::svc_run))
+ {
+ ACE_Task_Base *task_ptr = (ACE_Task_Base *) arg;
+ ACE_Thread_Manager *thr_mgr_ptr = task_ptr->thr_mgr ();
+
+ // This calls the Task->close () hook.
+ task_ptr->cleanup (task_ptr, 0);
+
+ // This prevents a second invocation of the cleanup code
+ // (called later by <ACE_Thread_Manager::exit>.
+ thr_mgr_ptr->at_exit (task_ptr, 0, 0);
+ }
+#endif /* 0 */
+
+#if defined (ACE_WIN32) || defined (ACE_HAS_TSS_EMULATION)
+# if defined (ACE_WIN32) && defined (ACE_HAS_MFC) && (ACE_HAS_MFC != 0)
+ int using_afx = -1;
+ if (thr_desc)
+ using_afx = ACE_BIT_ENABLED (thr_desc->flags (), THR_USE_AFX);
+# endif /* ACE_WIN32 && ACE_HAS_MFC && (ACE_HAS_MFC != 0) */
+ // Call TSS destructors.
+ ACE_OS::cleanup_tss (0 /* not main thread */);
+
+# if defined (ACE_WIN32)
+ // Exit the thread. Allow CWinThread-destructor to be invoked
+ // from AfxEndThread. _endthreadex will be called from
+ // AfxEndThread so don't exit the thread now if we are running
+ // an MFC thread.
+# if defined (ACE_HAS_MFC) && (ACE_HAS_MFC != 0)
+ if (using_afx != -1)
+ {
+ if (using_afx)
+ ::AfxEndThread ((DWORD) status);
+ else
+ ACE_ENDTHREADEX (status);
+ }
+ else
+ {
+ // Not spawned by ACE_Thread_Manager, use the old buggy
+ // version. You should seriously consider using
+ // ACE_Thread_Manager to spawn threads. The following code
+ // is know to cause some problem.
+ CWinThread *pThread = ::AfxGetThread ();
+
+ if (!pThread || pThread->m_nThreadID != ACE_OS::thr_self ())
+ ACE_ENDTHREADEX (status);
+ else
+ ::AfxEndThread ((DWORD)status);
+ }
+# else
+
+ ACE_ENDTHREADEX (status);
+# endif /* ACE_HAS_MFC && ACE_HAS_MFS != 0*/
+# endif /* ACE_WIN32 */
+#endif /* ACE_WIN32 || ACE_HAS_TSS_EMULATION */
+
+#if defined (ACE_PSOS)
+ // This sequence of calls is documented by ISI as the proper way to
+ // clean up a pSOS task. They affect different components, so only
+ // try the ones for components that are built with ACE.
+# if defined (SC_PREPC) && (SC_PREPC == YES)
+ ::fclose (0); // Return pREPC+ resources
+# endif /* SC_PREPC */
+# if defined (SC_PHILE) && (SC_PHILE == YES)
+ ::close_f (0); // Return pHILE+ resources
+# endif /* SC_PHILE */
+# if defined (SC_PNA) && (SC_PNA == YES)
+ ::close (0); // Return pNA+ resources
+# endif /* SC_PNA */
+# if defined (SC_SC_PREPC) && (SC_PREPC == YES)
+ ::free (-1); // Return pREPC+ memory
+# endif /* SC_PREPC */
+ status = ::t_delete (0); // Suicide - only returns on error
+#endif /* ACE_PSOS */
+
+ return status;
+ }
+
+ ACE_NOTREACHED (return status);
+}
diff --git a/ace/Threads/Thread_Adapter.h b/ace/Threads/Thread_Adapter.h
new file mode 100644
index 00000000000..d7e8bd54f0f
--- /dev/null
+++ b/ace/Threads/Thread_Adapter.h
@@ -0,0 +1,92 @@
+
+//=============================================================================
+/**
+ * @file Thread_Adapter.h
+ *
+ * $Id$
+ *
+ * @author Carlos O'Ryan <coryan@uci.edu>
+ */
+//=============================================================================
+
+#ifndef ACE_THREAD_ADAPTER_H
+#define ACE_THREAD_ADAPTER_H
+#include "ace/pre.h"
+
+#include "ace/Base_Thread_Adapter.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+// Forward decl.
+class ACE_Thread_Manager;
+class ACE_Thread_Descriptor;
+
+/**
+ * @class ACE_Thread_Adapter
+ *
+ * @brief Converts a C++ function into a function <ace_thread_adapter>
+ * function that can be called from a thread creation routine
+ * (e.g., <pthread_create> or <_beginthreadex>) that expects an
+ * extern "C" entry point. This class also makes it possible to
+ * transparently provide hooks to register a thread with an
+ * <ACE_Thread_Manager>.
+ *
+ * This class is used in <ACE_OS::thr_create>. In general, the
+ * thread that creates an object of this class is different from
+ * the thread that calls <invoke> on this object. Therefore,
+ * the <invoke> method is responsible for deleting itself.
+ */
+class ACE_Export ACE_Thread_Adapter : public ACE_Base_Thread_Adapter
+{
+public:
+ ACE_Thread_Adapter (ACE_THR_FUNC user_func,
+ void *arg,
+ ACE_THR_C_FUNC entry_point = (ACE_THR_C_FUNC) ace_thread_adapter,
+ ACE_Thread_Manager *thr_mgr = 0,
+ ACE_Thread_Descriptor *td = 0
+# 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 */
+ /// Constructor.
+ );
+
+ /**
+ * Execute the <user_func_> with the <arg>. This function deletes
+ * <this>, thereby rendering the object useless after the call
+ * returns.
+ */
+ virtual void *invoke (void);
+
+ /// Accessor for the optional <Thread_Manager>.
+ ACE_Thread_Manager *thr_mgr (void);
+
+private:
+ /// Ensure that this object must be allocated on the heap.
+ ~ACE_Thread_Adapter (void);
+
+ /// Called by invoke, mainly here to separate the SEH stuff because
+ /// SEH on Win32 doesn't compile with local vars with destructors.
+ virtual void *invoke_i (void);
+
+private:
+ /// Optional thread manager.
+ ACE_Thread_Manager *thr_mgr_;
+
+ /// Friend declaration to avoid compiler warning: only defines a private
+ /// destructor and has no friends.
+ friend class ACE_Thread_Adapter_Has_Private_Destructor;
+};
+
+# if defined (ACE_HAS_INLINED_OSCALLS)
+# if defined (ACE_INLINE)
+# undef ACE_INLINE
+# endif /* ACE_INLINE */
+# define ACE_INLINE inline
+# include "ace/Thread_Adapter.inl"
+# endif /* ACE_HAS_INLINED_OSCALLS */
+
+#include "ace/post.h"
+#endif /* ACE_THREAD_ADAPTER_H */
diff --git a/ace/Threads/Thread_Adapter.inl b/ace/Threads/Thread_Adapter.inl
new file mode 100644
index 00000000000..53855b300cc
--- /dev/null
+++ b/ace/Threads/Thread_Adapter.inl
@@ -0,0 +1,7 @@
+// $Id$
+
+ACE_INLINE ACE_Thread_Manager *
+ACE_Thread_Adapter::thr_mgr (void)
+{
+ return this->thr_mgr_;
+}
diff --git a/ace/Threads/Thread_Control.cpp b/ace/Threads/Thread_Control.cpp
new file mode 100644
index 00000000000..e5fff02d507
--- /dev/null
+++ b/ace/Threads/Thread_Control.cpp
@@ -0,0 +1,90 @@
+// $Id$
+
+// <HACK ON>
+#include "ace/config-all.h"
+#if defined (ACE_LEGACY_MODE)
+// This silly include breaks a cycle when compiling in backwards
+// compatibility mode
+# include "ace/Thread_Exit.h"
+#endif /* ACE_LEGACY_MODE */
+// </HACK OFF>
+
+#include "ace/Thread_Control.h"
+#include "ace/Thread_Manager.h"
+
+ACE_RCSID(ace, Thread_Control, "$Id$")
+
+#if !defined (ACE_HAS_INLINED_OSCALLS)
+# include "ace/Thread_Control.inl"
+#endif /* ACE_HAS_INLINED_OS_CALLS */
+
+void
+ACE_Thread_Control::dump (void) const
+{
+ ACE_OS_TRACE ("ACE_Thread_Control::dump");
+}
+
+int
+ACE_Thread_Control::insert (ACE_Thread_Manager *tm, int insert)
+{
+ ACE_OS_TRACE ("ACE_Thread_Control::insert");
+
+ ACE_hthread_t t_id;
+ ACE_OS::thr_self (t_id);
+ this->tm_ = tm;
+
+ if (insert)
+ return this->tm_->insert_thr (ACE_OS::thr_self (), t_id);
+ else
+ return 0;
+}
+
+// Initialize the thread controller.
+
+ACE_Thread_Control::ACE_Thread_Control (ACE_Thread_Manager *t,
+ int insert)
+ : tm_ (t),
+ status_ (0)
+{
+ ACE_OS_TRACE ("ACE_Thread_Control::ACE_Thread_Control");
+
+ if (this->tm_ != 0 && insert)
+ {
+ ACE_hthread_t t_id;
+ ACE_OS::thr_self (t_id);
+ this->tm_->insert_thr (ACE_OS::thr_self (), t_id);
+ }
+}
+
+// Automatically kill thread on exit.
+
+ACE_Thread_Control::~ACE_Thread_Control (void)
+{
+ ACE_OS_TRACE ("ACE_Thread_Control::~ACE_Thread_Control");
+
+#if defined (ACE_HAS_RECURSIVE_THR_EXIT_SEMANTICS) || defined (ACE_HAS_TSS_EMULATION) || defined (ACE_WIN32)
+ this->exit (this->status_, 0);
+#else
+ this->exit (this->status_, 1);
+#endif /* ACE_HAS_RECURSIVE_THR_EXIT_SEMANTICS */
+}
+
+// Exit from thread (but clean up first).
+
+void *
+ACE_Thread_Control::exit (void *exit_status, int do_thr_exit)
+{
+ ACE_OS_TRACE ("ACE_Thread_Control::exit");
+
+ if (this->tm_ != 0)
+ return this->tm_->exit (exit_status, do_thr_exit);
+ else
+ {
+#if !defined (ACE_HAS_TSS_EMULATION)
+ // With ACE_HAS_TSS_EMULATION, we let ACE_Thread_Adapter::invoke ()
+ // exit the thread after cleaning up TSS.
+ ACE_OS::thr_exit (exit_status);
+#endif /* ! ACE_HAS_TSS_EMULATION */
+ return 0;
+ }
+}
diff --git a/ace/Threads/Thread_Control.h b/ace/Threads/Thread_Control.h
new file mode 100644
index 00000000000..fbf8f0f213f
--- /dev/null
+++ b/ace/Threads/Thread_Control.h
@@ -0,0 +1,101 @@
+
+//=============================================================================
+/**
+ * @file Thread_Control.h
+ *
+ * $Id$
+ *
+ * @author Carlos O'Ryan <coryan@uci.edu>
+ */
+//=============================================================================
+
+
+#ifndef ACE_THREAD_CONTROL_H
+#define ACE_THREAD_CONTROL_H
+#include "ace/pre.h"
+
+#include "ace/config-all.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#if !defined (ACE_LEGACY_MODE)
+# include "ace/OS.h"
+#endif /* ACE_LEGACY_MODE */
+
+class ACE_Thread_Manager;
+
+/**
+ * @class ACE_Thread_Control
+ *
+ * @brief Used to keep track of a thread's activities within its entry
+ * point function.
+ *
+ * A <ACE_Thread_Manager> uses this class to ensure that threads
+ * it spawns automatically register and unregister themselves
+ * with it.
+ * This class can be stored in thread-specific storage using the
+ * <ACE_TSS> wrapper. When a thread exits the
+ * <ACE_TSS::cleanup> function deletes this object, thereby
+ * ensuring that it gets removed from its associated
+ * <ACE_Thread_Manager>.
+ */
+class ACE_Export ACE_Thread_Control
+{
+public:
+ /// Initialize the thread control object. If <insert> != 0, then
+ /// register the thread with the Thread_Manager.
+ ACE_Thread_Control (ACE_Thread_Manager *tm = 0,
+ int insert = 0);
+
+ /// Remove the thread from its associated <Thread_Manager> and exit
+ /// the thread if <do_thr_exit> is enabled.
+ ~ACE_Thread_Control (void);
+
+ /// Remove this thread from its associated <Thread_Manager> and exit
+ /// the thread if <do_thr_exit> is enabled.
+ void *exit (void *status,
+ int do_thr_exit);
+
+ /// Store the <Thread_Manager> and use it to register ourselves for
+ /// correct shutdown.
+ int insert (ACE_Thread_Manager *tm, int insert = 0);
+
+ /// Returns the current <Thread_Manager>.
+ ACE_Thread_Manager *thr_mgr (void);
+
+ /// Atomically set a new <Thread_Manager> and return the old
+ /// <Thread_Manager>.
+ ACE_Thread_Manager *thr_mgr (ACE_Thread_Manager *);
+
+ /// Set the exit status (and return existing status).
+ void *status (void *status);
+
+ /// Get the current exit status.
+ void *status (void);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+private:
+ /// Pointer to the thread manager for this block of code.
+ ACE_Thread_Manager *tm_;
+
+ /// Keeps track of the exit status for the thread.
+ void *status_;
+};
+
+# if defined (ACE_HAS_INLINED_OSCALLS)
+# if defined (ACE_INLINE)
+# undef ACE_INLINE
+# endif /* ACE_INLINE */
+# define ACE_INLINE inline
+# include "ace/Thread_Control.inl"
+# endif /* ACE_HAS_INLINED_OSCALLS */
+
+#include "ace/post.h"
+#endif /* ACE_THREAD_CONTROL_H */
diff --git a/ace/Threads/Thread_Control.inl b/ace/Threads/Thread_Control.inl
new file mode 100644
index 00000000000..29cb24b1df3
--- /dev/null
+++ b/ace/Threads/Thread_Control.inl
@@ -0,0 +1,42 @@
+// -*- C++ -*-
+// $Id$
+
+// Set the exit status.
+
+ACE_INLINE void *
+ACE_Thread_Control::status (void *s)
+{
+ ACE_OS_TRACE ("ACE_Thread_Control::status");
+ return this->status_ = s;
+}
+
+// Get the exit status.
+
+ACE_INLINE void *
+ACE_Thread_Control::status (void)
+{
+ ACE_OS_TRACE ("ACE_Thread_Control::status");
+ return this->status_;
+}
+
+// Returns the current <Thread_Manager>.
+
+ACE_INLINE ACE_Thread_Manager *
+ACE_Thread_Control::thr_mgr (void)
+{
+ ACE_OS_TRACE ("ACE_Thread_Control::thr_mgr");
+ return this->tm_;
+}
+
+// Atomically set a new <Thread_Manager> and return the old
+// <Thread_Manager>.
+
+ACE_INLINE ACE_Thread_Manager *
+ACE_Thread_Control::thr_mgr (ACE_Thread_Manager *tm)
+{
+ ACE_OS_TRACE ("ACE_Thread_Control::thr_mgr");
+ ACE_Thread_Manager *o_tm = this->tm_;
+ this->tm_ = tm;
+ return o_tm;
+}
+
diff --git a/ace/Threads/Thread_Exit.cpp b/ace/Threads/Thread_Exit.cpp
new file mode 100644
index 00000000000..2128ac148f5
--- /dev/null
+++ b/ace/Threads/Thread_Exit.cpp
@@ -0,0 +1,144 @@
+// $Id$
+
+#include "ace/Thread_Exit.h"
+#include "ace/OS.h"
+#include "ace/Synch.h"
+#include "ace/Managed_Object.h"
+
+ACE_RCSID(ace, Thread_Exit, "$Id$")
+
+u_int ACE_Thread_Exit::is_constructed_ = 0;
+
+#if defined (ACE_HAS_SIG_C_FUNC)
+extern "C" void
+ACE_Thread_Exit_cleanup (void *instance, void *arg)
+{
+ ACE_Thread_Exit::cleanup (instance, arg);
+}
+#endif
+
+void
+ACE_Thread_Exit::cleanup (void *instance, void *)
+{
+ ACE_OS_TRACE ("ACE_Thread_Exit::cleanup");
+
+ delete (ACE_TSS_TYPE (ACE_Thread_Exit) *) instance;
+
+ ACE_Thread_Exit::is_constructed_ = 0;
+ // All TSS objects have been destroyed. Reset this flag so
+ // ACE_Thread_Exit singleton can be created again.
+}
+
+// NOTE: this preprocessor directive should match the one in
+// ACE_Task_Base::svc_run () below. This prevents the two statics
+// from being defined.
+
+ACE_Thread_Exit *
+ACE_Thread_Exit::instance (void)
+{
+#if defined (ACE_HAS_THREAD_SPECIFIC_STORAGE) || defined (ACE_HAS_TSS_EMULATION)
+ ACE_OS_TRACE ("ACE_Thread_Exit::instance");
+
+ // Determines if we were dynamically allocated.
+ static ACE_TSS_TYPE (ACE_Thread_Exit) *instance_;
+
+ // Implement the Double Check pattern.
+
+ if (ACE_Thread_Exit::is_constructed_ == 0)
+ {
+ ACE_MT (ACE_Thread_Mutex *lock =
+ ACE_Managed_Object<ACE_Thread_Mutex>::get_preallocated_object
+ (ACE_Object_Manager::ACE_THREAD_EXIT_LOCK);
+ ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, *lock, 0));
+
+ if (ACE_Thread_Exit::is_constructed_ == 0)
+ {
+ ACE_NEW_RETURN (instance_,
+ ACE_TSS_TYPE (ACE_Thread_Exit),
+ 0);
+
+ ACE_Thread_Exit::is_constructed_ = 1;
+
+ // Register for destruction with ACE_Object_Manager.
+#if defined ACE_HAS_SIG_C_FUNC
+ ACE_Object_Manager::at_exit (instance_,
+ ACE_Thread_Exit_cleanup,
+ 0);
+#else
+ ACE_Object_Manager::at_exit (instance_,
+ ACE_Thread_Exit::cleanup,
+ 0);
+#endif /* ACE_HAS_SIG_C_FUNC */
+ }
+ }
+
+ return ACE_TSS_GET (instance_, ACE_Thread_Exit);
+#else
+ return 0;
+#endif /* ACE_HAS_THREAD_SPECIFIC_STORAGE || ACE_HAS_TSS_EMULATION */
+}
+
+// Grab hold of the Task * so that we can close() it in the
+// destructor.
+
+ACE_Thread_Exit::ACE_Thread_Exit (void)
+{
+ ACE_OS_TRACE ("ACE_Thread_Exit::ACE_Thread_Exit");
+}
+
+// Set the this pointer...
+
+void
+ACE_Thread_Exit::thr_mgr (ACE_Thread_Manager *tm)
+{
+ ACE_OS_TRACE ("ACE_Thread_Exit::thr_mgr");
+
+ if (tm != 0)
+ this->thread_control_.insert (tm, 0);
+}
+
+// When this object is destroyed the Task is automatically closed
+// down!
+
+ACE_Thread_Exit::~ACE_Thread_Exit (void)
+{
+ ACE_OS_TRACE ("ACE_Thread_Exit::~ACE_Thread_Exit");
+}
+
+ACE_Thread_Exit_Maybe::ACE_Thread_Exit_Maybe (int flag)
+ : instance_ (0)
+{
+ if (flag)
+ {
+ ACE_NEW (instance_, ACE_Thread_Exit);
+ }
+}
+
+ACE_Thread_Exit_Maybe::~ACE_Thread_Exit_Maybe (void)
+{
+ delete this->instance_;
+}
+
+ACE_Thread_Exit *
+ACE_Thread_Exit_Maybe::operator -> (void) const
+{
+ return this->instance_;
+}
+
+ACE_Thread_Exit *
+ACE_Thread_Exit_Maybe::instance (void) const
+{
+ return this->instance_;
+}
+
+#if (defined (ACE_HAS_THREADS) && \
+ (defined (ACE_HAS_THREAD_SPECIFIC_STORAGE) || \
+ defined (ACE_HAS_TSS_EMULATION)))
+
+# if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION)
+ template class ACE_TSS<ACE_Thread_Exit>;
+#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA)
+#pragma instantiate ACE_TSS<ACE_Thread_Exit>
+#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */
+
+#endif /* ACE_HAS_THREADS && (ACE_HAS_THREAD_SPECIFIC_STORAGE || ACE_HAS_TSS_EMULATION) */
diff --git a/ace/Threads/Thread_Exit.h b/ace/Threads/Thread_Exit.h
new file mode 100644
index 00000000000..5b87817ffaa
--- /dev/null
+++ b/ace/Threads/Thread_Exit.h
@@ -0,0 +1,110 @@
+
+//=============================================================================
+/**
+ * @file Thread_Exit.h
+ *
+ * $Id$
+ *
+ * @author Carlos O'Ryan <coryan@uci.edu>
+ */
+//=============================================================================
+
+
+#ifndef ACE_THREAD_EXIT_H
+#define ACE_THREAD_EXIT_H
+#include "ace/pre.h"
+
+#include "ace/config-all.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "ace/OS.h"
+#include "ace/Thread_Control.h"
+
+/**
+ * @class ACE_Thread_Exit
+ *
+ * @brief Keep exit information for a Thread in thread specific storage.
+ * so that the thread-specific exit hooks will get called no
+ * matter how the thread exits (e.g., via <ACE_Thread::exit>, C++
+ * or Win32 exception, "falling off the end" of the thread entry
+ * point function, etc.).
+ *
+ * This clever little helper class is stored in thread-specific
+ * storage using the <ACE_TSS> wrapper. When a thread exits the
+ * <ACE_TSS::cleanup> function deletes this object, thereby
+ * closing it down gracefully.
+ */
+class ACE_Export ACE_Thread_Exit
+{
+public:
+ /// Capture the Thread that will be cleaned up automatically.
+ ACE_Thread_Exit (void);
+
+ /// Set the <ACE_Thread_Manager>.
+ void thr_mgr (ACE_Thread_Manager *tm);
+
+ /// Destructor calls the thread-specific exit hooks when a thread
+ /// exits.
+ ~ACE_Thread_Exit (void);
+
+ /// Singleton access point.
+ static ACE_Thread_Exit *instance (void);
+
+ /// Cleanup method, used by the <ACE_Object_Manager> to destroy the
+ /// singleton.
+ static void cleanup (void *instance, void *);
+
+private:
+ /// Allow OS_Object_Manager to reset the status of <is_constructed_>.
+ friend class ACE_OS_Object_Manager;
+
+ /// Automatically add/remove the thread from the
+ /// <ACE_Thread_Manager>.
+ ACE_Thread_Control thread_control_;
+
+ /**
+ * Used to detect whether we should create a new instance (or not)
+ * within the instance method -- we don't trust the instance_ ptr
+ * because the destructor may have run (if ACE::fini() was called).
+ * See bug #526.
+ * We don't follow the singleton pattern due to dependency issues.
+ */
+ static u_int is_constructed_;
+};
+
+/**
+ * @class ACE_Thread_Exit_Maybe
+ *
+ * @brief A version of ACE_Thread_Exit that is created dynamically
+ * under the hood if the flag is set to TRUE.
+ *
+ * Allows the appearance of a "smart pointer", but is not
+ * always created.
+ */
+class ACE_Export ACE_Thread_Exit_Maybe
+{
+public:
+ /// Don't create an ACE_Thread_Exit instance by default.
+ ACE_Thread_Exit_Maybe (int flag = 0);
+
+ /// Destroys the underlying ACE_Thread_Exit instance if it exists.
+ ~ACE_Thread_Exit_Maybe (void);
+
+ /// Delegates to underlying instance.
+ ACE_Thread_Exit * operator -> (void) const;
+
+ /// Returns the underlying instance.
+ ACE_Thread_Exit * instance (void) const;
+
+private:
+
+ /// Holds the underlying instance.
+ ACE_Thread_Exit *instance_;
+
+};
+
+#include "ace/post.h"
+#endif /* ACE_THREAD_EXIT_H */
diff --git a/ace/Threads/Thread_Manager.cpp b/ace/Threads/Thread_Manager.cpp
new file mode 100644
index 00000000000..fdf9c1b532a
--- /dev/null
+++ b/ace/Threads/Thread_Manager.cpp
@@ -0,0 +1,2238 @@
+// $Id$
+
+#include "ace/Synch_T.h"
+#include "ace/Thread_Manager.h"
+#include "ace/Dynamic.h"
+#include "ace/Object_Manager.h"
+#include "ace/Singleton.h"
+#include "ace/Auto_Ptr.h"
+#include "ace/Thread_Exit.h"
+
+#if !defined (__ACE_INLINE__)
+#include "ace/Thread_Manager.i"
+#endif /* __ACE_INLINE__ */
+
+ACE_RCSID(ace, Thread_Manager, "$Id$")
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Thread_Control)
+ACE_ALLOC_HOOK_DEFINE(ACE_Thread_Manager)
+
+#if ! defined (ACE_THREAD_MANAGER_LACKS_STATICS)
+// Process-wide Thread Manager.
+ACE_Thread_Manager *ACE_Thread_Manager::thr_mgr_ = 0;
+
+// Controls whether the Thread_Manager is deleted when we shut down
+// (we can only delete it safely if we created it!)
+int ACE_Thread_Manager::delete_thr_mgr_ = 0;
+#endif /* ! defined (ACE_THREAD_MANAGER_LACKS_STATICS) */
+
+void
+ACE_Thread_Manager::dump (void)
+{
+ ACE_TRACE ("ACE_Thread_Manager::dump");
+ // Cast away const-ness of this in order to use its non-const lock_.
+ ACE_MT (ACE_GUARD (ACE_Thread_Mutex, ace_mon,
+ ((ACE_Thread_Manager *) this)->lock_));
+
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\ngrp_id_ = %d"), this->grp_id_));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\ncurrent_count_ = %d"), this->thr_list_.size ()));
+
+ for (ACE_Double_Linked_List_Iterator<ACE_Thread_Descriptor> iter (this->thr_list_);
+ !iter.done ();
+ iter.advance ())
+ iter.next ()->dump ();
+
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+ACE_Thread_Descriptor::~ACE_Thread_Descriptor (void)
+{
+ delete this->sync_;
+}
+
+#if !defined(ACE_USE_ONE_SHOT_AT_THREAD_EXIT)
+void ACE_Thread_Descriptor::at_pop (int apply)
+
+{
+ ACE_TRACE ("ACE_Thread_Descriptor::at_pop");
+ // Get first at from at_exit_list
+ ACE_At_Thread_Exit* at = this->at_exit_list_;
+ // Remove at from at_exit list
+ this->at_exit_list_ = at->next_;
+ // Apply if required
+ if (apply)
+ {
+ at->apply ();
+ // Do the apply method
+ at->was_applied (1);
+ // Mark at has been applied to avoid double apply from
+ // at destructor
+ }
+ // If at is not owner delete at.
+ if (!at->is_owner ())
+ delete at;
+}
+
+void
+ACE_Thread_Descriptor::at_push (ACE_At_Thread_Exit* cleanup, int is_owner)
+
+{
+ ACE_TRACE ("ACE_Thread_Descriptor::at_push");
+ cleanup->is_owner (is_owner);
+ cleanup->td_ = this;
+ cleanup->next_ = at_exit_list_;
+ at_exit_list_ = cleanup;
+}
+
+int
+ACE_Thread_Descriptor::at_exit (ACE_At_Thread_Exit& cleanup)
+
+{
+ ACE_TRACE ("ACE_Thread_Descriptor::at_exit");
+ at_push (&cleanup, 1);
+ return 0;
+}
+
+int
+ACE_Thread_Descriptor::at_exit (ACE_At_Thread_Exit* cleanup)
+
+{
+ ACE_TRACE ("ACE_Thread_Descriptor::at_exit");
+ if (cleanup==0)
+ return -1;
+ else
+ {
+ this->at_push (cleanup);
+ return 0;
+ }
+}
+
+void
+ACE_Thread_Descriptor::do_at_exit ()
+
+{
+ ACE_TRACE ("ACE_Thread_Descriptor::do_at_exit");
+ while (at_exit_list_!=0)
+ this->at_pop ();
+}
+
+void
+ACE_Thread_Descriptor::terminate ()
+
+{
+ ACE_TRACE ("ACE_Thread_Descriptor::terminate");
+
+ if (!terminated_)
+ {
+ ACE_Log_Msg* log_msg = this->log_msg_;
+ terminated_ = 1;
+ // Run at_exit hooks
+ this->do_at_exit ();
+ // We must remove Thread_Descriptor from Thread_Manager list
+ if (this->tm_ != 0)
+ {
+ int close_handle = 0;
+
+#if !defined (VXWORKS)
+ // Threads created with THR_DAEMON shouldn't exist here, but
+ // just to be safe, let's put it here.
+
+ if (ACE_BIT_DISABLED (this->thr_state_, ACE_Thread_Manager::ACE_THR_JOINING))
+ {
+ if (ACE_BIT_DISABLED (this->flags_, THR_DETACHED | THR_DAEMON)
+ || ACE_BIT_ENABLED (this->flags_, THR_JOINABLE))
+ {
+ // Mark thread as terminated.
+ ACE_SET_BITS (this->thr_state_, ACE_Thread_Manager::ACE_THR_TERMINATED);
+ tm_->register_as_terminated (this);
+ // Must copy the information here because td will be
+ // "freed" below.
+ }
+#if defined (ACE_WIN32)
+ else
+ {
+ close_handle = 1;
+ }
+#endif /* ACE_WIN32 */
+ }
+#endif /* ! VXWORKS */
+
+ // Remove thread descriptor from the table.
+ if (this->tm_ != 0)
+ tm_->remove_thr (this, close_handle);
+ }
+
+ // Check if we need delete ACE_Log_Msg instance
+ // If ACE_TSS_cleanup was not executed first log_msg == 0
+ if (log_msg == 0)
+ {
+ // Only inform to ACE_TSS_cleanup that it must delete the log instance
+ // setting ACE_LOG_MSG thr_desc to 0.
+ ACE_LOG_MSG->thr_desc (0);
+ }
+ else
+ {
+ // Thread_Descriptor is the owner of the Log_Msg instance!!
+ // deleted.
+ this->log_msg_ = 0;
+ delete log_msg;
+ }
+ }
+}
+
+#endif /* !ACE_USE_ONE_SHOT_AT_THREAD_EXIT */
+
+int
+ACE_Thread_Descriptor::at_exit (void *object,
+ ACE_CLEANUP_FUNC cleanup_hook,
+ void *param)
+{
+ ACE_TRACE ("ACE_Thread_Descriptor::at_exit");
+#if defined(ACE_USE_ONE_SHOT_AT_THREAD_EXIT)
+ this->cleanup_info_.cleanup_hook_ = cleanup_hook;
+ this->cleanup_info_.object_ = object;
+ this->cleanup_info_.param_ = param;
+#else
+ // To keep compatibility, when cleanup_hook is null really is a at_pop
+ // without apply.
+ if (cleanup_hook == 0)
+ {
+ if (this->at_exit_list_!= 0)
+ this->at_pop(0);
+ }
+ else
+ {
+ ACE_At_Thread_Exit* cleanup;
+ ACE_NEW_RETURN (cleanup,
+ ACE_At_Thread_Exit_Func (object,
+ cleanup_hook,
+ param),
+ -1);
+ this->at_push (cleanup);
+ }
+#endif /* ACE_USE_ONE_SHOT_AT_THREAD_EXIT */
+ return 0;
+}
+
+void
+ACE_Thread_Descriptor::dump (void) const
+{
+ ACE_TRACE ("ACE_Thread_Descriptor::dump");
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\nthr_id_ = %d"), this->thr_id_));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\nthr_handle_ = %d"), this->thr_handle_));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\ngrp_id_ = %d"), this->grp_id_));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\nthr_state_ = %d"), this->thr_state_));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\ncleanup_info_.cleanup_hook_ = %x"), this->cleanup_info_.cleanup_hook_));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\nflags_ = %x\n"), this->flags_));
+
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+ACE_Thread_Descriptor::ACE_Thread_Descriptor (void)
+ :
+#if !defined(ACE_USE_ONE_SHOT_AT_THREAD_EXIT)
+ log_msg_ (0),
+ at_exit_list_ (0),
+ terminated_ (0)
+#endif /* !ACE_USE_ONE_SHOT_AT_THREAD_EXIT */
+{
+ ACE_TRACE ("ACE_Thread_Descriptor::ACE_Thread_Descriptor");
+ ACE_NEW (this->sync_,
+ ACE_DEFAULT_THREAD_MANAGER_LOCK);
+}
+
+void
+ACE_Thread_Descriptor::acquire_release (void)
+{
+ // Just try to acquire the lock then release it.
+#if defined (ACE_THREAD_MANAGER_USES_SAFE_SPAWN)
+ if (ACE_BIT_DISABLED (this->thr_state_, ACE_Thread_Manager::ACE_THR_SPAWNED))
+#endif /* ACE_THREAD_MANAGER_USES_SAFE_SPAWN */
+ {
+ this->sync_->acquire ();
+ // Acquire the lock before removing <td> from the thread table. If
+ // this thread is in the table already, it should simply acquire the
+ // lock easily.
+
+ // Once we get the lock, we must have registered.
+ ACE_ASSERT (ACE_BIT_ENABLED (this->thr_state_, ACE_Thread_Manager::ACE_THR_SPAWNED));
+
+ this->sync_->release ();
+ // Release the lock before putting it back to freelist.
+ }
+}
+
+// The following macro simplifies subsequence code.
+#define ACE_FIND(OP,INDEX) \
+ ACE_Thread_Descriptor *INDEX = OP; \
+
+ACE_Thread_Descriptor *
+ACE_Thread_Manager::thread_descriptor (ACE_thread_t thr_id)
+{
+ ACE_TRACE ("ACE_Thread_Manager::thread_descriptor");
+ ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, 0));
+
+ ACE_FIND (this->find_thread (thr_id), ptr);
+ return ptr;
+}
+
+ACE_Thread_Descriptor *
+ACE_Thread_Manager::hthread_descriptor (ACE_hthread_t thr_handle)
+{
+ ACE_TRACE ("ACE_Thread_Manager::hthread_descriptor");
+ ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, 0));
+
+ ACE_FIND (this->find_hthread (thr_handle), ptr);
+ return ptr;
+}
+
+// Return the thread descriptor (indexed by ACE_hthread_t).
+
+int
+ACE_Thread_Manager::thr_self (ACE_hthread_t &self)
+{
+ ACE_TRACE ("ACE_Thread_Manager::thr_self");
+
+ ACE_Thread_Descriptor *desc =
+ this->thread_desc_self ();
+
+ if (desc == 0)
+ return -1;
+ else
+ desc->self (self);
+
+ return 0;
+}
+
+// Initialize the synchronization variables.
+
+ACE_Thread_Manager::ACE_Thread_Manager (size_t prealloc,
+ size_t lwm,
+ size_t inc,
+ size_t hwm)
+ : grp_id_ (1),
+ automatic_wait_ (1)
+#if defined (ACE_HAS_THREADS)
+ , zero_cond_ (lock_)
+#endif /* ACE_HAS_THREADS */
+ , thread_desc_freelist_ (ACE_FREE_LIST_WITH_POOL,
+ prealloc, lwm, hwm, inc)
+{
+ ACE_TRACE ("ACE_Thread_Manager::ACE_Thread_Manager");
+}
+
+#if ! defined (ACE_THREAD_MANAGER_LACKS_STATICS)
+ACE_Thread_Manager *
+ACE_Thread_Manager::instance (void)
+{
+ ACE_TRACE ("ACE_Thread_Manager::instance");
+
+ if (ACE_Thread_Manager::thr_mgr_ == 0)
+ {
+ // Perform Double-Checked Locking Optimization.
+ ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon,
+ *ACE_Static_Object_Lock::instance (), 0));
+
+ if (ACE_Thread_Manager::thr_mgr_ == 0)
+ {
+ ACE_NEW_RETURN (ACE_Thread_Manager::thr_mgr_,
+ ACE_Thread_Manager,
+ 0);
+ ACE_Thread_Manager::delete_thr_mgr_ = 1;
+ }
+ }
+
+ return ACE_Thread_Manager::thr_mgr_;
+}
+
+ACE_Thread_Manager *
+ACE_Thread_Manager::instance (ACE_Thread_Manager *tm)
+{
+ ACE_TRACE ("ACE_Thread_Manager::instance");
+ ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon,
+ *ACE_Static_Object_Lock::instance (), 0));
+
+ ACE_Thread_Manager *t = ACE_Thread_Manager::thr_mgr_;
+ // We can't safely delete it since we don't know who created it!
+ ACE_Thread_Manager::delete_thr_mgr_ = 0;
+
+ ACE_Thread_Manager::thr_mgr_ = tm;
+ return t;
+}
+
+void
+ACE_Thread_Manager::close_singleton (void)
+{
+ ACE_TRACE ("ACE_Thread_Manager::close_singleton");
+
+ ACE_MT (ACE_GUARD (ACE_Recursive_Thread_Mutex, ace_mon,
+ *ACE_Static_Object_Lock::instance ()));
+
+ if (ACE_Thread_Manager::delete_thr_mgr_)
+ {
+ // First, we clean up the thread descriptor list.
+ ACE_Thread_Manager::thr_mgr_->close ();
+ delete ACE_Thread_Manager::thr_mgr_;
+ ACE_Thread_Manager::thr_mgr_ = 0;
+ ACE_Thread_Manager::delete_thr_mgr_ = 0;
+ }
+}
+#endif /* ! defined (ACE_THREAD_MANAGER_LACKS_STATICS) */
+
+// Close up and release all resources.
+
+int
+ACE_Thread_Manager::close ()
+{
+ ACE_TRACE ("ACE_Thread_Manager::close");
+
+ // Clean up the thread descriptor list.
+ if (this->automatic_wait_)
+ this->wait (0, 1);
+ else
+ {
+ ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1));
+
+ this->remove_thr_all ();
+ }
+
+ return 0;
+}
+
+ACE_Thread_Manager::~ACE_Thread_Manager (void)
+{
+ ACE_TRACE ("ACE_Thread_Manager::~ACE_Thread_Manager");
+ this->close ();
+}
+
+
+// Run the entry point for thread spawned under the control of the
+// <ACE_Thread_Manager>. This must be an extern "C" to make certain
+// compilers happy...
+//
+// The interaction with <ACE_Thread_Exit> and
+// <ace_thread_manager_adapter> works like this, with
+// ACE_HAS_THREAD_SPECIFIC_STORAGE or ACE_HAS_TSS_EMULATION:
+//
+// o Every thread in the <ACE_Thread_Manager> is run with
+// <ace_thread_manager_adapter>.
+//
+// o <ace_thread_manager_adapter> retrieves the singleton
+// <ACE_Thread_Exit> instance from <ACE_Thread_Exit::instance>.
+// The singleton gets created in thread-specific storage
+// in the first call to that function. The key point is that the
+// instance is in thread-specific storage.
+//
+// o A thread can exit by various means, such as <ACE_Thread::exit>, C++
+// or Win32 exception, "falling off the end" of the thread entry
+// point function, etc.
+//
+// o If you follow this so far, now it gets really fun . . .
+// When the thread-specific storage (for the thread that
+// is being destroyed) is cleaned up, the OS threads package (or
+// the ACE emulation of thread-specific storage) will destroy any
+// objects that are in thread-specific storage. It has a list of
+// them, and just walks down the list and destroys each one.
+//
+// o That's where the ACE_Thread_Exit destructor gets called.
+
+#if defined(ACE_USE_THREAD_MANAGER_ADAPTER)
+extern "C" void *
+ace_thread_manager_adapter (void *args)
+{
+#if defined (ACE_HAS_TSS_EMULATION)
+ // As early as we can in the execution of the new thread, allocate
+ // its local TS storage. Allocate it on the stack, to save dynamic
+ // allocation/dealloction.
+ void *ts_storage[ACE_TSS_Emulation::ACE_TSS_THREAD_KEYS_MAX];
+ ACE_TSS_Emulation::tss_open (ts_storage);
+#endif /* ACE_HAS_TSS_EMULATION */
+
+ ACE_Thread_Adapter *thread_args = (ACE_Thread_Adapter *) args;
+
+ // NOTE: this preprocessor directive should match the one in above
+ // ACE_Thread_Exit::instance (). With the Xavier Pthreads package,
+ // the exit_hook in TSS causes a seg fault. So, this works around
+ // that by creating exit_hook on the stack.
+#if defined (ACE_HAS_THREAD_SPECIFIC_STORAGE) || defined (ACE_HAS_TSS_EMULATION)
+ // Obtain our thread-specific exit hook and make sure that it knows
+ // how to clean us up! Note that we never use this pointer directly
+ // (it's stored in thread-specific storage), so it's ok to
+ // dereference it here and only store it as a reference.
+ ACE_Thread_Exit &exit_hook = *ACE_Thread_Exit::instance ();
+#else
+ // Without TSS, create an <ACE_Thread_Exit> instance. When this
+ // function returns, its destructor will be called because the
+ // object goes out of scope. The drawback with this appraoch is
+ // that the destructor _won't_ get called if <thr_exit> is called.
+ // So, threads shouldn't exit that way. Instead, they should return
+ // from <svc>.
+ ACE_Thread_Exit exit_hook;
+#endif /* ACE_HAS_THREAD_SPECIFIC_STORAGE || ACE_HAS_TSS_EMULATION */
+
+ // Keep track of the <Thread_Manager> that's associated with this
+ // <exit_hook>.
+ exit_hook.thr_mgr (thread_args->thr_mgr ());
+
+ // Invoke the user-supplied function with the args.
+ void *status = thread_args->invoke ();
+
+ return status;
+}
+#endif
+
+// Call the appropriate OS routine to spawn a thread. Should *not* be
+// called with the lock_ held...
+
+int
+ACE_Thread_Manager::spawn_i (ACE_THR_FUNC func,
+ void *args,
+ long flags,
+ ACE_thread_t *t_id,
+ ACE_hthread_t *t_handle,
+ long priority,
+ int grp_id,
+ void *stack,
+ size_t stack_size,
+ ACE_Task_Base *task)
+{
+ // First, threads created by Thread Manager should not be daemon threads.
+ // Using assertion is probably a bit too strong. However, it helps
+ // finding this kind of error as early as possible. Perhaps we can replace
+ // assertion by returning error.
+ ACE_ASSERT (ACE_BIT_DISABLED (flags, THR_DAEMON));
+
+ // Create a new thread running <func>. *Must* be called with the
+ // <lock_> held...
+ // Get a "new" Thread Descriptor from the freelist.
+ auto_ptr<ACE_Thread_Descriptor> new_thr_desc (this->thread_desc_freelist_.remove ());
+
+ // Reset thread descriptor status
+ new_thr_desc->reset (this);
+
+ ACE_Thread_Adapter *thread_args = 0;
+# if defined (ACE_HAS_WIN32_STRUCTURAL_EXCEPTIONS)
+ ACE_NEW_RETURN (thread_args,
+ ACE_Thread_Adapter (func,
+ args,
+ (ACE_THR_C_FUNC) ace_thread_adapter,
+ this,
+ new_thr_desc.get (),
+ ACE_OS_Object_Manager::seh_except_selector(),
+ ACE_OS_Object_Manager::seh_except_handler()),
+ -1);
+#else
+ ACE_NEW_RETURN (thread_args,
+ ACE_Thread_Adapter (func,
+ args,
+ (ACE_THR_C_FUNC) ace_thread_adapter,
+ this,
+ new_thr_desc.get ()),
+ -1);
+# endif /* ACE_HAS_WIN32_STRUCTURAL_EXCEPTIONS */
+
+ ACE_TRACE ("ACE_Thread_Manager::spawn_i");
+ ACE_hthread_t thr_handle;
+
+#if defined (VXWORKS) && ! defined (ACE_HAS_PACE)
+ // On VxWorks, ACE_thread_t is char *. If t_id is 0, allocate space
+ // for ACE_OS::thr_create () to store the task name. If t_id is not
+ // 0, and it doesn't point to a 0 char *, then the non-zero char *
+ // will be used for the task name in ACE_OS::thr_create (). If t_id
+ // is not 0, but does point to a 0 char *, the t_id will be set to
+ // point to the task name in the TCB in ACE_OS::thr_create ().
+ if (t_id == 0)
+ {
+ char *thr_id;
+ ACE_NEW_RETURN (thr_id,
+ char[16],
+ -1);
+ // Mark the thread ID to show that the ACE_Thread_Manager
+ // allocated it.
+ thr_id[0] = ACE_THR_ID_ALLOCATED;
+ thr_id[1] = '\0';
+ t_id = &thr_id;
+ }
+#else /* ! VXWORKS */
+ ACE_thread_t thr_id;
+ if (t_id == 0)
+ t_id = &thr_id;
+#endif /* ! VXWORKS */
+
+ new_thr_desc->sync_->acquire ();
+ // Acquire the <sync_> lock to block the spawned thread from
+ // removing this Thread Descriptor before it gets put into our
+ // thread table.
+
+ int result = ACE_Thread::spawn (func,
+ args,
+ flags,
+ t_id,
+ &thr_handle,
+ priority,
+ stack,
+ stack_size,
+ thread_args);
+
+ if (result != 0)
+ {
+ // _Don't_ clobber errno here! result is either 0 or -1, and
+ // ACE_OS::thr_create () already set errno! D. Levine 28 Mar 1997
+ // errno = result;
+ ACE_Errno_Guard guard (errno); // Lock release may smash errno
+ new_thr_desc->sync_->release ();
+ return -1;
+ }
+ else
+ {
+#if defined (ACE_HAS_WTHREADS)
+ // Have to duplicate handle if client asks for it.
+ // @@ How are thread handles implemented on AIX? Do they
+ // also need to be duplicated?
+ if (t_handle != 0)
+# if defined (ACE_HAS_WINCE)
+ *t_handle = thr_handle;
+# else /* ! ACE_HAS_WINCE */
+ (void) ::DuplicateHandle (::GetCurrentProcess (),
+ thr_handle,
+ ::GetCurrentProcess (),
+ t_handle,
+ 0,
+ TRUE,
+ DUPLICATE_SAME_ACCESS);
+# endif /* ! ACE_HAS_WINCE */
+#elif defined (VXWORKS)
+ if (t_handle != 0)
+ *t_handle = thr_handle;
+#else /* ! ACE_HAS_WTHREADS && ! VXWORKS */
+ ACE_UNUSED_ARG (t_handle);
+#endif /* ! ACE_HAS_WTHREADS && ! VXWORKS */
+
+ // append_thr also put the <new_thr_desc> into Thread_Manager's
+ // double-linked list. Only after this point, can we manipulate
+ // double-linked list from a spawned thread's context.
+ return this->append_thr (*t_id,
+ thr_handle,
+ ACE_THR_SPAWNED,
+ grp_id,
+ task,
+ flags,
+ new_thr_desc.release ());
+ }
+}
+
+int
+ACE_Thread_Manager::spawn (ACE_THR_FUNC func,
+ void *args,
+ long flags,
+ ACE_thread_t *t_id,
+ ACE_hthread_t *t_handle,
+ long priority,
+ int grp_id,
+ void *stack,
+ size_t stack_size)
+{
+ ACE_TRACE ("ACE_Thread_Manager::spawn");
+
+ ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1));
+
+ if (grp_id == -1)
+ grp_id = this->grp_id_++; // Increment the group id.
+
+ if (this->spawn_i (func, args, flags, t_id, t_handle,
+ priority, grp_id, stack, stack_size) == -1)
+ return -1;
+
+ return grp_id;
+}
+
+// Create N new threads running FUNC.
+
+int
+ACE_Thread_Manager::spawn_n (size_t n,
+ ACE_THR_FUNC func,
+ void *args,
+ long flags,
+ long priority,
+ int grp_id,
+ ACE_Task_Base *task,
+ ACE_hthread_t thread_handles[],
+ void *stack[],
+ size_t stack_size[])
+{
+ ACE_TRACE ("ACE_Thread_Manager::spawn_n");
+ ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1));
+
+ if (grp_id == -1)
+ grp_id = this->grp_id_++; // Increment the group id.
+
+ for (size_t i = 0; i < n; i++)
+ {
+ // @@ What should happen if this fails?! e.g., should we try to
+ // cancel the other threads that we've already spawned or what?
+ if (this->spawn_i (func,
+ args,
+ flags,
+ 0,
+ thread_handles == 0 ? 0 : &thread_handles[i],
+ priority,
+ grp_id,
+ stack == 0 ? 0 : stack[i],
+ stack_size == 0 ? 0 : stack_size[i],
+ task) == -1)
+ return -1;
+ }
+
+ return grp_id;
+}
+
+// Create N new threads running FUNC.
+
+int
+ACE_Thread_Manager::spawn_n (ACE_thread_t thread_ids[],
+ size_t n,
+ ACE_THR_FUNC func,
+ void *args,
+ long flags,
+ long priority,
+ int grp_id,
+ void *stack[],
+ size_t stack_size[],
+ ACE_hthread_t thread_handles[],
+ ACE_Task_Base *task)
+{
+ ACE_TRACE ("ACE_Thread_Manager::spawn_n");
+ ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1));
+
+ if (grp_id == -1)
+ grp_id = this->grp_id_++; // Increment the group id.
+
+ for (size_t i = 0; i < n; i++)
+ {
+ // @@ What should happen if this fails?! e.g., should we try to
+ // cancel the other threads that we've already spawned or what?
+ if (this->spawn_i (func,
+ args,
+ flags,
+ thread_ids == 0 ? 0 : &thread_ids[i],
+ thread_handles == 0 ? 0 : &thread_handles[i],
+ priority,
+ grp_id,
+ stack == 0 ? 0 : stack[i],
+ stack_size == 0 ? 0 : stack_size[i],
+ task) == -1)
+ return -1;
+ }
+
+ return grp_id;
+}
+
+// Append a thread into the pool (does not check for duplicates).
+// Must be called with locks held.
+
+int
+ACE_Thread_Manager::append_thr (ACE_thread_t t_id,
+ ACE_hthread_t t_handle,
+ ACE_UINT32 thr_state,
+ int grp_id,
+ ACE_Task_Base *task,
+ long flags,
+ ACE_Thread_Descriptor *td)
+{
+ ACE_TRACE ("ACE_Thread_Manager::append_thr");
+ ACE_Thread_Descriptor *thr_desc;
+
+ if (td == 0)
+ {
+ ACE_NEW_RETURN (thr_desc,
+ ACE_Thread_Descriptor,
+ -1);
+#if !defined(ACE_USE_ONE_SHOT_AT_THREAD_EXIT)
+ thr_desc->tm_ = this;
+ // Setup the Thread_Manager.
+#endif /* !ACE_USE_ONE_SHOT_AT_THREAD_EXIT */
+ }
+ else
+ thr_desc = td;
+
+ thr_desc->thr_id_ = t_id;
+ thr_desc->thr_handle_ = t_handle;
+ thr_desc->grp_id_ = grp_id;
+ thr_desc->task_ = task;
+ thr_desc->flags_ = flags;
+
+ this->thr_list_.insert_head (thr_desc);
+ ACE_SET_BITS (thr_desc->thr_state_, thr_state);
+ thr_desc->sync_->release ();
+
+ return 0;
+}
+
+// Return the thread descriptor (indexed by ACE_hthread_t).
+
+ACE_Thread_Descriptor *
+ACE_Thread_Manager::find_hthread (ACE_hthread_t h_id)
+{
+ for (ACE_Double_Linked_List_Iterator<ACE_Thread_Descriptor> iter (this->thr_list_);
+ !iter.done ();
+ iter.advance ())
+ if (ACE_OS::thr_cmp (iter.next ()->thr_handle_, h_id))
+ return iter.next ();
+
+ return 0;
+}
+
+// Locate the index in the table associated with <t_id>. Must be
+// called with the lock held.
+
+ACE_Thread_Descriptor *
+ACE_Thread_Manager::find_thread (ACE_thread_t t_id)
+{
+ ACE_TRACE ("ACE_Thread_Manager::find_thread");
+
+ for (ACE_Double_Linked_List_Iterator<ACE_Thread_Descriptor> iter (this->thr_list_);
+ !iter.done ();
+ iter.advance ())
+ if (ACE_OS::thr_equal (iter.next ()->thr_id_, t_id))
+ return iter.next ();
+ return 0;
+}
+
+// Insert a thread into the pool (checks for duplicates and doesn't
+// allow them to be inserted twice).
+
+int
+ACE_Thread_Manager::insert_thr (ACE_thread_t t_id,
+ ACE_hthread_t t_handle,
+ int grp_id,
+ long flags)
+{
+ ACE_TRACE ("ACE_Thread_Manager::insert_thr");
+ ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1));
+
+ // Check for duplicates and bail out if we're already registered...
+#if defined (VXWORKS)
+ if (this->find_hthread (t_handle) != 0 )
+ return -1;
+#else /* ! VXWORKS */
+ if (this->find_thread (t_id) != 0 )
+ return -1;
+#endif /* ! VXWORKS */
+
+ if (grp_id == -1)
+ grp_id = this->grp_id_++;
+
+ if (this->append_thr (t_id,
+ t_handle,
+ ACE_THR_SPAWNED,
+ grp_id,
+ 0,
+ flags) == -1)
+ return -1;
+
+ return grp_id;
+}
+
+// Run the registered hooks when the thread exits.
+
+void
+ACE_Thread_Manager::run_thread_exit_hooks (int i)
+{
+#if 0 // currently unused!
+ ACE_TRACE ("ACE_Thread_Manager::run_thread_exit_hooks");
+
+ // @@ Currently, we have just one hook. This should clearly be
+ // generalized to support an arbitrary number of hooks.
+
+ ACE_Thread_Descriptor *td = this->thread_desc_self ();
+ if (td != 0 && td->cleanup_info.cleanup_hook_ != 0)
+ {
+ (*td->cleanup_info_.cleanup_hook_)
+ (td->cleanup_info_.object_,
+ td->cleanup_info_.param_);
+
+ td->cleanup_info_.cleanup_hook_ = 0;
+ }
+ ACE_UNUSED_ARG (i);
+#else
+ ACE_UNUSED_ARG (i);
+#endif /* 0 */
+}
+
+// Remove a thread from the pool. Must be called with locks held.
+
+void
+ACE_Thread_Manager::remove_thr (ACE_Thread_Descriptor *td,
+ int close_handler)
+{
+ ACE_TRACE ("ACE_Thread_Manager::remove_thr");
+
+#if defined (VXWORKS)
+ ACE_thread_t tid = td->self ();
+#endif /* VXWORKS */
+
+#if !defined(ACE_USE_ONE_SHOT_AT_THREAD_EXIT)
+ td->tm_ = 0;
+#endif /* !ACE_USE_ONE_SHOT_AT_THREAD_EXIT */
+ this->thr_list_.remove (td);
+
+#if defined (VXWORKS) && ! defined (ACE_HAS_PACE)
+ // Delete the thread ID, if the ACE_Thread_Manager allocated it.
+ if (tid && tid[0] == ACE_THR_ID_ALLOCATED)
+ {
+ delete [] tid;
+ }
+#endif /* VXWORKS */
+
+#if defined (ACE_WIN32)
+ if (close_handler != 0)
+ ::CloseHandle (td->thr_handle_);
+#else
+ ACE_UNUSED_ARG (close_handler);
+#endif /* ACE_WIN32 */
+
+#if 1
+
+ this->thread_desc_freelist_.add (td);
+#else
+ delete td;
+#endif /* 1 */
+
+#if defined (ACE_HAS_THREADS)
+ // Tell all waiters when there are no more threads left in the pool.
+ if (this->thr_list_.size () == 0)
+ this->zero_cond_.broadcast ();
+#endif /* ACE_HAS_THREADS */
+}
+
+// Repeatedly call remove_thr on all table entries until there
+// is no thread left. Must be called with lock held.
+
+void
+ACE_Thread_Manager::remove_thr_all (void)
+{
+ ACE_Thread_Descriptor *td;
+
+ while ((td = this->thr_list_.delete_head ()) != 0)
+ {
+#if defined (ACE_WIN32)
+ // We need to let go handles if we want to let the threads
+ // run wild.
+ // @@ Do we need to close down AIX thread handles too?
+ ::CloseHandle (td->thr_handle_);
+#endif /* ACE_WIN32 */
+ delete td;
+ }
+
+}
+
+// ------------------------------------------------------------------
+// Factor out some common behavior to simplify the following methods.
+#define ACE_THR_OP(OP,STATE) \
+ int result = OP (td->thr_handle_); \
+ if (result == -1) { \
+ if (errno != ENOTSUP) \
+ this->thr_to_be_removed_.enqueue_tail (td); \
+ return -1; \
+ } \
+ else { \
+ ACE_SET_BITS (td->thr_state_, STATE); \
+ return 0; \
+ }
+
+int
+ACE_Thread_Manager::join_thr (ACE_Thread_Descriptor *td, int)
+{
+ ACE_TRACE ("ACE_Thread_Manager::join_thr");
+#if defined (ACE_HAS_PACE)
+ return ACE_Thread::join (td->thr_handle_);
+#else
+ int result = ACE_Thread::join (td->thr_handle_);
+ if (result != 0)
+ {
+ // Since the thread are being joined, we should
+ // let it remove itself from the list.
+
+ // this->remove_thr (td);
+ errno = result;
+ return -1;
+ }
+
+ return 0;
+#endif /* ACE_HAS_PACE */
+}
+
+int
+ACE_Thread_Manager::suspend_thr (ACE_Thread_Descriptor *td, int)
+{
+ ACE_TRACE ("ACE_Thread_Manager::suspend_thr");
+
+ int result = ACE_Thread::suspend (td->thr_handle_);
+ if (result == -1) {
+ if (errno != ENOTSUP)
+ this->thr_to_be_removed_.enqueue_tail (td);
+ return -1;
+ }
+ else {
+ ACE_SET_BITS (td->thr_state_, ACE_THR_SUSPENDED);
+ return 0;
+ }
+}
+
+int
+ACE_Thread_Manager::resume_thr (ACE_Thread_Descriptor *td, int)
+{
+ ACE_TRACE ("ACE_Thread_Manager::resume_thr");
+
+ int result = ACE_Thread::resume (td->thr_handle_);
+ if (result == -1) {
+ if (errno != ENOTSUP)
+ this->thr_to_be_removed_.enqueue_tail (td);
+ return -1;
+ }
+ else {
+ ACE_CLR_BITS (td->thr_state_, ACE_THR_SUSPENDED);
+ return 0;
+ }
+}
+
+int
+ACE_Thread_Manager::cancel_thr (ACE_Thread_Descriptor *td, int async_cancel)
+{
+ ACE_TRACE ("ACE_Thread_Manager::cancel_thr");
+ // Must set the state first and then try to cancel the thread.
+ ACE_SET_BITS (td->thr_state_, ACE_THR_CANCELLED);
+
+ if (async_cancel != 0)
+ // Note that this call only does something relevant if the OS
+ // platform supports asynchronous thread cancellation. Otherwise,
+ // it's a no-op.
+ return ACE_Thread::cancel (td->thr_id_);
+
+ return 0;
+}
+
+int
+ACE_Thread_Manager::kill_thr (ACE_Thread_Descriptor *td, int signum)
+{
+ ACE_TRACE ("ACE_Thread_Manager::kill_thr");
+
+ ACE_thread_t tid = td->thr_id_;
+#if defined (VXWORKS) && ! defined (ACE_HAS_PACE)
+ // Skip over the ID-allocated marker, if present.
+ tid += tid[0] == ACE_THR_ID_ALLOCATED ? 1 : 0;
+#endif /* VXWORKS */
+
+ int result = ACE_Thread::kill (tid, signum);
+
+ if (result != 0)
+ {
+ // Only remove a thread from us when there is a "real" error.
+ if (errno != ENOTSUP)
+ this->thr_to_be_removed_.enqueue_tail (td);
+
+ return -1;
+ }
+#if defined (CHORUS)
+ else if (signum == SIGTHREADKILL)
+ this->thr_to_be_removed_.enqueue_tail (td);
+#endif /* CHORUS */
+
+ return 0;
+}
+
+// ------------------------------------------------------------------
+// Factor out some common behavior to simplify the following methods.
+#define ACE_EXECUTE_OP(OP, ARG) \
+ ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1)); \
+ ACE_ASSERT (this->thr_to_be_removed_.is_empty ()); \
+ ACE_FIND (this->find_thread (t_id), ptr); \
+ if (ptr == 0) \
+ { \
+ errno = ENOENT; \
+ return -1; \
+ } \
+ int result = OP (ptr, ARG); \
+ ACE_Errno_Guard error (errno); \
+ while (! this->thr_to_be_removed_.is_empty ()) { \
+ ACE_Thread_Descriptor *td; \
+ this->thr_to_be_removed_.dequeue_head (td); \
+ this->remove_thr (td, 1); \
+ } \
+ return result
+
+// Suspend a single thread.
+
+int
+ACE_Thread_Manager::suspend (ACE_thread_t t_id)
+{
+ ACE_TRACE ("ACE_Thread_Manager::suspend");
+ ACE_EXECUTE_OP (this->suspend_thr, 0);
+}
+
+// Resume a single thread.
+
+int
+ACE_Thread_Manager::resume (ACE_thread_t t_id)
+{
+ ACE_TRACE ("ACE_Thread_Manager::resume");
+ ACE_EXECUTE_OP (this->resume_thr, 0);
+}
+
+// Cancel a single thread.
+
+int
+ACE_Thread_Manager::cancel (ACE_thread_t t_id, int async_cancel)
+{
+ ACE_TRACE ("ACE_Thread_Manager::cancel");
+ ACE_EXECUTE_OP (this->cancel_thr, async_cancel);
+}
+
+// Send a signal to a single thread.
+
+int
+ACE_Thread_Manager::kill (ACE_thread_t t_id, int signum)
+{
+ ACE_TRACE ("ACE_Thread_Manager::kill");
+ ACE_EXECUTE_OP (this->kill_thr, signum);
+}
+
+int
+ACE_Thread_Manager::check_state (ACE_UINT32 state,
+ ACE_thread_t id,
+ int enable)
+{
+ ACE_TRACE ("ACE_Thread_Manager::check_state");
+ ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1));
+
+ ACE_UINT32 thr_state;
+
+ int self_check = ACE_OS::thr_equal (id, ACE_OS::thr_self ());
+
+ // If we're checking the state of our thread, try to get the cached
+ // value out of TSS to avoid lookup.
+ if (self_check)
+ thr_state = this->thread_desc_self ()->thr_state_;
+ else
+ {
+ // Not calling from self, have to look it up from the list.
+ ACE_FIND (this->find_thread (id), ptr);
+ if (ptr == 0)
+ return 0;
+ thr_state = ptr->thr_state_;
+ }
+ if (enable)
+ return ACE_BIT_ENABLED (thr_state, state);
+
+ return ACE_BIT_DISABLED (thr_state, state);
+}
+
+// Test if a single thread is suspended.
+
+int
+ACE_Thread_Manager::testsuspend (ACE_thread_t t_id)
+{
+ ACE_TRACE ("ACE_Thread_Manager::testsuspend");
+ return this->check_state (ACE_THR_SUSPENDED, t_id);
+}
+
+// Test if a single thread is active (i.e., resumed).
+
+int
+ACE_Thread_Manager::testresume (ACE_thread_t t_id)
+{
+ ACE_TRACE ("ACE_Thread_Manager::testresume");
+ return this->check_state (ACE_THR_SUSPENDED, t_id, 0);
+}
+
+// Test if a single thread is cancelled.
+
+int
+ACE_Thread_Manager::testcancel (ACE_thread_t t_id)
+{
+ ACE_TRACE ("ACE_Thread_Manager::testcancel");
+ return this->check_state (ACE_THR_CANCELLED, t_id);
+}
+
+// Thread information query functions.
+
+int
+ACE_Thread_Manager::hthread_within (ACE_hthread_t handle)
+{
+ ACE_TRACE ("ACE_Thread_Manager::hthread_within");
+ ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_monx, this->lock_, -1));
+
+ for (ACE_Double_Linked_List_Iterator<ACE_Thread_Descriptor> iter (this->thr_list_);
+ !iter.done ();
+ iter.advance ())
+ if (ACE_OS::thr_cmp(iter.next ()->thr_handle_, handle))
+ return 1;
+
+ return 0;
+}
+
+int
+ACE_Thread_Manager::thread_within (ACE_thread_t tid)
+{
+ ACE_TRACE ("ACE_Thread_Manager::thread_within");
+ ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_monx, this->lock_, -1));
+
+ for (ACE_Double_Linked_List_Iterator<ACE_Thread_Descriptor> iter (this->thr_list_);
+ !iter.done ();
+ iter.advance ())
+ if (ACE_OS::thr_equal (iter.next ()->thr_id_, tid))
+ return 1;
+
+ return 0;
+}
+
+// Get group ids for a particular thread id.
+
+int
+ACE_Thread_Manager::get_grp (ACE_thread_t t_id, int &grp_id)
+{
+ ACE_TRACE ("ACE_Thread_Manager::get_grp");
+ ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1));
+
+ ACE_FIND (this->find_thread (t_id), ptr);
+
+ if (ptr)
+ grp_id = ptr->grp_id_;
+ else
+ return -1;
+ return 0;
+}
+
+// Set group ids for a particular thread id.
+
+int
+ACE_Thread_Manager::set_grp (ACE_thread_t t_id, int grp_id)
+{
+ ACE_TRACE ("ACE_Thread_Manager::set_grp");
+ ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1));
+
+ ACE_FIND (this->find_thread (t_id), ptr);
+ if (ptr)
+ ptr->grp_id_ = grp_id;
+ else
+ return -1;
+ return 0;
+}
+
+// Suspend a group of threads.
+
+int
+ACE_Thread_Manager::apply_grp (int grp_id,
+ ACE_THR_MEMBER_FUNC func,
+ int arg)
+{
+ ACE_TRACE ("ACE_Thread_Manager::apply_grp");
+ ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_monx, this->lock_, -1));
+ ACE_ASSERT (this->thr_to_be_removed_.is_empty ());
+
+ int result = 0;
+
+ for (ACE_Double_Linked_List_Iterator<ACE_Thread_Descriptor> iter (this->thr_list_);
+ !iter.done ();
+ iter.advance ())
+ if (iter.next ()->grp_id_ == grp_id)
+ if ((this->*func) (iter.next (), arg) == -1)
+ result = -1;
+
+ // Must remove threads after we have traversed the thr_list_ to
+ // prevent clobber thr_list_'s integrity.
+
+ if (! this->thr_to_be_removed_.is_empty ())
+ {
+ // Save/restore errno.
+ ACE_Errno_Guard error (errno);
+
+ for (ACE_Thread_Descriptor *td;
+ this->thr_to_be_removed_.dequeue_head (td) != -1;
+ )
+ this->remove_thr (td, 1);
+ }
+
+ return result;
+}
+
+int
+ACE_Thread_Manager::suspend_grp (int grp_id)
+{
+ ACE_TRACE ("ACE_Thread_Manager::suspend_grp");
+ return this->apply_grp (grp_id,
+ ACE_THR_MEMBER_FUNC (&ACE_Thread_Manager::suspend_thr));
+}
+
+// Resume a group of threads.
+
+int
+ACE_Thread_Manager::resume_grp (int grp_id)
+{
+ ACE_TRACE ("ACE_Thread_Manager::resume_grp");
+ return this->apply_grp (grp_id,
+ ACE_THR_MEMBER_FUNC (&ACE_Thread_Manager::resume_thr));
+}
+
+// Kill a group of threads.
+
+int
+ACE_Thread_Manager::kill_grp (int grp_id, int signum)
+{
+ ACE_TRACE ("ACE_Thread_Manager::kill_grp");
+ return this->apply_grp (grp_id,
+ ACE_THR_MEMBER_FUNC (&ACE_Thread_Manager::kill_thr), signum);
+}
+
+// Cancel a group of threads.
+
+int
+ACE_Thread_Manager::cancel_grp (int grp_id, int async_cancel)
+{
+ ACE_TRACE ("ACE_Thread_Manager::cancel_grp");
+ return this->apply_grp (grp_id,
+ ACE_THR_MEMBER_FUNC (&ACE_Thread_Manager::cancel_thr),
+ async_cancel);
+}
+
+int
+ACE_Thread_Manager::apply_all (ACE_THR_MEMBER_FUNC func, int arg)
+{
+ ACE_TRACE ("ACE_Thread_Manager::apply_all");
+ ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1));
+ ACE_ASSERT (this->thr_to_be_removed_.is_empty ());
+
+ int result = 0;
+
+ for (ACE_Double_Linked_List_Iterator<ACE_Thread_Descriptor> iter (this->thr_list_);
+ !iter.done ();
+ iter.advance ())
+ if ((this->*func)(iter.next (), arg) == -1)
+ result = -1;
+
+ // Must remove threads after we have traversed the thr_list_ to
+ // prevent clobber thr_list_'s integrity.
+
+ if (! this->thr_to_be_removed_.is_empty ())
+ {
+ // Save/restore errno.
+ ACE_Errno_Guard error (errno);
+
+ for (ACE_Thread_Descriptor *td;
+ this->thr_to_be_removed_.dequeue_head (td) != -1;
+ )
+ this->remove_thr (td, 1);
+ }
+
+ return result;
+}
+
+// Resume all threads that are suspended.
+
+int
+ACE_Thread_Manager::resume_all (void)
+{
+ ACE_TRACE ("ACE_Thread_Manager::resume_all");
+ return this->apply_all (ACE_THR_MEMBER_FUNC (&ACE_Thread_Manager::resume_thr));
+}
+
+int
+ACE_Thread_Manager::suspend_all (void)
+{
+ ACE_TRACE ("ACE_Thread_Manager::suspend_all");
+ return this->apply_all (ACE_THR_MEMBER_FUNC (&ACE_Thread_Manager::suspend_thr));
+}
+
+int
+ACE_Thread_Manager::kill_all (int sig)
+{
+ ACE_TRACE ("ACE_Thread_Manager::kill_all");
+ return this->apply_all (&ACE_Thread_Manager::kill_thr, sig);
+}
+
+int
+ACE_Thread_Manager::cancel_all (int async_cancel)
+{
+ ACE_TRACE ("ACE_Thread_Manager::cancel_all");
+ return this->apply_all (ACE_THR_MEMBER_FUNC (&ACE_Thread_Manager::cancel_thr),
+ async_cancel);
+}
+
+int
+ACE_Thread_Manager::join (ACE_thread_t tid, void **status)
+{
+ ACE_TRACE ("ACE_Thread_Manager::join");
+
+ ACE_Thread_Descriptor_Base tdb;
+ int found = 0;
+
+ {
+ ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1));
+
+#if !defined (VXWORKS)
+ for (ACE_Double_Linked_List_Iterator<ACE_Thread_Descriptor_Base> biter (this->terminated_thr_list_);
+ !biter.done ();
+ biter.advance ())
+ if (ACE_OS::thr_equal (biter.next ()->thr_id_, tid))
+ {
+ ACE_Thread_Descriptor_Base *tdb = biter.advance_and_remove (0);
+ if (ACE_Thread::join (tdb->thr_handle_) == -1)
+ return -1;
+
+# if defined (ACE_HAS_PTHREADS_DRAFT4) && defined (ACE_LACKS_SETDETACH)
+ // Must explicitly detach threads. Threads without THR_DETACHED
+ // were detached in ACE_OS::thr_create ().
+ ::pthread_detach (&tdb->thr_handle_);
+# endif /* ACE_HAS_PTHREADS_DRAFT4 && ACE_LACKS_SETDETACH */
+
+ delete tdb;
+ return 0;
+ // return immediately if we've found the thread we want to join.
+ }
+#endif /* !VXWORKS */
+
+ for (ACE_Double_Linked_List_Iterator<ACE_Thread_Descriptor> iter (this->thr_list_);
+ !iter.done ();
+ iter.advance ())
+ // If threads are created as THR_DETACHED or THR_DAEMON, we
+ // can't help much.
+ if (ACE_OS::thr_equal (iter.next ()->thr_id_,tid) &&
+ (ACE_BIT_DISABLED (iter.next ()->flags_, THR_DETACHED | THR_DAEMON)
+ || ACE_BIT_ENABLED (iter.next ()->flags_, THR_JOINABLE)))
+ {
+ tdb = *iter.next ();
+ ACE_SET_BITS (iter.next ()->thr_state_, ACE_THR_JOINING);
+ found = 1;
+ break;
+ }
+
+ if (found == 0)
+ return -1;
+ // Didn't find the thread we want or the thread is not joinable.
+ }
+
+# if defined (_AIX)
+ // The AIX xlC compiler does not match the proper function here - it
+ // confuses ACE_Thread::join(ACE_thread_t, ACE_thread_t *, void **=0) and
+ // ACE_Thread::join(ACE_hthread_t, void **=0). At least at 3.1.4.7 and .8.
+ // The 2nd arg is ignored for pthreads anyway.
+
+ // And, g++ on AIX needs the three-arg thr_join, also, to pick up the
+ // proper version from the AIX libraries.
+ if (ACE_Thread::join (tdb.thr_handle_, &tdb.thr_handle_, status) == -1)
+# else /* ! _AIX */
+ if (ACE_Thread::join (tdb.thr_handle_, status) == -1)
+# endif /* ! _AIX */
+ return -1;
+
+# if defined (ACE_HAS_PTHREADS_DRAFT4) && defined (ACE_LACKS_SETDETACH)
+ // Must explicitly detach threads. Threads without THR_DETACHED
+ // were detached in ACE_OS::thr_create ().
+
+# if defined (HPUX_10)
+ // HP-UX DCE threads' pthread_detach will smash thr_id if it's just given
+ // as an argument. Since the thread handle is still needed, give
+ // pthread_detach a junker to scribble on.
+ ACE_thread_t junker;
+ cma_handle_assign(&tdb.thr_handle_, &junker);
+ ::pthread_detach (&junker);
+# else
+ ::pthread_detach (&tdb.thr_handle_);
+ #endif /* HPUX_10 */
+# endif /* ACE_HAS_PTHREADS_DRAFT4 && ACE_LACKS_SETDETACH */
+ return 0;
+}
+
+// Wait for group of threads
+
+int
+ACE_Thread_Manager::wait_grp (int grp_id)
+{
+ ACE_TRACE ("ACE_Thread_Manager::wait_grp");
+
+ int copy_count = 0;
+ ACE_Thread_Descriptor_Base *copy_table = 0;
+
+ // We have to make sure that while we wait for these threads to
+ // exit, we do not have the lock. Therefore we make a copy of all
+ // interesting entries and let go of the lock.
+ {
+ ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1));
+
+#if !defined (VXWORKS)
+ ACE_NEW_RETURN (copy_table,
+ ACE_Thread_Descriptor_Base [this->thr_list_.size ()
+ + this->terminated_thr_list_.size ()],
+ -1);
+#else
+ ACE_NEW_RETURN (copy_table,
+ ACE_Thread_Descriptor_Base [this->thr_list_.size ()],
+ -1);
+#endif /* VXWORKS */
+
+ for (ACE_Double_Linked_List_Iterator<ACE_Thread_Descriptor> iter (this->thr_list_);
+ !iter.done ();
+ iter.advance ())
+ // If threads are created as THR_DETACHED or THR_DAEMON, we
+ // can't help much.
+ if (iter.next ()->grp_id_ == grp_id &&
+ (ACE_BIT_DISABLED (iter.next ()->flags_, THR_DETACHED | THR_DAEMON)
+ || ACE_BIT_ENABLED (iter.next ()->flags_, THR_JOINABLE)))
+ {
+ ACE_SET_BITS (iter.next ()->thr_state_, ACE_THR_JOINING);
+ copy_table[copy_count++] = *iter.next ();
+ }
+
+#if !defined (VXWORKS)
+ for (ACE_Double_Linked_List_Iterator<ACE_Thread_Descriptor_Base> biter (this->terminated_thr_list_);
+ !biter.done ();
+ biter.advance ())
+ // If threads are created as THR_DETACHED or THR_DAEMON, we
+ // can't help much.
+ if (biter.next ()->grp_id_ == grp_id)
+ {
+ ACE_Thread_Descriptor_Base *tdb = biter.advance_and_remove (0);
+ copy_table[copy_count++] = *tdb;
+ delete tdb;
+ }
+#endif /* !VXWORKS */
+ }
+
+ // Now actually join() with all the threads in this group.
+ int result = 0;
+
+ for (int i = 0;
+ i < copy_count && result != -1;
+ i++)
+ {
+ if (ACE_Thread::join (copy_table[i].thr_handle_) == -1)
+ result = -1;
+
+# if defined (ACE_HAS_PTHREADS_DRAFT4) && defined (ACE_LACKS_SETDETACH)
+ // Must explicitly detach threads. Threads without THR_DETACHED
+ // were detached in ACE_OS::thr_create ().
+ ::pthread_detach (&copy_table[i].thr_handle_);
+# endif /* ACE_HAS_PTHREADS_DRAFT4 && ACE_LACKS_SETDETACH */
+ }
+
+ delete [] copy_table;
+
+ return result;
+}
+
+// Must be called when thread goes out of scope to clean up its table
+// slot.
+
+void *
+ACE_Thread_Manager::exit (void *status, int do_thr_exit)
+{
+ ACE_TRACE ("ACE_Thread_Manager::exit");
+#if defined(ACE_USE_ONE_SHOT_AT_THREAD_EXIT)
+ int close_handle = 0;
+#endif /* ACE_USE_ONE_SHOT_AT_THREAD_EXIT */
+
+#if defined (ACE_WIN32)
+ // Remove detached thread handle.
+
+ if (do_thr_exit)
+ {
+#if 0
+ // @@ This callback is now taken care of by TSS_Cleanup. Do we
+ // need it anymore?
+
+ // On Win32, if we really wants to exit from a thread, we must
+ // first clean up the thread specific storage. By doing so,
+ // ACE_Thread_Manager::exit will be called again with
+ // do_thr_exit = 0 and cleaning up the ACE_Cleanup_Info (but not
+ // exiting the thread.) After the following call returns, we
+ // are safe to exit this thread.
+ delete ACE_Thread_Exit::instance ();
+#endif /* 0 */
+ ACE_Thread::exit (status);
+ }
+#endif /* ACE_WIN32 */
+
+#if defined(ACE_USE_ONE_SHOT_AT_THREAD_EXIT)
+ ACE_Cleanup_Info cleanup_info;
+
+ // Just hold onto the guard while finding this thread's id and
+ // copying the exit hook.
+ {
+ ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, 0));
+
+ // Find the thread id, but don't use the cache. It might have been
+ // deleted already.
+#if defined (VXWORKS)
+ ACE_hthread_t id;
+ ACE_OS::thr_self (id);
+ ACE_Thread_Descriptor *td = this->find_hthread (id);
+#else /* ! VXWORKS */
+ ACE_thread_t id = ACE_OS::thr_self ();
+ ACE_Thread_Descriptor *td = this->find_thread (id);
+#endif /* ! VXWORKS */
+
+ // Locate thread id.
+ if (td != 0)
+ {
+ // @@ Currently, we have just one hook. This should clearly
+ // be generalized to support an arbitrary number of hooks.
+
+ if (td->cleanup_info_.cleanup_hook_ != 0)
+ {
+ // Copy the hook so that we can call it after releasing
+ // the guard.
+ cleanup_info = td->cleanup_info_;
+ td->cleanup_info_.cleanup_hook_ = 0;
+ }
+
+#if !defined (VXWORKS)
+ // Threads created with THR_DAEMON shouldn't exist here, but
+ // just to be safe, let's put it here.
+
+ if (ACE_BIT_DISABLED (td->thr_state_, ACE_THR_JOINING))
+ if (ACE_BIT_DISABLED (td->flags_, THR_DETACHED | THR_DAEMON)
+ || ACE_BIT_ENABLED (td->flags_, THR_JOINABLE))
+ {
+ // Mark thread as terminated.
+ ACE_SET_BITS (td->thr_state_, ACE_THR_TERMINATED);
+ this->register_as_terminated (td);
+ // Must copy the information here because td will be "freed" below.
+ }
+#if defined (ACE_WIN32)
+ else
+ {
+ close_handle = 1;
+ }
+#endif /* ACE_WIN32 */
+#endif /* ! VXWORKS */
+
+ // Remove thread descriptor from the table.
+ this->remove_thr (td, close_handle);
+ }
+ // Release the guard.
+ }
+
+ // Call the cleanup hook.
+ if (cleanup_info.cleanup_hook_ != 0)
+ (*cleanup_info.cleanup_hook_) (cleanup_info.object_,
+ cleanup_info.param_);
+#else /* !ACE_USE_ONE_SHOT_AT_THREAD_EXIT */
+ // Just hold onto the guard while finding this thread's id and
+ {
+ ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, 0));
+
+ // Find the thread id, but don't use the cache. It might have been
+ // deleted already.
+#if defined (VXWORKS)
+ ACE_hthread_t id;
+ ACE_OS::thr_self (id);
+ ACE_Thread_Descriptor* td = this->find_hthread (id);
+#else /* ! VXWORKS */
+ ACE_thread_t id = ACE_OS::thr_self ();
+ ACE_Thread_Descriptor* td = this->find_thread (id);
+#endif /* ! VXWORKS */
+ if (td != 0)
+ {
+ // @@ We call Thread_Descriptor terminate this realize the cleanup
+ // process itself.
+ td->terminate();
+ }
+ }
+
+
+#endif /* !ACE_USE_ONE_SHOT_AT_THREAD_EXIT */
+
+ if (do_thr_exit)
+ {
+ ACE_Thread::exit (status);
+ // On reasonable systems <ACE_Thread::exit> should not return.
+ // However, due to horrible semantics with Win32 thread-specific
+ // storage this call can return (don't ask...).
+ }
+
+ return 0;
+}
+
+// Wait for all the threads to exit.
+
+int
+ACE_Thread_Manager::wait (const ACE_Time_Value *timeout,
+ int abandon_detached_threads)
+{
+ ACE_TRACE ("ACE_Thread_Manager::wait");
+
+#if defined (ACE_HAS_THREADS)
+ {
+ // Just hold onto the guard while waiting.
+ ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1));
+
+ if (ACE_Object_Manager::shutting_down () != 1)
+ {
+ // Program is not shutting down. Perform a normal wait on threads.
+ if (abandon_detached_threads != 0)
+ {
+ ACE_ASSERT (this->thr_to_be_removed_.is_empty ());
+ for (ACE_Double_Linked_List_Iterator<ACE_Thread_Descriptor>
+ iter (this->thr_list_);
+ !iter.done ();
+ iter.advance ())
+ if (ACE_BIT_ENABLED (iter.next ()->flags_,
+ THR_DETACHED | THR_DAEMON)
+ && ACE_BIT_DISABLED (iter.next ()->flags_, THR_JOINABLE))
+ {
+ this->thr_to_be_removed_.enqueue_tail (iter.next ());
+ ACE_SET_BITS (iter.next ()->thr_state_, ACE_THR_JOINING);
+ }
+
+ if (! this->thr_to_be_removed_.is_empty ())
+ {
+ ACE_Thread_Descriptor *td;
+ while (this->thr_to_be_removed_.dequeue_head (td) != -1)
+ this->remove_thr (td, 1);
+ }
+ }
+
+ while (this->thr_list_.size () > 0)
+ if (this->zero_cond_.wait (timeout) == -1)
+ return -1;
+ }
+ else
+ // Program is shutting down, no chance to wait on threads.
+ // Therefore, we'll just remove threads from the list.
+ this->remove_thr_all ();
+ // Release the guard, giving other threads a chance to run.
+ }
+
+#if !defined (VXWORKS)
+ // @@ VxWorks doesn't support thr_join (yet.) We are working
+ //on our implementation. Chorus'es thr_join seems broken.
+ ACE_Thread_Descriptor_Base *item;
+
+#if defined (CHORUS)
+ if (ACE_Object_Manager::shutting_down () != 1)
+ {
+#endif /* CHORUS */
+ while ((item = this->terminated_thr_list_.delete_head ()) != 0)
+ {
+ if (ACE_BIT_DISABLED (item->flags_, THR_DETACHED | THR_DAEMON)
+ || ACE_BIT_ENABLED (item->flags_, THR_JOINABLE))
+ // Detached handles shouldn't reached here.
+ ACE_Thread::join (item->thr_handle_);
+
+# if defined (ACE_HAS_PTHREADS_DRAFT4) && defined (ACE_LACKS_SETDETACH)
+ // Must explicitly detach threads. Threads without
+ // THR_DETACHED were detached in ACE_OS::thr_create ().
+ ::pthread_detach (&item->thr_handle_);
+# endif /* ACE_HAS_PTHREADS_DRAFT4 && ACE_LACKS_SETDETACH */
+ delete item;
+ }
+#if defined (CHORUS)
+ }
+#endif /* CHORUS */
+
+#endif /* ! VXWORKS */
+#else
+ ACE_UNUSED_ARG (timeout);
+ ACE_UNUSED_ARG (abandon_detached_threads);
+#endif /* ACE_HAS_THREADS */
+
+ return 0;
+}
+
+int
+ACE_Thread_Manager::apply_task (ACE_Task_Base *task,
+ ACE_THR_MEMBER_FUNC func,
+ int arg)
+{
+ ACE_TRACE ("ACE_Thread_Manager::apply_task");
+ ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1));
+ ACE_ASSERT (this->thr_to_be_removed_.is_empty ());
+
+ int result = 0;
+
+ for (ACE_Double_Linked_List_Iterator<ACE_Thread_Descriptor> iter (this->thr_list_);
+ !iter.done ();
+ iter.advance ())
+ if (iter.next ()->task_ == task
+ && (this->*func) (iter.next (), arg) == -1)
+ result = -1;
+
+ // Must remove threads after we have traversed the thr_list_ to
+ // prevent clobber thr_list_'s integrity.
+
+ if (! this->thr_to_be_removed_.is_empty ())
+ {
+ // Save/restore errno.
+ ACE_Errno_Guard error (errno);
+
+ for (ACE_Thread_Descriptor *td;
+ this->thr_to_be_removed_.dequeue_head (td) != -1;
+ )
+ this->remove_thr (td, 1);
+ }
+
+ return result;
+}
+
+// Wait for all threads to exit a task.
+
+int
+ACE_Thread_Manager::wait_task (ACE_Task_Base *task)
+{
+ int copy_count = 0;
+ ACE_Thread_Descriptor_Base *copy_table = 0;
+
+ // We have to make sure that while we wait for these threads to
+ // exit, we do not have the lock. Therefore we make a copy of all
+ // interesting entries and let go of the lock.
+ {
+ ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1));
+
+#if !defined (VXWORKS)
+ ACE_NEW_RETURN (copy_table,
+ ACE_Thread_Descriptor_Base [this->thr_list_.size ()
+ + this->terminated_thr_list_.size ()],
+ -1);
+#else
+ ACE_NEW_RETURN (copy_table,
+ ACE_Thread_Descriptor_Base [this->thr_list_.size ()],
+ -1);
+#endif /* VXWORKS */
+
+ for (ACE_Double_Linked_List_Iterator<ACE_Thread_Descriptor> iter (this->thr_list_);
+ !iter.done ();
+ iter.advance ())
+ // If threads are created as THR_DETACHED or THR_DAEMON, we
+ // can't wait on them here.
+ if (iter.next ()->task_ == task &&
+ (ACE_BIT_DISABLED (iter.next ()->flags_,
+ THR_DETACHED | THR_DAEMON)
+ || ACE_BIT_ENABLED (iter.next ()->flags_,
+ THR_JOINABLE)))
+ {
+ ACE_SET_BITS (iter.next ()->thr_state_,
+ ACE_THR_JOINING);
+ copy_table[copy_count++] = *iter.next ();
+ }
+
+#if !defined (VXWORKS)
+ for (ACE_Double_Linked_List_Iterator<ACE_Thread_Descriptor_Base> titer (this->terminated_thr_list_);
+ !titer.done ();
+ titer.advance ())
+ // If threads are created as THR_DETACHED or THR_DAEMON, we can't help much here.
+ if (titer.next ()->task_ == task)
+ {
+ ACE_Thread_Descriptor_Base *tdb =
+ titer.advance_and_remove (0);
+ copy_table[copy_count++] = *tdb;
+ delete tdb;
+ }
+#endif /* VXWORKS */
+ }
+
+ // Now to do the actual work
+ int result = 0;
+
+ for (int i = 0;
+ i < copy_count && result != -1;
+ i++)
+ {
+ if (ACE_Thread::join (copy_table[i].thr_handle_) == -1)
+ result = -1;
+
+# if defined (ACE_HAS_PTHREADS_DRAFT4) && defined (ACE_LACKS_SETDETACH)
+ // Must explicitly detach threads. Threads without THR_DETACHED
+ // were detached in ACE_OS::thr_create ().
+ ::pthread_detach (&copy_table[i].thr_handle_);
+# endif /* ACE_HAS_PTHREADS_DRAFT4 && ACE_LACKS_SETDETACH */
+ }
+
+ delete [] copy_table;
+
+ return result;
+}
+
+// Suspend a task
+
+int
+ACE_Thread_Manager::suspend_task (ACE_Task_Base *task)
+{
+ ACE_TRACE ("ACE_Thread_Manager::suspend_task");
+ return this->apply_task (task,
+ ACE_THR_MEMBER_FUNC (&ACE_Thread_Manager::suspend_thr));
+}
+
+// Resume a task.
+int
+ACE_Thread_Manager::resume_task (ACE_Task_Base *task)
+{
+ ACE_TRACE ("ACE_Thread_Manager::resume_task");
+ return this->apply_task (task,
+ ACE_THR_MEMBER_FUNC (&ACE_Thread_Manager::resume_thr));
+}
+
+// Kill a task.
+
+int
+ACE_Thread_Manager::kill_task (ACE_Task_Base *task, int /* signum */)
+{
+ ACE_TRACE ("ACE_Thread_Manager::kill_task");
+ return this->apply_task (task,
+ ACE_THR_MEMBER_FUNC (&ACE_Thread_Manager::kill_thr));
+}
+
+// Cancel a task.
+int
+ACE_Thread_Manager::cancel_task (ACE_Task_Base *task,
+ int async_cancel)
+{
+ ACE_TRACE ("ACE_Thread_Manager::cancel_task");
+ return this->apply_task (task,
+ ACE_THR_MEMBER_FUNC (&ACE_Thread_Manager::cancel_thr),
+ async_cancel);
+}
+
+// Locate the index in the table associated with <task> from the
+// beginning of the table up to an index. Must be called with the
+// lock held.
+
+ACE_Thread_Descriptor *
+ACE_Thread_Manager::find_task (ACE_Task_Base *task, int slot)
+{
+ ACE_TRACE ("ACE_Thread_Manager::find_task");
+
+ int i = 0;
+
+ for (ACE_Double_Linked_List_Iterator<ACE_Thread_Descriptor> iter (this->thr_list_);
+ !iter.done ();
+ iter.advance ())
+ {
+ if (i >= slot)
+ break;
+
+ if (task == iter.next ()->task_)
+ return iter.next ();
+
+ i++;
+ }
+
+ return 0;
+}
+
+// Returns the number of ACE_Task in a group.
+
+int
+ACE_Thread_Manager::num_tasks_in_group (int grp_id)
+{
+ ACE_TRACE ("ACE_Thread_Manager::num_tasks_in_group");
+ ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1));
+
+ int tasks_count = 0;
+ size_t i = 0;
+
+ for (ACE_Double_Linked_List_Iterator<ACE_Thread_Descriptor> iter (this->thr_list_);
+ !iter.done ();
+ iter.advance ())
+ {
+ if (iter.next ()->grp_id_ == grp_id
+ && this->find_task (iter.next ()->task_, i) == 0
+ && iter.next ()->task_ != 0)
+ tasks_count++;
+
+ i++;
+ }
+ return tasks_count;
+}
+
+// Returns the number of threads in an ACE_Task.
+
+int
+ACE_Thread_Manager::num_threads_in_task (ACE_Task_Base *task)
+{
+ ACE_TRACE ("ACE_Thread_Manager::num_threads_in_task");
+ ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1));
+
+ int threads_count = 0;
+
+ for (ACE_Double_Linked_List_Iterator<ACE_Thread_Descriptor> iter (this->thr_list_);
+ !iter.done ();
+ iter.advance ())
+ if (iter.next ()->task_ == task)
+ threads_count++;
+
+ return threads_count;
+}
+
+// Returns in task_list a list of ACE_Tasks registered with ACE_Thread_Manager.
+
+int
+ACE_Thread_Manager::task_all_list (ACE_Task_Base *task_list[],
+ size_t n)
+{
+ ACE_TRACE ("ACE_Thread_Manager::task_all_list");
+ ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1));
+
+ size_t task_list_count = 0;
+
+ for (ACE_Double_Linked_List_Iterator<ACE_Thread_Descriptor> iter (this->thr_list_);
+ !iter.done ();
+ iter.advance ())
+ {
+ if (task_list_count >= n)
+ break;
+
+ ACE_Task_Base *task_p = iter.next ()->task_;
+ if (0 != task_p)
+ {
+ // This thread has a task pointer; see if it's already in the
+ // list. Don't add duplicates.
+ size_t i = 0;
+ for (; i < task_list_count; ++i)
+ if (task_list[i] == task_p)
+ break;
+ if (i == task_list_count) // No match - add this one
+ task_list[task_list_count++] = task_p;
+ }
+ }
+
+ return task_list_count;
+}
+
+// Returns in thread_list a list of all thread ids
+
+int
+ACE_Thread_Manager::thread_all_list ( ACE_thread_t thread_list[],
+ size_t n)
+{
+ ACE_TRACE ("ACE_Thread_Manager::thread_all_list");
+ ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1));
+
+ size_t thread_count = 0;
+
+ for (ACE_Double_Linked_List_Iterator<ACE_Thread_Descriptor> iter (this->thr_list_);
+ !iter.done ();
+ iter.advance ())
+ {
+ if (thread_count >= n)
+ break;
+
+ thread_list[thread_count] = iter.next ()->thr_id_;
+ thread_count ++;
+ }
+
+ return thread_count;
+}
+
+// Returns in task_list a list of ACE_Tasks in a group.
+
+int
+ACE_Thread_Manager::task_list (int grp_id,
+ ACE_Task_Base *task_list[],
+ size_t n)
+{
+ ACE_TRACE ("ACE_Thread_Manager::task_list");
+ ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1));
+
+ ACE_Task_Base **task_list_iterator = task_list;
+ size_t task_list_count = 0;
+ size_t i = 0;
+
+ for (ACE_Double_Linked_List_Iterator<ACE_Thread_Descriptor> iter (this->thr_list_);
+ !iter.done ();
+ iter.advance ())
+ {
+ if (task_list_count >= n)
+ break;
+
+ if (iter.next ()->grp_id_ == grp_id
+ && this->find_task (iter.next ()->task_, i) == 0)
+ {
+ task_list_iterator[task_list_count] = iter.next ()->task_;
+ task_list_count++;
+ }
+
+ i++;
+ }
+
+ return task_list_count;
+}
+
+// Returns in thread_list a list of thread ids in an ACE_Task.
+
+int
+ACE_Thread_Manager::thread_list (ACE_Task_Base *task,
+ ACE_thread_t thread_list[],
+ size_t n)
+{
+ ACE_TRACE ("ACE_Thread_Manager::thread_list");
+ ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1));
+
+ size_t thread_count = 0;
+
+ for (ACE_Double_Linked_List_Iterator<ACE_Thread_Descriptor> iter (this->thr_list_);
+ !iter.done ();
+ iter.advance ())
+ {
+ if (thread_count >= n)
+ break;
+
+ if (iter.next ()->task_ == task)
+ {
+ thread_list[thread_count] = iter.next ()->thr_id_;
+ thread_count++;
+ }
+ }
+
+ return thread_count;
+}
+
+// Returns in thread_list a list of thread handles in an ACE_Task.
+
+int
+ACE_Thread_Manager::hthread_list (ACE_Task_Base *task,
+ ACE_hthread_t hthread_list[],
+ size_t n)
+{
+ ACE_TRACE ("ACE_Thread_Manager::hthread_list");
+ ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1));
+
+ size_t hthread_count = 0;
+
+ for (ACE_Double_Linked_List_Iterator<ACE_Thread_Descriptor> iter (this->thr_list_);
+ !iter.done ();
+ iter.advance ())
+ {
+ if (hthread_count >= n)
+ break;
+
+ if (iter.next ()->task_ == task)
+ {
+ hthread_list[hthread_count] = iter.next ()->thr_handle_;
+ hthread_count++;
+ }
+ }
+
+ return hthread_count;
+}
+
+int
+ACE_Thread_Manager::thread_grp_list (int grp_id,
+ ACE_thread_t thread_list[],
+ size_t n)
+{
+ ACE_TRACE ("ACE_Thread_Manager::thread_grp_list");
+ ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1));
+
+ size_t thread_count = 0;
+
+ for (ACE_Double_Linked_List_Iterator<ACE_Thread_Descriptor> iter (this->thr_list_);
+ !iter.done ();
+ iter.advance ())
+ {
+ if (thread_count >= n)
+ break;
+
+ if (iter.next ()->grp_id_ == grp_id)
+ {
+ thread_list[thread_count] = iter.next ()->thr_id_;
+ thread_count++;
+ }
+ }
+
+ return thread_count;
+}
+
+// Returns in thread_list a list of thread handles in an ACE_Task.
+
+int
+ACE_Thread_Manager::hthread_grp_list (int grp_id,
+ ACE_hthread_t hthread_list[],
+ size_t n)
+{
+ ACE_TRACE ("ACE_Thread_Manager::hthread_grp_list");
+ ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1));
+
+ size_t hthread_count = 0;
+
+ for (ACE_Double_Linked_List_Iterator<ACE_Thread_Descriptor> iter (this->thr_list_);
+ !iter.done ();
+ iter.advance ())
+ {
+ if (hthread_count >= n)
+ break;
+
+ if (iter.next ()->grp_id_ == grp_id)
+ {
+ hthread_list[hthread_count] = iter.next ()->thr_handle_;
+ hthread_count++;
+ }
+ }
+
+ return hthread_count;
+}
+
+int
+ACE_Thread_Manager::set_grp (ACE_Task_Base *task, int grp_id)
+{
+ ACE_TRACE ("ACE_Thread_Manager::set_grp");
+ ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1));
+
+ for (ACE_Double_Linked_List_Iterator<ACE_Thread_Descriptor> iter (this->thr_list_);
+ !iter.done ();
+ iter.advance ())
+ if (iter.next ()->task_ == task)
+ iter.next ()->grp_id_ = grp_id;
+
+ return 0;
+}
+
+int
+ACE_Thread_Manager::get_grp (ACE_Task_Base *task, int &grp_id)
+{
+ ACE_TRACE ("ACE_Thread_Manager::get_grp");
+ ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1));
+
+ ACE_FIND (this->find_task (task), ptr);
+ grp_id = ptr->grp_id_;
+ return 0;
+}
+
+#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION)
+# if defined (ACE_THREAD_MANAGER_LACKS_STATICS)
+ template class ACE_Singleton<ACE_Thread_Manager, ACE_SYNCH_MUTEX>;
+# endif /* defined (ACE_THREAD_MANAGER_LACKS_STATICS) */
+ template class ACE_Auto_Basic_Ptr<ACE_Thread_Descriptor>;
+ template class auto_ptr<ACE_Thread_Descriptor>;
+ template class ACE_Double_Linked_List<ACE_Thread_Descriptor_Base>;
+ template class ACE_Double_Linked_List_Iterator_Base<ACE_Thread_Descriptor_Base>;
+ template class ACE_Double_Linked_List_Iterator<ACE_Thread_Descriptor_Base>;
+ template class ACE_Double_Linked_List<ACE_Thread_Descriptor>;
+ template class ACE_Double_Linked_List_Iterator_Base<ACE_Thread_Descriptor>;
+ template class ACE_Double_Linked_List_Iterator<ACE_Thread_Descriptor>;
+ template class ACE_Node<ACE_Thread_Descriptor*>;
+ template class ACE_Unbounded_Queue<ACE_Thread_Descriptor*>;
+ template class ACE_Unbounded_Queue_Iterator<ACE_Thread_Descriptor*>;
+ template class ACE_Free_List<ACE_Thread_Descriptor>;
+ template class ACE_Locked_Free_List<ACE_Thread_Descriptor, ACE_DEFAULT_THREAD_MANAGER_LOCK>;
+#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA)
+# if defined (ACE_THREAD_MANAGER_LACKS_STATICS)
+ #pragma instantiate ACE_Singleton<ACE_Thread_Manager, ACE_SYNCH_MUTEX>
+# endif /* defined (ACE_THREAD_MANAGER_LACKS_STATICS) */
+ #pragma instantiate ACE_Auto_Basic_Ptr<ACE_Thread_Descriptor>
+ #pragma instantiate auto_ptr<ACE_Thread_Descriptor>
+ #pragma instantiate ACE_Double_Linked_List<ACE_Thread_Descriptor_Base>
+ #pragma instantiate ACE_Double_Linked_List_Iterator_Base<ACE_Thread_Descriptor_Base>
+ #pragma instantiate ACE_Double_Linked_List_Iterator<ACE_Thread_Descriptor_Base>
+ #pragma instantiate ACE_Double_Linked_List<ACE_Thread_Descriptor>
+ #pragma instantiate ACE_Double_Linked_List_Iterator_Base<ACE_Thread_Descriptor>
+ #pragma instantiate ACE_Double_Linked_List_Iterator<ACE_Thread_Descriptor>
+ #pragma instantiate ACE_Node<ACE_Thread_Descriptor*>
+ #pragma instantiate ACE_Unbounded_Queue<ACE_Thread_Descriptor*>
+ #pragma instantiate ACE_Unbounded_Queue_Iterator<ACE_Thread_Descriptor*>
+ #pragma instantiate ACE_Free_List<ACE_Thread_Descriptor>
+ #pragma instantiate ACE_Locked_Free_List<ACE_Thread_Descriptor, ACE_DEFAULT_THREAD_MANAGER_LOCK>
+#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */
diff --git a/ace/Threads/Thread_Manager.h b/ace/Threads/Thread_Manager.h
new file mode 100644
index 00000000000..e2c6d190db1
--- /dev/null
+++ b/ace/Threads/Thread_Manager.h
@@ -0,0 +1,1008 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Thread_Manager.h
+ *
+ * $Id$
+ *
+ * @author Douglas C. Schmidt <schmidt@cs.wustl.edu>
+ */
+//=============================================================================
+
+#ifndef ACE_THREAD_MANAGER_H
+#define ACE_THREAD_MANAGER_H
+#include "ace/pre.h"
+
+#include "ace/Thread.h"
+#include "ace/Thread_Adapter.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "ace/Synch.h"
+#include "ace/Unbounded_Queue.h"
+#include "ace/Containers.h"
+#include "ace/Free_List.h"
+#include "ace/Singleton.h"
+#include "ace/Log_Msg.h"
+
+// The following macros control how a Thread Manager manages a pool of
+// Thread_Descriptor. Currently, the default behavior is not to
+// preallocate any thread descriptor and never (well, almost never)
+// free up any thread descriptor until the Thread Manager gets
+// destructed. Which means, once your system is stable, you rarely
+// need to pay the price of memory allocation. On a deterministic
+// system, which means, the number of threads spawned can be
+// determined before hand, you can either redefine the memory pool
+// size macros to suit your need or constructed the Thread_Manager
+// accordingly. That way, you don't pay the price of memory
+// allocation when the system is really doing its job. OTOH, on
+// system with resources constraint, you may want to lower the size of
+// ACE_DEFAULT_THREAD_MANAGER_HWM to avoid unused memory hanging
+// around.
+
+#if !defined (ACE_DEFAULT_THREAD_MANAGER_PREALLOC)
+# define ACE_DEFAULT_THREAD_MANAGER_PREALLOC 0
+#endif /* ACE_DEFAULT_THREAD_MANAGER_PREALLOC */
+
+#if !defined (ACE_DEFAULT_THREAD_MANAGER_LWM)
+# define ACE_DEFAULT_THREAD_MANAGER_LWM 1
+#endif /* ACE_DEFAULT_THREAD_MANAGER_LWM */
+
+#if !defined (ACE_DEFAULT_THREAD_MANAGER_INC)
+# define ACE_DEFAULT_THREAD_MANAGER_INC 1
+#endif /* ACE_DEFAULT_THREAD_MANAGER_INC */
+
+#if !defined (ACE_DEFAULT_THREAD_MANAGER_HWM)
+# define ACE_DEFAULT_THREAD_MANAGER_HWM ACE_DEFAULT_FREE_LIST_HWM
+// this is a big number
+#endif /* ACE_DEFAULT_THREAD_MANAGER_HWM */
+
+// This is the synchronization mechanism used to prevent a thread
+// descriptor gets removed from the Thread_Manager before it gets
+// stash into it. If you want to disable this feature (and risk of
+// corrupting the freelist,) you define the lock as ACE_Null_Mutex.
+// Usually, if you can be sure that your threads will run for an
+// extended period of time, you can safely disable the lock.
+
+#if !defined (ACE_DEFAULT_THREAD_MANAGER_LOCK)
+# define ACE_DEFAULT_THREAD_MANAGER_LOCK ACE_SYNCH_MUTEX
+#endif /* ACE_DEFAULT_THREAD_MANAGER_LOCK */
+
+// Forward declarations.
+class ACE_Task_Base;
+class ACE_Thread_Manager;
+class ACE_Thread_Descriptor;
+
+#if !defined(ACE_USE_ONE_SHOT_AT_THREAD_EXIT)
+ /**
+ * @class ACE_At_Thread_Exit
+ *
+ * @brief Contains a method to be applied when a thread is terminated.
+ */
+class ACE_Export ACE_At_Thread_Exit
+{
+ friend class ACE_Thread_Descriptor;
+ friend class ACE_Thread_Manager;
+public:
+ // Default constructor
+ ACE_At_Thread_Exit (void);
+
+ // The destructor
+ virtual ~ACE_At_Thread_Exit (void);
+
+ // <At_Thread_Exit> has the ownership?
+ int is_owner (void) const;
+
+ // Set the ownership of the <At_Thread_Exit>.
+ int is_owner (int owner);
+
+ // This <At_Thread_Exit> was applied?
+ int was_applied (void) const;
+
+ // Set applied state of <At_Thread_Exit>.
+ int was_applied (int applied);
+
+protected:
+ /// The next <At_Thread_Exit> hook in the list.
+ ACE_At_Thread_Exit *next_;
+
+ // Do the apply if necessary
+ void do_apply (void);
+
+ /// The apply method.
+ virtual void apply (void) = 0;
+
+ /// The Thread_Descriptor where this at is registered.
+ ACE_Thread_Descriptor* td_;
+
+ /// The at was applied?
+ int was_applied_;
+
+ /// The at has the ownership of this?
+ int is_owner_;
+};
+
+class ACE_Export ACE_At_Thread_Exit_Func : public ACE_At_Thread_Exit
+{
+public:
+ // Constructor
+ ACE_At_Thread_Exit_Func (void *object,
+ ACE_CLEANUP_FUNC func,
+ void *param = 0);
+
+ virtual ~ACE_At_Thread_Exit_Func (void);
+
+protected:
+ /// The object to be cleanup
+ void *object_;
+
+ /// The cleanup func
+ ACE_CLEANUP_FUNC func_;
+
+ /// A param if required
+ void *param_;
+
+ // The apply method
+ void apply (void);
+};
+
+#endif /* !ACE_USE_ONE_SHOT_AT_THREAD_EXIT */
+
+/**
+ * @class ACE_Thread_Descriptor_Base
+ *
+ * @brief Basic information for thread descriptors. These information
+ * gets extracted out because we need it after a thread is
+ * terminated.
+ */
+class ACE_Export ACE_Thread_Descriptor_Base : public ACE_OS_Thread_Descriptor
+{
+
+ friend class ACE_Thread_Manager;
+ friend class ACE_Double_Linked_List<ACE_Thread_Descriptor_Base>;
+ friend class ACE_Double_Linked_List_Iterator_Base<ACE_Thread_Descriptor_Base>;
+ friend class ACE_Double_Linked_List_Iterator<ACE_Thread_Descriptor_Base>;
+ friend class ACE_Double_Linked_List<ACE_Thread_Descriptor>;
+ friend class ACE_Double_Linked_List_Iterator_Base<ACE_Thread_Descriptor>;
+ friend class ACE_Double_Linked_List_Iterator<ACE_Thread_Descriptor>;
+public:
+ ACE_Thread_Descriptor_Base (void);
+ ~ACE_Thread_Descriptor_Base (void);
+
+ // = We need the following operators to make Borland happy.
+
+ /// Equality operator.
+ int operator== (const ACE_Thread_Descriptor_Base &rhs) const;
+
+ /// Inequality operator.
+ int operator!= (const ACE_Thread_Descriptor_Base &rhs) const;
+
+ /// Group ID.
+ int grp_id (void) const;
+
+ /// Current state of the thread.
+ ACE_UINT32 state (void) const;
+
+ /// Return the pointer to an <ACE_Task_Base> or NULL if there's no
+ /// <ACE_Task_Base> associated with this thread.;
+ ACE_Task_Base *task (void) const;
+
+protected:
+ /// Reset this base thread descriptor.
+ void reset (void);
+
+ /// Unique thread ID.
+ ACE_thread_t thr_id_;
+
+ /// Unique handle to thread (used by Win32 and AIX).
+ ACE_hthread_t thr_handle_;
+
+ /// Group ID.
+ int grp_id_;
+
+ /// Current state of the thread.
+ ACE_UINT32 thr_state_;
+
+ /// Pointer to an <ACE_Task_Base> or NULL if there's no
+ /// <ACE_Task_Base>.
+ ACE_Task_Base *task_;
+
+ /// We need these pointers to maintain the double-linked list in a
+ /// thread managers.
+ ACE_Thread_Descriptor_Base *next_;
+ ACE_Thread_Descriptor_Base *prev_;
+};
+
+/**
+ * @class ACE_Thread_Descriptor
+ *
+ * @brief Information for controlling threads that run under the control
+ * of the <Thread_Manager>.
+ */
+class ACE_Export ACE_Thread_Descriptor : public ACE_Thread_Descriptor_Base
+{
+#if !defined(ACE_USE_ONE_SHOT_AT_THREAD_EXIT)
+ friend class ACE_At_Thread_Exit;
+#endif /* !ACE_USE_ONE_SHOT_AT_THREAD_EXIT */
+ friend class ACE_Thread_Manager;
+ friend class ACE_Double_Linked_List<ACE_Thread_Descriptor>;
+ friend class ACE_Double_Linked_List_Iterator<ACE_Thread_Descriptor>;
+public:
+ // = Initialization method.
+ ACE_Thread_Descriptor (void);
+
+ // = Accessor methods.
+ /// Unique thread id.
+ ACE_thread_t self (void) const;
+
+ /// Unique handle to thread (used by Win32 and AIX).
+ void self (ACE_hthread_t &);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+#if !defined(ACE_USE_ONE_SHOT_AT_THREAD_EXIT)
+ /**
+ * This cleanup function must be called only for ACE_TSS_cleanup.
+ * The ACE_TSS_cleanup delegate Log_Msg instance destruction when
+ * Log_Msg cleanup is called before terminate.
+ */
+ void log_msg_cleanup(ACE_Log_Msg* log_msg);
+
+ /**
+ * Register an At_Thread_Exit hook and the ownership is acquire by
+ * Thread_Descriptor, this is the usual case when the AT is dynamically
+ * allocated.
+ */
+ int at_exit (ACE_At_Thread_Exit* cleanup);
+
+ /// Register an At_Thread_Exit hook and the ownership is retained for the
+ /// caller. Normally used when the at_exit hook is created in stack.
+ int at_exit (ACE_At_Thread_Exit& cleanup);
+#endif /* !ACE_USE_ONE_SHOT_AT_THREAD_EXIT */
+
+ /**
+ * Register an object (or array) for cleanup at thread termination.
+ * "cleanup_hook" points to a (global, or static member) function
+ * that is called for the object or array when it to be destroyed.
+ * It may perform any necessary cleanup specific for that object or
+ * its class. "param" is passed as the second parameter to the
+ * "cleanup_hook" function; the first parameter is the object (or
+ * array) to be destroyed. Returns 0 on success, non-zero on
+ * failure: -1 if virtual memory is exhausted or 1 if the object (or
+ * arrayt) had already been registered.
+ */
+ int at_exit (void *object,
+ ACE_CLEANUP_FUNC cleanup_hook,
+ void *param);
+
+ /// Do nothing destructor to keep some compilers happy
+ ~ACE_Thread_Descriptor (void);
+
+ /**
+ * Do nothing but to acquire the thread descriptor's lock and
+ * release. This will first check if the thread is registered or
+ * not. If it is already registered, there's no need to reacquire
+ * the lock again. This is used mainly to get newly spawned thread
+ * in synch with thread manager and prevent it from accessing its
+ * thread descriptor before it gets fully built. This function is
+ * only called from ACE_Log_Msg::thr_desc.
+ */
+ void acquire_release (void);
+
+ /**
+ * Set/get the <next_> pointer. These are required by the
+ * ACE_Free_List. ACE_INLINE is specified here because one version
+ * of g++ couldn't grok this code without it.
+ */
+ ACE_INLINE_FOR_GNUC void set_next (ACE_Thread_Descriptor *td);
+ ACE_INLINE_FOR_GNUC ACE_Thread_Descriptor *get_next (void) const;
+
+private:
+ /// Reset this thread descriptor.
+ void reset (ACE_Thread_Manager *tm);
+
+#if !defined (ACE_USE_ONE_SHOT_AT_THREAD_EXIT)
+ /// Pop an At_Thread_Exit from at thread termination list, apply the at
+ /// if apply is true.
+ void at_pop (int apply = 1);
+
+ /// Push an At_Thread_Exit to at thread termination list and set the
+ /// ownership of at.
+ void at_push (ACE_At_Thread_Exit* cleanup,
+ int is_owner = 0);
+
+ /// Run the AT_Thread_Exit hooks.
+ void do_at_exit (void);
+
+ /// terminate realize the cleanup process to thread termination
+ void terminate (void);
+
+ /// Thread_Descriptor is the ownership of ACE_Log_Msg if log_msg_!=0
+ /// This can occur because ACE_TSS_cleanup was executed before terminate.
+ ACE_Log_Msg *log_msg_;
+
+ /// The AT_Thread_Exit list
+ ACE_At_Thread_Exit *at_exit_list_;
+#endif /* !ACE_USE_ONE_SHOT_AT_THREAD_EXIT */
+
+ /**
+ * Stores the cleanup info for a thread.
+ * @@ Note, this should be generalized to be a stack of
+ * <ACE_Cleanup_Info>s.
+ */
+ ACE_Cleanup_Info cleanup_info_;
+
+#if !defined(ACE_USE_ONE_SHOT_AT_THREAD_EXIT)
+ /// Pointer to an <ACE_Thread_Manager> or NULL if there's no
+ /// <ACE_Thread_Manager>.
+ ACE_Thread_Manager* tm_;
+#endif /* !ACE_USE_ONE_SHOT_AT_THREAD_EXIT */
+
+ /// Registration lock to prevent premature removal of thread descriptor.
+ ACE_DEFAULT_THREAD_MANAGER_LOCK *sync_;
+
+#if !defined(ACE_USE_ONE_SHOT_AT_THREAD_EXIT)
+ /// Keep track of termination status.
+ int terminated_;
+#endif /* !ACE_USE_ONE_SHOT_AT_THREAD_EXIT */
+};
+
+// Forward declaration.
+class ACE_Thread_Control;
+
+// This typedef should be (and used to be) inside the
+// ACE_Thread_Manager declaration. But, it caused compilation
+// problems on g++/VxWorks/i960 with -g. Note that
+// ACE_Thread_Manager::THR_FUNC is only used internally in
+// ACE_Thread_Manager, so it's not useful for anyone else.
+// It also caused problems on IRIX5 with g++.
+#if defined (__GNUG__)
+typedef int (ACE_Thread_Manager::*ACE_THR_MEMBER_FUNC)(ACE_Thread_Descriptor *, int);
+#endif /* __GNUG__ */
+
+/**
+ * @class ACE_Thread_Manager
+ *
+ * @brief Manages a pool of threads.
+ *
+ * This class allows operations on groups of threads atomically.
+ * The default behavior of thread manager is to wait on
+ * all threads under it's management when it gets destructed.
+ * Therefore, remember to remove a thread from thread manager if
+ * you don't want it to wait for the thread. There are also
+ * function to disable this default wait-on-exit behavior.
+ * However, if your program depends on turning this off to run
+ * correctly, you are probably doing something wrong. Rule of
+ * thumb, use ACE_Thread to manage your daemon threads.
+ * Notice that if there're threads live beyond the scope of
+ * <main>, you are sure to have resource leaks in your program.
+ * Remember to wait on threads before exiting <main> if that
+ * could happen in your programs.
+ */
+class ACE_Export ACE_Thread_Manager
+{
+public:
+ friend class ACE_Thread_Control;
+#if !defined(ACE_USE_ONE_SHOT_AT_THREAD_EXIT)
+ friend class ACE_Thread_Descriptor;
+#endif /* !ACE_USE_ONE_SHOT_AT_THREAD_EXIT */
+
+#if !defined (__GNUG__)
+ typedef int (ACE_Thread_Manager::*ACE_THR_MEMBER_FUNC)(ACE_Thread_Descriptor *, int);
+#endif /* !__GNUG__ */
+
+ // These are the various states a thread managed by the
+ // <Thread_Manager> can be in.
+ enum
+ {
+ /// Uninitialized.
+ ACE_THR_IDLE = 0x00000000,
+
+ /// Created but not yet running.
+ ACE_THR_SPAWNED = 0x00000001,
+
+ /// Thread is active (naturally, we don't know if it's actually
+ /// *running* because we aren't the scheduler...).
+ ACE_THR_RUNNING = 0x00000002,
+
+ /// Thread is suspended.
+ ACE_THR_SUSPENDED = 0x00000004,
+
+ /// Thread has been cancelled (which is an indiction that it needs to
+ /// terminate...).
+ ACE_THR_CANCELLED = 0x00000008,
+
+ /// Thread has shutdown, but the slot in the thread manager hasn't
+ /// been reclaimed yet.
+ ACE_THR_TERMINATED = 0x00000010,
+
+ /// Join operation has been invoked on the thread by thread manager.
+ ACE_THR_JOINING = 0x10000000
+ };
+
+ // = Initialization and termination methods.
+ /**
+ * @breif Initialization and termination methods.
+ *
+ * Internally, ACE_Thread_Manager keeps a freelist for caching
+ * resources it uses to keep track of managed threads (not the
+ * threads themselves.) @a prealloc, @a lwm, @a inc, @hwm
+ * determine the initial size, the low water mark, increment step,
+ * and high water mark of the freelist.
+ *
+ * @sa ACE_Free_List
+ */
+ ACE_Thread_Manager (size_t preaolloc = ACE_DEFAULT_THREAD_MANAGER_PREALLOC,
+ size_t lwm = ACE_DEFAULT_THREAD_MANAGER_LWM,
+ size_t inc = ACE_DEFAULT_THREAD_MANAGER_INC,
+ size_t hwm = ACE_DEFAULT_THREAD_MANAGER_HWM);
+ virtual ~ACE_Thread_Manager (void);
+
+#if ! defined (ACE_THREAD_MANAGER_LACKS_STATICS)
+ /// Get pointer to a process-wide <ACE_Thread_Manager>.
+ static ACE_Thread_Manager *instance (void);
+
+ /// Set pointer to a process-wide <ACE_Thread_Manager> and return
+ /// existing pointer.
+ static ACE_Thread_Manager *instance (ACE_Thread_Manager *);
+
+ /// Delete the dynamically allocated Singleton
+ static void close_singleton (void);
+#endif /* ! defined (ACE_THREAD_MANAGER_LACKS_STATICS) */
+
+ /// No-op. Currently unused.
+ int open (size_t size = 0);
+
+ /**
+ * Release all resources.
+ * By default, this method will wait till all threads
+ * exit. However, when called from <close_singleton>, most global resources
+ * are destroyed and thus, we don't try to wait but just clean up the thread
+ * descriptor list.
+ */
+ int close (void);
+
+ // The <ACE_thread_t> * argument to each of the <spawn> family member
+ // functions is interpreted and used as shown in the following
+ // table. NOTE: the final option, to provide task names, is _only_
+ // supported on VxWorks!
+ //
+ // Value of ACE_thread_t * argument Use Platforms
+ // ================================ ========================== =========
+ // 0 Not used. All
+ // non-0 (and points to 0 char * The task name is passed All
+ // on VxWorks) back in the char *.
+ // non-0, points to non-0 char * The char * is used as VxWorks only
+ // the task name. The
+ // argument is not modified.
+
+ /**
+ * Create a new thread, which executes <func>.
+ * Returns: on success a unique group id that can be used to control
+ * other threads added to the same group. On failure, returns -1.
+ */
+ int spawn (ACE_THR_FUNC func,
+ void *args = 0,
+ long flags = THR_NEW_LWP | THR_JOINABLE,
+ ACE_thread_t * = 0,
+ ACE_hthread_t *t_handle = 0,
+ long priority = ACE_DEFAULT_THREAD_PRIORITY,
+ int grp_id = -1,
+ void *stack = 0,
+ size_t stack_size = 0);
+
+ /**
+ * Create N new threads, all of which execute <func>.
+ * Returns: on success a unique group id that can be used to control
+ * all of the threads in the same group. On failure, returns -1.
+ */
+ int spawn_n (size_t n,
+ ACE_THR_FUNC func,
+ void *args = 0,
+ long flags = THR_NEW_LWP | THR_JOINABLE,
+ long priority = ACE_DEFAULT_THREAD_PRIORITY,
+ int grp_id = -1,
+ ACE_Task_Base *task = 0,
+ ACE_hthread_t thread_handles[] = 0,
+ void *stack[] = 0,
+ size_t stack_size[] = 0);
+
+ /**
+ * Spawn N new threads, which execute <func> with argument <arg>.
+ * If <thread_ids> != 0 the thread_ids of successfully spawned
+ * threads will be placed into the <thread_ids> buffer (which must
+ * be the same size as <n>). If <stack> != 0 it is assumed to be an
+ * array of <n> pointers to the base of the stacks to use for the
+ * threads being spawned. If <stack_size> != 0 it is assumed to be
+ * an array of <n> values indicating how big each of the
+ * corresponding <stack>s are. If <thread_handles> != 0 it is
+ * assumed to be an array of <n> thread_handles that will be
+ * assigned the values of the thread handles being spawned. Returns
+ * -1 on failure (<errno> will explain...), otherwise returns the
+ * group id of the threads.
+ */
+ int spawn_n (ACE_thread_t thread_ids[],
+ size_t n,
+ ACE_THR_FUNC func,
+ void *args,
+ long flags,
+ long priority = ACE_DEFAULT_THREAD_PRIORITY,
+ int grp_id = -1,
+ void *stack[] = 0,
+ size_t stack_size[] = 0,
+ ACE_hthread_t thread_handles[] = 0,
+ ACE_Task_Base *task = 0);
+
+ /**
+ * Called to clean up when a thread exits. If <do_thread_exit> is
+ * non-0 then <ACE_Thread::exit> is called to exit the thread, in
+ * which case <status> is passed as the exit value of the thread.
+ * Should _not_ be called by main thread.
+ */
+ void *exit (void *status = 0,
+ int do_thread_exit = 1);
+
+ /**
+ * Block until there are no more threads running in the
+ * <Thread_Manager> or <timeout> expires. Note that <timeout> is
+ * treated as "absolute" time. Returns 0 on success and -1 on
+ * failure. If <abandon_detached_threads> is set, wait will first
+ * check thru its thread list for threads with THR_DETACHED or
+ * THR_DAEMON flags set and remove these threads. Notice that
+ * unlike other wait_* function, by default, <wait> does wait on
+ * all thread spawned by this thread_manager no matter the detached
+ * flags are set or not unless it is called with
+ * <abandon_detached_threads> flag set.
+ * NOTE that if this function is called while the ACE_Object_Manager
+ * is shutting down (as a result of program rundown via ACE::fini),
+ * it will not wait for any threads to complete. If you must wait for
+ * threads spawned by this thread manager to complete and you are in a
+ * ACE rundown situation (such as your object is being destroyed by the
+ * ACE_Object_Manager) you can use wait_grp instead.
+ */
+ int wait (const ACE_Time_Value *timeout = 0,
+ int abandon_detached_threads = 0);
+
+ /// Join a thread specified by <tid>. Do not wait on a detached thread.
+ int join (ACE_thread_t tid, void **status = 0);
+
+ /**
+ * Block until there are no more threads running in a group.
+ * Returns 0 on success and -1 on failure. Notice that wait_grp
+ * will not wait on detached threads.
+ */
+ int wait_grp (int grp_id);
+
+ // = Accessors for ACE_Thread_Descriptors.
+ /**
+ * Get a pointer to the calling thread's own thread_descriptor.
+ * This must be called from a spawn thread. This function will
+ * fetch the info from TSS.
+ */
+ ACE_Thread_Descriptor *thread_desc_self (void);
+
+ /// Return a pointer to the thread's Thread_Descriptor,
+ /// 0 if fail.
+ ACE_Thread_Descriptor *thread_descriptor (ACE_thread_t);
+
+ /// Return a pointer to the thread's Thread_Descriptor,
+ /// 0 if fail.
+ ACE_Thread_Descriptor *hthread_descriptor (ACE_hthread_t);
+
+ /**
+ * Return the "real" handle to the calling thread, caching it if
+ * necessary in TSS to speed up subsequent lookups. This is
+ * necessary since on some platforms (e.g., Win32) we can't get this
+ * handle via direct method calls. Notice that you should *not*
+ * close the handle passed back from this method. It is used
+ * internally by Thread Manager. On the other hand, you *have to*
+ * use this internal thread handle when working on Thread_Manager.
+ * Return -1 if fail.
+ */
+ int thr_self (ACE_hthread_t &);
+
+ /**
+ * Return the unique ID of the thread. This is not strictly
+ * necessary (because a thread can always just call
+ * <ACE_Thread::self>). However, we put it here to be complete.
+ */
+ ACE_thread_t thr_self (void);
+
+ /**
+ * Returns a pointer to the current <ACE_Task_Base> we're executing
+ * in if this thread is indeed running in an <ACE_Task_Base>, else
+ * return 0.
+ */
+ ACE_Task_Base *task (void);
+
+ // = Suspend methods, which isn't supported on POSIX pthreads (will not block).
+ /**
+ * Suspend all threads
+ * Suspend a single thread.
+ * Suspend a group of threads.
+ * True if <t_id> is inactive (i.e., suspended), else false.
+ */
+ int suspend_all (void);
+ int suspend (ACE_thread_t);
+ int suspend_grp (int grp_id);
+ int testsuspend (ACE_thread_t t_id);
+
+ // = Resume methods, which isn't supported on POSIX pthreads (will not block).
+ /**
+ * Resume all stopped threads
+ * Resume a single thread.
+ * Resume a group of threads.
+ * True if <t_id> is active (i.e., resumed), else false.
+ */
+ int resume_all (void);
+ int resume (ACE_thread_t);
+ int resume_grp (int grp_id);
+ int testresume (ACE_thread_t t_id);
+
+ // = Send signals to one or more threads without blocking.
+ /**
+ * Send <signum> to all stopped threads. Not supported on platforms
+ * that do not have advanced signal support, such as Win32.
+ * Send the <signum> to a single thread. Not supported on platforms
+ * that do not have advanced signal support, such as Win32.
+ * Send <signum> to a group of threads, not supported on platforms
+ * that do not have advanced signal support, such as Win32.
+ */
+ int kill_all (int signum);
+ int kill (ACE_thread_t,
+ int signum);
+ int kill_grp (int grp_id,
+ int signum);
+
+ // = Cancel methods, which provides a cooperative thread-termination mechanism (will not block).
+ /**
+ * Cancel's all the threads.
+ * Cancel a single thread.
+ * Cancel a group of threads.
+ * True if <t_id> is cancelled, else false.
+ */
+ int cancel_all (int async_cancel = 0);
+ int cancel (ACE_thread_t, int async_cancel = 0);
+ int cancel_grp (int grp_id, int async_cancel = 0);
+ int testcancel (ACE_thread_t t_id);
+
+ // = Set/get group ids for a particular thread id.
+ int set_grp (ACE_thread_t,
+ int grp_id);
+ int get_grp (ACE_thread_t,
+ int &grp_id);
+
+ // = The following methods are new methods which resemble current
+ // methods in <ACE_Thread Manager>. For example, the <apply_task>
+ // method resembles the <apply_thr> method, and <suspend_task>
+ // resembles <suspend_thr>.
+
+ // = Operations on ACE_Tasks.
+
+ /**
+ * Block until there are no more threads running in <task>. Returns
+ * 0 on success and -1 on failure. Note that <wait_task> will not
+ * wait on detached threads.
+ * Suspend all threads in an ACE_Task.
+ * Resume all threads in an ACE_Task.
+ * Send a signal <signum> to all threads in an <ACE_Task>.
+ */
+ int wait_task (ACE_Task_Base *task);
+ int suspend_task (ACE_Task_Base *task);
+ int resume_task (ACE_Task_Base *task);
+ int kill_task (ACE_Task_Base *task,
+ int signum);
+
+ /**
+ * Cancel all threads in an <ACE_Task>. If <async_cancel> is non-0,
+ * then asynchronously cancel these threads if the OS platform
+ * supports cancellation. Otherwise, perform a "cooperative"
+ * cancellation.
+ */
+ int cancel_task (ACE_Task_Base *task, int async_cancel = 0);
+
+ // = Collect thread handles in the thread manager. Notice that
+ // the collected information is just a snapshot.
+ /// Check if the thread is managed by the thread manager. Return true if
+ /// the thread is found, false otherwise.
+ int hthread_within (ACE_hthread_t handle);
+ int thread_within (ACE_thread_t tid);
+
+ /// Returns the number of <ACE_Task_Base> in a group.
+ int num_tasks_in_group (int grp_id);
+
+ /// Returns the number of threads in an <ACE_Task_Base>.
+ int num_threads_in_task (ACE_Task_Base *task);
+
+ /**
+ * Returns in <task_list> a list of up to <n> <ACE_Tasks> in a
+ * group. The caller must allocate the memory for <task_list>. In
+ * case of an error, -1 is returned. If no requested values are
+ * found, 0 is returned, otherwise correct number of retrieved
+ * values are returned.
+ */
+ int task_list (int grp_id,
+ ACE_Task_Base *task_list[],
+ size_t n);
+
+ /**
+ * Returns in <thread_list> a list of up to <n> thread ids in an
+ * <ACE_Task_Base>. The caller must allocate the memory for
+ * <thread_list>. In case of an error, -1 is returned. If no
+ * requested values are found, 0 is returned, otherwise correct
+ * number of retrieved values are returned.
+ */
+ int thread_list (ACE_Task_Base *task,
+ ACE_thread_t thread_list[],
+ size_t n);
+
+ /**
+ * Returns in <hthread_list> a list of up to <n> thread handles in
+ * an <ACE_Task_Base>. The caller must allocate memory for
+ * <hthread_list>. In case of an error, -1 is returned. If no
+ * requested values are found, 0 is returned, otherwise correct
+ * number of retrieved values are returned.
+ */
+ int hthread_list (ACE_Task_Base *task,
+ ACE_hthread_t hthread_list[],
+ size_t n);
+
+ /**
+ * Returns in <thread_list> a list of up to <n> thread ids in a
+ * group <grp_id>. The caller must allocate the memory for
+ * <thread_list>. In case of an error, -1 is returned. If no
+ * requested values are found, 0 is returned, otherwise correct
+ * number of retrieved values are returned.
+ */
+ int thread_grp_list (int grp_id,
+ ACE_thread_t thread_list[],
+ size_t n);
+
+ /**
+ * Returns in <hthread_list> a list of up to <n> thread handles in
+ * a group <grp_id>. The caller must allocate memory for
+ * <hthread_list>.
+ */
+ int hthread_grp_list (int grp_id,
+ ACE_hthread_t hthread_list[],
+ size_t n);
+
+ /**
+ * Returns in <task_list> a list of up to <n> <ACE_Tasks>. The
+ * caller must allocate the memory for <task_list>. In case of an
+ * error, -1 is returned. If no requested values are found, 0 is
+ * returned, otherwise correct number of retrieved values are
+ * returned.
+ */
+ int task_all_list (ACE_Task_Base *task_list[],
+ size_t n);
+
+ /**
+ * Returns in <thread_list> a list of up to <n> thread ids. The
+ * caller must allocate the memory for <thread_list>. In case of an
+ * error, -1 is returned. If no requested values are found, 0 is
+ * returned, otherwise correct number of retrieved values are
+ * returned.
+ */
+ int thread_all_list (ACE_thread_t thread_list[],
+ size_t n);
+
+ // = Set/get group ids for a particular task.
+ int set_grp (ACE_Task_Base *task, int grp_id);
+ int get_grp (ACE_Task_Base *task, int &grp_id);
+
+ /// Return a count of the current number of threads active in the
+ /// <Thread_Manager>.
+ int count_threads (void) const;
+
+#if !defined(ACE_USE_ONE_SHOT_AT_THREAD_EXIT)
+ /**
+ * Register an At_Thread_Exit hook and the ownership is acquire by
+ * Thread_Descriptor, this is the usual case when the AT is dynamically
+ * allocated.
+ */
+ int at_exit (ACE_At_Thread_Exit* cleanup);
+
+ /// Register an At_Thread_Exit hook and the ownership is retained for the
+ /// caller. Normally used when the at_exit hook is created in stack.
+ int at_exit (ACE_At_Thread_Exit& cleanup);
+#endif /* !ACE_USE_ONE_SHOT_AT_THREAD_EXIT */
+
+ /**
+ *
+ *****
+ * @deprecated This function is deprecated. Please use the previous two
+ * at_exit method. Notice that you should avoid mixing this method
+ * with the previous two at_exit methods.
+ *****
+ *
+ * Register an object (or array) for cleanup at
+ * thread termination. "cleanup_hook" points to a (global, or
+ * static member) function that is called for the object or array
+ * when it to be destroyed. It may perform any necessary cleanup
+ * specific for that object or its class. "param" is passed as the
+ * second parameter to the "cleanup_hook" function; the first
+ * parameter is the object (or array) to be destroyed.
+ * "cleanup_hook", for example, may delete the object (or array).
+ * If <cleanup_hook> == 0, the <object> will _NOT_ get cleanup at
+ * thread exit. You can use this to cancel the previously added
+ * at_exit.
+ */
+ int at_exit (void *object,
+ ACE_CLEANUP_FUNC cleanup_hook,
+ void *param);
+
+ /// Access function to determine whether the Thread_Manager will
+ /// wait for its thread to exit or not when being closing down.
+ void wait_on_exit (int dowait);
+ int wait_on_exit (void);
+
+ /// Dump the state of an object.
+ void dump (void);
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+protected:
+ /// Create a new thread (must be called with locks held).
+ virtual int spawn_i (ACE_THR_FUNC func,
+ void *args,
+ long flags,
+ ACE_thread_t * = 0,
+ ACE_hthread_t *t_handle = 0,
+ long priority = ACE_DEFAULT_THREAD_PRIORITY,
+ int grp_id = -1,
+ void *stack = 0,
+ size_t stack_size = 0,
+ ACE_Task_Base *task = 0);
+
+ /// Run the registered hooks when the thread exits.
+ void run_thread_exit_hooks (int i);
+
+ /// Locate the index of the table slot occupied by <t_id>. Returns
+ /// -1 if <t_id> is not in the table doesn't contain <t_id>.
+ ACE_Thread_Descriptor *find_thread (ACE_thread_t t_id);
+
+ /// Locate the index of the table slot occupied by <h_id>. Returns
+ /// -1 if <h_id> is not in the table doesn't contain <h_id>.
+ ACE_Thread_Descriptor *find_hthread (ACE_hthread_t h_id);
+
+ /**
+ * Locate the thread descriptor address of the list occupied by
+ * <task>. Returns 0 if <task> is not in the table doesn't contain
+ * <task>.
+ */
+ ACE_Thread_Descriptor *find_task (ACE_Task_Base *task,
+ int slot = -1);
+
+ /// Insert a thread in the table (checks for duplicates).
+ int insert_thr (ACE_thread_t t_id,
+ ACE_hthread_t,
+ int grp_id = -1,
+ long flags = 0);
+
+ /// Append a thread in the table (adds at the end, growing the table
+ /// if necessary).
+ int append_thr (ACE_thread_t t_id, ACE_hthread_t,
+ ACE_UINT32,
+ int grp_id,
+ ACE_Task_Base *task = 0,
+ long flags = 0,
+ ACE_Thread_Descriptor *td = 0);
+
+ /// Remove thread from the table.
+ void remove_thr (ACE_Thread_Descriptor *td,
+ int close_handler);
+
+ /// Remove all threads from the table.
+ void remove_thr_all (void);
+
+ // = The following four methods implement a simple scheme for
+ // operating on a collection of threads atomically.
+
+ /**
+ * Efficiently check whether <thread> is in a particular <state>.
+ * This call updates the TSS cache if possible to speed up
+ * subsequent searches.
+ */
+ int check_state (ACE_UINT32 state,
+ ACE_thread_t thread,
+ int enable = 1);
+
+ /// Apply <func> to all members of the table that match the <task>
+ int apply_task (ACE_Task_Base *task,
+ ACE_THR_MEMBER_FUNC,
+ int = 0);
+
+ /// Apply <func> to all members of the table that match the <grp_id>.
+ int apply_grp (int grp_id,
+ ACE_THR_MEMBER_FUNC func,
+ int arg = 0);
+
+ /// Apply <func> to all members of the table.
+ int apply_all (ACE_THR_MEMBER_FUNC,
+ int = 0);
+
+ /// Join the thread described in <tda>.
+ int join_thr (ACE_Thread_Descriptor *td,
+ int = 0);
+
+ /// Resume the thread described in <tda>.
+ int resume_thr (ACE_Thread_Descriptor *td,
+ int = 0);
+
+ /// Suspend the thread described in <tda>.
+ int suspend_thr (ACE_Thread_Descriptor *td,
+ int = 0);
+
+ /// Send signal <signum> to the thread described in <tda>.
+ int kill_thr (ACE_Thread_Descriptor *td,
+ int signum);
+
+ /// Set the cancellation flag for the thread described in <tda>.
+ int cancel_thr (ACE_Thread_Descriptor *td,
+ int async_cancel = 0);
+
+ /// Register a thread as terminated and put it into the <terminated_thr_list_>.
+ int register_as_terminated (ACE_Thread_Descriptor *td);
+
+ /**
+ * Keeping a list of thread descriptors within the thread manager.
+ * Double-linked list enables us to cache the entries in TSS
+ * and adding/removing thread descriptor entries without
+ * affecting other thread's descriptor entries.
+ */
+ ACE_Double_Linked_List<ACE_Thread_Descriptor> thr_list_;
+
+#if !defined (VXWORKS)
+ /// Collect terminated but not yet joined thread entries.
+ ACE_Double_Linked_List<ACE_Thread_Descriptor_Base> terminated_thr_list_;
+#endif /* VXWORKS */
+
+ /// Collect pointers to thread descriptors of threads to be removed later.
+ ACE_Unbounded_Queue<ACE_Thread_Descriptor*> thr_to_be_removed_;
+
+ /// Keeps track of the next group id to assign.
+ int grp_id_;
+
+ /// Set if we want the Thread_Manager to wait on all threads before
+ /// being closed, reset otherwise.
+ int automatic_wait_;
+
+ // = ACE_Thread_Mutex and condition variable for synchronizing termination.
+#if defined (ACE_HAS_THREADS)
+ /// Serialize access to the <zero_cond_>.
+ ACE_Thread_Mutex lock_;
+
+ /// Keep track of when there are no more threads.
+ ACE_Condition_Thread_Mutex zero_cond_;
+#endif /* ACE_HAS_THREADS */
+
+private:
+ ACE_Locked_Free_List<ACE_Thread_Descriptor, ACE_SYNCH_MUTEX> thread_desc_freelist_;
+
+#if ! defined (ACE_THREAD_MANAGER_LACKS_STATICS)
+ /// Pointer to a process-wide <ACE_Thread_Manager>.
+ static ACE_Thread_Manager *thr_mgr_;
+
+ /// Must delete the <thr_mgr_> if non-0.
+ static int delete_thr_mgr_;
+#endif /* ! defined (ACE_THREAD_MANAGER_LACKS_STATICS) */
+};
+
+#if defined (ACE_THREAD_MANAGER_LACKS_STATICS)
+#define ACE_THREAD_MANAGER_SINGLETON_DEFINE \
+ ACE_Singleton<ACE_Thread_Manager, ACE_SYNCH_MUTEX>;
+typedef ACE_Singleton<ACE_Thread_Manager, ACE_SYNCH_MUTEX> ACE_THREAD_MANAGER_SINGLETON;
+#endif /* defined (ACE_THREAD_MANAGER_LACKS_STATICS) */
+
+#if defined (__ACE_INLINE__)
+#include "ace/Thread_Manager.i"
+#endif /* __ACE_INLINE__ */
+
+#include "ace/post.h"
+#endif /* ACE_THREAD_MANAGER_H */
diff --git a/ace/Threads/Thread_Manager.i b/ace/Threads/Thread_Manager.i
new file mode 100644
index 00000000000..36b808b7e9c
--- /dev/null
+++ b/ace/Threads/Thread_Manager.i
@@ -0,0 +1,322 @@
+/* -*- C++ -*- */
+// $Id$
+
+// Thread_Manager.i
+
+#if !defined(ACE_USE_ONE_SHOT_AT_THREAD_EXIT)
+ACE_INLINE
+ACE_At_Thread_Exit::ACE_At_Thread_Exit (void)
+ : next_ (0),
+ td_ (0),
+ was_applied_ (0),
+ is_owner_ (1)
+{
+}
+
+ACE_INLINE int
+ACE_At_Thread_Exit::was_applied() const
+
+{
+ return was_applied_;
+}
+
+ACE_INLINE int
+ACE_At_Thread_Exit::was_applied (int applied)
+{
+ was_applied_ = applied;
+ if (was_applied_)
+ td_ = 0;
+ return was_applied_;
+}
+
+ACE_INLINE int
+ACE_At_Thread_Exit::is_owner() const
+{
+ return is_owner_;
+}
+
+ACE_INLINE int
+ACE_At_Thread_Exit::is_owner (int owner)
+{
+ is_owner_ = owner;
+ return is_owner_;
+}
+
+ACE_INLINE void
+ACE_At_Thread_Exit::do_apply (void)
+{
+ if (!this->was_applied_ && this->is_owner_)
+ td_->at_pop();
+}
+
+ACE_INLINE
+ACE_At_Thread_Exit::~ACE_At_Thread_Exit (void)
+{
+ this->do_apply ();
+}
+
+ACE_INLINE
+ACE_At_Thread_Exit_Func::ACE_At_Thread_Exit_Func (void *object,
+ ACE_CLEANUP_FUNC func,
+ void *param)
+ : object_(object),
+ func_(func),
+ param_(param)
+{
+}
+
+ACE_INLINE
+ACE_At_Thread_Exit_Func::~ACE_At_Thread_Exit_Func (void)
+{
+ this->do_apply ();
+}
+
+ACE_INLINE void
+ACE_At_Thread_Exit_Func::apply ()
+{
+ func_ (object_, param_);
+}
+#endif /* ! ACE_USE_ONE_SHOT_AT_THREAD_EXIT */
+
+ACE_INLINE
+ACE_Thread_Descriptor_Base::ACE_Thread_Descriptor_Base (void)
+ : ACE_OS_Thread_Descriptor (),
+ thr_id_ (ACE_OS::NULL_thread),
+ thr_handle_ (ACE_OS::NULL_hthread),
+ grp_id_ (0),
+ thr_state_ (ACE_Thread_Manager::ACE_THR_IDLE),
+ task_ (0),
+ next_ (0),
+ prev_ (0)
+{
+}
+
+ACE_INLINE
+ACE_Thread_Descriptor_Base::~ACE_Thread_Descriptor_Base (void)
+{
+}
+
+ACE_INLINE int
+ACE_Thread_Descriptor_Base::operator==(const ACE_Thread_Descriptor_Base &rhs) const
+{
+ return ACE_OS::thr_cmp (this->thr_handle_, rhs.thr_handle_) == 0
+ && ACE_OS::thr_equal (this->thr_id_, rhs.thr_id_) == 0;
+}
+
+ACE_INLINE int
+ACE_Thread_Descriptor_Base::operator!=(const ACE_Thread_Descriptor_Base &rhs) const
+{
+ return !(*this == rhs);
+}
+
+ACE_INLINE ACE_Task_Base *
+ACE_Thread_Descriptor_Base::task (void) const
+{
+ ACE_TRACE ("ACE_Thread_Descriptor_Base::task");
+ return this->task_;
+}
+
+// Group ID.
+
+ACE_INLINE int
+ACE_Thread_Descriptor_Base::grp_id (void) const
+{
+ ACE_TRACE ("ACE_Thread_Descriptor_Base::grp_id");
+ return grp_id_;
+}
+
+// Current state of the thread.
+ACE_INLINE ACE_UINT32
+ACE_Thread_Descriptor_Base::state (void) const
+{
+ ACE_TRACE ("ACE_Thread_Descriptor_Base::state");
+ return thr_state_;
+}
+
+// Reset this base descriptor.
+ACE_INLINE void
+ACE_Thread_Descriptor_Base::reset (void)
+{
+ ACE_TRACE ("ACE_Thread_Descriptor_Base::reset");
+ this->thr_id_ = ACE_OS::NULL_thread;
+ this->thr_handle_ = ACE_OS::NULL_hthread;
+ this->grp_id_ = 0;
+ this->thr_state_ = ACE_Thread_Manager::ACE_THR_IDLE;
+ this->task_ = 0;
+ this->flags_ = 0;
+}
+
+// Unique thread id.
+ACE_INLINE ACE_thread_t
+ACE_Thread_Descriptor::self (void) const
+{
+ ACE_TRACE ("ACE_Thread_Descriptor::self");
+ return this->thr_id_;
+}
+
+// Unique kernel-level thread handle.
+
+ACE_INLINE void
+ACE_Thread_Descriptor::self (ACE_hthread_t &handle)
+{
+ ACE_TRACE ("ACE_Thread_Descriptor::self");
+ handle = this->thr_handle_;
+}
+
+#if !defined(ACE_USE_ONE_SHOT_AT_THREAD_EXIT)
+ACE_INLINE void
+ACE_Thread_Descriptor::log_msg_cleanup (ACE_Log_Msg* log_msg)
+
+{
+ log_msg_ = log_msg;
+}
+#endif /* !ACE_USE_ONE_SHOT_AT_THREAD_EXIT */
+
+// Set the <next_> pointer
+ACE_INLINE void
+ACE_Thread_Descriptor::set_next (ACE_Thread_Descriptor *td)
+{
+ ACE_TRACE ("ACE_Thread_Descriptor::set_next");
+ this->next_ = td;
+}
+
+// Get the <next_> pointer
+ACE_INLINE ACE_Thread_Descriptor *
+ACE_Thread_Descriptor::get_next (void) const
+{
+ ACE_TRACE ("ACE_Thread_Descriptor::get_next");
+ return ACE_static_cast (ACE_Thread_Descriptor * ACE_CAST_CONST,
+ this->next_);
+}
+
+// Reset this thread descriptor
+ACE_INLINE void
+ACE_Thread_Descriptor::reset (ACE_Thread_Manager *tm)
+{
+ ACE_TRACE ("ACE_Thread_Descriptor::reset");
+ this->ACE_Thread_Descriptor_Base::reset ();
+#if defined(ACE_USE_ONE_SHOT_AT_THREAD_EXIT)
+ this->cleanup_info_.cleanup_hook_ = 0;
+ this->cleanup_info_.object_ = 0;
+ this->cleanup_info_.param_ = 0;
+#else /* !ACE_USE_ONE_SHOT_AT_THREAD_EXIT */
+ this->at_exit_list_ = 0;
+ // Start the at_exit hook list.
+ this->tm_ = tm;
+ // Setup the Thread_Manager.
+ this->log_msg_ = 0;
+ this->terminated_ = 0;
+#endif /* !ACE_USE_ONE_SHOT_AT_THREAD_EXIT */
+}
+
+ACE_INLINE ACE_Thread_Descriptor *
+ACE_Thread_Manager::thread_desc_self (void)
+{
+ // This method must be called with lock held.
+
+ // Try to get it from cache.
+ ACE_Thread_Descriptor *desc = ACE_LOG_MSG->thr_desc ();
+
+#if 1
+ ACE_ASSERT (desc != 0);
+ // Thread descriptor should always get cached.
+#else
+ if (desc == 0)
+ {
+ ACE_thread_t id = ACE_OS::thr_self ();
+
+ desc = this->find_thread (id);
+
+ // Thread descriptor adapter might not have been put into the
+ // list yet.
+ if (desc != 0)
+ // Update the TSS cache.
+ ACE_LOG_MSG->thr_desc (desc);
+ }
+#endif
+ return desc;
+}
+
+// Return the unique ID of the thread.
+
+ACE_INLINE ACE_thread_t
+ACE_Thread_Manager::thr_self (void)
+{
+ ACE_TRACE ("ACE_Thread_Manager::thr_self");
+ return ACE_Thread::self ();
+}
+
+ACE_INLINE ACE_Task_Base *
+ACE_Thread_Manager::task (void)
+{
+ ACE_TRACE ("ACE_Thread_Manager::task");
+
+ ACE_Thread_Descriptor *td = this->thread_desc_self () ;
+
+ if (td == 0)
+ return 0;
+ else
+ return td->task ();
+}
+
+ACE_INLINE int
+ACE_Thread_Manager::open (size_t)
+{
+ // Currently no-op.
+ return 0;
+}
+
+#if !defined(ACE_USE_ONE_SHOT_AT_THREAD_EXIT)
+ACE_INLINE int
+ACE_Thread_Manager::at_exit (ACE_At_Thread_Exit* at)
+{
+ return this->thread_desc_self ()->at_exit (at);
+}
+
+ACE_INLINE int
+ACE_Thread_Manager::at_exit (ACE_At_Thread_Exit& at)
+{
+ return this->thread_desc_self ()->at_exit (at);
+}
+#endif /* !ACE_USE_ONE_SHOT_AT_THREAD_EXIT */
+
+ACE_INLINE int
+ACE_Thread_Manager::at_exit (void *object,
+ ACE_CLEANUP_FUNC cleanup_hook,
+ void *param)
+{
+ return this->thread_desc_self ()->at_exit (object,
+ cleanup_hook,
+ param);
+}
+
+ACE_INLINE void
+ACE_Thread_Manager::wait_on_exit (int do_wait)
+{
+ this->automatic_wait_ = do_wait;
+}
+
+ACE_INLINE int
+ACE_Thread_Manager::wait_on_exit (void)
+{
+ return this->automatic_wait_;
+}
+
+ACE_INLINE int
+ACE_Thread_Manager::register_as_terminated (ACE_Thread_Descriptor *td)
+{
+#if defined (VXWORKS)
+ ACE_UNUSED_ARG (td);
+#else /* ! VXWORKS */
+ ACE_Thread_Descriptor_Base *tdb;
+ ACE_NEW_RETURN (tdb, ACE_Thread_Descriptor_Base (*td), -1);
+ this->terminated_thr_list_.insert_tail (tdb);
+#endif /* ! VXWORKS */
+ return 0;
+}
+
+ACE_INLINE int
+ACE_Thread_Manager::count_threads (void) const
+{
+ return this->thr_list_.size ();
+}
diff --git a/ace/Threads/Token.cpp b/ace/Threads/Token.cpp
new file mode 100644
index 00000000000..cb2b2d2c618
--- /dev/null
+++ b/ace/Threads/Token.cpp
@@ -0,0 +1,545 @@
+// $Id$
+
+#include "ace/Thread.h"
+#include "ace/Token.h"
+#include "ace/Log_Msg.h"
+
+#if defined (DEBUGGING)
+#include "ace/streams.h"
+#endif /* DEBUGGING */
+
+ACE_RCSID(ace, Token, "$Id$")
+
+#if defined (ACE_HAS_THREADS)
+
+#if !defined (__ACE_INLINE__)
+#include "ace/Synch_T.h"
+#include "ace/Token.i"
+#endif /* __ACE_INLINE__ */
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Token)
+
+
+void
+ACE_Token::dump (void) const
+{
+ ACE_TRACE ("ACE_Token::dump");
+
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\nthread = %d"), ACE_Thread::self ()));
+ // @@ Is there a portable way to do this?
+ // ACE_DEBUG ((LM_DEBUG, "\nowner_ = %l", (long) this->owner_));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\nowner_ addr = %x"), &this->owner_));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\nwaiters_ = %d"), this->waiters_));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\nin_use_ = %d"), this->in_use_));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\nnesting level = %d"), this->nesting_level_));
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+ACE_Token::ACE_Token_Queue_Entry::ACE_Token_Queue_Entry (ACE_Thread_Mutex &m,
+ ACE_thread_t t_id)
+ : next_ (0),
+ thread_id_ (t_id),
+#if defined (ACE_TOKEN_USES_SEMAPHORE)
+ cv_ (0),
+#else
+ cv_ (m),
+#endif /* ACE_TOKEN_USES_SEMAPHORE */
+ runable_ (0)
+{
+#if defined (ACE_TOKEN_USES_SEMAPHORE)
+ ACE_UNUSED_ARG (m);
+#endif /* ACE_TOKEN_USES_SEMAPHORE */
+
+ ACE_TRACE ("ACE_Token::ACE_Token_Queue_Entry::ACE_Token_Queue_Entry");
+}
+
+ACE_Token::ACE_Token_Queue_Entry::ACE_Token_Queue_Entry (ACE_Thread_Mutex &m,
+ ACE_thread_t t_id,
+ ACE_Condition_Attributes &attributes)
+ : next_ (0),
+ thread_id_ (t_id),
+#if defined (ACE_TOKEN_USES_SEMAPHORE)
+ cv_ (0),
+#else
+ cv_ (m, attributes),
+#endif /* ACE_TOKEN_USES_SEMAPHORE */
+ runable_ (0)
+{
+#if defined (ACE_TOKEN_USES_SEMAPHORE)
+ ACE_UNUSED_ARG (m);
+ ACE_UNUSED_ARG (attributes);
+#endif /* ACE_TOKEN_USES_SEMAPHORE */
+
+ ACE_TRACE ("ACE_Token::ACE_Token_Queue_Entry::ACE_Token_Queue_Entry");
+}
+
+ACE_Token::ACE_Token_Queue::ACE_Token_Queue (void)
+ : head_ (0),
+ tail_ (0)
+{
+ ACE_TRACE ("ACE_Token::ACE_Token_Queue::ACE_Token_Queue");
+}
+
+//
+// Remove an entry from the list. Must be called with locks held.
+//
+void
+ACE_Token::ACE_Token_Queue::remove_entry (ACE_Token::ACE_Token_Queue_Entry *entry)
+{
+ ACE_TRACE ("ACE_Token::ACE_Token_Queue::remove_entry");
+ ACE_Token_Queue_Entry *curr = 0;
+ ACE_Token_Queue_Entry *prev = 0;
+
+ if (this->head_ == 0)
+ return;
+
+ for (curr = this->head_;
+ curr != 0 && curr != entry;
+ curr = curr->next_)
+ prev = curr;
+
+ if (curr == 0)
+ // Didn't find the entry...
+ return;
+ else if (prev == 0)
+ // Delete at the head.
+ this->head_ = this->head_->next_;
+ else
+ // Delete in the middle.
+ prev->next_ = curr->next_;
+
+ // We need to update the tail of the list if we've deleted the last
+ // entry.
+ if (curr->next_ == 0)
+ this->tail_ = prev;
+}
+
+//
+// Add an entry into the list. Must be called with locks held.
+//
+void
+ACE_Token::ACE_Token_Queue::insert_entry (ACE_Token::ACE_Token_Queue_Entry &entry,
+ int requeue_position)
+{
+ if (this->head_ == 0)
+ {
+ // No other threads - just add me
+ this->head_ = &entry;
+ this->tail_ = &entry;
+ }
+ else if (requeue_position == -1)
+ {
+ // Insert at the end of the queue.
+ this->tail_->next_ = &entry;
+ this->tail_ = &entry;
+ }
+ else if (requeue_position == 0)
+ {
+ // Insert at head of queue.
+ entry.next_ = this->head_;
+ this->head_ = &entry;
+ }
+ else
+ // Insert in the middle of the queue somewhere.
+ {
+ // Determine where our thread should go in the queue of waiters.
+
+ ACE_Token::ACE_Token_Queue_Entry *insert_after = this->head_;
+ while (requeue_position-- && insert_after->next_ != 0)
+ insert_after = insert_after->next_;
+
+ entry.next_ = insert_after->next_;
+
+ if (entry.next_ == 0)
+ this->tail_ = &entry;
+
+ insert_after->next_ = &entry;
+ }
+}
+
+ACE_Token::ACE_Token (const ACE_TCHAR *name, void *any)
+ : lock_ (name, (ACE_mutexattr_t *) any),
+ owner_ (ACE_OS::NULL_thread),
+ in_use_ (0),
+ waiters_ (0),
+ nesting_level_ (0),
+ attributes_ (USYNC_THREAD)
+{
+// ACE_TRACE ("ACE_Token::ACE_Token");
+}
+
+ACE_Token::~ACE_Token (void)
+{
+ ACE_TRACE ("ACE_Token::~ACE_Token");
+}
+
+int
+ACE_Token::shared_acquire (void (*sleep_hook_func)(void *),
+ void *arg,
+ ACE_Time_Value *timeout,
+ ACE_Token_Op_Type op_type)
+{
+ ACE_TRACE ("ACE_Token::shared_acquire");
+ ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1);
+
+#if defined (DEBUGGING)
+ this->dump ();
+#endif /* DEBUGGING */
+
+ ACE_thread_t thr_id = ACE_Thread::self ();
+
+ // Nobody holds the token.
+ if (!this->in_use_)
+ {
+ // Its mine!
+ this->in_use_ = op_type;
+ this->owner_ = thr_id;
+ return 0;
+ }
+
+ //
+ // Someone already holds the token.
+ //
+
+ // Check if it is us.
+ if (ACE_OS::thr_equal (thr_id, this->owner_))
+ {
+ this->nesting_level_++;
+ return 0;
+ }
+
+ // Do a quick check for "polling" behavior.
+ if (timeout != 0 && timeout->sec () == 0 && timeout->usec () == 0)
+ {
+ errno = ETIME;
+ return -1;
+ }
+
+ //
+ // We've got to sleep until we get the token.
+ //
+
+ // Which queue we should end up in...
+ ACE_Token_Queue *queue = (op_type == ACE_Token::READ_TOKEN
+ ? &this->readers_
+ : &this->writers_);
+
+ // Allocate queue entry on stack. This works since we don't exit
+ // this method's activation record until we've got the token.
+ ACE_Token::ACE_Token_Queue_Entry my_entry (this->lock_,
+ thr_id,
+ this->attributes_);
+ queue->insert_entry (my_entry);
+ this->waiters_++;
+
+ // Execute appropriate <sleep_hook> callback. (@@ should these
+ // methods return a success/failure status, and if so, what should
+ // we do with it?)
+ int ret = 0;
+ if (sleep_hook_func)
+ {
+ (*sleep_hook_func) (arg);
+ ret++;
+ }
+ else
+ {
+ // Execute virtual method.
+ this->sleep_hook ();
+ ret++;
+ }
+
+ int timed_out = 0;
+ int error = 0;
+
+ // Sleep until we've got the token (ignore signals).
+ do
+ {
+ int result = my_entry.wait (timeout,
+ this->lock_);
+
+ if (result == -1)
+ {
+ // Note, this should obey whatever thread-specific interrupt
+ // policy is currently in place...
+ if (errno == EINTR)
+ continue;
+
+#if defined (DEBUGGING)
+ cerr << '(' << ACE_Thread::self () << ')'
+ << " acquire: "
+ << (errno == ETIME ? "timed out" : "error occurred")
+ << endl;
+#endif /* DEBUGGING */
+
+ // We come here if a timeout occurs or some serious
+ // ACE_Condition object error.
+ if (errno == ETIME)
+ timed_out = 1;
+ else
+ error = 1;
+
+ // Stop the loop.
+ break;
+ }
+ }
+ while (!ACE_OS::thr_equal (thr_id, this->owner_));
+
+ // Do this always and irrespective of the result of wait().
+ this->waiters_--;
+ queue->remove_entry (&my_entry);
+
+#if defined (DEBUGGING)
+ cerr << '(' << ACE_Thread::self () << ')'
+ << " acquire (UNBLOCKED)" << endl;
+#endif /* DEBUGGING */
+
+ // If timeout occured
+ if (timed_out)
+ {
+ // This thread was still selected to own the token.
+ if (my_entry.runable_)
+ {
+ // Wakeup next waiter since this thread timed out.
+ this->wakeup_next_waiter ();
+ }
+
+ // Return error.
+ return -1;
+ }
+ else if (error)
+ {
+ // Return error.
+ return -1;
+ }
+
+ // If this is a normal wakeup, this thread should be runnable.
+ ACE_ASSERT (my_entry.runable_);
+
+ return ret;
+}
+
+// By default this is a no-op.
+
+/* virtual */
+void
+ACE_Token::sleep_hook (void)
+{
+ ACE_TRACE ("ACE_Token::sleep_hook");
+}
+
+int
+ACE_Token::acquire (ACE_Time_Value *timeout)
+{
+ ACE_TRACE ("ACE_Token::acquire");
+ return this->shared_acquire (0, 0, timeout, ACE_Token::WRITE_TOKEN);
+}
+
+// Acquire the token, sleeping until it is obtained or until <timeout>
+// expires.
+
+int
+ACE_Token::acquire (void (*sleep_hook_func)(void *),
+ void *arg,
+ ACE_Time_Value *timeout)
+{
+ ACE_TRACE ("ACE_Token::acquire");
+ return this->shared_acquire (sleep_hook_func, arg, timeout, ACE_Token::WRITE_TOKEN);
+}
+
+// Try to renew the token.
+
+int
+ACE_Token::renew (int requeue_position,
+ ACE_Time_Value *timeout)
+{
+ ACE_TRACE ("ACE_Token::renew");
+ ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1);
+
+#if defined (DEBUGGING)
+ this->dump ();
+#endif /* DEBUGGING */
+ // ACE_ASSERT (ACE_OS::thr_equal (ACE_Thread::self (), this->owner_));
+
+ // Check to see if there are any waiters worth giving up the lock
+ // for.
+
+ // If no writers and either we are a writer or there are no readers.
+ if (this->writers_.head_ == 0 &&
+ (this->in_use_ == ACE_Token::WRITE_TOKEN ||
+ this->readers_.head_ == 0))
+ // Immediate return.
+ return 0;
+
+ // We've got to sleep until we get the token again.
+
+ // Determine which queue should this thread go to.
+ ACE_Token::ACE_Token_Queue *this_threads_queue =
+ this->in_use_ == ACE_Token::READ_TOKEN ?
+ &this->readers_ : &this->writers_;
+
+ ACE_Token::ACE_Token_Queue_Entry my_entry (this->lock_,
+ this->owner_);
+
+ this_threads_queue->insert_entry (my_entry,
+ requeue_position);
+ this->waiters_++;
+
+ // Remember nesting level...
+ int save_nesting_level_ = this->nesting_level_;
+
+ // Reset state for new owner.
+ this->nesting_level_ = 0;
+
+ // Wakeup waiter.
+ this->wakeup_next_waiter ();
+
+ int timed_out = 0;
+ int error = 0;
+
+ // Sleep until we've got the token (ignore signals).
+ do
+ {
+ int result = my_entry.wait (timeout,
+ this->lock_);
+
+ if (result == -1)
+ {
+ // Note, this should obey whatever thread-specific interrupt
+ // policy is currently in place...
+ if (errno == EINTR)
+ continue;
+
+#if defined (DEBUGGING)
+ cerr << '(' << ACE_Thread::self () << ')'
+ << " renew: "
+ << (errno == ETIME ? "timed out" : "error occurred")
+ << endl;
+#endif /* DEBUGGING */
+
+ // We come here if a timeout occurs or some serious
+ // ACE_Condition object error.
+ if (errno == ETIME)
+ timed_out = 1;
+ else
+ error = 1;
+
+ // Stop the loop.
+ break;
+ }
+ }
+ while (!ACE_OS::thr_equal (my_entry.thread_id_, this->owner_));
+
+ // Do this always and irrespective of the result of wait().
+ this->waiters_--;
+ this_threads_queue->remove_entry (&my_entry);
+
+#if defined (DEBUGGING)
+ cerr << '(' << ACE_Thread::self () << ')'
+ << " acquire (UNBLOCKED)" << endl;
+#endif /* DEBUGGING */
+
+ // If timeout occured
+ if (timed_out)
+ {
+ // This thread was still selected to own the token.
+ if (my_entry.runable_)
+ {
+ // Wakeup next waiter since this thread timed out.
+ this->wakeup_next_waiter ();
+ }
+
+ // Return error.
+ return -1;
+ }
+ else if (error)
+ {
+ // Return error.
+ return -1;
+ }
+
+ // If this is a normal wakeup, this thread should be runnable.
+ ACE_ASSERT (my_entry.runable_);
+
+ // Reinstate nesting level.
+ this->nesting_level_ = save_nesting_level_;
+
+ return 0;
+}
+
+// Release the current holder of the token (which had
+// better be the caller's thread!).
+
+int
+ACE_Token::release (void)
+{
+ ACE_TRACE ("ACE_Token::release");
+ ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1);
+
+ // ACE_ASSERT (ACE_OS::thr_equal (ACE_Thread::self (), this->owner_));
+
+#if defined (DEBUGGING)
+ this->dump ();
+#endif /* DEBUGGING */
+
+ // Nested release...
+ if (this->nesting_level_ > 0)
+ --this->nesting_level_;
+ else
+ {
+ //
+ // Regular release...
+ //
+
+ // Wakeup waiter.
+ this->wakeup_next_waiter ();
+ }
+
+ return 0;
+}
+
+void
+ACE_Token::wakeup_next_waiter (void)
+{
+ ACE_TRACE ("ACE_Token::wakeup_next_waiter");
+
+ // Reset state for new owner.
+ this->owner_ = ACE_OS::NULL_thread;
+ this->in_use_ = 0;
+
+ // Any waiters...
+ if (this->writers_.head_ == 0 &&
+ this->readers_.head_ == 0)
+ {
+ // No more waiters...
+ return;
+ }
+
+ // Wakeup next waiter.
+ ACE_Token_Queue *queue;
+
+ // Writer threads get priority to run first.
+ if (this->writers_.head_ != 0)
+ {
+ this->in_use_ = ACE_Token::WRITE_TOKEN;
+ queue = &this->writers_;
+ }
+ else
+ {
+ this->in_use_ = ACE_Token::READ_TOKEN;
+ queue = &this->readers_;
+ }
+
+ // Wake up waiter and make it runable.
+ queue->head_->runable_ = 1;
+ queue->head_->signal ();
+
+ this->owner_ = queue->head_->thread_id_;
+}
+
+#endif /* ACE_HAS_THREADS */
+
+#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION)
+#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA)
+#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */
diff --git a/ace/Threads/Token.h b/ace/Threads/Token.h
new file mode 100644
index 00000000000..8d9cc641059
--- /dev/null
+++ b/ace/Threads/Token.h
@@ -0,0 +1,290 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Token.h
+ *
+ * $Id$
+ *
+ * @author Original author
+ * @author Karl-Heinz Dorn (kdorn@erlh.siemens.de)
+ * @author Ported to ACE by
+ * @author Douglas C. Schmidt (schmidt@cs.wustl.edu)
+ */
+//=============================================================================
+
+#ifndef ACE_TOKEN_H
+#define ACE_TOKEN_H
+#include "ace/pre.h"
+
+#include "ace/Synch.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#if defined (ACE_HAS_THREADS)
+
+#if (defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)) || defined (VXWORKS) || defined (ACE_PSOS)
+// If platforms support semaphores with timed wait, then we use semaphores instead of c.v.
+# define ACE_TOKEN_USES_SEMAPHORE
+#endif /* (ACE_WIN32 && !ACE_HAS_WINCE) || VXWORKS || ACE_PSOS */
+
+/**
+ * @class ACE_Token
+ *
+ * @brief Class that acquires, renews, and releases a synchronization
+ * token that is serviced in strict FIFO ordering and that also
+ * supports (1) recursion and (2) readers/writer semantics.
+ *
+ * This class is a more general-purpose synchronization mechanism
+ * than many native OS mutexes. For example, it implements
+ * "recursive mutex" semantics, where a thread that owns the token
+ * can reacquire it without deadlocking. If the same thread calls
+ * <acquire> multiple times, however, it must call <release> an
+ * equal number of times before the token is actually released.
+ * Threads that are blocked awaiting the token are serviced in
+ * strict FIFO order as other threads release the token (Solaris
+ * and Pthread mutexes don't strictly enforce an acquisition
+ * order). There are two FIFO lists within the class. Write
+ * acquires always have higher priority over read acquires. Which
+ * means, if you use both write/read operations, care must be
+ * taken to avoid starvation on the readers. Notice that the
+ * read/write acquire operations do not have the usual semantic of
+ * reader/writer locks. Only one reader can acquire the token at
+ * a time (which is different from the usual reader/writer locks
+ * where several readers can acquire a lock at the same time as
+ * long as there is no writer waiting for the lock). We choose
+ * the names to (1) borrow the semantic to give writers higher
+ * priority and (2) support a common interface for all locking
+ * classes in ACE.
+ */
+class ACE_Export ACE_Token
+{
+public:
+ // = Initialization and termination.
+
+ ACE_Token (const ACE_TCHAR *name = 0, void * = 0);
+ virtual ~ACE_Token (void);
+
+ // = Synchronization operations.
+
+ /**
+ * Acquire the token, sleeping until it is obtained or until the
+ * expiration of <timeout>, which is treated as "absolute" time. If
+ * some other thread currently holds the token then <sleep_hook> is
+ * called before our thread goes to sleep. This <sleep_hook> can be
+ * used by the requesting thread to unblock a token-holder that is
+ * sleeping, e.g., by means of writing to a pipe (the ACE
+ * ACE_Reactor uses this functionality). Return values: 0 if
+ * acquires without calling <sleep_hook> 1 if <sleep_hook> is
+ * called. 2 if the token is signaled. -1 if failure or timeout
+ * occurs (if timeout occurs errno == ETIME) If <timeout> ==
+ * <&ACE_Time_Value::zero> then acquire has polling semantics (and
+ * does *not* call <sleep_hook>).
+ */
+ int acquire (void (*sleep_hook)(void *),
+ void *arg = 0,
+ ACE_Time_Value *timeout = 0);
+
+ /**
+ * This behaves just like the previous <acquire> method, except that
+ * it invokes the virtual function called <sleep_hook> that can be
+ * overridden by a subclass of ACE_Token.
+ */
+ int acquire (ACE_Time_Value *timeout = 0);
+
+ /**
+ * This should be overridden by a subclass to define the appropriate
+ * behavior before <acquire> goes to sleep. By default, this is a
+ * no-op...
+ */
+ virtual void sleep_hook (void);
+
+ /**
+ * An optimized method that efficiently reacquires the token if no
+ * other threads are waiting. This is useful for situations where
+ * you don't want to degrade the quality of service if there are
+ * other threads waiting to get the token. If <requeue_position> ==
+ * -1 and there are other threads waiting to obtain the token we are
+ * queued at the end of the list of waiters. If <requeue_position>
+ * > -1 then it indicates how many entries to skip over before
+ * inserting our thread into the list of waiters (e.g.,
+ * <requeue_position> == 0 means "insert at front of the queue").
+ * Renew has the rather odd semantics such that if there are other
+ * waiting threads it will give up the token even if the
+ * nesting_level_ > 1. I'm not sure if this is really the right
+ * thing to do (since it makes it possible for shared data to be
+ * changed unexpectedly) so use with caution... This method
+ * maintians the original token priority. As in <acquire>, the
+ * <timeout> value is an absolute time.
+ */
+ int renew (int requeue_position = 0,
+ ACE_Time_Value *timeout = 0);
+
+ /// Become interface-compliant with other lock mechanisms (implements
+ /// a non-blocking <acquire>).
+ int tryacquire (void);
+
+ /// Shuts down the ACE_Token instance.
+ int remove (void);
+
+ /// Relinquish the token. If there are any waiters then the next one
+ /// in line gets it.
+ int release (void);
+
+ /// Behave like acquire but in a lower priority. It should probably
+ /// be called acquire_yield.
+ int acquire_read (void);
+
+ /// More sophisticate version of acquire_read.
+ int acquire_read (void (*sleep_hook)(void *),
+ void *arg = 0,
+ ACE_Time_Value *timeout = 0);
+
+ /// Just calls <acquire>.
+ int acquire_write (void);
+
+ /// More sophisticate version of acquire_write.
+ int acquire_write (void (*sleep_hook)(void *),
+ void *arg = 0,
+ ACE_Time_Value *timeout = 0);
+
+ /// Lower priority try_acquire.
+ int tryacquire_read (void);
+
+ /// Just calls <tryacquire>.
+ int tryacquire_write (void);
+
+ /// Assumes the caller has acquired the token and returns 0.
+ int tryacquire_write_upgrade (void);
+
+ // = Accessor methods.
+
+ /// Return the number of threads that are currently waiting to get
+ /// the token.
+ int waiters (void);
+
+ /// Return the id of the current thread that owns the token.
+ ACE_thread_t current_owner (void);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+ // = The following structure implements a ACE_FIFO of waiter threads
+ // that are asleep waiting to obtain the token.
+
+ struct ACE_Token_Queue_Entry
+ {
+ ACE_Token_Queue_Entry (ACE_Thread_Mutex &m,
+ ACE_thread_t t_id);
+ // Constructor
+
+ ACE_Token_Queue_Entry (ACE_Thread_Mutex &m,
+ ACE_thread_t t_id,
+ ACE_Condition_Attributes &attributes);
+ // Constructor using a pre-allocated attributes
+
+ int wait (ACE_Time_Value *timeout, ACE_Thread_Mutex &lock);
+ // Entry blocks on the token.
+
+ int signal (void);
+ // Notify (unblock) the entry.
+
+ ACE_Token_Queue_Entry *next_;
+ // Pointer to next waiter.
+
+ ACE_thread_t thread_id_;
+ // ACE_Thread id of this waiter.
+
+#if defined (ACE_TOKEN_USES_SEMAPHORE)
+ ACE_Semaphore cv_;
+ // ACE_Semaphore object used to wake up waiter when it can run again.
+#else
+ ACE_Condition_Thread_Mutex cv_;
+ // ACE_Condition object used to wake up waiter when it can run again.
+#endif /* ACE_TOKEN_USES_SEMAPHORE */
+
+ int runable_;
+ // Ok to run.
+ };
+
+private:
+ enum ACE_Token_Op_Type
+ {
+ READ_TOKEN = 1,
+ WRITE_TOKEN
+ };
+
+ struct ACE_Token_Queue
+ {
+ ACE_Token_Queue (void);
+
+ void remove_entry (ACE_Token_Queue_Entry *);
+ // Remove a waiter from the queue.
+
+ void insert_entry (ACE_Token_Queue_Entry &entry,
+ int requeue_position = -1);
+ // Insert a waiter into the queue.
+
+ ACE_Token_Queue_Entry *head_;
+ // Head of the list of waiting threads.
+
+ ACE_Token_Queue_Entry *tail_;
+ // Tail of the list of waiting threads.
+ };
+
+ /// Implements the <acquire> and <tryacquire> methods above.
+ int shared_acquire (void (*sleep_hook_func)(void *),
+ void *arg,
+ ACE_Time_Value *timeout,
+ ACE_Token_Op_Type op_type);
+
+ /// Wake next in line for ownership.
+ void wakeup_next_waiter (void);
+
+ /// A queue of writer threads.
+ ACE_Token_Queue writers_;
+
+ /// A queue of reader threads.
+ ACE_Token_Queue readers_;
+
+ /// ACE_Thread_Mutex used to lock internal data structures.
+ ACE_Thread_Mutex lock_;
+
+ /// Current owner of the token.
+ ACE_thread_t owner_;
+
+ /// Some thread (i.e., <owner_>) is using the token. We need this
+ /// extra variable to deal with POSIX pthreads madness...
+ int in_use_;
+
+ /// Number of waiters.
+ int waiters_;
+
+ /// Current nesting level.
+ int nesting_level_;
+
+ /// The attributes for the condition variables, optimizes lock time.
+ ACE_Condition_Attributes attributes_;
+};
+
+#if defined (__ACE_INLINE__)
+#include "ace/Synch_T.h"
+#include "ace/Token.i"
+#endif /* __ACE_INLINE__ */
+#else
+class ACE_Export ACE_Token
+{
+public:
+ int acquire (ACE_Time_Value * = 0) { ACE_NOTSUP_RETURN (-1); }
+ int tryacquire (void) { ACE_NOTSUP_RETURN (-1); }
+ int remove (void) { ACE_NOTSUP_RETURN (-1); }
+ int release (void) { ACE_NOTSUP_RETURN (-1); }
+};
+#endif /* ACE_HAS_THREADS */
+#include "ace/post.h"
+#endif /* ACE_TOKEN_H */
diff --git a/ace/Threads/Token.i b/ace/Threads/Token.i
new file mode 100644
index 00000000000..e5b7aaf94a9
--- /dev/null
+++ b/ace/Threads/Token.i
@@ -0,0 +1,123 @@
+/* -*- C++ -*- */
+// $Id$
+
+// Token.i
+
+ACE_INLINE int
+ACE_Token::remove (void)
+{
+ ACE_TRACE ("ACE_Token::remove");
+ // Don't have an implementation for this yet...
+ ACE_NOTSUP_RETURN (-1);
+}
+
+ACE_INLINE int
+ACE_Token::tryacquire (void)
+{
+ ACE_TRACE ("ACE_Token::tryacquire");
+ return this->shared_acquire
+ (0, 0, (ACE_Time_Value *) &ACE_Time_Value::zero, ACE_Token::WRITE_TOKEN);
+}
+
+ACE_INLINE int
+ACE_Token::waiters (void)
+{
+ ACE_TRACE ("ACE_Token::waiters");
+ ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1);
+
+ int ret = this->waiters_;
+ return ret;
+}
+
+ACE_INLINE ACE_thread_t
+ACE_Token::current_owner (void)
+{
+ ACE_TRACE ("ACE_Token::current_owner");
+ ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, this->owner_);
+
+ return this->owner_;
+}
+
+ACE_INLINE int
+ACE_Token::acquire_read (void)
+{
+ ACE_TRACE ("ACE_Token::acquire_read");
+ return this->shared_acquire
+ (0, 0, 0, ACE_Token::READ_TOKEN);
+}
+
+ACE_INLINE int
+ACE_Token::acquire_write (void)
+{
+ ACE_TRACE ("ACE_Token::acquire_write");
+ return this->shared_acquire
+ (0, 0, 0, ACE_Token::WRITE_TOKEN);
+}
+
+ACE_INLINE int
+ACE_Token::tryacquire_read (void)
+{
+ ACE_TRACE ("ACE_Token::tryacquire_read");
+ return this->shared_acquire
+ (0, 0, (ACE_Time_Value *) &ACE_Time_Value::zero, ACE_Token::READ_TOKEN);
+}
+
+ACE_INLINE int
+ACE_Token::acquire_read (void (*sleep_hook_func)(void *),
+ void *arg,
+ ACE_Time_Value *timeout)
+{
+ ACE_TRACE ("ACE_Token::acquire_read");
+ return this->shared_acquire (sleep_hook_func, arg, timeout, ACE_Token::READ_TOKEN);
+}
+
+ACE_INLINE int
+ACE_Token::tryacquire_write (void)
+{
+ ACE_TRACE ("ACE_Token::tryacquire_write");
+ return this->shared_acquire
+ (0, 0, (ACE_Time_Value *) &ACE_Time_Value::zero, ACE_Token::WRITE_TOKEN);
+}
+
+ACE_INLINE int
+ACE_Token::tryacquire_write_upgrade (void)
+{
+ ACE_TRACE ("ACE_Token::tryacquire_write_upgrade");
+ return 0;
+}
+
+ACE_INLINE int
+ACE_Token::acquire_write (void (*sleep_hook_func)(void *),
+ void *arg,
+ ACE_Time_Value *timeout)
+{
+ ACE_TRACE ("ACE_Token::acquire_write");
+ return this->shared_acquire (sleep_hook_func, arg, timeout, ACE_Token::WRITE_TOKEN);
+}
+
+ACE_INLINE int
+ACE_Token::ACE_Token_Queue_Entry::wait (ACE_Time_Value *timeout, ACE_Thread_Mutex &lock)
+{
+#if defined (ACE_TOKEN_USES_SEMAPHORE)
+ lock.release ();
+ int retv = (timeout == 0 ?
+ this->cv_.acquire () :
+ this->cv_.acquire (*timeout));
+ lock.acquire ();
+ return retv;
+#else
+ ACE_UNUSED_ARG (lock);
+ return this->cv_.wait (timeout);
+#endif /* ACE_TOKEN_USES_SEMAPHORE */
+}
+
+ACE_INLINE int
+ACE_Token::ACE_Token_Queue_Entry::signal (void)
+{
+ return
+#if defined (ACE_TOKEN_USES_SEMAPHORE)
+ this->cv_.release ();
+#else
+ this->cv_.signal ();
+#endif /* ACE_TOKEN_USES_SEMAPHORE */
+}
diff --git a/ace/Timer/Basic_Stats.cpp b/ace/Timer/Basic_Stats.cpp
new file mode 100644
index 00000000000..00509d827ce
--- /dev/null
+++ b/ace/Timer/Basic_Stats.cpp
@@ -0,0 +1,73 @@
+// $Id$
+
+#include "ace/Basic_Stats.h"
+#include "ace/Log_Msg.h"
+
+#if !defined (__ACE_INLINE__)
+#include "ace/Basic_Stats.inl"
+#endif /* __ACE_INLINE__ */
+
+ACE_RCSID(ace, Basic_Stats, "$Id$")
+
+void
+ACE_Basic_Stats::accumulate (const ACE_Basic_Stats &rhs)
+{
+ if (rhs.samples_count_ == 0)
+ return;
+
+ if (this->samples_count_ == 0)
+ {
+ this->samples_count_ = rhs.samples_count_;
+
+ this->min_ = rhs.min_;
+ this->max_ = rhs.max_;
+ this->sum_ = rhs.sum_;
+ this->sum2_ = rhs.sum2_;
+
+ return;
+ }
+ this->samples_count_ += rhs.samples_count_;
+
+ if (this->min_ > rhs.min_)
+ this->min_ = rhs.min_;
+ if (this->max_ < rhs.max_)
+ this->max_ = rhs.max_;
+
+ this->sum_ += rhs.sum_;
+ this->sum2_ += rhs.sum2_;
+}
+
+void
+ACE_Basic_Stats::dump_results (const ACE_TCHAR *msg,
+ ACE_UINT32 sf) const
+{
+ if (this->samples_count () == 0u)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_LIB_TEXT ("%s : no data collected\n"), msg));
+ return;
+ }
+
+ ACE_UINT64 avg = this->sum_ / this->samples_count_;
+ ACE_UINT64 dev =
+#if defined ACE_LACKS_LONGLONG_T
+ ACE_static_cast (ACE_U_LongLong,
+ this->sum2_ / this->samples_count_)
+ - avg * ACE_U64_TO_U32(avg);
+#else /* ! ACE_LACKS_LONGLONG_T */
+ this->sum2_ / this->samples_count_ - avg * avg;
+#endif /* ! ACE_LACKS_LONGLONG_T */
+
+ double l_min = ACE_CU64_TO_CU32 (this->min_) / sf;
+ double l_max = ACE_CU64_TO_CU32 (this->max_) / sf;
+ double l_avg = ACE_CU64_TO_CU32 (avg) / sf;
+ double l_dev = ACE_CU64_TO_CU32 (dev) / (sf * sf);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_LIB_TEXT ("%s latency : %.2f[%d]/%.2f/%.2f[%d]/%.2f (min/avg/max/var^2)\n"),
+ msg,
+ l_min, this->min_at_,
+ l_avg,
+ l_max, this->max_at_,
+ l_dev));
+}
diff --git a/ace/Timer/Basic_Stats.h b/ace/Timer/Basic_Stats.h
new file mode 100644
index 00000000000..722c92ae355
--- /dev/null
+++ b/ace/Timer/Basic_Stats.h
@@ -0,0 +1,87 @@
+
+//=============================================================================
+/**
+ * @file Basic_Stats.h
+ *
+ * $Id$
+ *
+ * @author Carlos O'Ryan <coryan@uci.edu>
+ */
+//=============================================================================
+
+
+#ifndef ACE_BASIC_STATS_H
+#define ACE_BASIC_STATS_H
+#include "ace/pre.h"
+
+#include "ace/config-all.h"
+#include "ace/Basic_Types.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+/// Collect basic stats about a series of samples
+/**
+ * Compute the average and standard deviation (aka jitter) for an
+ * arbitrary number of samples, using constant space.
+ * Normally used for latency statistics.
+ */
+class ACE_Export ACE_Basic_Stats
+{
+public:
+ /// Constructor
+ /**
+ * The number of samples is pre-allocated, and cannot changes once
+ * the class is initialized.
+ */
+ ACE_Basic_Stats (void);
+
+ /// The number of samples received so far
+ ACE_UINT32 samples_count (void) const;
+
+ /// Record one sample.
+ void sample (ACE_UINT64 value);
+
+ /// Update the values to reflect the stats in @param rhs
+ void accumulate (const ACE_Basic_Stats &rhs);
+
+ /// Dump all the samples
+ /**
+ * Prints out the results, using @param msg as a prefix for each
+ * message and scaling all the numbers by @param scale_factor.
+ * The latter is useful because high resolution timer samples are
+ * acquired in clock ticks, but often presented in microseconds.
+ */
+ void dump_results (const ACE_TCHAR *msg,
+ ACE_UINT32 scale_factor) const;
+
+private:
+ /// The number of samples
+ ACE_UINT32 samples_count_;
+
+ /// The minimum value
+ ACE_UINT64 min_;
+
+ /// The number of the sample that had the minimum value
+ ACE_UINT32 min_at_;
+
+ /// The maximum value
+ ACE_UINT64 max_;
+
+ /// The number of the sample that had the maximum value
+ ACE_UINT32 max_at_;
+
+ /// The sum of all the values
+ ACE_UINT64 sum_;
+
+ /// The sum of the square of all the values
+ ACE_UINT64 sum2_;
+};
+
+#if defined (__ACE_INLINE__)
+#include "ace/Basic_Stats.inl"
+#endif /* __ACE_INLINE__ */
+
+#include "ace/post.h"
+#endif /* ACE_BASIC_STATS_H */
diff --git a/ace/Timer/Basic_Stats.inl b/ace/Timer/Basic_Stats.inl
new file mode 100644
index 00000000000..4ed1baca459
--- /dev/null
+++ b/ace/Timer/Basic_Stats.inl
@@ -0,0 +1,59 @@
+// $Id$
+
+ACE_INLINE
+ACE_Basic_Stats::ACE_Basic_Stats (void)
+ : samples_count_ (0)
+ , min_ (0)
+ , min_at_ (0)
+ , max_ (0)
+ , max_at_ (0)
+ , sum_ (0)
+ , sum2_ (0)
+{
+}
+
+ACE_INLINE ACE_UINT32
+ACE_Basic_Stats::samples_count (void) const
+{
+ return this->samples_count_;
+}
+
+ACE_INLINE void
+ACE_Basic_Stats::sample (ACE_UINT64 value)
+{
+ ++this->samples_count_;
+
+ if (this->samples_count_ == 1u)
+ {
+ this->min_ = value;
+ this->min_at_ = this->samples_count_;
+ this->max_ = value;
+ this->max_at_ = this->samples_count_;
+ this->sum_ = value;
+#if defined ACE_LACKS_LONGLONG_T
+ this->sum2_ = value * ACE_U64_TO_U32 (value);
+#else /* ! ACE_LACKS_LONGLONG_T */
+ this->sum2_ = value * value;
+#endif /* ! ACE_LACKS_LONGLONG_T */
+ }
+ else
+ {
+ if (this->min_ > value)
+ {
+ this->min_ = value;
+ this->min_at_ = this->samples_count_;
+ }
+ if (this->max_ < value)
+ {
+ this->max_ = value;
+ this->max_at_ = this->samples_count_;
+ }
+
+ this->sum_ += value;
+#if defined ACE_LACKS_LONGLONG_T
+ this->sum2_ += value * ACE_U64_TO_U32 (value);
+#else /* ! ACE_LACKS_LONGLONG_T */
+ this->sum2_ += value * value;
+#endif /* ! ACE_LACKS_LONGLONG_T */
+ }
+}
diff --git a/ace/Timer/High_Res_Timer.cpp b/ace/Timer/High_Res_Timer.cpp
new file mode 100644
index 00000000000..c589ab67abc
--- /dev/null
+++ b/ace/Timer/High_Res_Timer.cpp
@@ -0,0 +1,525 @@
+// $Id$
+
+// Be very carefull before changing the calculations inside
+// ACE_High_Res_Timer. The precision matters and we are using integer
+// calculations not floating point. Also look good at the emulated 64
+// bit int class (inside Basic_Types{h,i,cpp} before changing
+// anything. It's operator/ only returns 32 bits not 64 bits, among
+// other things.
+
+#include "ace/High_Res_Timer.h"
+
+#if !defined (__ACE_INLINE__)
+#include "ace/High_Res_Timer.i"
+#endif /* __ACE_INLINE__ */
+
+#include "ace/Stats.h"
+
+ACE_RCSID(ace, High_Res_Timer, "$Id$")
+
+ACE_ALLOC_HOOK_DEFINE(ACE_High_Res_Timer)
+
+// For Intel platforms, a scale factor is required for
+// ACE_OS::gethrtime. We'll still set this to one to prevent division
+// by zero errors.
+#if (defined (ACE_WIN32) || defined (ACE_HAS_POWERPC_TIMER) || \
+ defined (ACE_HAS_PENTIUM) || defined (ACE_HAS_ALPHA_TIMER)) && \
+ !defined (ACE_HAS_HI_RES_TIMER)
+
+# include "ace/Synch.h"
+# include "ace/Object_Manager.h"
+
+ // Initialize the global_scale_factor_ to 1. The first
+ // ACE_High_Res_Timer instance construction will override this
+ // value.
+ /* static */
+ ACE_UINT32 ACE_High_Res_Timer::global_scale_factor_ = 1u;
+
+#else /* ! (ACE_WIN32 || ACE_HAS_POWERPC_TIMER || \
+ ACE_HAS_PENTIUM || ACE_HAS_ALPHA_TIMER) ||
+ ACE_HAS_HI_RES_TIMER */
+ // A scale_factor of 1000 converts nanosecond ticks to microseconds.
+ // That is, on these platforms, 1 tick == 1 nanosecond.
+ /* static */
+ ACE_UINT32 ACE_High_Res_Timer::global_scale_factor_ = 1000u;
+#endif /* ! (ACE_WIN32 || ACE_HAS_POWERPC_TIMER || \
+ ACE_HAS_PENTIUM || ACE_HAS_ALPHA_TIMER) ||
+ ACE_HAS_HI_RES_TIMER */
+
+// This is used to tell if the global_scale_factor_ has been
+// set, and if high resolution timers are supported.
+/* static */
+int ACE_High_Res_Timer::global_scale_factor_status_ = 0;
+
+
+#if defined (linux)
+// Determine the apparent CPU clock speed from /proc/cpuinfo
+ACE_UINT32
+ACE_High_Res_Timer::get_cpuinfo (void)
+{
+ ACE_UINT32 scale_factor = 1u;
+
+ // Get the BogoMIPS from /proc/cpuinfo. It works fine on Alpha and
+ // Pentium Pro. For other CPUs, it will be necessary to interpret
+ // the BogoMips, as described in the BogoMips mini-HOWTO. Note that
+ // this code assumes an order to the /proc/cpuinfo contents. The
+ // BogoMips rating had better come after CPU type and model info.
+#if !defined (__alpha__)
+ int supported = 0;
+#endif /* __alpha__ */
+
+ FILE *cpuinfo = ACE_OS::fopen ("/proc/cpuinfo", "r");
+
+ if (cpuinfo != 0)
+ {
+ ACE_TCHAR buf[128];
+
+ // ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\nReading /proc/cpuinfo...")));
+
+ while (ACE_OS::fgets (buf, sizeof buf, cpuinfo))
+ {
+#if defined (__alpha__)
+ ACE_UINT32 whole;
+ ACE_UINT32 fractional;
+ if (::sscanf (buf,
+ "BogoMIPS : %d.%d\n",
+ &whole,
+ &fractional) == 2
+ || ::sscanf (buf,
+ "bogomips : %d.%d\n",
+ &whole,
+ &fractional) == 2)
+ {
+ scale_factor = whole;
+ break;
+ }
+#else
+ double mhertz = 1;
+ double bmips = 1;
+ ACE_TCHAR arg[128];
+
+ // CPU type?
+ if (::sscanf (buf, "cpu : %s\n", arg) == 1)
+ {
+ // If this is an Alpha chip, then the BogoMips rating is
+ // usable...
+ if (ACE_OS::strncmp (arg,
+ "Alpha",
+ 5) == 0)
+ {
+ supported = 1;
+ // ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT (" recognized Alpha chip...")));
+ }
+ }
+ // Pentium CPU model?
+ else if (supported == 0
+ && ::sscanf (buf, "model name : Pentium %s\n", arg) == 1)
+ {
+ // But if we don't have the right kind of Intel chip,
+ // just quit.
+ if (ACE_OS::strcmp (arg, "II") == 0
+ || ACE_OS::strcmp (arg, "III") == 0
+ || ACE_OS::strcmp (arg, "IV") == 0
+ || ACE_OS::strcmp (arg, "Pro") == 0)
+ {
+ supported = 1;
+ // ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT (" recognized Pentium Pro/II chip...")));
+ }
+ }
+ else if (::sscanf (buf, "cpu MHz : %lf\n", &mhertz) == 1)
+ {
+ if (supported)
+ {
+ scale_factor = (ACE_UINT32) (mhertz + 0.5);
+ }
+ break;
+ }
+ else if (::sscanf (buf, "bogomips : %lf\n", &bmips) == 1
+ || ::sscanf (buf, "BogoMIPS : %lf\n", &bmips) == 1)
+ {
+ if (supported)
+ {
+ scale_factor = (ACE_UINT32) (bmips + 0.5);
+ // ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT (" setting the clock scale factor to %u"), scale_factor));
+ }
+#if 0
+ else
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_LIB_TEXT ("\nThe BogoMIPS metric is not supported on this platform"
+ "\n\tReport the results of the clock calibration and"
+ "\n\tthe contents of /proc/cpuinfo to the ace-users mailing list")));
+ }
+#endif /* 0 */
+ break;
+ }
+#endif /* __alpha__ */
+ }
+
+ // ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT (" (done)\n")));
+
+ ACE_OS::fclose (cpuinfo);
+ }
+
+ return scale_factor;
+}
+#endif /* linux */
+
+ACE_UINT32
+ACE_High_Res_Timer::global_scale_factor (void)
+{
+#if (defined (ACE_WIN32) || defined (ACE_HAS_POWERPC_TIMER) || \
+ defined (ACE_HAS_PENTIUM) || defined (ACE_HAS_ALPHA_TIMER)) && \
+ !defined (ACE_HAS_HI_RES_TIMER) && \
+ ((defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)) || \
+ defined (ghs) || defined (__GNUG__) || defined (__KCC))
+ // Check if the global scale factor needs to be set, and do if so.
+ if (ACE_High_Res_Timer::global_scale_factor_status_ == 0)
+ {
+ // Grab ACE's static object lock. This doesn't have anything to
+ // do with static objects; it's just a convenient lock to use.
+ ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon,
+ *ACE_Static_Object_Lock::instance (), 0));
+
+ // Double check
+ if (ACE_High_Res_Timer::global_scale_factor_status_ == 0)
+ {
+# if defined (ACE_WIN32)
+ LARGE_INTEGER freq;
+ if (::QueryPerformanceFrequency (&freq))
+ {
+ // We have a high-res timer
+# if defined (ACE_LACKS_LONGLONG_T)
+ ACE_UINT64 uint64_freq(freq.u.LowPart, (ACE_UINT32) freq.u.HighPart);
+ ACE_High_Res_Timer::global_scale_factor
+ (uint64_freq / (ACE_UINT32) ACE_ONE_SECOND_IN_USECS);
+# else
+ ACE_High_Res_Timer::global_scale_factor
+ (ACE_static_cast (unsigned int,
+ freq.QuadPart / ACE_HR_SCALE_CONVERSION));
+# endif // (ACE_LACKS_LONGLONG_T)
+
+ ACE_High_Res_Timer::global_scale_factor_status_ = 1;
+ }
+ else
+ // High-Res timers not supported
+ ACE_High_Res_Timer::global_scale_factor_status_ = -1;
+
+ return ACE_High_Res_Timer::global_scale_factor_;
+
+# elif defined (linux)
+ ACE_High_Res_Timer::global_scale_factor (ACE_High_Res_Timer::get_cpuinfo ());
+# endif /* ! ACE_WIN32 && ! (linux && __alpha__) */
+
+# if !defined (ACE_WIN32)
+ if (ACE_High_Res_Timer::global_scale_factor_ == 1u)
+ // Failed to retrieve CPU speed from system, so calculate it.
+ ACE_High_Res_Timer::calibrate ();
+# endif // (ACE_WIN32)
+ }
+ }
+
+ ACE_High_Res_Timer::global_scale_factor_status_ = 1;
+#endif /* (ACE_WIN32 || ACE_HAS_POWERPC_TIMER || \
+ ACE_HAS_PENTIUM || ACE_HAS_ALPHA_TIMER) && \
+ ! ACE_HAS_HIGH_RES_TIMER &&
+ ((WIN32 && ! WINCE) || ghs || __GNUG__) */
+
+ return ACE_High_Res_Timer::global_scale_factor_;
+}
+
+ACE_High_Res_Timer::ACE_High_Res_Timer (void)
+{
+ ACE_TRACE ("ACE_High_Res_Timer::ACE_High_Res_Timer");
+
+ this->reset ();
+
+ // Make sure that the global scale factor is set.
+ (void) global_scale_factor ();
+}
+
+ACE_UINT32
+ACE_High_Res_Timer::calibrate (const ACE_UINT32 usec,
+ const u_int iterations)
+{
+ const ACE_Time_Value sleep_time (0, usec);
+ ACE_Stats delta_hrtime;
+ // In units of 100 usec, to avoid overflow.
+ ACE_Stats actual_sleeps;
+
+ for (u_int i = 0;
+ i < iterations;
+ ++i)
+ {
+ const ACE_Time_Value actual_start =
+ ACE_OS::gettimeofday ();
+ const ACE_hrtime_t start =
+ ACE_OS::gethrtime ();
+ ACE_OS::sleep (sleep_time);
+ const ACE_hrtime_t stop =
+ ACE_OS::gethrtime ();
+ const ACE_Time_Value actual_delta =
+ ACE_OS::gettimeofday () - actual_start;
+
+ // Store the sample.
+ delta_hrtime.sample (ACE_U64_TO_U32 (stop - start));
+ actual_sleeps.sample (actual_delta.msec () * 100u);
+ }
+
+ // Calculate the mean value of the samples, with no fractional
+ // precision. Use it for the global scale factor.
+ ACE_Stats_Value ticks (0);
+ delta_hrtime.mean (ticks);
+
+ ACE_Stats_Value actual_sleep (0);
+ actual_sleeps.mean (actual_sleep);
+
+ // The addition of 5 below rounds instead of truncates.
+ const ACE_UINT32 scale_factor =
+ (ticks.whole () / actual_sleep.whole () + 5) /
+ 10u /* usec/100 usec */;
+ ACE_High_Res_Timer::global_scale_factor (scale_factor);
+
+ return scale_factor;
+}
+
+void
+ACE_High_Res_Timer::dump (void) const
+{
+ ACE_TRACE ("ACE_High_Res_Timer::dump");
+
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\nglobal_scale_factor_: %u\n"),
+ global_scale_factor ()));
+#if defined (ACE_LACKS_LONGLONG_T)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_LIB_TEXT (":\nstart_.hi (): %8x; start_.lo (): %8x;\n")
+ ACE_LIB_TEXT ("end_.hi (): %8x; end_.lo (): %8x;\n")
+ ACE_LIB_TEXT ("total_.hi (): %8x; total_.lo (): %8x;\n")
+ ACE_LIB_TEXT ("start_incr_.hi () %8x; start_incr_.lo (): %8x;\n"),
+ start_.hi (), start_.lo (),
+ end_.hi (), end_.lo (),
+ total_.hi (), total_.lo (),
+ start_incr_.hi (), start_incr_.lo ()));
+#else /* ! ACE_LACKS_LONGLONG_T */
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_LIB_TEXT (":\nstart_.hi (): %8x; start_.lo (): %8x;\n")
+ ACE_LIB_TEXT ("end_.hi (): %8x; end_.lo (): %8x;\n")
+ ACE_LIB_TEXT ("total_.hi (): %8x; total_.lo (): %8x;\n")
+ ACE_LIB_TEXT ("start_incr_.hi () %8x; start_incr_.lo (): %8x;\n"),
+ ACE_CU64_TO_CU32 (start_ >> 32),
+ ACE_CU64_TO_CU32 (start_ & 0xfffffffful),
+ ACE_CU64_TO_CU32 (end_ >> 32),
+ ACE_CU64_TO_CU32 (end_ & 0xfffffffful),
+ ACE_CU64_TO_CU32 (total_ >> 32),
+ ACE_CU64_TO_CU32 (total_ & 0xfffffffful),
+ ACE_CU64_TO_CU32 (start_incr_ >> 32),
+ ACE_CU64_TO_CU32 (start_incr_ & 0xfffffffful)));
+#endif /* ! ACE_LACKS_LONGLONG_T */
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+void
+ACE_High_Res_Timer::reset (void)
+{
+ ACE_TRACE ("ACE_High_Res_Timer::reset");
+
+ start_ = 0;
+ end_ = 0;
+ total_ = 0;
+ start_incr_ = 0;
+}
+
+void
+ACE_High_Res_Timer::elapsed_time (ACE_Time_Value &tv) const
+{
+ hrtime_to_tv (tv, end_ - start_);
+}
+
+#if defined (ACE_HAS_POSIX_TIME)
+// Note... Win32 does not have ACE_HAS_POSIX_TIME, so the scale factor
+// does not need to take into account the different units on Win32.
+
+void
+ACE_High_Res_Timer::elapsed_time (struct timespec &elapsed_time) const
+{
+ // This implementation should be cleaned up.
+
+ // Just grab the nanoseconds. That is, leave off all values above
+ // microsecond. This equation is right! Don't mess with me! (It
+ // first strips off everything but the portion less than 1 usec.
+ // Then it converts that to nanoseconds by dividing by the scale
+ // factor to convert to usec, and multiplying by 1000.) The cast
+ // avoids a MSVC 4.1 compiler warning about narrowing.
+ u_long nseconds = ACE_static_cast (u_long,
+ (this->end_ - this->start_) %
+ global_scale_factor () * 1000u /
+ global_scale_factor ());
+
+ // Get just the microseconds (dropping any left over nanoseconds).
+ ACE_UINT32 useconds = (ACE_UINT32) ((this->end_ - this->start_) / global_scale_factor ());
+
+#if ! defined(ACE_HAS_BROKEN_TIMESPEC_MEMBERS)
+ elapsed_time.tv_sec = (time_t) (useconds / ACE_ONE_SECOND_IN_USECS);
+ // Transforms one second in microseconds into nanoseconds.
+ elapsed_time.tv_nsec = (time_t) ((useconds % ACE_ONE_SECOND_IN_USECS) * 1000u + nseconds);
+#else
+ elapsed_time.ts_sec = (time_t) (useconds / ACE_ONE_SECOND_IN_USECS);
+ // Transforms one second in microseconds into nanoseconds.
+ elapsed_time.ts_nsec = (time_t) ((useconds % ACE_ONE_SECOND_IN_USECS) * 1000u + nseconds);
+#endif /* ACE_HAS_BROKEN_TIMESPEC_MEMBERS */
+}
+#endif /* ACE_HAS_POSIX_TIME */
+
+void
+ACE_High_Res_Timer::elapsed_time_incr (ACE_Time_Value &tv) const
+{
+ hrtime_to_tv (tv, total_);
+}
+
+void
+ACE_High_Res_Timer::elapsed_time (ACE_hrtime_t &nanoseconds) const
+{
+ // Please do _not_ rearrange this equation. It is carefully
+ // designed and tested to avoid overflow on machines that don't have
+ // native 64-bit ints. In particular, division can be a problem.
+ // For more background on this, please see bugzilla #1024.
+#if defined (ACE_WIN32)
+ nanoseconds = (this->end_ - this->start_)
+ * (1024000000u / ACE_High_Res_Timer::global_scale_factor());
+#else
+ nanoseconds = (this->end_ - this->start_)
+ * (1024000u / ACE_High_Res_Timer::global_scale_factor ());
+#endif /* ACE_WIN32 */
+ // Caution - Borland has a problem with >>=, so resist the tempatation.
+ nanoseconds = nanoseconds >> 10;
+ // Right shift is implemented for non native 64-bit ints
+ // operator/ only for a 32 bit result !
+}
+
+void
+ACE_High_Res_Timer::elapsed_time_incr (ACE_hrtime_t &nanoseconds) const
+{
+ // Same as above.
+#if defined (ACE_WIN32)
+ nanoseconds = this->total_
+ * (1024000000u / ACE_High_Res_Timer::global_scale_factor());
+#else
+ nanoseconds = this->total_
+ * (1024000u / ACE_High_Res_Timer::global_scale_factor ());
+#endif
+ // Caution - Borland has a problem with >>=, so resist the tempatation.
+ nanoseconds = nanoseconds >> 10;
+}
+
+#if !defined (ACE_HAS_WINCE)
+void
+ACE_High_Res_Timer::print_ave (const ACE_TCHAR *str,
+ const int count,
+ ACE_HANDLE handle) const
+{
+ ACE_TRACE ("ACE_High_Res_Timer::print_ave");
+
+ // Get the total number of nanoseconds elapsed.
+ ACE_hrtime_t total_nanoseconds;
+ this->elapsed_time (total_nanoseconds);
+
+ // Separate to seconds and nanoseconds.
+ u_long total_secs =
+ ACE_static_cast (u_long,
+ total_nanoseconds / (ACE_UINT32) ACE_ONE_SECOND_IN_NSECS);
+ ACE_UINT32 extra_nsecs =
+ ACE_static_cast (ACE_UINT32,
+ total_nanoseconds % (ACE_UINT32) ACE_ONE_SECOND_IN_NSECS);
+
+ ACE_TCHAR buf[100];
+ if (count > 1)
+ {
+ ACE_hrtime_t avg_nsecs = total_nanoseconds / (ACE_UINT32) count;
+ ACE_OS::sprintf (buf,
+ ACE_LIB_TEXT (" count = %d, total (secs %lu, usecs %u), avg usecs = %lu\n"),
+ count,
+ total_secs,
+ (extra_nsecs + 500u) / 1000u,
+ (u_long) ((avg_nsecs + 500u) / 1000u));
+ }
+ else
+ ACE_OS::sprintf (buf,
+ ACE_LIB_TEXT (" total %3lu.%06lu secs\n"),
+ total_secs,
+ (extra_nsecs + 500lu) / 1000lu);
+
+ ACE_OS::write (handle,
+ str,
+ ACE_OS::strlen (str));
+ ACE_OS::write (handle,
+ buf,
+ ACE_OS::strlen (buf));
+}
+
+void
+ACE_High_Res_Timer::print_total (const ACE_TCHAR *str,
+ const int count,
+ ACE_HANDLE handle) const
+{
+ ACE_TRACE ("ACE_High_Res_Timer::print_total");
+
+ // Get the total number of nanoseconds elapsed.
+ ACE_hrtime_t total_nanoseconds;
+ this->elapsed_time (total_nanoseconds);
+
+ // Separate to seconds and nanoseconds.
+ u_long total_secs =
+ (u_long) (total_nanoseconds / (ACE_UINT32) ACE_ONE_SECOND_IN_NSECS);
+ ACE_UINT32 extra_nsecs =
+ (ACE_UINT32) (total_nanoseconds % (ACE_UINT32) ACE_ONE_SECOND_IN_NSECS);
+
+ ACE_TCHAR buf[100];
+ if (count > 1)
+ {
+ ACE_hrtime_t avg_nsecs = this->total_ / (ACE_UINT32) count;
+
+ ACE_OS::sprintf (buf,
+ ACE_LIB_TEXT (" count = %d, total (secs %lu, usecs %u), avg usecs = %lu\n"),
+ count,
+ total_secs,
+ (extra_nsecs + 500u) / 1000u,
+ (u_long) ((avg_nsecs + 500u) / 1000u));
+ }
+ else
+ ACE_OS::sprintf (buf,
+ ACE_LIB_TEXT (" total %3lu.%06u secs\n"),
+ total_secs,
+ (extra_nsecs + 500u) / 1000u);
+
+ ACE_OS::write (handle,
+ str,
+ ACE_OS::strlen (str));
+ ACE_OS::write (handle,
+ buf,
+ ACE_OS::strlen (buf));
+}
+#endif /* !ACE_HAS_WINCE */
+
+int
+ACE_High_Res_Timer::get_env_global_scale_factor (const ACE_TCHAR *env)
+{
+#if !defined (ACE_HAS_WINCE)
+ if (env != 0)
+ {
+ const ACE_TCHAR *env_value = ACE_OS::getenv (env);
+ if (env_value != 0)
+ {
+ int value = ACE_OS::atoi (env_value);
+ if (value > 0)
+ {
+ ACE_High_Res_Timer::global_scale_factor (value);
+ return 0;
+ }
+ }
+ }
+#else
+ ACE_UNUSED_ARG (env);
+#endif /* !ACE_HAS_WINCE */
+ return -1;
+}
diff --git a/ace/Timer/High_Res_Timer.h b/ace/Timer/High_Res_Timer.h
new file mode 100644
index 00000000000..cffa4c07da8
--- /dev/null
+++ b/ace/Timer/High_Res_Timer.h
@@ -0,0 +1,308 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file High_Res_Timer.h
+ *
+ * $Id$
+ *
+ * @author Douglas C. Schmidt <schmidt@cs.wustl.edu>
+ */
+//=============================================================================
+
+#ifndef ACE_HIGH_RES_TIMER_H
+#define ACE_HIGH_RES_TIMER_H
+#include "ace/pre.h"
+
+#include "ace/ACE.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+/**
+ * @class ACE_High_Res_Timer
+ *
+ * @brief A high resolution timer class wrapper that encapsulates
+ * OS-specific high-resolution timers, such as those found on
+ * Solaris, AIX, Win32/Pentium, and VxWorks.
+ *
+ * Most of the member functions don't return values. The only
+ * reason that one would fail is if high-resolution time isn't
+ * supported on the platform. To avoid impacting performance
+ * and complicating the interface, in that case,
+ * <ACE_OS::gettimeofday> is used instead.
+ * The global scale factor is required for platforms that have
+ * high-resolution timers that return units other than
+ * microseconds, such as clock ticks. It is represented as a
+ * static u_long, can only be accessed through static methods,
+ * and is used by all instances of High Res Timer. The member
+ * functions that return or print times use the global scale
+ * factor. They divide the "time" that they get from
+ * <ACE_OS::gethrtime> by global_scale_factor_ to obtain the
+ * time in microseconds. Its units are therefore 1/microsecond.
+ * On Windows the global_scale_factor_ units are 1/millisecond.
+ * There's a macro <ACE_HR_SCALE_CONVERSION> which gives the
+ * units/second. Because it's possible that the units/second
+ * changes in the future, it's recommended to use it instead
+ * of a "hard coded" solution.
+ * Dependend on the platform and used class members, there's a
+ * maximum elapsed period before overflow (which is not checked).
+ * Look at the documentation with some members functions.
+ * On some (most?) implementations it's not recommended to measure
+ * "long" timeperiods, because the error's can accumulate fast.
+ * This is probably not a problem profiling code, but could be
+ * on if the high resolution timer class is used to initiate
+ * actions after a "long" timeout.
+ * On Solaris, a scale factor of 1000 should be used because its
+ * high-resolution timer returns nanoseconds. However, on Intel
+ * platforms, we use RDTSC which returns the number of clock
+ * ticks since system boot. For a 200MHz cpu, each clock tick
+ * is 1/200 of a microsecond; the global_scale_factor_ should
+ * therefore be 200 or 200000 if it's in unit/millisecond.
+ * On Windows ::QueryPerformanceCounter() is used, which can be a
+ * different implementation depending on the used windows HAL
+ * (Hardware Abstraction Layer). On some it uses the PC "timer chip"
+ * while it uses RDTSC on others.
+ * NOTE: the elapsed time calculations in the print methods use
+ * ACE_hrtime_t values. Those methods do _not_ check for overflow!
+ * NOTE: Gabe <begeddov@proaxis.com> raises this issue regarding
+ * <ACE_OS::gethrtime>: on multi-processors, the processor that
+ * you query for your <timer.stop> value might not be the one
+ * you queried for <timer.start>. Its not clear how much
+ * divergence there would be, if any.
+ * This issue is not mentioned in the Solaris 2.5.1 gethrtime
+ * man page.
+ * A RDTSC NOTE: RDTSC is the Intel Pentium read-time stamp counter
+ * and is actualy a 64 bit clock cycle counter, which is increased
+ * with every cycle. It has a low overhead and can be read within
+ * 16 (pentium) or 32 (pentium II,III,...) cycles, but it doesn't
+ * serialize the processor, which could give wrong timings when
+ * profiling very short code fragments.
+ * Problematic is that some power sensitive devices
+ * (laptops for example, but probably also embeded devices),
+ * do change the cycle rate while running.
+ * Some pentiums can run on (at least) two clock frequency's.
+ * Another problem arises with multiprocessor computers, there
+ * are reports that the different RDTSC's are not always kept
+ * in sync.
+ * A windows "timer chip" NOTE: (8254-compatible real-time clock)
+ * When ::QueryPerformanceCounter() uses the 8254 it has a
+ * frequency off about 1.193 Mhz (or sometimes 3.579 Mhz?) and
+ * reading it requires some time (several thousand cycles).
+ */
+class ACE_Export ACE_High_Res_Timer
+{
+public:
+ // = Initialization method.
+
+ /**
+ * global_scale_factor_ is set to <gsf>. All High_Res_Timers use
+ * global_scale_factor_. This allows applications to set the scale
+ * factor just once for all High_Res_Timers. Check
+ * High_Res_Timer.cpp for the default global_scale_factors for
+ * several platforms. For many platforms (e.g., Solaris), the
+ * global_scale_factor_ is set to 1000 so that <scale_factor> need
+ * not be set. Careful, a <scale_factor> of 0 will cause division
+ * by zero exceptions.
+ * Depending on the platform its units are 1/microsecond or
+ * 1/millisecond. Use <ACE_HR_SCALE_CONVERSION> inside calculations
+ * instead a hardcoded value.
+ */
+ static void global_scale_factor (ACE_UINT32 gsf);
+
+ /// Returns the global_scale_factor.
+ static ACE_UINT32 global_scale_factor (void);
+
+ // On Win32, QueryPerformanceFrequency is used as a base for the global
+ // scale factor. The value this returns is often too small to be usefully
+ // converted to "ticks"/second - it loses unacceptably high levels of
+ // precision. So on Win32, global_scale_factor_ is in ticks/msec, not
+ // ticks/usec as on all others.
+#if defined (ACE_WIN32)
+# define ACE_HR_SCALE_CONVERSION (ACE_ONE_SECOND_IN_MSECS)
+#else
+# define ACE_HR_SCALE_CONVERSION (ACE_ONE_SECOND_IN_USECS)
+#endif /* ACE_WIN32 */
+
+ /**
+ * Sets the global_scale_factor to the value in the <env>
+ * environment variable. Returns 0 on success, -1 on failure. Note
+ * if <env> points to string "0" (value zero), this call will fail.
+ * This is basically a no-op on CE because there is no concept of
+ * environment variable on CE.
+ */
+ static int get_env_global_scale_factor (const ACE_TCHAR *env
+ = ACE_LIB_TEXT ("ACE_SCALE_FACTOR"));
+
+ /**
+ * Set (and return, for info) the global scale factor by sleeping
+ * for <usec> and counting the number of intervening clock cycles.
+ * Average over <iterations> of <usec> each. On some platforms,
+ * such as Pentiums, this is called automatically during the first
+ * ACE_High_Res_Timer construction with the default parameter
+ * values. An application can override that by calling calibrate
+ * with any desired parameter values _prior_ to constructing the
+ * first ACE_High_Res_Timer instance.
+ * Beware for platforms that can change the cycle rate on the fly.
+ */
+ static ACE_UINT32 calibrate (const ACE_UINT32 usec = 500000,
+ const u_int iterations = 10);
+
+ /// Initialize the timer.
+ ACE_High_Res_Timer (void);
+
+ /// dtor.
+ ~ACE_High_Res_Timer (void);
+
+ /// Reinitialize the timer.
+ void reset (void);
+
+ /// Start timing.
+ void start (const ACE_OS::ACE_HRTimer_Op = ACE_OS::ACE_HRTIMER_GETTIME);
+
+ /// Stop timing.
+ void stop (const ACE_OS::ACE_HRTimer_Op = ACE_OS::ACE_HRTIMER_GETTIME);
+
+ /// Set <tv> to the number of microseconds elapsed.
+ /**
+ * Could overflow within hours on windows with emulated 64 bit int's
+ * and a fast counter. VC++ and Borland normaly use __int64 and
+ * so normaly don't have this problem.
+ */
+ void elapsed_time (ACE_Time_Value &tv) const;
+
+ /// Set <nanoseconds> to the number of nanoseconds elapsed.
+ /**
+ * Will overflow when measuring more than 194 day's.
+ */
+ void elapsed_time (ACE_hrtime_t &nanoseconds) const;
+
+#if defined (ACE_HAS_POSIX_TIME)
+ /// Returns the elapsed (stop - start) time in a struct timespec
+ /// (sec, nsec).
+ void elapsed_time (struct timespec &) const;
+#endif /* ACE_HAS_POSIX_TIME */
+
+ /// Sets <usecs> to the elapsed (stop - start) time in microseconds.
+ /**
+ * Will overflow on windows when measuring more than appox. 2^^54 ticks.
+ * Is still more than 48 days with a 4 Ghz counter.
+ */
+ void elapsed_microseconds (ACE_hrtime_t &usecs) const;
+
+ /// Start incremental timing.
+ void start_incr (const ACE_OS::ACE_HRTimer_Op = ACE_OS::ACE_HRTIMER_GETTIME);
+
+ /// Stop incremental timing.
+ void stop_incr (const ACE_OS::ACE_HRTimer_Op = ACE_OS::ACE_HRTIMER_GETTIME);
+
+ /// Set <tv> to the number of microseconds elapsed between all calls
+ /// to start_incr and stop_incr.
+ void elapsed_time_incr (ACE_Time_Value &tv) const;
+
+ /// Set <nsec> to the number of nanoseconds elapsed between all calls
+ /// to start_incr and stop_incr.
+ void elapsed_time_incr (ACE_hrtime_t &nanoseconds) const;
+
+#if !defined (ACE_HAS_WINCE)
+ // @@ WINCE These two functions are currently not supported on Windows CE.
+ // However, we should probably use the handle and ACE_Log_Msg to
+ // print out the result.
+ /// Print total time. NOTE: only use <print_total> if incremental
+ /// timings had been used!
+ void print_total (const ACE_TCHAR *message,
+ const int iterations = 1,
+ ACE_HANDLE handle = ACE_STDOUT) const;
+
+ /// Print average time.
+ void print_ave (const ACE_TCHAR *message,
+ const int iterations = 1,
+ ACE_HANDLE handle = ACE_STDOUT) const;
+#endif /* !ACE_HAS_WINCE */
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+ /**
+ * Get the current "time" as the high resolution counter at this time.
+ * This is intended to be useful for supplying to a ACE_Timer_Queue
+ * as the gettimeofday function, thereby basing the timer calculations
+ * on the high res timer rather than wall clock time.
+ */
+ static ACE_Time_Value gettimeofday_hr (void);
+
+ /**
+ * THIS FUNCTION IS DEPRECATED. PLEASE USE <ACE_OS::gettimeofday>
+ * INSTEAD! Calls <ACE_High_Res_Timer::hrtime_to_tv> passing
+ * <ACE_OS::gethrtime>. This function can be used to parameterize
+ * objects such as <ACE_Timer_Queue::gettimeofday>. If
+ * <global_scale_factor_> is not set, and we're on a platform that
+ * requires <global_scale_factor_> (e.g., Win32),
+ * ACE_OS::gettimeofday will be used instead of <ACE_OS::gethrtime>.
+ * This allows applications on Intel to use <High_Res_Timer> even
+ * when <global_scale_factor> is not set. However, setting the
+ * <global_scale_factor_> appropriately will result in the finest
+ * resolution possible.
+ */
+ static ACE_Time_Value gettimeofday (const ACE_OS::ACE_HRTimer_Op =
+ ACE_OS::ACE_HRTIMER_GETTIME);
+
+ /// Converts an <hrt> to <tv> using global_scale_factor_.
+ static void hrtime_to_tv (ACE_Time_Value &tv,
+ const ACE_hrtime_t hrt);
+
+#if defined (linux)
+ /**
+ * This is used to find out the Mhz of the machine for the scale
+ * factor. If there are any problems getting it, we just return 1
+ * (the default).
+ */
+ static ACE_UINT32 get_cpuinfo (void);
+#endif /* defined (linux) */
+
+private:
+ /**
+ * For internal use: gets the high-resolution time using
+ * <ACE_OS::gethrtime>. Except on platforms that require that the
+ * <global_scale_factor_> be set, such as ACE_WIN32, uses the
+ * low-resolution clock if the <global_scale_factor_> has not been
+ * set.
+ */
+ static ACE_hrtime_t gettime (const ACE_OS::ACE_HRTimer_Op =
+ ACE_OS::ACE_HRTIMER_GETTIME);
+
+ /// Starting time.
+ ACE_hrtime_t start_;
+
+ /// Ending time.
+ ACE_hrtime_t end_;
+
+ /// Total elapsed time.
+ ACE_hrtime_t total_;
+
+ /// Start time of incremental timing.
+ ACE_hrtime_t start_incr_;
+
+ /// Converts ticks to microseconds. That is, ticks /
+ /// global_scale_factor_ == microseconds.
+ static ACE_UINT32 global_scale_factor_;
+
+ /**
+ * Indicates the status of the global scale factor,
+ * 0 = hasn't been set
+ * 1 = been set
+ * -1 = HR timer not supported
+ */
+ static int global_scale_factor_status_;
+};
+
+#if defined (__ACE_INLINE__)
+#include "ace/High_Res_Timer.i"
+#endif /* __ACE_INLINE__ */
+
+#include "ace/post.h"
+#endif /* ACE_HIGH_RES_TIMER_H */
diff --git a/ace/Timer/High_Res_Timer.i b/ace/Timer/High_Res_Timer.i
new file mode 100644
index 00000000000..34c494dce16
--- /dev/null
+++ b/ace/Timer/High_Res_Timer.i
@@ -0,0 +1,158 @@
+/* -*- C++ -*- */
+// $Id$
+
+// Be very carefull before changing the calculations inside
+// ACE_High_Res_Timer. The precision matters and we are using integer
+// calculations not floating point. Also look good at the emulated 64
+// bit int class (inside Basic_Types{h,i,cpp} before changing
+// anything. It's operator/ only returns 32 bits not 64 bits, among
+// other things.
+
+ACE_INLINE void
+ACE_High_Res_Timer::hrtime_to_tv (ACE_Time_Value &tv,
+ const ACE_hrtime_t hrt)
+{
+ // The following are based on the units of global_scale_factor_
+ // being 1/microsecond. Therefore, dividing by it converts
+ // clock ticks to microseconds.
+ tv.sec ((long) (hrt / (ACE_UINT32) ACE_HR_SCALE_CONVERSION /
+ global_scale_factor ()));
+
+ // Calculate usec in a manner that's compatible with ACE_U_LongLong.
+ // hrt = (tv.sec * ACE_ONE_SECOND_IN_USECS + tv.usec) * global_scale_factor_
+ // tv.usec = hrt / global_scale_factor_ - tv.sec * ACE_ONE_SECOND_IN_USECS
+ // That first term will be lossy, so factor out global_scale_factor_:
+ // tv.usec = (hrt - tv.sec * ACE_ONE_SECOND_IN_USECS * global_scale_factor_)/
+ // global_scale_factor
+ ACE_hrtime_t tmp = tv.sec ();
+ tmp *= ((ACE_UINT32) ACE_HR_SCALE_CONVERSION * global_scale_factor ());
+#if defined (ACE_WIN32)
+ // Win32's scale factor is in ticks/msec, so multiply up to usec.
+ ACE_hrtime_t subsec = hrt - tmp; // Remainder of ticks < 1sec
+ ACE_UINT32 msec = (ACE_UINT32) (subsec / global_scale_factor ()); // #msec
+ ACE_hrtime_t usec64 = subsec - (msec * global_scale_factor ());
+# if defined (ACE_LACKS_LONGLONG_T)
+ ACE_UINT32 usec = usec64.lo();
+# else
+ ACE_UINT32 usec = (ACE_UINT32) usec64;
+# endif // ACE_LACKS_LONGLONG_T
+ // (tick * usec/msec) / tick/msec = usec
+ usec = (usec * 1000) / (ACE_UINT32) global_scale_factor ();
+ tv.usec ((msec * 1000) + usec);
+#else
+ tv.usec ((long) ((hrt - tmp) / global_scale_factor ()));
+#endif
+}
+
+
+ACE_INLINE ACE_Time_Value
+ACE_High_Res_Timer::gettimeofday (const ACE_OS::ACE_HRTimer_Op op)
+{
+#if defined (ACE_WIN32)
+ // Get the global scale factor if there isn't one yet.
+ if (ACE_High_Res_Timer::global_scale_factor_status_ == 0)
+ ACE_High_Res_Timer::global_scale_factor ();
+
+ // If there isn't a high-res timer, use gettimeofday ();
+ if (ACE_High_Res_Timer::global_scale_factor_status_ == -1)
+ return ACE_OS::gettimeofday ();
+#endif /* ACE_WIN32 */
+
+ ACE_Time_Value tv;
+ ACE_High_Res_Timer::hrtime_to_tv (tv,
+ ACE_OS::gethrtime (op));
+ return tv;
+}
+
+
+// Get the current high res timer as the time of day. This is intended
+// to be used for a gettimeofday replacement in ACE_Timer_Queue and
+// derived classes so the timers will bebased on high res timers rather
+// than wall clock time. It uses the ACE_High_Res_Timer::gettimeofday
+// function, which is deprecated. If it gets removed, please move the
+// code down here, intact.
+ACE_INLINE ACE_Time_Value
+ACE_High_Res_Timer::gettimeofday_hr (void)
+{
+ return ACE_High_Res_Timer::gettimeofday ();
+}
+
+
+ACE_INLINE ACE_hrtime_t
+ACE_High_Res_Timer::gettime (const ACE_OS::ACE_HRTimer_Op op)
+{
+#if defined (ACE_WIN32)
+ // Get the global scale factor if there isn't one yet.
+ if (ACE_High_Res_Timer::global_scale_factor_status_ == 0)
+ ACE_High_Res_Timer::global_scale_factor ();
+
+ // If there isn't a high-res timer, use gettimeofday ();
+ if (ACE_High_Res_Timer::global_scale_factor_status_ == -1)
+ {
+ ACE_Time_Value tv = ACE_OS::gettimeofday ();
+ // Return the time in microseconds because the global_scale_factor_
+ // is 1.
+ return tv.sec () * ACE_ONE_SECOND_IN_USECS + tv.usec ();
+ }
+#endif /* ACE_WIN32 */
+
+ return ACE_OS::gethrtime (op);
+}
+
+ACE_INLINE
+ACE_High_Res_Timer::~ACE_High_Res_Timer (void)
+{
+}
+
+ACE_INLINE void
+ACE_High_Res_Timer::start (const ACE_OS::ACE_HRTimer_Op op)
+{
+ ACE_TRACE ("ACE_High_Res_Timer::start");
+ this->start_ = ACE_High_Res_Timer::gettime (op);
+}
+
+ACE_INLINE void
+ACE_High_Res_Timer::stop (const ACE_OS::ACE_HRTimer_Op op)
+{
+ ACE_TRACE ("ACE_High_Res_Timer::stop");
+ this->end_ = ACE_High_Res_Timer::gettime (op);
+}
+
+ACE_INLINE void
+ACE_High_Res_Timer::start_incr (const ACE_OS::ACE_HRTimer_Op op)
+{
+ ACE_TRACE ("ACE_High_Res_Timer::start_incr");
+ this->start_incr_ = ACE_High_Res_Timer::gettime (op);
+}
+
+ACE_INLINE void
+ACE_High_Res_Timer::stop_incr (const ACE_OS::ACE_HRTimer_Op op)
+{
+ ACE_TRACE ("ACE_High_Res_Timer::stop_incr");
+ this->total_ += ACE_High_Res_Timer::gettime (op) - this->start_incr_;
+}
+
+ACE_INLINE void
+ACE_High_Res_Timer::elapsed_microseconds (ACE_hrtime_t &usecs) const
+{
+#if defined (ACE_WIN32)
+ // Win32 scale factor is in msec
+ // This could give overflow when measuring a long time with a
+ // big global_scale_factor() (> 48 days with a 4Ghz tick freq.)
+ // To be looked after in the future.
+ usecs = (ACE_hrtime_t) (((this->end_ - this->start_) * 1000) /
+ global_scale_factor ());
+#else
+ usecs =
+ (ACE_hrtime_t) ((this->end_ - this->start_) / global_scale_factor ());
+#endif
+
+
+
+}
+
+ACE_INLINE void
+ACE_High_Res_Timer::global_scale_factor (ACE_UINT32 gsf)
+{
+ global_scale_factor_ = gsf;
+}
diff --git a/ace/Timer/Profile_Timer.cpp b/ace/Timer/Profile_Timer.cpp
new file mode 100644
index 00000000000..2f4ef9f8f87
--- /dev/null
+++ b/ace/Timer/Profile_Timer.cpp
@@ -0,0 +1,418 @@
+// $Id$
+
+#include "ace/Profile_Timer.h"
+#include "ace/Log_Msg.h"
+
+#if !defined (__ACE_INLINE__)
+# include "ace/Profile_Timer.i"
+#endif /* __ACE_INLINE__ */
+
+ACE_RCSID(ace, Profile_Timer, "$Id$")
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Profile_Timer)
+
+#if (defined (ACE_HAS_PRUSAGE_T) || defined (ACE_HAS_GETRUSAGE)) && !defined (ACE_WIN32)
+
+void
+ACE_Profile_Timer::dump (void) const
+{
+ ACE_TRACE ("ACE_Profile_Timer::dump");
+}
+
+// Initialize interval timer.
+
+ACE_Profile_Timer::ACE_Profile_Timer (void)
+{
+ ACE_TRACE ("ACE_Profile_Timer::ACE_Profile_Timer");
+ ACE_OS::memset (&this->end_usage_, 0, sizeof this->end_usage_);
+ ACE_OS::memset (&this->begin_usage_, 0, sizeof this->begin_usage_);
+ ACE_OS::memset (&this->last_usage_, 0, sizeof this->last_usage_);
+
+# if defined (ACE_HAS_PRUSAGE_T)
+ ACE_OS::memset (&this->last_usage_, 0, sizeof this->last_usage_);
+ char buf[20];
+ ACE_OS::sprintf (buf, "/proc/%d", ACE_static_cast (int, ACE_OS::getpid ()));
+
+ this->proc_handle_ = ACE_OS::open (buf, O_RDONLY, 0);
+ if (this->proc_handle_ == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("%p\n"),
+ buf));
+# elif defined (ACE_HAS_GETRUSAGE)
+ ACE_OS::memset (&this->begin_time_, 0, sizeof this->begin_time_);
+ ACE_OS::memset (&this->end_time_, 0, sizeof this->end_time_);
+ ACE_OS::memset (&this->last_time_, 0, sizeof this->last_time_);
+# endif /* ACE_HAS_PRUSAGE_T */
+}
+
+// Terminate the interval timer.
+ACE_Profile_Timer::~ACE_Profile_Timer (void)
+{
+ ACE_TRACE ("ACE_Profile_Timer::~ACE_Profile_Timer");
+# if defined (ACE_HAS_PRUSAGE_T)
+ if (ACE_OS::close (this->proc_handle_) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("ACE_Profile_Timer::~ACE_Profile_Timer")));
+# endif /* ACE_HAS_PRUSAGE_T */
+}
+
+// Return the resource utilization.
+
+void
+ACE_Profile_Timer::get_rusage (ACE_Profile_Timer::Rusage &usage)
+{
+ ACE_TRACE ("ACE_Profile_Timer::get_rusage");
+ usage = this->end_usage_;
+}
+
+# if defined (ACE_HAS_PRUSAGE_T)
+
+// Compute the amount of resource utilization since the start time.
+
+void
+ACE_Profile_Timer::elapsed_rusage (ACE_Profile_Timer::Rusage &rusage)
+{
+ ACE_TRACE ("ACE_Profile_Timer::elapsed_rusage");
+ rusage.pr_lwpid =
+ this->end_usage_.pr_lwpid - this->last_usage_.pr_lwpid;
+ rusage.pr_count =
+ this->end_usage_.pr_count - this->last_usage_.pr_count;
+ rusage.pr_minf =
+ this->end_usage_.pr_minf - this->last_usage_.pr_minf;
+ rusage.pr_majf =
+ this->end_usage_.pr_majf - this->last_usage_.pr_majf;
+ rusage.pr_inblk =
+ this->end_usage_.pr_inblk - this->last_usage_.pr_inblk;
+ rusage.pr_oublk =
+ this->end_usage_.pr_oublk - this->last_usage_.pr_oublk;
+ rusage.pr_msnd =
+ this->end_usage_.pr_msnd - this->last_usage_.pr_msnd;
+ rusage.pr_mrcv =
+ this->end_usage_.pr_mrcv - this->last_usage_.pr_mrcv;
+ rusage.pr_sigs =
+ this->end_usage_.pr_sigs - this->last_usage_.pr_sigs;
+ this->subtract (rusage.pr_wtime,
+ this->end_usage_.pr_wtime,
+ this->last_usage_.pr_wtime);
+ this->subtract (rusage.pr_ltime,
+ this->end_usage_.pr_ltime,
+ this->last_usage_.pr_ltime);
+ this->subtract (rusage.pr_slptime,
+ this->end_usage_.pr_slptime,
+ this->last_usage_.pr_slptime);
+ rusage.pr_vctx =
+ this->end_usage_.pr_vctx - this->last_usage_.pr_vctx;
+ rusage.pr_ictx =
+ this->end_usage_.pr_ictx - this->last_usage_.pr_ictx;
+ rusage.pr_sysc =
+ this->end_usage_.pr_sysc - this->last_usage_.pr_sysc;
+ rusage.pr_ioch =
+ this->end_usage_.pr_ioch - this->last_usage_.pr_ioch;
+}
+
+// Compute the elapsed time.
+
+void
+ACE_Profile_Timer::compute_times (ACE_Elapsed_Time &et)
+{
+ ACE_TRACE ("ACE_Profile_Timer::compute_times");
+ timespec_t td;
+
+ ACE_Profile_Timer::Rusage &end = this->end_usage_;
+ ACE_Profile_Timer::Rusage &begin = this->begin_usage_;
+
+ this->subtract (td, end.pr_tstamp, begin.pr_tstamp);
+ // Convert nanoseconds into seconds.
+ et.real_time = td.tv_sec + ((double) td.tv_nsec) / ACE_ONE_SECOND_IN_NSECS;
+ this->subtract (td, end.pr_utime, begin.pr_utime);
+ // Convert nanoseconds into seconds.
+ et.user_time = td.tv_sec + ((double) td.tv_nsec) / ACE_ONE_SECOND_IN_NSECS;
+ this->subtract (td, end.pr_stime, begin.pr_stime);
+ // Convert nanoseconds into seconds.
+ et.system_time = td.tv_sec + ((double) td.tv_nsec) / ACE_ONE_SECOND_IN_NSECS;
+}
+
+// Determine the difference between T1 and T2.
+
+void
+ACE_Profile_Timer::subtract (timespec_t &tdiff, timespec_t &t1, timespec_t &t0)
+{
+ ACE_TRACE ("ACE_Profile_Timer::subtract");
+ tdiff.tv_sec = t1.tv_sec - t0.tv_sec;
+ tdiff.tv_nsec = t1.tv_nsec - t0.tv_nsec;
+
+ // Normalize the time.
+
+ while (tdiff.tv_nsec < 0)
+ {
+ tdiff.tv_sec--;
+ tdiff.tv_nsec += ACE_ONE_SECOND_IN_NSECS;
+ }
+}
+
+# elif defined (ACE_HAS_GETRUSAGE)
+// Compute the amount of resource utilization since the start time.
+
+void
+ACE_Profile_Timer::elapsed_rusage (ACE_Profile_Timer::Rusage &usage)
+{
+ ACE_TRACE ("ACE_Profile_Timer::elapsed_rusage");
+# if !defined (ACE_HAS_LIMITED_RUSAGE_T)
+ // integral shared memory size
+ usage.ru_ixrss =
+ this->end_usage_.ru_ixrss - this->last_usage_.ru_ixrss;
+ // integral unshared data "
+ usage.ru_idrss =
+ this->end_usage_.ru_idrss - this->last_usage_.ru_idrss;
+ // integral unshared stack "
+ usage.ru_isrss =
+ this->end_usage_.ru_isrss - this->last_usage_.ru_isrss;
+ // page reclaims - total vmfaults
+ usage.ru_minflt =
+ this->end_usage_.ru_minflt - this->last_usage_.ru_minflt;
+ // page faults
+ usage.ru_majflt =
+ this->end_usage_.ru_majflt - this->last_usage_.ru_majflt;
+ // swaps
+ usage.ru_nswap =
+ this->end_usage_.ru_nswap - this->last_usage_.ru_nswap;
+ // block input operations
+ usage.ru_inblock =
+ this->end_usage_.ru_inblock - this->last_usage_.ru_inblock;
+ // block output operations
+ usage.ru_oublock =
+ this->end_usage_.ru_oublock - this->last_usage_.ru_oublock;
+ // messages sent
+ usage.ru_msgsnd =
+ this->end_usage_.ru_msgsnd - this->last_usage_.ru_msgsnd;
+ // messages received
+ usage.ru_msgrcv =
+ this->end_usage_.ru_msgrcv - this->last_usage_.ru_msgrcv;
+ // signals received
+ usage.ru_nsignals =
+ this->end_usage_.ru_nsignals - this->last_usage_.ru_nsignals;
+ // voluntary context switches
+ usage.ru_nvcsw =
+ this->end_usage_.ru_nvcsw - this->last_usage_.ru_nvcsw;
+ // involuntary context switches
+ usage.ru_nivcsw =
+ this->end_usage_.ru_nivcsw - this->last_usage_.ru_nivcsw;
+ this->subtract (usage.ru_utime,
+ this->end_usage_.ru_utime,
+ this->last_usage_.ru_utime);
+ this->subtract (usage.ru_stime,
+ this->end_usage_.ru_stime,
+ this->last_usage_.ru_stime);
+# else
+ ACE_UNUSED_ARG(usage);
+# endif /* ACE_HAS_LIMITED_RUSAGE_T */
+}
+
+void
+ACE_Profile_Timer::compute_times (ACE_Elapsed_Time &et)
+{
+ ACE_TRACE ("ACE_Profile_Timer::compute_times");
+
+ timeval td;
+
+ this->subtract (td, this->end_time_, this->begin_time_);
+ et.real_time = td.tv_sec + ((double) td.tv_usec) / ACE_ONE_SECOND_IN_USECS;
+
+ this->subtract (td, this->end_usage_.ru_utime, this->begin_usage_.ru_utime);
+ et.user_time = td.tv_sec + ((double) td.tv_usec) / ACE_ONE_SECOND_IN_USECS;
+
+ this->subtract (td, this->end_usage_.ru_stime, this->begin_usage_.ru_stime);
+ et.system_time = td.tv_sec + ((double) td.tv_usec) / ACE_ONE_SECOND_IN_USECS;
+}
+
+// Determine the difference between T1 and T2.
+
+void
+ACE_Profile_Timer::subtract (timeval &tdiff, timeval &t1, timeval &t0)
+{
+ ACE_TRACE ("ACE_Profile_Timer::subtract");
+ tdiff.tv_sec = t1.tv_sec - t0.tv_sec;
+ tdiff.tv_usec = t1.tv_usec - t0.tv_usec;
+
+ // Normalize the time.
+
+ while (tdiff.tv_usec < 0)
+ {
+ tdiff.tv_sec--;
+ tdiff.tv_usec += ACE_ONE_SECOND_IN_USECS;
+ }
+}
+
+# endif /* ACE_HAS_PRUSAGE_T */
+
+// Compute the amount of time that has elapsed between start and stop.
+
+int
+ACE_Profile_Timer::elapsed_time (ACE_Elapsed_Time &et)
+{
+ ACE_TRACE ("ACE_Profile_Timer::elapsed_time");
+ this->compute_times (et);
+ return 0;
+}
+
+#elif defined (ACE_WIN32) /* defined (ACE_HAS_PRUSAGE_T) || defined (ACE_HAS_GETRUSAGE) */
+
+void
+ACE_Profile_Timer::dump (void) const
+{
+ ACE_TRACE ("ACE_Profile_Timer::dump");
+ timer_.dump ();
+}
+
+// Initialize interval timer.
+ACE_Profile_Timer::ACE_Profile_Timer (void)
+ : timer_ ()
+{
+ ACE_TRACE ("ACE_Profile_Timer::ACE_Profile_Timer");
+# if defined (ACE_HAS_GETRUSAGE)
+
+ ACE_OS::memset (&this->end_usage_, 0, sizeof this->end_usage_);
+ ACE_OS::memset (&this->begin_usage_, 0, sizeof this->begin_usage_);
+ ACE_OS::memset (&this->last_usage_, 0, sizeof this->last_usage_);
+
+ ACE_OS::memset (&this->begin_time_, 0, sizeof this->begin_time_);
+ ACE_OS::memset (&this->end_time_, 0, sizeof this->end_time_);
+ ACE_OS::memset (&this->last_time_, 0, sizeof this->last_time_);
+# endif /* ACE_HAS_GETRUSAGE */
+}
+
+int
+ACE_Profile_Timer::elapsed_time (ACE_Elapsed_Time &et)
+{
+ ACE_TRACE ("ACE_Profile_Timer::elapsed_time");
+
+ ACE_hrtime_t delta_t; // nanoseconds
+ timer_.elapsed_time (delta_t);
+# if defined (ACE_LACKS_LONGLONG_T)
+ et.real_time = delta_t / (double) ACE_ONE_SECOND_IN_NSECS;
+# else
+ et.real_time = (__int64) delta_t / (double) ACE_ONE_SECOND_IN_NSECS;
+# endif /* ACE_LACKS_LONGLONG_T */
+# if defined (ACE_HAS_GETRUSAGE)
+ ACE_Time_Value atv = ACE_Time_Value (this->end_usage_.ru_utime)
+ - ACE_Time_Value (this->begin_usage_.ru_utime);
+ et.user_time = atv.sec () + ((double) atv.usec ()) / ACE_ONE_SECOND_IN_USECS;
+
+ atv = ACE_Time_Value (this->end_usage_.ru_stime)
+ - ACE_Time_Value (this->begin_usage_.ru_stime);
+ et.system_time = atv.sec () + ((double) atv.usec ()) / ACE_ONE_SECOND_IN_USECS;
+# else /* ACE_HAS_GETRUSAGE */
+ et.user_time = 0;
+ et.system_time = 0;
+# endif /* ACE_HAS_GETRUSAGE */
+
+ return 0;
+}
+
+// Return the resource utilization.
+
+void
+ACE_Profile_Timer::get_rusage (ACE_Profile_Timer::Rusage &usage)
+{
+ ACE_TRACE ("ACE_Profile_Timer::get_rusage");
+# if defined (ACE_HAS_GETRUSAGE)
+ usage = this->end_usage_;
+# else /* ACE_HAS_GETRUSAGE */
+ usage = 0;
+# endif /* ACE_HAS_GETRUSAGE */
+}
+
+// Compute the amount of resource utilization since the start time.
+
+void
+ACE_Profile_Timer::elapsed_rusage (ACE_Profile_Timer::Rusage &usage)
+{
+ ACE_TRACE ("ACE_Profile_Timer::elapsed_rusage");
+
+# if defined (ACE_HAS_GETRUSAGE)
+ usage.ru_utime =
+ this->end_usage_.ru_utime - this->begin_usage_.ru_utime;
+ usage.ru_stime =
+ this->end_usage_.ru_stime - this->begin_usage_.ru_stime;
+# else /* ACE_HAS_GETRUSAGE */
+ usage = 0;
+# endif /* ACE_HAS_GETRUSAGE */
+}
+
+# if defined (ACE_HAS_GETRUSAGE)
+// Determine the difference between T1 and T2.
+
+void
+ACE_Profile_Timer::subtract (timeval &tdiff, timeval &t1, timeval &t0)
+{
+ ACE_TRACE ("ACE_Profile_Timer::subtract");
+ tdiff.tv_sec = t1.tv_sec - t0.tv_sec;
+ tdiff.tv_usec = t1.tv_usec - t0.tv_usec;
+
+ // Normalize the time.
+
+ while (tdiff.tv_usec < 0)
+ {
+ tdiff.tv_sec--;
+ tdiff.tv_usec += ACE_ONE_SECOND_IN_USECS;
+ }
+}
+# endif /* ACE_HAS_GETRUSAGE */
+
+#else
+
+void
+ACE_Profile_Timer::dump (void) const
+{
+ ACE_TRACE ("ACE_Profile_Timer::dump");
+ timer_.dump ();
+}
+
+ACE_Profile_Timer::ACE_Profile_Timer (void)
+ : timer_ ()
+{
+ ACE_TRACE ("ACE_Profile_Timer::ACE_Profile_Timer");
+}
+
+int
+ACE_Profile_Timer::elapsed_time (ACE_Elapsed_Time &et)
+{
+ ACE_TRACE ("ACE_Profile_Timer::elapsed_time");
+
+# if defined (ACE_LACKS_FLOATING_POINT)
+ ACE_Time_Value delta_t; /* elapsed time will be in microseconds */
+ timer_.elapsed_time (delta_t);
+
+ // Store the time in usecs.
+ et.real_time = delta_t.sec () * ACE_ONE_SECOND_IN_USECS +
+ delta_t.usec ();
+# else /* ! ACE_LACKS_FLOATING_POINT */
+ ACE_hrtime_t delta_t; /* nanoseconds */
+ timer_.elapsed_time (delta_t);
+
+ et.real_time = delta_t / (double) ACE_ONE_SECOND_IN_NSECS;
+# endif /* ! ACE_LACKS_FLOATING_POINT */
+
+ et.user_time = 0;
+ et.system_time = 0;
+
+ return 0;
+}
+
+void
+ACE_Profile_Timer::get_rusage (ACE_Profile_Timer::Rusage &usage)
+{
+ ACE_TRACE ("ACE_Profile_Timer::get_rusage");
+ usage = 0;
+}
+
+
+void
+ACE_Profile_Timer::elapsed_rusage (ACE_Profile_Timer::Rusage &usage)
+{
+ ACE_TRACE ("ACE_Profile_Timer::elapsed_rusage");
+ usage = 0;
+}
+
+#endif /* defined (ACE_HAS_PRUSAGE_T) ||
+ defined (ACE_HAS_GETRUSAGE) && !defined (ACE_WIN32) */
diff --git a/ace/Timer/Profile_Timer.h b/ace/Timer/Profile_Timer.h
new file mode 100644
index 00000000000..8bdacb52fbf
--- /dev/null
+++ b/ace/Timer/Profile_Timer.h
@@ -0,0 +1,133 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Profile_Timer.h
+ *
+ * $Id$
+ *
+ * @author Douglas C. Schmidt <schmidt@cs.wustl.edu>
+ */
+//=============================================================================
+
+
+#ifndef ACE_PROFILE_TIMER_H
+#define ACE_PROFILE_TIMER_H
+#include "ace/pre.h"
+
+#include "ace/ACE.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "ace/Time_Value.h"
+#include "ace/High_Res_Timer.h"
+
+/**
+ * @class ACE_Profile_Timer
+ *
+ * @brief This class provides both a timing mechanism and a mechanism
+ * for reporting the resource usage of a process.
+ */
+class ACE_Export ACE_Profile_Timer
+{
+public:
+
+ /**
+ * @class ACE_Elapsed_Time
+ *
+ * @brief Keeps track of the various user, system, and elapsed (real)
+ * times.
+ *
+ * If <ACE_HAS_FLOATING_POINT> is enabled these values are in
+ * microseconds, otherwise, they are in seconds.
+ */
+ class ACE_Elapsed_Time
+ {
+ public:
+ ACE_timer_t real_time;
+ ACE_timer_t user_time;
+ ACE_timer_t system_time;
+ };
+
+ typedef ACE_Rusage Rusage;
+
+ // = Initialization and termination methods.
+ /// Default constructor.
+ ACE_Profile_Timer (void);
+
+ /// Shutdown the timer.
+ ~ACE_Profile_Timer (void);
+
+ // = Timer methods.
+ /// Activate the timer.
+ int start (void);
+
+ /// Stop the timer.
+ int stop (void);
+
+ // = Resource utilization methods.
+ /// Compute the time elapsed since <start>.
+ int elapsed_time (ACE_Elapsed_Time &et);
+
+ /// Compute the amount of resource utilization since the start time.
+ void elapsed_rusage (ACE_Profile_Timer::Rusage &rusage);
+
+ /// Return the resource utilization (don't recompute it).
+ void get_rusage (ACE_Profile_Timer::Rusage &rusage);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+private:
+ /// Compute how much time has elapsed.
+ void compute_times (ACE_Elapsed_Time &et);
+
+ /// Keep track of the starting resource utilization.
+ ACE_Profile_Timer::Rusage begin_usage_;
+
+ /// Keep track of the ending resource utilization.
+ ACE_Profile_Timer::Rusage end_usage_;
+
+ /// Keep track of the last rusage for incremental timing.
+ ACE_Profile_Timer::Rusage last_usage_;
+
+#if defined (ACE_HAS_PRUSAGE_T)
+ /// Substract two timestructs and store their difference.
+ void subtract (timespec_t &tdiff, timespec_t &t0, timespec_t &t1);
+
+ /// I/O handle for /proc file system.
+ ACE_HANDLE proc_handle_;
+
+#elif defined (ACE_HAS_GETRUSAGE)
+ /// Substract two timestructs and store their difference.
+ void subtract (timeval &tdiff,
+ timeval &t0,
+ timeval &t1);
+
+ /// Keep track of the beginning time.
+ timeval begin_time_;
+
+ /// Keep track of the ending time.
+ timeval end_time_;
+
+ /// Keep track of the last time for incremental timing.
+ timeval last_time_;
+#endif /* ACE_HAS_PRUSAGE_T */
+
+#if defined (ACE_WIN32) || (!defined (ACE_HAS_PRUSAGE_T) && !defined (ACE_HAS_GETRUSAGE))
+ /// The high resolution timer
+ ACE_High_Res_Timer timer_;
+#endif /* ACE_WIN32 || !ACE_HAS_PRUSAGE_T && !ACE_HAS_GETRUSAGE */
+};
+
+#if defined (__ACE_INLINE__)
+# include "ace/Profile_Timer.i"
+#endif /* __ACE_INLINE__ */
+
+#include "ace/post.h"
+#endif /* ACE_PROFILE_TIMER_H */
diff --git a/ace/Timer/Profile_Timer.i b/ace/Timer/Profile_Timer.i
new file mode 100644
index 00000000000..e77af9b1686
--- /dev/null
+++ b/ace/Timer/Profile_Timer.i
@@ -0,0 +1,104 @@
+/* -*- C++ -*- */
+// $Id$
+
+#if (defined (ACE_HAS_PRUSAGE_T) || defined (ACE_HAS_GETRUSAGE)) && !defined (ACE_WIN32)
+
+# if defined (ACE_HAS_PRUSAGE_T)
+ACE_INLINE int
+ACE_Profile_Timer::start (void)
+{
+ ACE_TRACE ("ACE_Profile_Timer::start");
+ return ACE_OS::ioctl (this->proc_handle_,
+ PIOCUSAGE,
+ &this->begin_usage_);
+}
+
+ACE_INLINE int
+ACE_Profile_Timer::stop (void)
+{
+ ACE_TRACE ("ACE_Profile_Timer::stop");
+ this->last_usage_ = this->end_usage_;
+ return ACE_OS::ioctl (this->proc_handle_,
+ PIOCUSAGE,
+ &this->end_usage_);
+}
+# elif defined (ACE_HAS_GETRUSAGE)
+ACE_INLINE int
+ACE_Profile_Timer::start (void)
+{
+ ACE_TRACE ("ACE_Profile_Timer::start");
+ this->begin_time_ = ACE_OS::gettimeofday ();
+ ACE_OS::getrusage (RUSAGE_SELF,
+ &this->begin_usage_);
+ return 0;
+}
+
+ACE_INLINE int
+ACE_Profile_Timer::stop (void)
+{
+ ACE_TRACE ("ACE_Profile_Timer::stop");
+ this->last_time_ = this->end_time_;
+ this->end_time_ = ACE_OS::gettimeofday ();
+ this->last_usage_ = this->end_usage_;
+ ACE_OS::getrusage (RUSAGE_SELF,
+ &this->end_usage_);
+ return 0;
+}
+
+# endif /* ACE_HAS_PRUSAGE_T */
+
+#elif defined (ACE_WIN32)
+
+ACE_INLINE
+ACE_Profile_Timer::~ACE_Profile_Timer (void)
+{
+}
+
+ACE_INLINE int
+ACE_Profile_Timer::start (void)
+{
+ ACE_TRACE ("ACE_Profile_Timer::start");
+# if defined (ACE_HAS_GETRUSAGE)
+ ACE_OS::getrusage (RUSAGE_SELF,
+ &this->begin_usage_);
+# endif /* ACE_HAS_GETRUSAGE */
+ this->timer_.start ();
+ return 0;
+}
+
+ACE_INLINE int
+ACE_Profile_Timer::stop (void)
+{
+ ACE_TRACE ("ACE_Profile_Timer::stop");
+ this->timer_.stop ();
+# if defined (ACE_HAS_GETRUSAGE)
+ this->last_usage_ = this->end_usage_;
+ ACE_OS::getrusage (RUSAGE_SELF, &this->end_usage_);
+# endif /* ACE_HAS_GETRUSAGE */
+ return 0;
+}
+
+#else
+
+ACE_INLINE int
+ACE_Profile_Timer::start (void)
+{
+ ACE_TRACE ("ACE_Profile_Timer::start");
+ this->timer_.start ();
+ return 0;
+}
+
+ACE_INLINE int
+ACE_Profile_Timer::stop (void)
+{
+ ACE_TRACE ("ACE_Profile_Timer::stop");
+ this->timer_.stop ();
+ return 0;
+}
+
+ACE_INLINE
+ACE_Profile_Timer::~ACE_Profile_Timer (void)
+{
+}
+
+#endif /* defined (ACE_HAS_PRUSAGE_T) || defined (ACE_HAS_GETRUSAGE) */
diff --git a/ace/Timer/System_Time.cpp b/ace/Timer/System_Time.cpp
new file mode 100644
index 00000000000..9e2f2b69380
--- /dev/null
+++ b/ace/Timer/System_Time.cpp
@@ -0,0 +1,141 @@
+// System_Time.cpp
+// $Id$
+
+#include "ace/System_Time.h"
+
+ACE_RCSID(ace, System_Time, "$Id$")
+
+ACE_System_Time::ACE_System_Time (const ACE_TCHAR *poolname)
+ : delta_time_ (0)
+{
+ ACE_TRACE ("ACE_System_Time::ACE_System_Time");
+
+ // Only create a new unique filename for the memory pool file
+ // if the user didn't supply one...
+ if (poolname == 0)
+ {
+#if defined (ACE_DEFAULT_BACKING_STORE)
+ // Create a temporary file.
+ ACE_OS::strcpy (this->poolname_,
+ ACE_DEFAULT_BACKING_STORE);
+#else /* ACE_DEFAULT_BACKING_STORE */
+ if (ACE_Lib_Find::get_temp_dir (this->poolname_,
+ MAXPATHLEN - 17) == -1)
+ // -17 for ace-malloc-XXXXXX
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("Temporary path too long, ")
+ ACE_LIB_TEXT ("defaulting to current directory\n")));
+ this->poolname_[0] = 0;
+ }
+
+ // Add the filename to the end
+ ACE_OS::strcat (this->poolname_, ACE_LIB_TEXT ("ace-malloc-XXXXXX"));
+
+#endif /* ACE_DEFAULT_BACKING_STORE */
+ }
+ else
+ ACE_OS::strsncpy (this->poolname_,
+ poolname,
+ (sizeof this->poolname_ / sizeof (ACE_TCHAR)));
+
+ ACE_NEW (this->shmem_,
+ ALLOCATOR (this->poolname_));
+}
+
+ACE_System_Time::~ACE_System_Time (void)
+{
+ ACE_TRACE ("ACE_System_Time::~ACE_System_Time");
+ delete this->shmem_;
+}
+
+// Get the local system time.
+
+int
+ACE_System_Time::get_local_system_time (ACE_UINT32 &time_out)
+{
+ ACE_TRACE ("ACE_System_Time::get_local_system_time");
+ time_out = ACE_OS::time (0);
+ return 0;
+}
+
+int
+ACE_System_Time::get_local_system_time (ACE_Time_Value &time_out)
+{
+ ACE_TRACE ("ACE_System_Time::get_local_system_time");
+ time_out.sec (ACE_OS::time (0));
+ return 0;
+}
+
+// Get the system time of the central time server.
+
+int
+ACE_System_Time::get_master_system_time (ACE_UINT32 &time_out)
+{
+ ACE_TRACE ("ACE_System_Time::get_master_system_time");
+
+ if (this->delta_time_ == 0)
+ {
+ // Try to find it
+ void * temp;
+ if (this->shmem_->find (ACE_DEFAULT_TIME_SERVER_STR, temp) == -1)
+ {
+ // No time entry in shared memory (meaning no Clerk exists)
+ // so return the local time of the host.
+ return this->get_local_system_time (time_out);
+ }
+ else
+ // Extract the delta time.
+ this->delta_time_ = (long *) temp;
+ }
+
+ ACE_UINT32 local_time;
+
+ // If delta_time is positive, it means that the system clock is
+ // ahead of our local clock so add delta to the local time to get an
+ // approximation of the system time. Else if delta time is negative,
+ // it means that our local clock is ahead of the system clock, so
+ // return the last local time stored (to avoid time conflicts).
+ if (*this->delta_time_ >=0 )
+ {
+ this->get_local_system_time (local_time);
+ time_out = local_time + (ACE_UINT32) *this->delta_time_;
+ }
+ else
+ // Return the last local time. Note that this is stored as the
+ // second field in shared memory.
+ time_out = *(this->delta_time_ + 1);
+ return 0;
+}
+
+int
+ACE_System_Time::get_master_system_time (ACE_Time_Value &time_out)
+{
+ ACE_TRACE ("ACE_System_Time::get_master_system_time");
+ ACE_UINT32 to;
+ if (this->get_master_system_time (to) == -1)
+ return -1;
+ time_out.sec (to);
+ return 0;
+}
+
+// Synchronize local system time with the central time server using
+// specified mode (currently unimplemented).
+
+int
+ACE_System_Time::sync_local_system_time (ACE_System_Time::Sync_Mode)
+{
+ ACE_TRACE ("ACE_System_Time::sync_local_system_time");
+ ACE_NOTSUP_RETURN (-1);
+}
+
+#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION)
+template class ACE_Malloc_T<ACE_MMAP_MEMORY_POOL, ACE_Null_Mutex, ACE_Control_Block>;
+template class ACE_Malloc<ACE_MMAP_MEMORY_POOL, ACE_Null_Mutex>;
+template class ACE_Allocator_Adapter<ACE_Malloc<ACE_MMAP_MEMORY_POOL, ACE_Null_Mutex> >;
+#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA)
+#pragma instantiate ACE_Malloc_T<ACE_MMAP_MEMORY_POOL, ACE_Null_Mutex, ACE_Control_Block>
+#pragma instantiate ACE_Malloc<ACE_MMAP_MEMORY_POOL, ACE_Null_Mutex>
+#pragma instantiate ACE_Allocator_Adapter<ACE_Malloc<ACE_MMAP_MEMORY_POOL, ACE_Null_Mutex> >
+#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */
+
diff --git a/ace/Timer/System_Time.h b/ace/Timer/System_Time.h
new file mode 100644
index 00000000000..3374d031cac
--- /dev/null
+++ b/ace/Timer/System_Time.h
@@ -0,0 +1,87 @@
+/* -*- C++ -*- */
+
+
+//=============================================================================
+/**
+ * @file System_Time.h
+ *
+ * $Id$
+ *
+ * @author Prashant Jain
+ * @author Tim H. Harrison and Douglas C. Schmidt
+ */
+//=============================================================================
+
+
+#ifndef ACE_SYSTEM_TIME_H
+#define ACE_SYSTEM_TIME_H
+#include "ace/pre.h"
+
+#include "ace/OS.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "ace/Memory_Pool.h"
+#include "ace/Malloc_T.h"
+
+/**
+ * @class ACE_System_Time
+ *
+ * @brief Defines the timer services of the OS interface to access the
+ * system time either on the local host or on the central time
+ * server in the network.
+ */
+class ACE_Export ACE_System_Time
+{
+public:
+ /**
+ * enumeration types to specify mode of synchronization with master
+ * clock. Jump will set local system time directly (thus possibly
+ * producing time gaps or ambiguous local system times. Adjust will
+ * smoothly slow down or speed up the local system clock to reach
+ * the system time of the master clock.
+ */
+ enum Sync_Mode { Jump, Adjust };
+
+ /// Default constructor.
+ ACE_System_Time (const ACE_TCHAR *poolname = 0);
+
+ /// Default destructor.
+ ~ACE_System_Time (void);
+
+ /// Get the local system time, i.e., the value returned by
+ /// <ACE_OS::time>.
+ static int get_local_system_time (ACE_UINT32 &time_out);
+
+ /// Get the local system time, i.e., the value returned by
+ /// <ACE_OS::time>.
+ static int get_local_system_time (ACE_Time_Value &time_out);
+
+ /// Get the system time of the central time server.
+ int get_master_system_time (ACE_UINT32 &time_out);
+
+ /// Get the system time of the central time server.
+ int get_master_system_time (ACE_Time_Value &time_out);
+
+ /// synchronize local system time with the central time server using
+ /// specified mode.
+ int sync_local_system_time (ACE_System_Time::Sync_Mode mode);
+
+private:
+ typedef ACE_Malloc <ACE_MMAP_MEMORY_POOL, ACE_Null_Mutex> MALLOC;
+ typedef ACE_Allocator_Adapter<MALLOC> ALLOCATOR;
+
+ /// Our allocator (used for obtaining system time from shared memory).
+ ALLOCATOR *shmem_;
+
+ /// The name of the pool used by the allocator.
+ ACE_TCHAR poolname_[MAXPATHLEN + 1];
+
+ /// Pointer to delta time kept in shared memory.
+ long *delta_time_;
+};
+
+#include "ace/post.h"
+#endif /* ACE_SYSTEM_TIME_H */
diff --git a/ace/Timer/Time_Request_Reply.cpp b/ace/Timer/Time_Request_Reply.cpp
new file mode 100644
index 00000000000..79a17254de2
--- /dev/null
+++ b/ace/Timer/Time_Request_Reply.cpp
@@ -0,0 +1,188 @@
+// $Id$
+
+#include "ace/Time_Request_Reply.h"
+#include "ace/Log_Msg.h"
+
+ACE_RCSID(ace, Time_Request_Reply, "$Id$")
+
+// Default "do nothing" constructor.
+
+ACE_Time_Request::ACE_Time_Request (void)
+{
+ ACE_TRACE ("ACE_Time_Request::ACE_Time_Request");
+}
+
+// Create a ACE_Time_Request message.
+
+ACE_Time_Request::ACE_Time_Request (ACE_INT32 t, // Type of request.
+ const ACE_UINT32 time,
+ ACE_Time_Value *timeout) // Max time waiting for request.
+{
+ ACE_TRACE ("ACE_Time_Request::ACE_Time_Request");
+ this->msg_type (t);
+
+ // If timeout is a NULL pointer, then block forever...
+ if (timeout == 0)
+ {
+ this->transfer_.block_forever_ = 1;
+ this->transfer_.sec_timeout_ = 0;
+ this->transfer_.usec_timeout_ = 0;
+ }
+ else // Do a "timed wait."
+ {
+ this->block_forever (0);
+ // Keep track of how long client is willing to wait.
+ this->transfer_.sec_timeout_ = timeout->sec ();
+ this->transfer_.usec_timeout_ = timeout->usec ();
+ }
+
+ // Copy time into request
+ this->time_ = this->transfer_.time_ = time;
+}
+
+// Initialize length_ in order to avoid problems with byte-ordering
+void
+ACE_Time_Request::init (void)
+{
+ ACE_TRACE ("ACE_Time_Request::init");
+// this->length (sizeof this->transfer_);
+}
+
+// Get the fixed size of message
+ssize_t
+ACE_Time_Request::size (void) const
+{
+ ACE_TRACE ("ACE_Time_Request::size");
+ return sizeof (this->transfer_);
+}
+
+// = Set/get the type of the message.
+ACE_INT32
+ACE_Time_Request::msg_type (void) const
+{
+ ACE_TRACE ("ACE_Time_Request::msg_type");
+ return this->transfer_.msg_type_;
+}
+
+void
+ACE_Time_Request::msg_type (ACE_INT32 t)
+{
+ ACE_TRACE ("ACE_Time_Request::msg_type");
+ this->transfer_.msg_type_ = t;
+}
+
+// = Set/get the blocking semantics.
+ACE_UINT32
+ACE_Time_Request::block_forever (void) const
+{
+ ACE_TRACE ("ACE_Time_Request::block_forever");
+ return this->transfer_.block_forever_;
+}
+
+void
+ACE_Time_Request::block_forever (ACE_UINT32 bs)
+{
+ ACE_TRACE ("ACE_Time_Request::block_forever");
+ this->transfer_.block_forever_ = bs;
+}
+
+// = Set/get the timeout.
+ACE_Time_Value
+ACE_Time_Request::timeout (void) const
+{
+ ACE_TRACE ("ACE_Time_Request::timeout");
+ return ACE_Time_Value (this->transfer_.sec_timeout_, this->transfer_.usec_timeout_);
+}
+
+void
+ACE_Time_Request::timeout (const ACE_Time_Value timeout)
+{
+ ACE_TRACE ("ACE_Time_Request::timeout");
+ this->transfer_.sec_timeout_ = timeout.sec ();
+ this->transfer_.usec_timeout_ = timeout.usec ();
+}
+
+// = Set/get the time
+ACE_UINT32
+ACE_Time_Request::time (void) const
+{
+ ACE_TRACE ("ACE_Time_Request::time");
+ return this->time_;
+}
+
+void
+ACE_Time_Request::time (ACE_UINT32 t)
+{
+ ACE_TRACE ("ACE_Time_Request::time");
+ this->time_ = t;
+}
+
+// Encode the transfer buffer into network byte order
+// so that it can be sent to the server.
+int
+ACE_Time_Request::encode (void *&buf)
+{
+ ACE_TRACE ("ACE_Time_Request::encode");
+ // Compute the length *before* doing the marshaling.
+
+ buf = (void *) &this->transfer_;
+ this->transfer_.block_forever_ = htonl (this->transfer_.block_forever_);
+ this->transfer_.usec_timeout_ = htonl (this->transfer_.usec_timeout_);
+ this->transfer_.sec_timeout_ = htonl (this->transfer_.sec_timeout_);
+ this->transfer_.msg_type_ = htonl (this->transfer_.msg_type_);
+ this->transfer_.time_ = htonl (this->transfer_.time_);
+
+ return this->size (); // Always fixed
+}
+
+// Decode the transfer buffer into host byte byte order
+// so that it can be used by the server.
+int
+ACE_Time_Request::decode (void)
+{
+ ACE_TRACE ("ACE_Time_Request::decode");
+ // Decode
+ this->transfer_.block_forever_ = ntohl (this->transfer_.block_forever_);
+ this->transfer_.usec_timeout_ = ntohl (this->transfer_.usec_timeout_);
+ this->transfer_.sec_timeout_ = ntohl (this->transfer_.sec_timeout_);
+ this->transfer_.msg_type_ = ntohl (this->transfer_.msg_type_);
+ this->transfer_.time_ = ntohl (this->transfer_.time_);
+
+ this->time_ = this->transfer_.time_;
+ return 0;
+}
+
+// Print out the current values of the ACE_Time_Request.
+
+void
+ACE_Time_Request::dump (void) const
+{
+ ACE_TRACE ("ACE_Time_Request::dump");
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("*******\nlength = %d\n"),
+ this->size ()));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("message-type = ")));
+
+ switch (this->msg_type ())
+ {
+ case ACE_Time_Request::TIME_UPDATE:
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("TIME_UPDATE\n")));
+ break;
+ default:
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("<unknown type> = %d\n"), this->msg_type ()));
+ break;
+ }
+
+ if (this->block_forever ())
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("blocking forever\n")));
+ else
+ {
+#if !defined (ACE_NLOGGING)
+ ACE_Time_Value tv = this->timeout ();
+#endif /* ! ACE_NLOGGING */
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("waiting for %d secs and %d usecs\n"),
+ tv.sec (), tv.usec ()));
+ }
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("*******\ntime = %d\n"),
+ this->time ()));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("+++++++\n")));
+}
diff --git a/ace/Timer/Time_Request_Reply.h b/ace/Timer/Time_Request_Reply.h
new file mode 100644
index 00000000000..e50f96b0182
--- /dev/null
+++ b/ace/Timer/Time_Request_Reply.h
@@ -0,0 +1,121 @@
+/* -*- C++ -*- */
+//=============================================================================
+/**
+ * @file Time_Request_Reply.h
+ *
+ * $Id$
+ *
+ * Define the format used to exchange messages between the
+ * ACE_Time_Server and clerks.
+ *
+ * @author Prashant Jain
+ */
+//=============================================================================
+
+
+#ifndef ACE_TIME_REQUEST_REPLY_H
+#define ACE_TIME_REQUEST_REPLY_H
+#include "ace/pre.h"
+
+#include "ace/Time_Value.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "ace/SString.h"
+
+/**
+ * @class ACE_Time_Request
+ *
+ * @brief Message format for delivering requests to the ACE_Time Server.
+ *
+ * This class is implemented to minimize data copying.
+ * In particular, all marshaling is done in situ...
+ */
+class ACE_Export ACE_Time_Request
+{
+public:
+ enum Constants
+ {
+ /// Request message types.
+ TIME_UPDATE = 01,
+
+ /// Class-specific constant values.
+ MAX_TIME_LEN = MAXPATHLEN + 1
+ };
+
+ /// Default constructor.
+ ACE_Time_Request (void);
+
+ /// Create a <ACE_Time_Request> message.
+ ACE_Time_Request (ACE_INT32 msg_type, // Type of request.
+ const ACE_UINT32 time,
+ ACE_Time_Value *timeout = 0); // Max time waiting for request.
+
+ /// Initialize length_ in order to ensure correct byte ordering
+ /// before a request is sent.
+ void init (void);
+
+ // Get the fixed size of message
+ ssize_t size (void) const;
+
+ // = Set/get the type of the message.
+ ACE_INT32 msg_type (void) const;
+ void msg_type (ACE_INT32);
+
+ // = Set/get the time
+ ACE_UINT32 time (void) const;
+ void time (ACE_UINT32 t);
+
+ // = Set/get the blocking semantics.
+ ACE_UINT32 block_forever (void) const;
+ void block_forever (ACE_UINT32);
+
+ // = Set/get the timeout.
+ ACE_Time_Value timeout (void) const;
+ void timeout (const ACE_Time_Value timeout);
+
+ /// Encode the message before transmission.
+ int encode (void *&);
+
+ /// Decode message after reception.
+ int decode (void);
+
+ /// Print out the values of the message for debugging purposes.
+ void dump (void) const;
+
+private:
+ // = The 5 fields in the <Transfer> struct are transmitted to the server.
+ // The remaining 2 fields are not tranferred -- they are used only on
+ // the server-side to simplify lookups.
+
+ struct Transfer
+ {
+ ACE_INT32 msg_type_;
+ // Type of the request (i.e., <TIME_UPDATE>)
+
+ ACE_UINT32 block_forever_;
+ // Indicates if we should block forever. If 0, then <secTimeout_>
+ // and <usecTimeout_> indicates how long we should wait.
+
+ ACE_UINT32 sec_timeout_;
+ // Max seconds willing to wait for name if not blocking forever.
+
+ ACE_UINT32 usec_timeout_;
+ // Max micro seconds to wait for name if not blocking forever.
+
+ ACE_UINT32 time_;
+ // The data portion contains <time_>
+ };
+
+ /// Transfer buffer.
+ Transfer transfer_;
+
+ /// Time
+ ACE_UINT32 time_;
+};
+
+
+#include "ace/post.h"
+#endif /* ACE_TIME_REQUEST_REPLY_H */
diff --git a/ace/Timer/Time_Value.h b/ace/Timer/Time_Value.h
new file mode 100644
index 00000000000..e9fa59e27f7
--- /dev/null
+++ b/ace/Timer/Time_Value.h
@@ -0,0 +1,28 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Time_Value.h
+ *
+ * $Id$
+ *
+ * @author Doug Schmidt
+ */
+//=============================================================================
+
+
+#ifndef ACE_TIME_VALUE_H
+#define ACE_TIME_VALUE_H
+#include "ace/pre.h"
+
+// This file is no longer used and is only here due to backwards
+// compatibility. All the functionality has been merged into OS.h.
+
+#include "ace/OS/OS.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "ace/post.h"
+#endif /* ACE_TIME_VALUE */
diff --git a/ace/Timer/Timeprobe.cpp b/ace/Timer/Timeprobe.cpp
new file mode 100644
index 00000000000..cdfdb116913
--- /dev/null
+++ b/ace/Timer/Timeprobe.cpp
@@ -0,0 +1,44 @@
+// $Id$
+
+#include "ace/OS.h"
+
+ACE_RCSID(ace, Timeprobe, "$Id$")
+
+#if defined (ACE_COMPILE_TIMEPROBES)
+
+#include "ace/Timeprobe.h"
+
+#if !defined (__ACE_INLINE__)
+#include "ace/Timeprobe.i"
+#endif /* __ACE_INLINE__ */
+
+#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION)
+template class ACE_Timeprobe<ACE_TIMEPROBE_MUTEX>;
+template class ACE_Function_Timeprobe<ACE_Timeprobe<ACE_TIMEPROBE_MUTEX> >;
+template class ACE_Unbounded_Set_Iterator<ACE_Event_Descriptions>;
+template class ACE_Unbounded_Set<ACE_Event_Descriptions>;
+template class ACE_Node<ACE_Event_Descriptions>;
+#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA)
+#pragma instantiate ACE_Timeprobe<ACE_TIMEPROBE_MUTEX>
+#pragma instantiate ACE_Function_Timeprobe<ACE_Timeprobe<ACE_TIMEPROBE_MUTEX> >
+#pragma instantiate ACE_Unbounded_Set_Iterator<ACE_Event_Descriptions>
+#pragma instantiate ACE_Unbounded_Set<ACE_Event_Descriptions>
+#pragma instantiate ACE_Node<ACE_Event_Descriptions>
+#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */
+
+# if defined (ACE_TSS_TIMEPROBES)
+#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION)
+template class ACE_TSS_Singleton<ACE_TIMEPROBE_WITH_LOCKING, ACE_SYNCH_NULL_MUTEX>;
+#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA)
+#pragma instantiate ACE_TSS_Singleton<ACE_TIMEPROBE_WITH_LOCKING, ACE_SYNCH_NULL_MUTEX>
+#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */
+# else /* ACE_TSS_TIMEPROBES */
+#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION)
+template class ACE_Singleton<ACE_TIMEPROBE_WITH_LOCKING, ACE_SYNCH_MUTEX>;
+#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA)
+#pragma instantiate ACE_Singleton<ACE_TIMEPROBE_WITH_LOCKING, ACE_SYNCH_MUTEX>
+#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */
+# endif /* ACE_TSS_TIMEPROBES */
+
+#endif /* ACE_COMPILE_TIMEPROBES */
+
diff --git a/ace/Timer/Timeprobe.h b/ace/Timer/Timeprobe.h
new file mode 100644
index 00000000000..91033b54ece
--- /dev/null
+++ b/ace/Timer/Timeprobe.h
@@ -0,0 +1,176 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Timeprobe.h
+ *
+ * $Id$
+ *
+ * @author Irfan Pyarali
+ *
+ * If users want to use time probes the ACE_COMPILE_TIMEPROBES flag
+ * must be defined when compiling ACE. This can be achieved by doing
+ * one of the following: . Use make probe = 1 if you are using the
+ * make utility. . Define ACE_COMPILE_TIMEPROBES in config.h . Define
+ * ACE_COMPILE_TIMEPROBES in the VC project file. . Other regular
+ * methods will also work. It is not necessary to define
+ * ACE_COMPILE_TIMEPROBES when using time probes you simply need
+ * ACE_ENABLE_TIMEPROBES. You can use the ACE_TIMEPROBE_* macros to
+ * program the time probes and use the ACE_ENABLE_TIMEPROBE to enable
+ * the time probes. If you define ACE_ENABLE_TIMEPROBE in your code
+ * but forget to compile ACE with ACE_COMPILE_TIMEPROBES you will end
+ * up with linker errors. Remember that ACE_COMPILE_TIMEPROBES means
+ * that the ACE library will contain code for time probes. This is
+ * only useful when compiling ACE. ACE_ENABLE_TIMEPROBES means that
+ * the ACE_TIMEPROBE_* macros should spring to life.
+ *
+ */
+//=============================================================================
+
+
+#ifndef ACE_TIMEPROBE_H
+#define ACE_TIMEPROBE_H
+#include "ace/pre.h"
+
+#include "ace/OS.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#if defined (ACE_ENABLE_TIMEPROBES)
+ #if !defined (ACE_COMPILE_TIMEPROBES)
+ #define ACE_COMPILE_TIMEPROBES
+ #endif /* ACE_COMPILE_TIMEPROBES */
+#endif /* ACE_ENABLE_TIMEPROBES */
+
+#if defined (ACE_COMPILE_TIMEPROBES)
+
+/**
+ * @class ACE_Event_Descriptions
+ *
+ * @brief Event Descriptions.
+ */
+class ACE_Export ACE_Event_Descriptions
+{
+public:
+ /// Event descriptions
+ const char **descriptions_;
+
+ /// Minimum id of this description set
+ u_long minimum_id_;
+
+ /// Comparison
+ int operator== (const ACE_Event_Descriptions &rhs) const;
+};
+
+/**
+ * @class ACE_timeprobe_t
+ *
+ * @brief Time probe record.
+ */
+class ACE_Export ACE_timeprobe_t
+{
+public:
+ /// Events are record as strings or numbers.
+ union event
+ {
+ u_long event_number_;
+ const char *event_description_;
+ };
+
+ /// Type of event.
+ enum event_type
+ {
+ NUMBER,
+ STRING
+ };
+
+ /// Event.
+ event event_;
+
+ /// Type of event.
+ event_type event_type_;
+
+ /// Timestamp.
+ ACE_hrtime_t time_;
+
+ /// Id of thread posting the time probe.
+ ACE_thread_t thread_;
+};
+
+#if defined (__ACE_INLINE__)
+#include "ace/Timeprobe.i"
+#endif /* __ACE_INLINE__ */
+
+#include "ace/Synch.h"
+#include "ace/Singleton.h"
+#include "ace/Timeprobe_T.h"
+
+// If ACE_MT_TIMEPROBES is defined, use a Thread_Mutex to lock the
+// internal state of ACE_Timerprobe. This allows multiple threads to
+// use the same ACE_Timerprobe.
+# if defined (ACE_MT_TIMEPROBES)
+typedef ACE_SYNCH_MUTEX ACE_TIMEPROBE_MUTEX;
+# else /* ACE_MT_TIMEPROBES */
+typedef ACE_SYNCH_NULL_MUTEX ACE_TIMEPROBE_MUTEX;
+# endif /* ACE_MT_TIMEPROBES */
+
+typedef ACE_Timeprobe<ACE_TIMEPROBE_MUTEX>
+ ACE_TIMEPROBE_WITH_LOCKING;
+
+// If ACE_TSS_TIMEPROBES is defined, store the ACE_Timeprobe singleton
+// in thread specific storage. This allows multiple threads to use
+// their own instance of ACE_Timerprobe, without interfering with each
+// other.
+# if defined (ACE_TSS_TIMEPROBES)
+# define ACE_TIMEPROBE_SINGLETON_TYPE ACE_TSS_Singleton
+# define ACE_TIMEPROBE_SINGLETON_LOCK_TYPE ACE_SYNCH_NULL_MUTEX
+# else /* ACE_TSS_TIMEPROBES */
+# define ACE_TIMEPROBE_SINGLETON_TYPE ACE_Singleton
+# define ACE_TIMEPROBE_SINGLETON_LOCK_TYPE ACE_SYNCH_MUTEX
+# endif /* ACE_TSS_TIMEPROBES */
+
+#if defined (_MSC_VER)
+// Disable warning of using Microsoft Extension.
+#pragma warning(disable:4231)
+#endif /* _MSC_VER */
+
+typedef ACE_TIMEPROBE_SINGLETON_TYPE<ACE_TIMEPROBE_WITH_LOCKING, ACE_TIMEPROBE_SINGLETON_LOCK_TYPE>
+ ACE_TIMEPROBE_SINGLETON;
+
+ACE_SINGLETON_DECLARE (ACE_TIMEPROBE_SINGLETON_TYPE, \
+ ACE_TIMEPROBE_WITH_LOCKING, \
+ ACE_TIMEPROBE_SINGLETON_LOCK_TYPE);
+
+#if defined (_MSC_VER)
+// Default back the warning of using Microsoft Extension.
+#pragma warning(default:4231)
+#endif /* _MSC_VER */
+
+#endif /* ACE_COMPILE_TIMEPROBES */
+
+// If ACE_ENABLE_TIMEPROBES is defined, the macros below will
+// work. Otherwise, they just vanish. Using this macro, you can
+// control which files/libraries are probed.
+#if defined (ACE_ENABLE_TIMEPROBES) && defined (ACE_COMPILE_TIMEPROBES)
+
+# define ACE_TIMEPROBE_RESET ACE_TIMEPROBE_SINGLETON::instance ()->reset ()
+# define ACE_TIMEPROBE(id) ACE_TIMEPROBE_SINGLETON::instance ()->timeprobe (id)
+# define ACE_TIMEPROBE_PRINT ACE_TIMEPROBE_SINGLETON::instance ()->print_times ()
+# define ACE_TIMEPROBE_PRINT_ABSOLUTE ACE_TIMEPROBE_SINGLETON::instance ()->print_absolute_times ()
+# define ACE_TIMEPROBE_EVENT_DESCRIPTIONS(descriptions, minimum_id) static int ace_timeprobe_##descriptions##_return = ACE_TIMEPROBE_SINGLETON::instance ()->event_descriptions (descriptions, minimum_id)
+# define ACE_FUNCTION_TIMEPROBE(X) ACE_Function_Timeprobe<ACE_TIMEPROBE_WITH_LOCKING> function_timeprobe (*ACE_TIMEPROBE_SINGLETON::instance (), X)
+
+#else /* ACE_ENABLE_TIMEPROBES && ACE_COMPILE_TIMEPROBES */
+
+# define ACE_TIMEPROBE_RESET
+# define ACE_TIMEPROBE(id)
+# define ACE_TIMEPROBE_PRINT
+# define ACE_TIMEPROBE_PRINT_ABSOLUTE
+# define ACE_TIMEPROBE_EVENT_DESCRIPTIONS(descriptions, minimum_id)
+# define ACE_FUNCTION_TIMEPROBE(X)
+
+#endif /* ACE_ENABLE_TIMEPROBES && ACE_COMPILE_TIMEPROBES */
+#include "ace/post.h"
+#endif /* ACE_TIMEPROBE_H */
diff --git a/ace/Timer/Timeprobe.i b/ace/Timer/Timeprobe.i
new file mode 100644
index 00000000000..31f022f77b4
--- /dev/null
+++ b/ace/Timer/Timeprobe.i
@@ -0,0 +1,8 @@
+// $Id$
+
+ACE_INLINE int
+ACE_Event_Descriptions::operator== (const ACE_Event_Descriptions &rhs) const
+{
+ return this->minimum_id_ == rhs.minimum_id_ &&
+ this->descriptions_ == rhs.descriptions_;
+}
diff --git a/ace/Timer/Timeprobe_T.cpp b/ace/Timer/Timeprobe_T.cpp
new file mode 100644
index 00000000000..988565ccee1
--- /dev/null
+++ b/ace/Timer/Timeprobe_T.cpp
@@ -0,0 +1,300 @@
+// $Id$
+
+#ifndef ACE_TIMEPROBE_T_C
+#define ACE_TIMEPROBE_T_C
+
+#include "ace/OS.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+ACE_RCSID(ace, Timeprobe_T, "$Id$")
+
+#if defined (ACE_COMPILE_TIMEPROBES)
+
+#include "ace/Timeprobe.h"
+#include "ace/High_Res_Timer.h"
+
+template <class ACE_LOCK>
+ACE_Timeprobe<ACE_LOCK>::ACE_Timeprobe (u_long size)
+ : timeprobes_ (0),
+ lock_ (),
+ max_size_ (size),
+ current_size_ (0)
+{
+ ACE_NEW (this->timeprobes_,
+ ACE_timeprobe_t[this->max_size_]);
+
+#if defined (VXWORKS)
+ if (sysProcNumGet () == 0)
+ this->current_slot_vme_address_ = (u_int *) 0xDa010000;
+ else
+ this->current_slot_vme_address_ = (u_int *) 0xD8010000;
+#endif /* VXWORKS */
+}
+
+template <class ACE_LOCK>
+ACE_Timeprobe<ACE_LOCK>::ACE_Timeprobe (const ACE_Timeprobe<ACE_LOCK> &)
+{
+ //
+ // Stupid MSVC is forcing me to define this; please don't use it.
+ //
+
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("ACE_NOTSUP: %s, line %d\n"), __FILE__, __LINE__));
+ errno = ENOTSUP;
+}
+
+template <class ACE_LOCK>
+ACE_Timeprobe<ACE_LOCK>::~ACE_Timeprobe (void)
+{
+ delete [] this->timeprobes_;
+}
+
+template <class ACE_LOCK> void
+ACE_Timeprobe<ACE_LOCK>::timeprobe (u_long event)
+{
+ ACE_GUARD (ACE_LOCK, ace_mon, this->lock_);
+
+ ACE_ASSERT (this->current_size_ < this->max_size_);
+
+ this->timeprobes_[this->current_size_].event_.event_number_ = event;
+ this->timeprobes_[this->current_size_].event_type_ = ACE_timeprobe_t::NUMBER;
+ this->timeprobes_[this->current_size_].time_ = ACE_OS::gethrtime ();
+ this->timeprobes_[this->current_size_].thread_ = ACE_OS::thr_self ();
+
+ this->current_size_++;
+
+#if defined (VMETRO_TIME_TEST) && (VXWORKS)
+ // If we are using the VMETRO board to get time samples, then write
+ // to the other boards VME address.
+ *this->current_slot_vme_address_ = event;
+#endif /* VMETRO_TIME_TEST && VXWORKS */
+}
+
+template <class ACE_LOCK> void
+ACE_Timeprobe<ACE_LOCK>::timeprobe (const char *event)
+{
+ ACE_GUARD (ACE_LOCK, ace_mon, this->lock_);
+
+ ACE_ASSERT (this->current_size_ < this->max_size_);
+
+ this->timeprobes_[this->current_size_].event_.event_description_ = event;
+ this->timeprobes_[this->current_size_].event_type_ = ACE_timeprobe_t::STRING;
+ this->timeprobes_[this->current_size_].time_ = ACE_OS::gethrtime ();
+ this->timeprobes_[this->current_size_].thread_ = ACE_OS::thr_self ();
+
+ this->current_size_++;
+}
+
+template <class ACE_LOCK> void
+ACE_Timeprobe<ACE_LOCK>::reset (void)
+{
+ ACE_GUARD (ACE_LOCK, ace_mon, this->lock_);
+
+ this->current_size_ = 0;
+}
+
+template <class ACE_LOCK> ACE_Unbounded_Set<ACE_Event_Descriptions> &
+ACE_Timeprobe<ACE_LOCK>::event_descriptions (void)
+{
+ return this->event_descriptions_;
+}
+
+template <class ACE_LOCK> ACE_Unbounded_Set<ACE_Event_Descriptions> &
+ACE_Timeprobe<ACE_LOCK>::sorted_event_descriptions (void)
+{
+ return this->sorted_event_descriptions_;
+}
+
+template <class ACE_LOCK> u_int *
+ACE_Timeprobe<ACE_LOCK>::current_slot_vme_address (void)
+{
+ return this->current_slot_vme_address_;
+}
+
+template <class ACE_LOCK> ACE_timeprobe_t *
+ACE_Timeprobe<ACE_LOCK>::timeprobes (void)
+{
+ return this->timeprobes_;
+}
+
+template <class ACE_LOCK> ACE_LOCK &
+ACE_Timeprobe<ACE_LOCK>::lock (void)
+{
+ return this->lock_;
+}
+
+template <class ACE_LOCK> u_long
+ACE_Timeprobe<ACE_LOCK>::max_size (void)
+{
+ return this->max_size_;
+}
+
+template <class ACE_LOCK> u_long
+ACE_Timeprobe<ACE_LOCK>::current_size (void)
+{
+ return this->current_size_;
+}
+
+template <class ACE_LOCK> int
+ACE_Timeprobe<ACE_LOCK>::event_descriptions (const char **descriptions,
+ u_long minimum_id)
+{
+ ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->lock_, -1);
+
+ ACE_Event_Descriptions events;
+ events.descriptions_ = descriptions;
+ events.minimum_id_ = minimum_id;
+
+ this->event_descriptions_.insert (events);
+
+ return 0;
+}
+
+template <class ACE_LOCK> void
+ACE_Timeprobe<ACE_LOCK>::print_times (void)
+{
+ ACE_GUARD (ACE_LOCK, ace_mon, this->lock_);
+
+ // Sort the event descriptions
+ this->sort_event_descriptions_i ();
+
+ ACE_DEBUG ((LM_DEBUG,
+ "\nACE_Timeprobe; %d timestamps were recorded:\n",
+ this->current_size_));
+
+ if (this->current_size_ == 0)
+ return;
+
+ ACE_DEBUG ((LM_DEBUG,
+ "\n%-50.50s %8.8s %13.13s\n\n",
+ "Event",
+ "thread",
+ "usec"));
+
+ ACE_DEBUG ((LM_DEBUG,
+ "%-50.50s %8.8x %13.13s\n",
+ this->find_description_i (0),
+ this->timeprobes_[0].thread_,
+ "START"));
+
+ ACE_UINT32 gsf = ACE_High_Res_Timer::global_scale_factor ();
+ for (u_long i = 1; i < this->current_size_; i++)
+ {
+ ACE_hrtime_t time_difference =
+ this->timeprobes_[i].time_ - this->timeprobes_[i-1].time_;
+
+ ACE_UINT32 elapsed_time_in_micro_seconds =
+ (ACE_UINT32) (time_difference / gsf);
+ ACE_UINT32 remainder =
+ (ACE_UINT32) (time_difference % gsf);
+ // Convert to the fractional part in microseconds, with 3 digits
+ // of precision (hence the 1000).
+ ACE_UINT32 fractional = remainder * 1000 / gsf;
+
+ ACE_DEBUG ((LM_DEBUG,
+ "%-50.50s %8.8x %10u.%03.3u\n",
+ this->find_description_i (i),
+ this->timeprobes_[i].thread_,
+ (unsigned int) elapsed_time_in_micro_seconds,
+ (unsigned int) fractional));
+ }
+}
+
+template <class ACE_LOCK> void
+ACE_Timeprobe<ACE_LOCK>::print_absolute_times (void)
+{
+ ACE_GUARD (ACE_LOCK, ace_mon, this->lock_);
+
+ // Sort the event descriptions
+ this->sort_event_descriptions_i ();
+
+ ACE_DEBUG ((LM_DEBUG,
+ "\nACE_Timeprobe; %d timestamps were recorded:\n",
+ this->current_size_));
+
+ if (this->current_size_ == 0)
+ return;
+
+ ACE_DEBUG ((LM_DEBUG,
+ "\n%-50.50s %8.8s %13.13s\n\n",
+ "Event",
+ "thread",
+ "stamp"));
+
+ for (u_long i = 0; i < this->current_size_; i++)
+ {
+ char buf[64];
+ ACE_OS::sprintf (buf, "%llu", this->timeprobes_[i].time_);
+ ACE_DEBUG ((LM_DEBUG,
+ "%-50.50s %8.8x %13.13s\n",
+ this->find_description_i (i),
+ this->timeprobes_[i].thread_,
+ buf));
+ }
+}
+
+template <class ACE_LOCK> const char *
+ACE_Timeprobe<ACE_LOCK>::find_description_i (u_long i)
+{
+ if (this->timeprobes_[i].event_type_ == ACE_timeprobe_t::STRING)
+ return this->timeprobes_[i].event_.event_description_;
+ else
+ {
+ EVENT_DESCRIPTIONS::iterator iterator = this->sorted_event_descriptions_.begin ();
+ for (u_long j = 0;
+ j < this->sorted_event_descriptions_.size () - 1;
+ iterator++, j++)
+ {
+ EVENT_DESCRIPTIONS::iterator next_event_descriptions = iterator;
+ next_event_descriptions++;
+
+ if (this->timeprobes_[i].event_.event_number_ < (*next_event_descriptions).minimum_id_)
+ break;
+ }
+ return (*iterator).descriptions_[this->timeprobes_[i].event_.event_number_ - (*iterator).minimum_id_];
+ }
+}
+
+template <class ACE_LOCK> void
+ACE_Timeprobe<ACE_LOCK>::sort_event_descriptions_i (void)
+{
+ size_t total_elements = this->event_descriptions_.size ();
+
+ for (size_t i = 0;
+ i < total_elements;
+ i++)
+ {
+ EVENT_DESCRIPTIONS::iterator iterator = this->event_descriptions_.begin ();
+ ACE_Event_Descriptions min_entry = *iterator;
+
+ for (;
+ iterator != this->event_descriptions_.end ();
+ iterator++)
+ if ((*iterator).minimum_id_ < min_entry.minimum_id_)
+ min_entry = *iterator;
+
+ this->sorted_event_descriptions_.insert (min_entry);
+ this->event_descriptions_.remove (min_entry);
+ }
+}
+
+template <class Timeprobe>
+ACE_Function_Timeprobe<Timeprobe>::ACE_Function_Timeprobe (Timeprobe &timeprobe,
+ u_long event)
+ : timeprobe_ (timeprobe),
+ event_ (event)
+{
+ this->timeprobe_.timeprobe (this->event_);
+}
+
+template <class Timeprobe>
+ACE_Function_Timeprobe<Timeprobe>::~ACE_Function_Timeprobe (void)
+{
+ this->timeprobe_.timeprobe (this->event_ + 1);
+}
+
+#endif /* ACE_COMPILE_TIMEPROBES */
+#endif /* ACE_TIMEPROBE_T_C */
diff --git a/ace/Timer/Timeprobe_T.h b/ace/Timer/Timeprobe_T.h
new file mode 100644
index 00000000000..52740f6456f
--- /dev/null
+++ b/ace/Timer/Timeprobe_T.h
@@ -0,0 +1,188 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Timeprobe_T.h
+ *
+ * $Id$
+ *
+ * @author Irfan Pyarali
+ */
+//=============================================================================
+
+
+#ifndef ACE_TIMEPROBE_T_H
+#define ACE_TIMEPROBE_T_H
+#include "ace/pre.h"
+
+#include "ace/OS.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#if defined (ACE_COMPILE_TIMEPROBES)
+
+#include "ace/Unbounded_Set.h"
+
+/**
+ * @class ACE_Timeprobe
+ *
+ * @brief This class is used to instrument code. This is accomplished
+ * by inserting time probes at different location in the code.
+ * ACE_Timeprobe then measures the time difference between two
+ * time probes.
+ *
+ * This class provides a lightweight implementation for
+ * measuring the time required to execute code between two time
+ * probes. When a time probe executes, it records the time, the
+ * id of the calling thread, and an event description. The
+ * event description can either be an unsigned long or a string
+ * (char *). If string are used, care must be taken cause only
+ * pointer copies are done and the string data is *not* copied.
+ * The recorded time probes can then be printed by calling
+ * <print_times>. If you have used unsigned longs as event
+ * descriptions in any of your time probes, you must have
+ * provided an event description table that maps the unsigned
+ * longs to readable strings. This map is a simple array of
+ * strings, and the event number is used as the index into the
+ * array when looking for the event description. If you have
+ * only used strings for the event description, this map is not
+ * necessary.
+ * Multiple maps can also be used to chunk up the time probes.
+ * Each one can be added by calling <event_descriptions>.
+ * Different tables are used internally by consulting the
+ * minimum_id for each table. It is up to the user to make sure
+ * that multiple tables do not share the same event id range.
+ */
+template <class ACE_LOCK>
+class ACE_Timeprobe
+{
+public:
+
+ /// Self
+ typedef ACE_Timeprobe<ACE_LOCK>
+ SELF;
+
+ /// We can hold multiple event description tables.
+ typedef ACE_Unbounded_Set<ACE_Event_Descriptions>
+ EVENT_DESCRIPTIONS;
+
+ /// Create Timeprobes with <size> slots
+ ACE_Timeprobe (u_long size = ACE_DEFAULT_TIMEPROBE_TABLE_SIZE);
+
+ /// Destructor.
+ ~ACE_Timeprobe (void);
+
+ /// Record a time. <event> is used to describe this time probe.
+ void timeprobe (u_long event);
+
+ /// Record a time. <id> is used to describe this time probe.
+ void timeprobe (const char *id);
+
+ /// Record event descriptions.
+ int event_descriptions (const char **descriptions,
+ u_long minimum_id);
+
+ /// Print the time probes.
+ void print_times (void);
+
+ /// Print the time probes.
+ void print_absolute_times (void);
+
+ /// Reset the slots. All old time probes will be lost.
+ void reset (void);
+
+ ACE_Timeprobe (const ACE_Timeprobe<ACE_LOCK> &);
+ // Not implemented (stupid MSVC won't let it be protected).
+
+ // = (Somewhat private) Accessors
+
+ /// Event Descriptions
+ ACE_Unbounded_Set<ACE_Event_Descriptions> &event_descriptions (void);
+
+ /// Sorted Event Descriptions.
+ ACE_Unbounded_Set<ACE_Event_Descriptions> &sorted_event_descriptions (void);
+
+ /// VME slot address.
+ u_int *current_slot_vme_address (void);
+
+ /// Find description of event <i>
+ const char *find_description_i (u_long i);
+
+ /// Sort event descriptions
+ void sort_event_descriptions_i (void);
+
+ /// Time probe slots
+ ACE_timeprobe_t *timeprobes (void);
+
+ /// Synchronization variable.
+ ACE_LOCK &lock (void);
+
+ /// Max size of timestamp table
+ u_long max_size (void);
+
+ /// Current size of timestamp table
+ u_long current_size (void);
+
+protected:
+
+ /// Event Descriptions
+ EVENT_DESCRIPTIONS event_descriptions_;
+
+ /// Sorted Event Descriptions.
+ EVENT_DESCRIPTIONS sorted_event_descriptions_;
+
+ /// Added sections below here to make compatible with the VMETRO
+ /// board test.
+ u_int *current_slot_vme_address_;
+
+ /// Time probe slots
+ ACE_timeprobe_t *timeprobes_;
+
+ /// Synchronization variable.
+ ACE_LOCK lock_;
+
+ /// Max size of timestamp table
+ u_long max_size_;
+
+ /// Current size of timestamp table
+ u_long current_size_;
+};
+
+/**
+ * @class ACE_Function_Timeprobe
+ *
+ * @brief Auto pointer like time probes. It will record <event> on
+ * construction and <event + 1> on destruction.
+ */
+template <class Timeprobe>
+class ACE_Function_Timeprobe
+{
+public:
+ /// Constructor.
+ ACE_Function_Timeprobe (Timeprobe &timeprobe,
+ u_long event);
+
+ /// Destructor.
+ ~ACE_Function_Timeprobe (void);
+
+protected:
+ /// Reference to timeprobe.
+ Timeprobe &timeprobe_;
+
+ /// Event.
+ u_long event_;
+};
+
+#if defined (ACE_TEMPLATES_REQUIRE_SOURCE)
+#include "ace/Timeprobe_T.cpp"
+#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */
+
+#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA)
+#pragma implementation ("Timeprobe_T.cpp")
+#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */
+
+#endif /* ACE_COMPILE_TIMEPROBES */
+#include "ace/post.h"
+#endif /* ACE_TIMEPROBE_T_H */
diff --git a/ace/Timer/Timer_Hash.cpp b/ace/Timer/Timer_Hash.cpp
new file mode 100644
index 00000000000..a37df2e2fb4
--- /dev/null
+++ b/ace/Timer/Timer_Hash.cpp
@@ -0,0 +1,123 @@
+// $Id$
+
+// Timer_Hash.cpp
+
+#if !defined (ACE_TIMER_HASH_C)
+#define ACE_TIMER_HASH_C
+
+#include "ace/Timer_Hash.h"
+
+#if defined (ACE_HAS_BROKEN_HPUX_TEMPLATES)
+#include "ace/Timer_Hash_T.cpp"
+#endif /* ACE_HAS_BROKEN_HPUX_TEMPLATES */
+
+ACE_RCSID(ace, Timer_Hash, "$Id$")
+
+#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION)
+template class ACE_Free_List<ACE_Timer_Node_T<ACE_Event_Handler *> >;
+template class ACE_Locked_Free_List<ACE_Timer_Node_T<ACE_Event_Handler *>,
+ ACE_Null_Mutex>;
+template class ACE_Timer_Hash_Upcall <ACE_Event_Handler *,
+ ACE_Event_Handler_Handle_Timeout_Upcall<ACE_SYNCH_RECURSIVE_MUTEX>,
+ ACE_SYNCH_RECURSIVE_MUTEX>;
+
+template class ACE_Timer_Queue_T <ACE_Event_Handler *,
+ ACE_Hash_Upcall,
+ ACE_Null_Mutex>;
+
+template class ACE_Timer_Queue_Iterator_T <ACE_Event_Handler *,
+ ACE_Hash_Upcall,
+ ACE_Null_Mutex>;
+
+template class ACE_Timer_List_T <ACE_Event_Handler *,
+ ACE_Hash_Upcall,
+ ACE_Null_Mutex>;
+
+template class ACE_Timer_List_Iterator_T <ACE_Event_Handler *,
+ ACE_Hash_Upcall,
+ ACE_Null_Mutex>;
+
+template class ACE_Timer_Heap_T <ACE_Event_Handler *,
+ ACE_Hash_Upcall,
+ ACE_Null_Mutex>;
+
+template class ACE_Timer_Heap_Iterator_T <ACE_Event_Handler *,
+ ACE_Hash_Upcall,
+ ACE_Null_Mutex>;
+
+template class ACE_Timer_Hash_T<ACE_Event_Handler *,
+ ACE_Event_Handler_Handle_Timeout_Upcall<ACE_SYNCH_RECURSIVE_MUTEX>,
+ ACE_SYNCH_RECURSIVE_MUTEX,
+ ACE_Hash_Timer_List>;
+
+template class ACE_Timer_Hash_Iterator_T<ACE_Event_Handler *,
+ ACE_Event_Handler_Handle_Timeout_Upcall<ACE_SYNCH_RECURSIVE_MUTEX>,
+ ACE_SYNCH_RECURSIVE_MUTEX,
+ ACE_Hash_Timer_List>;
+
+template class ACE_Timer_Hash_T<ACE_Event_Handler *,
+ ACE_Event_Handler_Handle_Timeout_Upcall<ACE_SYNCH_RECURSIVE_MUTEX>,
+ ACE_SYNCH_RECURSIVE_MUTEX,
+ ACE_Hash_Timer_Heap>;
+
+template class ACE_Timer_Hash_Iterator_T<ACE_Event_Handler *,
+ ACE_Event_Handler_Handle_Timeout_Upcall<ACE_SYNCH_RECURSIVE_MUTEX>,
+ ACE_SYNCH_RECURSIVE_MUTEX,
+ ACE_Hash_Timer_Heap>;
+
+#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA)
+#pragma instantiate ACE_Free_List<ACE_Timer_Node_T<ACE_Event_Handler *> >
+#pragma instantiate ACE_Locked_Free_List<ACE_Timer_Node_T<ACE_Event_Handler *>, \
+ ACE_Null_Mutex>
+#pragma instantiate ACE_Timer_Hash_Upcall <ACE_Event_Handler *, \
+ ACE_Event_Handler_Handle_Timeout_Upcall<ACE_SYNCH_RECURSIVE_MUTEX>, \
+ ACE_SYNCH_RECURSIVE_MUTEX>
+
+#pragma instantiate ACE_Timer_Queue_T <ACE_Event_Handler *, \
+ ACE_Hash_Upcall, \
+ ACE_Null_Mutex>
+
+#pragma instantiate ACE_Timer_Queue_Iterator_T <ACE_Event_Handler *, \
+ ACE_Hash_Upcall, \
+ ACE_Null_Mutex>
+
+#pragma instantiate ACE_Timer_List_T <ACE_Event_Handler *, \
+ ACE_Hash_Upcall, \
+ ACE_Null_Mutex>
+
+#pragma instantiate ACE_Timer_List_Iterator_T <ACE_Event_Handler *, \
+ ACE_Hash_Upcall, \
+ ACE_Null_Mutex>
+
+#pragma instantiate ACE_Timer_Heap_T <ACE_Event_Handler *, \
+ ACE_Hash_Upcall, \
+ ACE_Null_Mutex>
+
+#pragma instantiate ACE_Timer_Heap_Iterator_T <ACE_Event_Handler *, \
+ ACE_Hash_Upcall, \
+ ACE_Null_Mutex>
+
+#pragma instantiate ACE_Timer_Hash_T<ACE_Event_Handler *, \
+ ACE_Event_Handler_Handle_Timeout_Upcall<ACE_SYNCH_RECURSIVE_MUTEX>, \
+ ACE_SYNCH_RECURSIVE_MUTEX, \
+ ACE_Hash_Timer_List>
+
+#pragma instantiate ACE_Timer_Hash_Iterator_T<ACE_Event_Handler *, \
+ ACE_Event_Handler_Handle_Timeout_Upcall<ACE_SYNCH_RECURSIVE_MUTEX>, \
+ ACE_SYNCH_RECURSIVE_MUTEX, \
+ ACE_Hash_Timer_List>
+
+#pragma instantiate ACE_Timer_Hash_T<ACE_Event_Handler *, \
+ ACE_Event_Handler_Handle_Timeout_Upcall<ACE_SYNCH_RECURSIVE_MUTEX>, \
+ ACE_SYNCH_RECURSIVE_MUTEX, \
+ ACE_Hash_Timer_Heap>
+
+#pragma instantiate ACE_Timer_Hash_Iterator_T<ACE_Event_Handler *, \
+ ACE_Event_Handler_Handle_Timeout_Upcall<ACE_SYNCH_RECURSIVE_MUTEX>, \
+ ACE_SYNCH_RECURSIVE_MUTEX, \
+ ACE_Hash_Timer_Heap>
+
+#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */
+
+
+#endif /* ACE_TIMER_HASH_C */
diff --git a/ace/Timer/Timer_Hash.h b/ace/Timer/Timer_Hash.h
new file mode 100644
index 00000000000..189fbb7bace
--- /dev/null
+++ b/ace/Timer/Timer_Hash.h
@@ -0,0 +1,71 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Timer_Hash.h
+ *
+ * $Id$
+ *
+ * @author Darrell Brunsch <brunsch@cs.wustl.edu>
+ */
+//=============================================================================
+
+
+#ifndef ACE_TIMER_HASH_H
+#define ACE_TIMER_HASH_H
+#include "ace/pre.h"
+
+#include "ace/Timer_Hash_T.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "ace/Timer_Heap_T.h"
+#include "ace/Timer_List_T.h"
+
+// The following typedef are here for ease of use
+
+typedef ACE_Timer_Hash_Upcall <ACE_Event_Handler *,
+ ACE_Event_Handler_Handle_Timeout_Upcall<ACE_SYNCH_RECURSIVE_MUTEX>,
+ ACE_SYNCH_RECURSIVE_MUTEX>
+ ACE_Hash_Upcall;
+
+typedef ACE_Timer_List_T <ACE_Event_Handler *,
+ ACE_Hash_Upcall,
+ ACE_Null_Mutex>
+ ACE_Hash_Timer_List;
+
+typedef ACE_Timer_Heap_T <ACE_Event_Handler *,
+ ACE_Hash_Upcall,
+ ACE_Null_Mutex>
+ ACE_Hash_Timer_Heap;
+
+
+typedef ACE_Timer_Hash_T<ACE_Event_Handler *,
+ ACE_Event_Handler_Handle_Timeout_Upcall<ACE_SYNCH_RECURSIVE_MUTEX>,
+ ACE_SYNCH_RECURSIVE_MUTEX,
+ ACE_Hash_Timer_List>
+
+ ACE_Timer_Hash;
+
+typedef ACE_Timer_Hash_Iterator_T<ACE_Event_Handler *,
+ ACE_Event_Handler_Handle_Timeout_Upcall<ACE_SYNCH_RECURSIVE_MUTEX>,
+ ACE_SYNCH_RECURSIVE_MUTEX,
+ ACE_Hash_Timer_List>
+ ACE_Timer_Hash_Iterator;
+
+typedef ACE_Timer_Hash_T<ACE_Event_Handler *,
+ ACE_Event_Handler_Handle_Timeout_Upcall<ACE_SYNCH_RECURSIVE_MUTEX>,
+ ACE_SYNCH_RECURSIVE_MUTEX,
+ ACE_Hash_Timer_Heap>
+ ACE_Timer_Hash_Heap;
+
+typedef ACE_Timer_Hash_Iterator_T<ACE_Event_Handler *,
+ ACE_Event_Handler_Handle_Timeout_Upcall<ACE_SYNCH_RECURSIVE_MUTEX>,
+ ACE_SYNCH_RECURSIVE_MUTEX,
+ ACE_Hash_Timer_Heap>
+ ACE_Timer_Hash_Heap_Iterator;
+
+#include "ace/post.h"
+#endif /* ACE_TIMER_HASH_H */
diff --git a/ace/Timer/Timer_Hash_T.cpp b/ace/Timer/Timer_Hash_T.cpp
new file mode 100644
index 00000000000..ac303cca469
--- /dev/null
+++ b/ace/Timer/Timer_Hash_T.cpp
@@ -0,0 +1,622 @@
+// $Id$
+
+#ifndef ACE_TIMER_HASH_T_C
+#define ACE_TIMER_HASH_T_C
+
+#include "ace/Timer_Hash_T.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "ace/High_Res_Timer.h"
+#include "ace/Log_Msg.h"
+
+ACE_RCSID(ace,
+ Timer_Hash_T,
+ "$Id$")
+
+struct Hash_Token
+{
+ Hash_Token (const void *act,
+ size_t pos,
+ long orig_id)
+ : act_ (act),
+ pos_ (pos),
+ orig_id_ (orig_id)
+ {}
+
+ const void *act_;
+ size_t pos_;
+ long orig_id_;
+};
+
+// Default constructor
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK>
+ACE_Timer_Hash_Upcall<TYPE, FUNCTOR, ACE_LOCK>::ACE_Timer_Hash_Upcall (void)
+ : timer_hash_ (0)
+{
+ // Nothing
+}
+
+// Constructor that specifies a Timer_Hash to call up to
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK>
+ACE_Timer_Hash_Upcall<TYPE, FUNCTOR, ACE_LOCK>::ACE_Timer_Hash_Upcall (ACE_Timer_Queue_T<TYPE, FUNCTOR, ACE_LOCK> *timer_hash)
+ : timer_hash_ (timer_hash)
+{
+ // Nothing
+}
+
+// Calls up to timer_hash's upcall functor
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK> int
+ACE_Timer_Hash_Upcall<TYPE, FUNCTOR, ACE_LOCK>::timeout (ACE_Timer_Queue_T<ACE_Event_Handler *,
+ ACE_Timer_Hash_Upcall<TYPE, FUNCTOR, ACE_LOCK>,
+ ACE_Null_Mutex> &timer_queue,
+ ACE_Event_Handler *handler,
+ const void *arg,
+ const ACE_Time_Value &cur_time)
+{
+ ACE_UNUSED_ARG (timer_queue);
+
+ Hash_Token *h = ACE_reinterpret_cast (Hash_Token *,
+ ACE_const_cast (void *,
+ arg));
+ int result =
+ this->timer_hash_->upcall_functor ().timeout (*this->timer_hash_,
+ handler,
+ h->act_,
+ cur_time);
+ delete h;
+ return result;
+}
+
+
+// Calls up to timer_hash's upcall functor
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK> int
+ACE_Timer_Hash_Upcall<TYPE, FUNCTOR, ACE_LOCK>::cancellation (ACE_Timer_Queue_T<ACE_Event_Handler *,
+ ACE_Timer_Hash_Upcall<TYPE, FUNCTOR, ACE_LOCK>,
+ ACE_Null_Mutex> &timer_queue,
+ ACE_Event_Handler *handler)
+{
+ ACE_UNUSED_ARG (timer_queue);
+ return this->timer_hash_->upcall_functor ().cancellation (*this->timer_hash_,
+ handler);
+}
+
+
+// Calls up to timer_hash's upcall functor
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK> int
+ACE_Timer_Hash_Upcall<TYPE, FUNCTOR, ACE_LOCK>::deletion (ACE_Timer_Queue_T<ACE_Event_Handler *,
+ ACE_Timer_Hash_Upcall<TYPE, FUNCTOR, ACE_LOCK>,
+ ACE_Null_Mutex> &timer_queue,
+ ACE_Event_Handler *handler,
+ const void *arg)
+{
+ ACE_UNUSED_ARG (timer_queue);
+
+ Hash_Token *h = ACE_reinterpret_cast (Hash_Token *,
+ ACE_const_cast (void *,
+ arg));
+ int result =
+ this->timer_hash_->upcall_functor ().deletion (*this->timer_hash_,
+ handler,
+ h->act_);
+ delete h;
+ return result;
+}
+
+
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK, class BUCKET>
+ACE_Timer_Hash_Iterator_T<TYPE, FUNCTOR, ACE_LOCK, BUCKET>::ACE_Timer_Hash_Iterator_T (ACE_Timer_Hash_T<TYPE, FUNCTOR, ACE_LOCK, BUCKET> &hash)
+ : timer_hash_ (hash)
+{
+ this->first ();
+ // Nothing
+}
+
+// Positions the iterator at the first node in the timing hash table
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK, class BUCKET> void
+ACE_Timer_Hash_Iterator_T<TYPE, FUNCTOR, ACE_LOCK, BUCKET>::first (void)
+{
+ for (this->position_ = 0;
+ this->position_ < this->timer_hash_.table_size_;
+ this->position_++)
+ {
+ // Check for an empty entry
+ if (!this->timer_hash_.table_[this->position_]->is_empty ())
+ {
+ this->iter_ = &this->timer_hash_.table_[this->position_]->iter ();
+ this->iter_->first ();
+ return;
+ }
+ }
+
+ // Didn't find any
+ this->iter_ = 0;
+}
+
+// Positions the iterator at the next node in the bucket or goes to the next
+// bucket
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK, class BUCKET> void
+ACE_Timer_Hash_Iterator_T<TYPE, FUNCTOR, ACE_LOCK, BUCKET>::next (void)
+{
+ if (this->isdone ())
+ return;
+
+ // If there is no more in the current bucket, go to the next
+ if (this->iter_->isdone ())
+ {
+ for (this->position_++;
+ this->position_ < this->timer_hash_.table_size_;
+ this->position_++)
+ {
+ // Check for an empty entry
+ if (!this->timer_hash_.table_[this->position_]->is_empty ())
+ {
+ this->iter_ = &this->timer_hash_.table_[this->position_]->iter ();
+ this->iter_->first ();
+ return;
+ }
+ }
+
+ // Didn't find any.
+ this->iter_ = 0;
+ }
+ else
+ this->iter_->next ();
+}
+
+// Returns true when we are at the end (when bucket_item_ == 0)
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK, class BUCKET> int
+ACE_Timer_Hash_Iterator_T<TYPE, FUNCTOR, ACE_LOCK, BUCKET>::isdone (void) const
+{
+ return this->iter_ == 0;
+}
+
+// Returns the node at the current position in the sequence
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK, class BUCKET> ACE_Timer_Node_T<TYPE> *
+ACE_Timer_Hash_Iterator_T<TYPE, FUNCTOR, ACE_LOCK, BUCKET>::item (void)
+{
+ if (this->isdone ())
+ return 0;
+
+ return this->iter_->item ();
+}
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK, class BUCKET> ACE_Timer_Queue_Iterator_T<TYPE, FUNCTOR, ACE_LOCK> &
+ACE_Timer_Hash_T<TYPE, FUNCTOR, ACE_LOCK, BUCKET>::iter (void)
+{
+ this->iterator_->first ();
+ return *this->iterator_;
+}
+
+// Create an empty queue.
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK, class BUCKET>
+ACE_Timer_Hash_T<TYPE, FUNCTOR, ACE_LOCK, BUCKET>::ACE_Timer_Hash_T (size_t table_size,
+ FUNCTOR *upcall_functor,
+ ACE_Free_List<ACE_Timer_Node_T <TYPE> > *freelist)
+ : ACE_Timer_Queue_T<TYPE, FUNCTOR, ACE_LOCK> (upcall_functor, freelist),
+ size_ (0),
+ table_size_ (table_size),
+ table_functor_ (this),
+ earliest_position_ (0)
+{
+ ACE_TRACE ("ACE_Timer_Hash_T::ACE_Timer_Hash_T");
+
+ ACE_NEW (table_,
+ BUCKET *[table_size]);
+
+ this->gettimeofday (ACE_OS::gettimeofday);
+
+ for (size_t i = 0;
+ i < table_size;
+ i++)
+ {
+ ACE_NEW (this->table_[i],
+ BUCKET (&this->table_functor_,
+ this->free_list_));
+ this->table_[i]->gettimeofday (ACE_OS::gettimeofday);
+ }
+
+ ACE_NEW (iterator_,
+ HASH_ITERATOR (*this));
+}
+
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK, class BUCKET>
+ACE_Timer_Hash_T<TYPE, FUNCTOR, ACE_LOCK, BUCKET>::ACE_Timer_Hash_T (FUNCTOR *upcall_functor,
+ ACE_Free_List<ACE_Timer_Node_T <TYPE> > *freelist)
+ : ACE_Timer_Queue_T<TYPE, FUNCTOR, ACE_LOCK> (upcall_functor, freelist),
+ size_ (0),
+ table_size_ (ACE_DEFAULT_TIMER_HASH_TABLE_SIZE),
+ table_functor_ (this),
+ earliest_position_ (0)
+{
+ ACE_TRACE ("ACE_Timer_Hash_T::ACE_Timer_Hash_T");
+
+ ACE_NEW (table_,
+ BUCKET *[ACE_DEFAULT_TIMER_HASH_TABLE_SIZE]);
+
+
+ this->gettimeofday (ACE_OS::gettimeofday);
+
+ for (size_t i = 0;
+ i < this->table_size_;
+ i++)
+ {
+ ACE_NEW (this->table_[i],
+ BUCKET (&this->table_functor_,
+ this->free_list_));
+ this->table_[i]->gettimeofday (ACE_OS::gettimeofday);
+ }
+
+ ACE_NEW (iterator_,
+ HASH_ITERATOR (*this));
+}
+
+// Remove all remaining items in the Queue.
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK, class BUCKET>
+ACE_Timer_Hash_T<TYPE, FUNCTOR, ACE_LOCK, BUCKET>::~ACE_Timer_Hash_T (void)
+{
+ ACE_TRACE ("ACE_Timer_Hash_T::~ACE_Timer_Hash_T");
+ ACE_MT (ACE_GUARD (ACE_LOCK, ace_mon, this->mutex_));
+
+ delete iterator_;
+
+ for (size_t i = 0;
+ i < this->table_size_;
+ i++)
+ delete this->table_[i];
+
+ delete [] this->table_;
+}
+
+// Checks if queue is empty.
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK, class BUCKET> int
+ACE_Timer_Hash_T<TYPE, FUNCTOR, ACE_LOCK, BUCKET>::is_empty (void) const
+{
+ ACE_TRACE ("ACE_Timer_Hash_T::is_empty");
+ return this->table_[this->earliest_position_]->is_empty ();
+}
+
+// Returns earliest time in a non-empty bucket
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK, class BUCKET> const ACE_Time_Value &
+ACE_Timer_Hash_T<TYPE, FUNCTOR, ACE_LOCK, BUCKET>::earliest_time (void) const
+{
+ ACE_TRACE ("ACE_Timer_Hash_T::earliest_time");
+ return this->table_[this->earliest_position_]->earliest_time ();
+}
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK, class BUCKET> void
+ACE_Timer_Hash_T<TYPE, FUNCTOR, ACE_LOCK, BUCKET>::dump (void) const
+{
+ ACE_TRACE ("ACE_Timer_Hash_T::dump");
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\ntable_size_ = %d"), this->table_size_));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\nearliest_position_ = %d"), this->earliest_position_));
+
+ for (size_t i = 0; i < this->table_size_; i++)
+ if (!this->table_[i]->is_empty ())
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\nBucket %d contains nodes"), i));
+
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\n")));
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+// Reschedule a periodic timer. This function must be called with the
+// mutex lock held.
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK, class BUCKET> void
+ACE_Timer_Hash_T<TYPE, FUNCTOR, ACE_LOCK, BUCKET>::reschedule (ACE_Timer_Node_T<TYPE> *expired)
+{
+ ACE_TRACE ("ACE_Timer_Hash_T::reschedule");
+
+ size_t position =
+ expired->get_timer_value ().usec () % this->table_size_;
+
+ Hash_Token *h = ACE_reinterpret_cast (Hash_Token *,
+ ACE_const_cast (void *,
+ expired->get_act ()));
+
+ h->orig_id_ = this->table_[position]->schedule (expired->get_type (),
+ h,
+ expired->get_timer_value (),
+ expired->get_interval ());
+
+ if (this->table_[this->earliest_position_]->is_empty ()
+ || this->table_[position]->earliest_time ()
+ < this->table_[this->earliest_position_]->earliest_time ())
+ this->earliest_position_ = position;
+}
+
+// Insert a new handler that expires at time future_time; if interval
+// is > 0, the handler will be reinvoked periodically.
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK, class BUCKET> long
+ACE_Timer_Hash_T<TYPE, FUNCTOR, ACE_LOCK, BUCKET>::schedule (const TYPE &type,
+ const void *act,
+ const ACE_Time_Value &future_time,
+ const ACE_Time_Value &interval)
+{
+ ACE_TRACE ("ACE_Timer_Hash_T::schedule");
+ ACE_MT (ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, -1));
+
+ size_t position =
+ future_time.usec () % this->table_size_;
+
+ Hash_Token *h;
+
+ ACE_NEW_RETURN (h,
+ Hash_Token (act,
+ position,
+ 0),
+ -1);
+
+ h->orig_id_ = this->table_[position]->schedule (type,
+ h,
+ future_time,
+ interval);
+
+ if (this->table_[this->earliest_position_]->is_empty ()
+ || this->table_[position]->earliest_time ()
+ < this->table_[this->earliest_position_]->earliest_time ())
+ this->earliest_position_ = position;
+
+ ++this->size_;
+
+ return ACE_reinterpret_cast (long,
+ h);
+}
+
+// Locate and update the inteval on the timer_id
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK, class BUCKET> int
+ACE_Timer_Hash_T<TYPE, FUNCTOR, ACE_LOCK, BUCKET>::reset_interval (long timer_id,
+ const ACE_Time_Value &interval)
+{
+ ACE_TRACE ("ACE_Timer_Hash_T::reset_interval");
+ ACE_MT (ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, -1));
+
+ // Make sure we are getting a valid <timer_id>, not an error
+ // returned by <schedule>.
+ if (timer_id == -1)
+ return -1;
+
+ Hash_Token *h = ACE_reinterpret_cast (Hash_Token *,
+ timer_id);
+
+ return this->table_[h->pos_]->reset_interval (h->orig_id_,
+ interval);
+}
+
+// Locate and remove the single <ACE_Event_Handler> with a value of
+// <timer_id> from the correct table timer queue.
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK, class BUCKET> int
+ACE_Timer_Hash_T<TYPE, FUNCTOR, ACE_LOCK, BUCKET>::cancel (long timer_id,
+ const void **act,
+ int dont_call)
+{
+ ACE_TRACE ("ACE_Timer_Hash_T::cancel");
+ ACE_MT (ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, -1));
+
+ // Make sure we are getting a valid <timer_id>, not an error
+ // returned by <schedule>.
+ if (timer_id == -1)
+ return 0;
+
+ Hash_Token *h = ACE_reinterpret_cast (Hash_Token *,
+ timer_id);
+
+ int result = this->table_[h->pos_]->cancel (h->orig_id_,
+ act,
+ dont_call);
+
+ if (h->pos_ == this->earliest_position_)
+ this->find_new_earliest ();
+
+ if (act != 0)
+ *act = h->act_;
+
+ delete h;
+
+ --this->size_;
+
+ return result;
+}
+
+// Locate and remove all values of <type> from the timer queue.
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK, class BUCKET> int
+ACE_Timer_Hash_T<TYPE, FUNCTOR, ACE_LOCK, BUCKET>::cancel (const TYPE &type,
+ int dont_call)
+{
+ ACE_TRACE ("ACE_Timer_Hash_T::cancel");
+
+ ACE_MT (ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, -1));
+
+ size_t i; // loop variable.
+
+ Hash_Token **timer_ids;
+
+ ACE_NEW_RETURN (timer_ids,
+ Hash_Token *[this->size_],
+ -1);
+ size_t pos = 0;
+
+ for (i = 0;
+ i < this->table_size_;
+ i++)
+ {
+ ACE_Timer_Queue_Iterator_T<TYPE,
+ ACE_Timer_Hash_Upcall<TYPE, FUNCTOR, ACE_LOCK>,
+ ACE_Null_Mutex> &iter =
+ this->table_[i]->iter ();
+
+ for (iter.first ();
+ !iter.isdone ();
+ iter.next ())
+ if (iter.item ()->get_type () == type)
+ timer_ids[pos++] =
+ ACE_reinterpret_cast (Hash_Token *,
+ ACE_const_cast (void *,
+ iter.item ()->get_act ()));
+ }
+
+ if (pos > this->size_)
+ return -1;
+
+ for (i = 0; i < pos; i++)
+ {
+ this->table_[timer_ids[i]->pos_]->cancel (timer_ids[i]->orig_id_,
+ 0,
+ 1);
+ delete timer_ids[i];
+ --this->size_;
+ }
+
+ delete [] timer_ids;
+
+ if (dont_call == 0)
+ this->upcall_functor ().cancellation (*this,
+ type);
+ this->find_new_earliest ();
+
+ return pos;
+}
+
+// Removes the earliest node and finds the new earliest position
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK, class BUCKET> ACE_Timer_Node_T<TYPE> *
+ACE_Timer_Hash_T<TYPE, FUNCTOR, ACE_LOCK, BUCKET>::remove_first (void)
+{
+ if (this->is_empty ())
+ return 0;
+
+ ACE_Timer_Node_T<TYPE> *temp =
+ this->table_[this->earliest_position_]->remove_first ();
+
+ this->find_new_earliest ();
+
+ --this->size_;
+
+ return temp;
+}
+
+// Finds a new earliest position
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK, class BUCKET> void
+ACE_Timer_Hash_T<TYPE, FUNCTOR, ACE_LOCK, BUCKET>::find_new_earliest (void)
+{
+ for (size_t i = 0; i < this->table_size_; i++)
+ if (!this->table_[i]->is_empty ())
+ if (this->table_[this->earliest_position_]->is_empty ()
+ || this->earliest_time () == ACE_Time_Value::zero
+ || this->table_[i]->earliest_time () <= this->earliest_time ())
+ this->earliest_position_ = i;
+}
+
+// Returns the earliest node without removing it
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK, class BUCKET> ACE_Timer_Node_T<TYPE> *
+ACE_Timer_Hash_T<TYPE, FUNCTOR, ACE_LOCK, BUCKET>::get_first (void)
+{
+ ACE_TRACE ("ACE_Timer_Hash_T::get_first");
+
+ if (this->is_empty ())
+ return 0;
+
+ return this->table_[this->earliest_position_]->get_first ();
+}
+
+// Dummy version of expire to get rid of warnings in Sun CC 4.2
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK, class BUCKET> int
+ACE_Timer_Hash_T<TYPE, FUNCTOR, ACE_LOCK, BUCKET>::expire ()
+{
+ return ACE_Timer_Queue_T<TYPE,FUNCTOR,ACE_LOCK>::expire();
+}
+
+// Specialized expire for Timer Hash
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK, class BUCKET> int
+ACE_Timer_Hash_T<TYPE, FUNCTOR, ACE_LOCK, BUCKET>::expire (const ACE_Time_Value &cur_time)
+{
+ ACE_TRACE ("ACE_Timer_Hash_T::expire");
+ ACE_MT (ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, -1));
+
+ int number_of_timers_expired = 0;
+
+ ACE_Timer_Node_T<TYPE> *expired;
+
+ // Go through the table and expire anything that can be expired
+
+ for (size_t i = 0;
+ i < this->table_size_;
+ i++)
+ {
+ while (!this->table_[i]->is_empty ()
+ && this->table_[i]->earliest_time () <= cur_time)
+ {
+ expired = this->table_[i]->get_first ();
+ TYPE type = expired->get_type ();
+ const void *act = expired->get_act ();
+ int reclaim = 1;
+
+ // Check if this is an interval timer.
+ if (expired->get_interval () > ACE_Time_Value::zero)
+ {
+ // Make sure that we skip past values that have already
+ // "expired".
+ do
+ expired->set_timer_value (expired->get_timer_value ()
+ + expired->get_interval ());
+ while (expired->get_timer_value () <= cur_time);
+
+ // Since this is an interval timer, we need to
+ // reschedule it.
+ this->reschedule (expired);
+ reclaim = 0;
+ }
+
+ // Now remove the timer from the original table... if
+ // it's a simple, non-recurring timer, it's got to be
+ // removed anyway. If it was rescheduled, it's been
+ // scheduled into the correct table (regardless of whether
+ // it's the same one or not) already.
+ this->table_[i]->cancel (expired->get_timer_id ());
+
+ Hash_Token *h = ACE_reinterpret_cast (Hash_Token *,
+ ACE_const_cast (void *,
+ act));
+ // Call the functor.
+ this->upcall (type,
+ h->act_,
+ cur_time);
+ if (reclaim)
+ {
+ --this->size_;
+ delete h;
+ }
+ number_of_timers_expired++;
+ }
+ }
+
+ return number_of_timers_expired;
+}
+
+#endif /* ACE_TIMER_HASH_T_C */
diff --git a/ace/Timer/Timer_Hash_T.h b/ace/Timer/Timer_Hash_T.h
new file mode 100644
index 00000000000..36efdb169d5
--- /dev/null
+++ b/ace/Timer/Timer_Hash_T.h
@@ -0,0 +1,283 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Timer_Hash_T.h
+ *
+ * $Id$
+ *
+ * @author Darrell Brunsch <brunsch@cs.wustl.edu>
+ */
+//=============================================================================
+
+#ifndef ACE_TIMER_HASH_T_H
+#define ACE_TIMER_HASH_T_H
+#include "ace/pre.h"
+
+#include "ace/Timer_Queue_T.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "ace/Free_List.h"
+
+// Forward declaration.
+template <class TYPE, class FUNCTOR, class ACE_LOCK, class BUCKET>
+class ACE_Timer_Hash_T;
+
+/**
+ * @class ACE_Timer_Hash_Upcall
+ *
+ * @brief Functor for Timer_Hash
+ *
+ * This class calls up to the Timer Hash's functor from the
+ * timer queues in the hash table
+ */
+template <class TYPE, class FUNCTOR, class ACE_LOCK>
+class ACE_Timer_Hash_Upcall
+{
+public:
+ typedef ACE_Timer_Queue_T<ACE_Event_Handler *,
+ ACE_Timer_Hash_Upcall<TYPE, FUNCTOR, ACE_LOCK>,
+ ACE_Null_Mutex>
+ TIMER_QUEUE;
+
+ /// Default constructor (creates an invalid object, but needs to be here
+ /// so timer queues using this functor can be constructed)
+ ACE_Timer_Hash_Upcall (void);
+
+ /// Constructor that specifies a Timer_Hash to call up to
+ ACE_Timer_Hash_Upcall (ACE_Timer_Queue_T<TYPE, FUNCTOR, ACE_LOCK> *timer_hash);
+
+ /// This method is called when the timer expires
+ int timeout (TIMER_QUEUE &timer_queue,
+ ACE_Event_Handler *handler,
+ const void *arg,
+ const ACE_Time_Value &cur_time);
+
+ /// This method is called when the timer is canceled
+ int cancellation (TIMER_QUEUE &timer_queue,
+ ACE_Event_Handler *handler);
+
+ /// This method is called when the timer queue is destroyed and
+ /// the timer is still contained in it
+ int deletion (TIMER_QUEUE &timer_queue,
+ ACE_Event_Handler *handler,
+ const void *arg);
+
+private:
+ /// Timer Queue to do the calling up to
+ ACE_Timer_Queue_T<TYPE, FUNCTOR, ACE_LOCK> *timer_hash_;
+
+ // = Don't allow these operations for now.
+ ACE_UNIMPLEMENTED_FUNC (ACE_Timer_Hash_Upcall (const ACE_Timer_Hash_Upcall<TYPE, FUNCTOR, ACE_LOCK> &))
+ ACE_UNIMPLEMENTED_FUNC (void operator= (const ACE_Timer_Hash_Upcall<TYPE, FUNCTOR, ACE_LOCK> &))
+};
+
+/**
+ * @class ACE_Timer_Hash_Iterator_T
+ *
+ * @brief Iterates over an <ACE_Timer_Hash>.
+ *
+ * This is a generic iterator that can be used to visit every
+ * node of a timer queue. Be aware that it doesn't transverse
+ * in the order of timeout values.
+ */
+template <class TYPE, class FUNCTOR, class ACE_LOCK, class BUCKET>
+class ACE_Timer_Hash_Iterator_T : public ACE_Timer_Queue_Iterator_T <TYPE, FUNCTOR, ACE_LOCK>
+{
+public:
+ /// Constructor.
+ ACE_Timer_Hash_Iterator_T (ACE_Timer_Hash_T<TYPE, FUNCTOR, ACE_LOCK, BUCKET> &);
+
+ /// Positions the iterator at the earliest node in the Timer Queue
+ virtual void first (void);
+
+ /// Positions the iterator at the next node in the Timer Queue
+ virtual void next (void);
+
+ /// Returns true when there are no more nodes in the sequence
+ virtual int isdone (void) const;
+
+ /// Returns the node at the current position in the sequence
+ virtual ACE_Timer_Node_T<TYPE> *item (void);
+
+protected:
+ /// Pointer to the <ACE_Timer_Hash> that we are iterating over.
+ ACE_Timer_Hash_T<TYPE, FUNCTOR, ACE_LOCK, BUCKET> &timer_hash_;
+
+ /// Current position in <timer_hash_>'s table
+ size_t position_;
+
+ /// Current iterator used on <position>'s bucket
+ ACE_Timer_Queue_Iterator_T<TYPE, ACE_Timer_Hash_Upcall<TYPE, FUNCTOR, ACE_LOCK>, ACE_Null_Mutex> *iter_;
+};
+
+/**
+ * @class ACE_Timer_Hash_T
+ *
+ * @brief Provides a hash table of <BUCKET>s as an implementation for
+ * a timer queue.
+ *
+ * This implementation uses a hash table of BUCKETs. The hash
+ * is based on the time_value of the event. Unlike other Timer
+ * Queues, ACE_Timer_Hash does not expire events in order.
+ */
+template <class TYPE, class FUNCTOR, class ACE_LOCK, class BUCKET>
+class ACE_Timer_Hash_T : public ACE_Timer_Queue_T<TYPE, FUNCTOR, ACE_LOCK>
+{
+public:
+ /// Type of iterator
+ typedef ACE_Timer_Hash_Iterator_T<TYPE, FUNCTOR, ACE_LOCK, BUCKET>
+ HASH_ITERATOR;
+
+ /// Iterator is a friend
+ friend class ACE_Timer_Hash_Iterator_T<TYPE, FUNCTOR, ACE_LOCK, BUCKET>;
+
+ /// Type inherited from
+ typedef ACE_Timer_Queue_T<TYPE, FUNCTOR, ACE_LOCK> INHERITED;
+
+ // = Initialization and termination methods.
+ /**
+ * Default constructor. <table_size> determines the size of the
+ * hash table. <upcall_functor> is the instance of the FUNCTOR
+ * to be used by the buckets. If <upcall_functor> is 0, a default
+ * FUNCTOR will be created.
+ */
+ ACE_Timer_Hash_T (size_t table_size,
+ FUNCTOR *upcall_functor = 0,
+ ACE_Free_List<ACE_Timer_Node_T <TYPE> > *freelist = 0);
+
+ /**
+ * Default constructor. <upcall_functor> is the instance of the
+ * FUNCTOR to be used by the queue. If <upcall_functor> is 0, Timer
+ * Hash will create a default FUNCTOR. <freelist> the freelist of
+ * timer nodes. If 0, then a default freelist will be created. The default
+ * size will be ACE_DEFAULT_TIMERS and there will be no preallocation.
+ */
+ ACE_Timer_Hash_T (FUNCTOR *upcall_functor = 0, ACE_Free_List<ACE_Timer_Node_T <TYPE> > *freelist = 0);
+
+ /// Destructor
+ virtual ~ACE_Timer_Hash_T (void);
+
+ /// True if queue is empty, else false.
+ virtual int is_empty (void) const;
+
+ /// Returns the time of the earlier node in the <ACE_Timer_Hash>.
+ /// Must be called on a non-empty queue.
+ virtual const ACE_Time_Value &earliest_time (void) const;
+
+ /**
+ * Schedule <type> that will expire after <delay> amount of time,
+ * which is specified in absolute time. If it expires then <act> is
+ * passed in as the value to the <functor>. If <interval> is != to
+ * <ACE_Time_Value::zero> then it is used to reschedule the <type>
+ * automatically, using relative time to the current <gettimeofday>.
+ * This method returns a <timer_id> that is a pointer to a token
+ * which stores information about the event. This <timer_id> can be
+ * used to cancel the timer before it expires. Returns -1 on
+ * failure.
+ */
+ virtual long schedule (const TYPE &type,
+ const void *act,
+ const ACE_Time_Value &delay,
+ const ACE_Time_Value &interval = ACE_Time_Value::zero);
+
+ /**
+ * Resets the interval of the timer represented by <timer_id> to
+ * <interval>, which is specified in relative time to the current
+ * <gettimeofday>. If <interval> is equal to
+ * <ACE_Time_Value::zero>, the timer will become a non-rescheduling
+ * timer. Returns 0 if successful, -1 if not.
+ */
+ virtual int reset_interval (long timer_id,
+ const ACE_Time_Value &interval);
+
+ /**
+ * Cancel all timer associated with <type>. If <dont_call> is 0
+ * then the <functor> will be invoked. Returns number of timers
+ * cancelled.
+ */
+ virtual int cancel (const TYPE &type,
+ int dont_call_handle_close = 1);
+
+ /**
+ * Cancel the single timer that matches the <timer_id> value (which
+ * was returned from the <schedule> method). If act is non-NULL
+ * then it will be set to point to the ``magic cookie'' argument
+ * passed in when the timer was registered. This makes it possible
+ * to free up the memory and avoid memory leaks. If <dont_call> is
+ * 0 then the <functor> will be invoked. Returns 1 if cancellation
+ * succeeded and 0 if the <timer_id> wasn't found.
+ */
+ virtual int cancel (long timer_id,
+ const void **act = 0,
+ int dont_call_handle_close = 1);
+
+ /**
+ * Run the <functor> for all timers whose values are <=
+ * <ACE_OS::gettimeofday>. Also accounts for <timer_skew>. Returns
+ * the number of timers canceled.
+ */
+ virtual int expire (void);
+
+ /**
+ * Run the <functor> for all timers whose values are <= <cur_time>.
+ * This does not account for <timer_skew>. Returns the number of
+ * timers canceled.
+ */
+ virtual int expire (const ACE_Time_Value &current_time);
+
+ /// Returns a pointer to this <ACE_Timer_Queue>'s iterator.
+ virtual ACE_Timer_Queue_Iterator_T<TYPE, FUNCTOR, ACE_LOCK> &iter (void);
+
+ /// Removes the earliest node from the queue and returns it
+ virtual ACE_Timer_Node_T<TYPE> *remove_first (void);
+
+ /// Dump the state of an object.
+ virtual void dump (void) const;
+
+ /// Reads the earliest node from the queue and returns it.
+ virtual ACE_Timer_Node_T<TYPE> *get_first (void);
+
+private:
+ /// Reschedule an "interval" <ACE_Timer_Node>.
+ virtual void reschedule (ACE_Timer_Node_T<TYPE> *);
+
+ /// Finds the earliest node
+ void find_new_earliest (void);
+
+ /// Keeps track of the size of the queue
+ size_t size_;
+
+ /// Table of BUCKETS
+ BUCKET **table_;
+
+ /// Keeps track of the size of table_
+ size_t table_size_;
+
+ /// Functor used for the table's timer queues
+ ACE_Timer_Hash_Upcall<TYPE, FUNCTOR, ACE_LOCK> table_functor_;
+
+ /// Index to the position with the earliest entry
+ size_t earliest_position_;
+
+ /// Iterator used to expire timers.
+ HASH_ITERATOR *iterator_;
+
+ // = Don't allow these operations for now.
+ ACE_UNIMPLEMENTED_FUNC (ACE_Timer_Hash_T (const ACE_Timer_Hash_T<TYPE, FUNCTOR, ACE_LOCK, BUCKET> &))
+ ACE_UNIMPLEMENTED_FUNC (void operator= (const ACE_Timer_Hash_T<TYPE, FUNCTOR, ACE_LOCK, BUCKET> &))
+};
+
+#if defined (ACE_TEMPLATES_REQUIRE_SOURCE) && !defined(ACE_HAS_BROKEN_HPUX_TEMPLATES)
+#include "ace/Timer_Hash_T.cpp"
+#endif /* ACE_TEMPLATES_REQUIRE_SOURCE && !ACE_HAS_BROKEN_HPUX_TEMPLATES */
+
+#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA)
+#pragma implementation ("Timer_Hash_T.cpp")
+#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */
+
+#include "ace/post.h"
+#endif /* ACE_TIMER_HASH_T_H */
diff --git a/ace/Timer/Timer_Heap.cpp b/ace/Timer/Timer_Heap.cpp
new file mode 100644
index 00000000000..8132c874f10
--- /dev/null
+++ b/ace/Timer/Timer_Heap.cpp
@@ -0,0 +1,43 @@
+// $Id$
+
+#if !defined (ACE_TIMER_HEAP_C)
+#define ACE_TIMER_HEAP_C
+
+#include "ace/Timer_Heap.h"
+
+ACE_RCSID(ace, Timer_Heap, "$Id$")
+
+#if defined (ACE_HAS_BROKEN_HPUX_TEMPLATES)
+#include "ace/Timer_Hash.h"
+#include "ace/Timer_Heap_T.cpp"
+#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION)
+template class
+ ACE_Timer_Heap_T<
+ ACE_Event_Handler*,
+ ACE_Timer_Hash_Upcall<
+ ACE_Event_Handler*,
+ ACE_Event_Handler_Handle_Timeout_Upcall<ACE_Null_Mutex>,
+ ACE_Null_Mutex>,
+ ACE_Null_Mutex>;
+
+template class
+ ACE_Timer_Heap_Iterator_T<
+ ACE_Event_Handler*,
+ ACE_Timer_Hash_Upcall<
+ ACE_Event_Handler*,
+ ACE_Event_Handler_Handle_Timeout_Upcall<ACE_Null_Mutex>,
+ ACE_Null_Mutex>,
+ ACE_Null_Mutex>;
+#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */
+#endif /* ACE_HAS_BROKEN_HPUX_TEMPLATES */
+
+#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION)
+template class ACE_Timer_Heap_T<ACE_Event_Handler *, ACE_Event_Handler_Handle_Timeout_Upcall<ACE_SYNCH_RECURSIVE_MUTEX>, ACE_SYNCH_RECURSIVE_MUTEX>;
+template class ACE_Timer_Heap_Iterator_T<ACE_Event_Handler *, ACE_Event_Handler_Handle_Timeout_Upcall<ACE_SYNCH_RECURSIVE_MUTEX>, ACE_SYNCH_RECURSIVE_MUTEX>;
+#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA)
+#pragma instantiate ACE_Timer_Heap_T<ACE_Event_Handler *, ACE_Event_Handler_Handle_Timeout_Upcall<ACE_SYNCH_RECURSIVE_MUTEX>, ACE_SYNCH_RECURSIVE_MUTEX>
+#pragma instantiate ACE_Timer_Heap_Iterator_T<ACE_Event_Handler *, ACE_Event_Handler_Handle_Timeout_Upcall<ACE_SYNCH_RECURSIVE_MUTEX>, ACE_SYNCH_RECURSIVE_MUTEX>
+#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */
+
+
+#endif /* ACE_TIMER_HEAP_C */
diff --git a/ace/Timer/Timer_Heap.h b/ace/Timer/Timer_Heap.h
new file mode 100644
index 00000000000..5db29677f75
--- /dev/null
+++ b/ace/Timer/Timer_Heap.h
@@ -0,0 +1,38 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Timer_Heap.h
+ *
+ * $Id$
+ *
+ * @author Doug Schmidt
+ */
+//=============================================================================
+
+
+#ifndef ACE_TIMER_HEAP_H
+#define ACE_TIMER_HEAP_H
+#include "ace/pre.h"
+
+#include "ace/Timer_Heap_T.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+// The following typedef are here for ease of use and backward
+// compatibility.
+
+typedef ACE_Timer_Heap_T<ACE_Event_Handler *,
+ ACE_Event_Handler_Handle_Timeout_Upcall<ACE_SYNCH_RECURSIVE_MUTEX>,
+ ACE_SYNCH_RECURSIVE_MUTEX>
+ ACE_Timer_Heap;
+
+typedef ACE_Timer_Heap_Iterator_T<ACE_Event_Handler *,
+ ACE_Event_Handler_Handle_Timeout_Upcall<ACE_SYNCH_RECURSIVE_MUTEX>,
+ ACE_SYNCH_RECURSIVE_MUTEX>
+ ACE_Timer_Heap_Iterator;
+
+#include "ace/post.h"
+#endif /* ACE_TIMER_HEAP_H */
diff --git a/ace/Timer/Timer_Heap_T.cpp b/ace/Timer/Timer_Heap_T.cpp
new file mode 100644
index 00000000000..c3596238621
--- /dev/null
+++ b/ace/Timer/Timer_Heap_T.cpp
@@ -0,0 +1,785 @@
+// $Id$
+
+#ifndef ACE_TIMER_HEAP_T_C
+#define ACE_TIMER_HEAP_T_C
+
+#include "ace/Timer_Heap_T.h"
+#include "ace/Log_Msg.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+ACE_RCSID(ace, Timer_Heap_T, "$Id$")
+
+// Define some simple macros to clarify the code.
+#define ACE_HEAP_PARENT(X) (X == 0 ? 0 : (((X) - 1) / 2))
+#define ACE_HEAP_LCHILD(X) (((X)+(X))+1)
+
+// Constructor that takes in an <ACE_Timer_Heap_T> to iterate over.
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK>
+ACE_Timer_Heap_Iterator_T<TYPE, FUNCTOR, ACE_LOCK>::ACE_Timer_Heap_Iterator_T (ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK> &heap)
+ : timer_heap_ (heap)
+{
+ ACE_TRACE ("ACE_Timer_Heap_Iterator_T::ACE_Timer_Heap_Iterator");
+ this->first();
+}
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK>
+ACE_Timer_Heap_Iterator_T<TYPE, FUNCTOR, ACE_LOCK>::~ACE_Timer_Heap_Iterator_T (void)
+{
+}
+
+// Positions the iterator at the first node in the heap array
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK> void
+ACE_Timer_Heap_Iterator_T<TYPE, FUNCTOR, ACE_LOCK>::first (void)
+{
+ this->position_ = 0;
+}
+
+// Positions the iterator at the next node in the heap array
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK> void
+ACE_Timer_Heap_Iterator_T<TYPE, FUNCTOR, ACE_LOCK>::next (void)
+{
+ if (this->position_ != this->timer_heap_.cur_size_)
+ this->position_++;
+}
+
+// Returns true the <position_> is at the end of the heap array
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK> int
+ACE_Timer_Heap_Iterator_T<TYPE, FUNCTOR, ACE_LOCK>::isdone (void) const
+{
+ return this->position_ == this->timer_heap_.cur_size_;
+}
+
+// Returns the node at the current position in the heap or 0 if at the end
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK> ACE_Timer_Node_T<TYPE> *
+ACE_Timer_Heap_Iterator_T<TYPE, FUNCTOR, ACE_LOCK>::item (void)
+{
+ if (this->position_ != this->timer_heap_.cur_size_)
+ return this->timer_heap_.heap_[this->position_];
+ return 0;
+}
+
+// Constructor
+// Note that timer_ids_curr_ and timer_ids_min_free_ both start at 0.
+// Since timer IDs are assigned by first incrementing the timer_ids_curr_
+// value, the first ID assigned will be 1 (just as in the previous design).
+// When it's time to wrap, the next ID given out will be 0.
+template <class TYPE, class FUNCTOR, class ACE_LOCK>
+ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK>::ACE_Timer_Heap_T (size_t size,
+ int preallocate,
+ FUNCTOR *upcall_functor,
+ ACE_Free_List<ACE_Timer_Node_T <TYPE> > *freelist)
+ : ACE_Timer_Queue_T<TYPE,FUNCTOR,ACE_LOCK> (upcall_functor, freelist),
+ max_size_ (size),
+ cur_size_ (0),
+ cur_limbo_ (0),
+ timer_ids_curr_ (0),
+ timer_ids_min_free_ (0),
+ preallocated_nodes_ (0),
+ preallocated_nodes_freelist_ (0)
+{
+ ACE_TRACE ("ACE_Timer_Heap_T::ACE_Timer_Heap_T");
+
+ // Create the heap array.
+ ACE_NEW (this->heap_,
+ ACE_Timer_Node_T<TYPE> *[size]);
+
+ // Create the parallel
+ ACE_NEW (this->timer_ids_,
+ long[size]);
+
+ // Initialize the "freelist," which uses negative values to
+ // distinguish freelist elements from "pointers" into the <heap_>
+ // array.
+ for (size_t i = 0; i < size; i++)
+ this->timer_ids_[i] = -1;
+
+ if (preallocate)
+ {
+ ACE_NEW (this->preallocated_nodes_,
+ ACE_Timer_Node_T<TYPE>[size]);
+
+ // Add allocated array to set of such arrays for deletion on
+ // cleanup.
+ this->preallocated_node_set_.insert (this->preallocated_nodes_);
+
+ // Form the freelist by linking the next_ pointers together.
+ for (size_t j = 1; j < size; j++)
+ this->preallocated_nodes_[j - 1].set_next (&this->preallocated_nodes_[j]);
+
+ // NULL-terminate the freelist.
+ this->preallocated_nodes_[size - 1].set_next (0);
+
+ // Assign the freelist pointer to the front of the list.
+ this->preallocated_nodes_freelist_ =
+ &this->preallocated_nodes_[0];
+ }
+
+ ACE_NEW (iterator_,
+ HEAP_ITERATOR (*this));
+}
+
+// Note that timer_ids_curr_ and timer_ids_min_free_ both start at 0.
+// Since timer IDs are assigned by first incrementing the timer_ids_curr_
+// value, the first ID assigned will be 1 (just as in the previous design).
+// When it's time to wrap, the next ID given out will be 0.
+template <class TYPE, class FUNCTOR, class ACE_LOCK>
+ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK>::ACE_Timer_Heap_T (FUNCTOR *upcall_functor,
+ ACE_Free_List<ACE_Timer_Node_T <TYPE> > *freelist)
+ : ACE_Timer_Queue_T<TYPE,FUNCTOR,ACE_LOCK> (upcall_functor, freelist),
+ max_size_ (ACE_DEFAULT_TIMERS),
+ cur_size_ (0),
+ cur_limbo_ (0),
+ timer_ids_curr_ (0),
+ timer_ids_min_free_ (0),
+ preallocated_nodes_ (0),
+ preallocated_nodes_freelist_ (0)
+{
+ ACE_TRACE ("ACE_Timer_Heap_T::ACE_Timer_Heap_T");
+
+ // Create the heap array.
+#if defined (__IBMCPP__) && (__IBMCPP__ >= 400) && defined (_WINDOWS)
+ ACE_NEW (this->heap_,
+ ACE_Timer_Node_T<TYPE> *[ACE_DEFAULT_TIMERS]);
+#else
+ ACE_NEW (this->heap_,
+ ACE_Timer_Node_T<TYPE> *[this->max_size_]);
+#endif /* defined (__IBMCPP__) && (__IBMCPP__ >= 400) && defined (_WINDOWS) */
+
+ // Create the parallel array.
+ ACE_NEW (this->timer_ids_,
+ long[this->max_size_]);
+
+ // Initialize the "freelist," which uses negative values to
+ // distinguish freelist elements from "pointers" into the <heap_>
+ // array.
+ for (size_t i = 0; i < this->max_size_; i++)
+ this->timer_ids_[i] = -1;
+
+ ACE_NEW (iterator_,
+ HEAP_ITERATOR (*this));
+}
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK>
+ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK>::~ACE_Timer_Heap_T (void)
+{
+ ACE_TRACE ("ACE_Timer_Heap_T::~ACE_Timer_Heap_T");
+
+ delete iterator_;
+
+ // Clean up all the nodes still in the queue
+ for (size_t i = 0; i < this->cur_size_; i++)
+ {
+ this->upcall_functor ().deletion (*this,
+ this->heap_[i]->get_type (),
+ this->heap_[i]->get_act ());
+ this->free_node (this->heap_[i]);
+ }
+
+ delete [] this->heap_;
+ delete [] this->timer_ids_;
+
+ // clean up any preallocated timer nodes
+ if (preallocated_nodes_ != 0)
+ {
+ ACE_Unbounded_Set_Iterator<ACE_Timer_Node_T<TYPE> *>
+ set_iterator (this->preallocated_node_set_);
+
+ for (ACE_Timer_Node_T<TYPE> **entry = 0;
+ set_iterator.next (entry) !=0;
+ set_iterator.advance ())
+ delete [] *entry;
+ }
+}
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK> int
+ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK>::pop_freelist (void)
+{
+ ACE_TRACE ("ACE_Timer_Heap_T::pop_freelist");
+
+ // Scan for a free timer ID. Note that since this function is called
+ // _after_ the check for a full timer heap, we are guaranteed to find
+ // a free ID, even if we need to wrap around and start reusing freed IDs.
+ // On entry, the curr_ index is at the previous ID given out; start
+ // up where we left off last time.
+ // NOTE - a timer_ids_ slot with -2 is out of the heap, but not freed.
+ // It must be either freed (free_node) or rescheduled (reschedule).
+ ++this->timer_ids_curr_;
+ while (this->timer_ids_curr_ < this->max_size_ &&
+ (this->timer_ids_[this->timer_ids_curr_] >= 0 ||
+ this->timer_ids_[this->timer_ids_curr_] == -2 ))
+ ++this->timer_ids_curr_;
+ if (this->timer_ids_curr_ == this->max_size_)
+ {
+ ACE_ASSERT (this->timer_ids_min_free_ < this->max_size_);
+ this->timer_ids_curr_ = this->timer_ids_min_free_;
+ // We restarted the free search at min. Since min won't be
+ // free anymore, and curr_ will just keep marching up the list
+ // on each successive need for an ID, reset min_free_ to the
+ // size of the list until an ID is freed that curr_ has already
+ // gone past (see push_freelist).
+ this->timer_ids_min_free_ = this->max_size_;
+ }
+
+ // We need to truncate this to <int> for backwards compatibility.
+ int new_id = ACE_static_cast (int,
+ this->timer_ids_curr_);
+ return new_id;
+}
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK> void
+ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK>::push_freelist (int old_id)
+{
+ ACE_TRACE ("ACE_Timer_Heap_T::push_freelist");
+
+ // Since this ID has already been checked by one of the public
+ // functions, it's safe to cast it here.
+ size_t oldid = size_t (old_id);
+
+ // The freelist values in the <timer_ids_> are negative, so set the
+ // freed entry back to 'free'. If this is the new lowest value free
+ // timer ID that curr_ won't see on it's normal march through the list,
+ // remember it.
+ ACE_ASSERT (this->timer_ids_[oldid] >= 0 || this->timer_ids_[oldid] == -2);
+ if (this->timer_ids_[oldid] == -2)
+ --this->cur_limbo_;
+ else
+ --this->cur_size_;
+ this->timer_ids_[oldid] = -1;
+ if (oldid < this->timer_ids_min_free_ && oldid <= this->timer_ids_curr_)
+ this->timer_ids_min_free_ = oldid;
+ return;
+}
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK> int
+ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK>::timer_id (void)
+{
+ ACE_TRACE ("ACE_Timer_Heap_T::timer_id");
+
+ // Return the next item off the freelist and use it as the timer id.
+ return this->pop_freelist ();
+}
+
+// Checks if queue is empty.
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK> int
+ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK>::is_empty (void) const
+{
+ ACE_TRACE ("ACE_Timer_Heap_T::is_empty");
+ return this->cur_size_ == 0;
+}
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK> ACE_Timer_Queue_Iterator_T<TYPE, FUNCTOR, ACE_LOCK> &
+ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK>::iter (void)
+{
+ this->iterator_->first ();
+ return *this->iterator_;
+}
+
+// Returns earliest time in a non-empty queue.
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK> const ACE_Time_Value &
+ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK>::earliest_time (void) const
+{
+ ACE_TRACE ("ACE_Timer_Heap_T::earliest_time");
+ return this->heap_[0]->get_timer_value ();
+}
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK> void
+ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK>::dump (void) const
+{
+ ACE_TRACE ("ACE_Timer_Heap_T::dump");
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\nmax_size_ = %d"), this->max_size_));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\ncur_size_ = %d"), this->cur_size_));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\ncur_limbo_= %d"), this->cur_limbo_));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\nids_curr_ = %d"),
+ this->timer_ids_curr_));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\nmin_free_ = %d"),
+ this->timer_ids_min_free_));
+
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\nheap_ = \n")));
+
+ for (size_t i = 0; i < this->cur_size_; i++)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_LIB_TEXT ("%d\n"),
+ i));
+ this->heap_[i]->dump ();
+ }
+
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\ntimer_ids_ = \n")));
+
+ for (size_t j = 0; j < this->max_size_; j++)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_LIB_TEXT ("%d\t%d\n"),
+ j,
+ this->timer_ids_[j]));
+
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK> void
+ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK>::copy (int slot,
+ ACE_Timer_Node_T<TYPE> *moved_node)
+{
+ // Insert <moved_node> into its new location in the heap.
+ this->heap_[slot] = moved_node;
+
+ ACE_ASSERT (moved_node->get_timer_id () >= 0
+ && moved_node->get_timer_id () < (int) this->max_size_);
+
+ // Update the corresponding slot in the parallel <timer_ids_> array.
+ this->timer_ids_[moved_node->get_timer_id ()] = slot;
+}
+
+// Remove the slot'th timer node from the heap, but do not reclaim its
+// timer ID or change the size of this timer heap object. The caller of
+// this function must call either free_node (to reclaim the timer ID
+// and the timer node memory, as well as decrement the size of the queue)
+// or reschedule (to reinsert the node in the heap at a new time).
+template <class TYPE, class FUNCTOR, class ACE_LOCK> ACE_Timer_Node_T<TYPE> *
+ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK>::remove (size_t slot)
+{
+ ACE_Timer_Node_T<TYPE> *removed_node =
+ this->heap_[slot];
+
+ // NOTE - the cur_size_ is being decremented since the queue has one
+ // less active timer in it. However, this ACE_Timer_Node is not being
+ // freed, and there is still a place for it in timer_ids_ (the timer ID
+ // is not being relinquished). The node can still be rescheduled, or
+ // it can be freed via free_node.
+ --this->cur_size_;
+
+ // Only try to reheapify if we're not deleting the last entry.
+
+ if (slot < this->cur_size_)
+ {
+ ACE_Timer_Node_T<TYPE> *moved_node =
+ this->heap_[this->cur_size_];
+
+ // Move the end node to the location being removed and update
+ // the corresponding slot in the parallel <timer_ids> array.
+ this->copy (slot, moved_node);
+
+ // If the <moved_node->time_value_> is great than or equal its
+ // parent it needs be moved down the heap.
+ size_t parent = ACE_HEAP_PARENT (slot);
+
+ if (moved_node->get_timer_value ()
+ >= this->heap_[parent]->get_timer_value ())
+ this->reheap_down (moved_node,
+ slot,
+ ACE_HEAP_LCHILD (slot));
+ else
+ this->reheap_up (moved_node,
+ slot,
+ parent);
+ }
+
+ this->timer_ids_[removed_node->get_timer_id ()] = -2;
+ ++this->cur_limbo_;
+ return removed_node;
+}
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK> void
+ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK>::reheap_down (ACE_Timer_Node_T<TYPE> *moved_node,
+ size_t slot,
+ size_t child)
+{
+ // Restore the heap property after a deletion.
+
+ while (child < this->cur_size_)
+ {
+ // Choose the smaller of the two children.
+ if (child + 1 < this->cur_size_
+ && this->heap_[child + 1]->get_timer_value ()
+ < this->heap_[child]->get_timer_value ())
+ child++;
+
+ // Perform a <copy> if the child has a larger timeout value than
+ // the <moved_node>.
+ if (this->heap_[child]->get_timer_value ()
+ < moved_node->get_timer_value ())
+ {
+ this->copy (slot,
+ this->heap_[child]);
+ slot = child;
+ child = ACE_HEAP_LCHILD (child);
+ }
+ else
+ // We've found our location in the heap.
+ break;
+ }
+
+ this->copy (slot, moved_node);
+}
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK> void
+ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK>::reheap_up (ACE_Timer_Node_T<TYPE> *moved_node,
+ size_t slot,
+ size_t parent)
+{
+ // Restore the heap property after an insertion.
+
+ while (slot > 0)
+ {
+ // If the parent node is greater than the <moved_node> we need
+ // to copy it down.
+ if (moved_node->get_timer_value ()
+ < this->heap_[parent]->get_timer_value ())
+ {
+ this->copy (slot, this->heap_[parent]);
+ slot = parent;
+ parent = ACE_HEAP_PARENT (slot);
+ }
+ else
+ break;
+ }
+
+ // Insert the new node into its proper resting place in the heap and
+ // update the corresponding slot in the parallel <timer_ids> array.
+ this->copy (slot,
+ moved_node);
+}
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK> void
+ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK>::insert (ACE_Timer_Node_T<TYPE> *new_node)
+{
+ if (this->cur_size_ + 2 >= this->max_size_)
+ this->grow_heap ();
+
+ this->reheap_up (new_node,
+ this->cur_size_,
+ ACE_HEAP_PARENT (this->cur_size_));
+ this->cur_size_++;
+}
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK> void
+ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK>::grow_heap (void)
+{
+ // All the containers will double in size from max_size_
+ size_t new_size = this->max_size_ * 2;
+
+ // First grow the heap itself.
+
+ ACE_Timer_Node_T<TYPE> **new_heap = 0;
+
+#if defined (__IBMCPP__) && (__IBMCPP__ >= 400) && defined (_WINDOWS)
+ ACE_NEW (new_heap,
+ ACE_Timer_Node_T<TYPE> *[1024]);
+#else
+ ACE_NEW (new_heap,
+ ACE_Timer_Node_T<TYPE> *[new_size]);
+#endif /* defined (__IBMCPP__) && (__IBMCPP__ >= 400) && defined (_WINDOWS) */
+ ACE_OS::memcpy (new_heap,
+ this->heap_,
+ this->max_size_ * sizeof *new_heap);
+ delete [] this->heap_;
+ this->heap_ = new_heap;
+
+ // Grow the array of timer ids.
+
+ long *new_timer_ids = 0;
+
+ ACE_NEW (new_timer_ids,
+ long[new_size]);
+
+ ACE_OS::memcpy (new_timer_ids,
+ this->timer_ids_,
+ this->max_size_ * sizeof (long));
+
+ delete [] timer_ids_;
+ this->timer_ids_ = new_timer_ids;
+
+ // And add the new elements to the end of the "freelist".
+ for (size_t i = this->max_size_; i < new_size; i++)
+ this->timer_ids_[i] = -((long) (i + 1));
+
+ // Grow the preallocation array (if using preallocation)
+ if (this->preallocated_nodes_ != 0)
+ {
+ // Create a new array with max_size elements to link in to
+ // existing list.
+#if defined (__IBMCPP__) && (__IBMCPP__ >= 400) && defined (_WINDOWS)
+ ACE_NEW (this->preallocated_nodes_,
+ ACE_Timer_Node_T<TYPE>[88]);
+#else
+ ACE_NEW (this->preallocated_nodes_,
+ ACE_Timer_Node_T<TYPE>[this->max_size_]);
+#endif /* defined (__IBMCPP__) && (__IBMCPP__ >= 400) && defined (_WINDOWS) */
+
+ // Add it to the set for later deletion
+ this->preallocated_node_set_.insert (this->preallocated_nodes_);
+
+ // Link new nodes together (as for original list).
+ for (size_t k = 1; k < this->max_size_; k++)
+ this->preallocated_nodes_[k - 1].set_next (&this->preallocated_nodes_[k]);
+
+ // NULL-terminate the new list.
+ this->preallocated_nodes_[this->max_size_ - 1].set_next (0);
+
+ // Link new array to the end of the existling list.
+ if (this->preallocated_nodes_freelist_ == 0)
+ this->preallocated_nodes_freelist_ =
+ &preallocated_nodes_[0];
+ else
+ {
+ ACE_Timer_Node_T<TYPE> *previous =
+ this->preallocated_nodes_freelist_;
+
+ for (ACE_Timer_Node_T<TYPE> *current = this->preallocated_nodes_freelist_->get_next ();
+ current != 0;
+ current = current->get_next ())
+ previous = current;
+
+ previous->set_next (&this->preallocated_nodes_[0]);
+ }
+ }
+
+ this->max_size_ = new_size;
+}
+
+// Reschedule a periodic timer. This function must be called with the
+// mutex lock held.
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK> void
+ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK>::reschedule (ACE_Timer_Node_T<TYPE> *expired)
+{
+ ACE_TRACE ("ACE_Timer_Heap_T::reschedule");
+
+ // If we are rescheduling, then the most recent call was to
+ // remove_first (). That called remove () to remove the node from the
+ // heap, but did not free the timer ID. The ACE_Timer_Node still has
+ // its assigned ID - just needs to be inserted at the new proper
+ // place, and the heap restored properly.
+ if (this->timer_ids_[expired->get_timer_id ()] == -2)
+ --this->cur_limbo_;
+ this->insert (expired);
+}
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK> ACE_Timer_Node_T<TYPE> *
+ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK>::alloc_node (void)
+{
+ ACE_Timer_Node_T<TYPE> *temp = 0;
+
+ // Only allocate a node if we are *not* using the preallocated heap.
+ if (this->preallocated_nodes_ == 0)
+ ACE_NEW_RETURN (temp,
+ ACE_Timer_Node_T<TYPE>,
+ 0);
+ else
+ {
+ // check to see if the heap needs to grow
+ if (this->preallocated_nodes_freelist_ == 0)
+ this->grow_heap ();
+
+ temp = this->preallocated_nodes_freelist_;
+
+ // Remove the first element from the freelist.
+ this->preallocated_nodes_freelist_ =
+ this->preallocated_nodes_freelist_->get_next ();
+ }
+ return temp;
+}
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK> void
+ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK>::free_node (ACE_Timer_Node_T<TYPE> *node)
+{
+
+ // Return this timer id to the freelist.
+ this->push_freelist (node->get_timer_id ());
+
+ // Only free up a node if we are *not* using the preallocated heap.
+ if (this->preallocated_nodes_ == 0)
+ delete node;
+ else
+ {
+ node->set_next (this->preallocated_nodes_freelist_);
+ this->preallocated_nodes_freelist_ = node;
+ }
+}
+
+// Insert a new timer that expires at time future_time; if interval is
+// > 0, the handler will be reinvoked periodically.
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK> long
+ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK>::schedule (const TYPE &type,
+ const void *act,
+ const ACE_Time_Value &future_time,
+ const ACE_Time_Value &interval)
+{
+ ACE_TRACE ("ACE_Timer_Heap_T::schedule");
+
+ ACE_MT (ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, -1));
+
+ if ((this->cur_size_ + this->cur_limbo_) < this->max_size_)
+ {
+ // Obtain the next unique sequence number.
+ int timer_id = this->timer_id ();
+
+ // Obtain the memory to the new node.
+ ACE_Timer_Node_T<TYPE> *temp = 0;
+
+ ACE_ALLOCATOR_RETURN (temp,
+ this->alloc_node (),
+ -1);
+ temp->set (type,
+ act,
+ future_time,
+ interval,
+ 0,
+ timer_id);
+
+ this->insert (temp);
+ return timer_id;
+ }
+ else
+ return -1;
+}
+
+// Locate and remove the single timer with a value of <timer_id> from
+// the timer queue.
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK> int
+ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK>::cancel (long timer_id,
+ const void **act,
+ int dont_call)
+{
+ ACE_TRACE ("ACE_Timer_Heap_T::cancel");
+ ACE_MT (ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, -1));
+
+ // Locate the ACE_Timer_Node that corresponds to the timer_id.
+
+ // Check to see if the timer_id is out of range
+ if (timer_id < 0
+ || (size_t) timer_id > this->max_size_)
+ return 0;
+
+ long timer_node_slot = this->timer_ids_[timer_id];
+
+ // Check to see if timer_id is still valid.
+ if (timer_node_slot < 0)
+ return 0;
+
+ if (timer_id != this->heap_[timer_node_slot]->get_timer_id ())
+ {
+ ACE_ASSERT (timer_id == this->heap_[timer_node_slot]->get_timer_id ());
+ return 0;
+ }
+ else
+ {
+ ACE_Timer_Node_T<TYPE> *temp =
+ this->remove (timer_node_slot);
+
+ if (dont_call == 0)
+ // Call the close hook.
+ this->upcall_functor ().cancellation (*this,
+ temp->get_type ());
+
+ if (act != 0)
+ *act = temp->get_act ();
+
+ this->free_node (temp);
+ return 1;
+ }
+}
+
+// Locate and update the inteval on the timer_id
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK> int
+ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK>::reset_interval (long timer_id,
+ const ACE_Time_Value &interval)
+{
+ ACE_TRACE ("ACE_Timer_Heap_T::reset_interval");
+ ACE_MT (ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, -1));
+
+ // Locate the ACE_Timer_Node that corresponds to the timer_id.
+
+ // Check to see if the timer_id is out of range
+ if (timer_id < 0
+ || (size_t) timer_id > this->max_size_)
+ return -1;
+
+ long timer_node_slot = this->timer_ids_[timer_id];
+
+ // Check to see if timer_id is still valid.
+ if (timer_node_slot < 0)
+ return -1;
+
+ if (timer_id != this->heap_[timer_node_slot]->get_timer_id ())
+ {
+ ACE_ASSERT (timer_id == this->heap_[timer_node_slot]->get_timer_id ());
+ return -1;
+ }
+ else
+ {
+ // Reset the timer interval
+ this->heap_[timer_node_slot]->set_interval (interval);
+ return 0;
+ }
+}
+
+// Locate and remove all values of <type> from the timer queue.
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK> int
+ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK>::cancel (const TYPE &type,
+ int dont_call)
+{
+ ACE_TRACE ("ACE_Timer_Heap_T::cancel");
+ ACE_MT (ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, -1));
+
+ int number_of_cancellations = 0;
+
+ // Try to locate the ACE_Timer_Node that matches the timer_id.
+
+ for (size_t i = 0; i < this->cur_size_; )
+ {
+ if (this->heap_[i]->get_type () == type)
+ {
+ ACE_Timer_Node_T<TYPE> *temp = this->remove (i);
+
+ number_of_cancellations++;
+
+ this->free_node (temp);
+ }
+ else
+ i++;
+ }
+
+ if (dont_call == 0)
+ this->upcall_functor ().cancellation (*this, type);
+
+ return number_of_cancellations;
+}
+
+// Returns the earliest node or returns 0 if the heap is empty.
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK> ACE_Timer_Node_T <TYPE> *
+ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK>::remove_first (void)
+{
+ ACE_TRACE ("ACE_Timer_Heap_T::remove_first");
+
+ if (this->cur_size_ == 0)
+ return 0;
+
+ return this->remove (0);
+}
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK> ACE_Timer_Node_T <TYPE> *
+ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK>::get_first (void)
+{
+ ACE_TRACE ("ACE_Timer_Heap_T::get_first");
+
+ return this->cur_size_ == 0 ? 0 : this->heap_[0];
+}
+
+#endif /* ACE_TIMER_HEAP_T_C */
diff --git a/ace/Timer/Timer_Heap_T.h b/ace/Timer/Timer_Heap_T.h
new file mode 100644
index 00000000000..6039225e797
--- /dev/null
+++ b/ace/Timer/Timer_Heap_T.h
@@ -0,0 +1,329 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Timer_Heap_T.h
+ *
+ * $Id$
+ *
+ * @author Douglas C. Schmidt <schmidt@cs.wustl.edu>
+ */
+//=============================================================================
+
+#ifndef ACE_TIMER_HEAP_T_H
+#define ACE_TIMER_HEAP_T_H
+#include "ace/pre.h"
+
+#include "ace/Timer_Queue_T.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "ace/Free_List.h"
+#include "ace/Unbounded_Set.h"
+
+// Forward declaration
+template <class TYPE, class FUNCTOR, class ACE_LOCK>
+class ACE_Timer_Heap_T;
+
+/**
+ * @class ACE_Timer_Heap_Iterator_T
+ *
+ * @brief Iterates over an <ACE_Timer_Heap_T>.
+ *
+ * This is a generic iterator that can be used to visit every
+ * node of a timer queue. Be aware that it doesn't transverse
+ * in the order of timeout values.
+ */
+template <class TYPE, class FUNCTOR, class ACE_LOCK>
+class ACE_Timer_Heap_Iterator_T : public ACE_Timer_Queue_Iterator_T<TYPE, FUNCTOR, ACE_LOCK>
+{
+public:
+ /// Constructor.
+ ACE_Timer_Heap_Iterator_T (ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK> &);
+
+ /// Destructor.
+ ~ACE_Timer_Heap_Iterator_T (void);
+
+ /// Positions the iterator at the earliest node in the Timer Queue
+ virtual void first (void);
+
+ /// Positions the iterator at the next node in the Timer Queue
+ virtual void next (void);
+
+ /// Returns true when there are no more nodes in the sequence
+ virtual int isdone (void) const;
+
+ /// Returns the node at the current position in the sequence
+ virtual ACE_Timer_Node_T<TYPE> *item (void);
+
+protected:
+ /// Pointer to the <ACE_Timer_Heap> that we are iterating over.
+ ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK> &timer_heap_;
+
+ /// Position in the array where the iterator is at
+ size_t position_;
+};
+
+/**
+ * @class ACE_Timer_Heap_T
+ *
+ * @brief Provides a very fast and predictable timer implementation.
+ *
+ * This implementation uses a heap-based callout queue of
+ * absolute times. Therefore, in the average and worst case,
+ * scheduling, canceling, and expiring timers is O(log N) (where
+ * N is the total number of timers). In addition, we can also
+ * preallocate as many @c ACE_Timer_Node objects as there are slots
+ * in the heap. This allows us to completely remove the need for
+ * dynamic memory allocation, which is important for real-time
+ * systems.
+ */
+template <class TYPE, class FUNCTOR, class ACE_LOCK>
+class ACE_Timer_Heap_T : public ACE_Timer_Queue_T<TYPE, FUNCTOR, ACE_LOCK>
+{
+public:
+ typedef ACE_Timer_Heap_Iterator_T<TYPE, FUNCTOR, ACE_LOCK> HEAP_ITERATOR;
+ friend class ACE_Timer_Heap_Iterator_T<TYPE, FUNCTOR, ACE_LOCK>;
+
+ typedef ACE_Timer_Queue_T<TYPE, FUNCTOR, ACE_LOCK> INHERITED;
+
+ // = Initialization and termination methods.
+ /**
+ * The Constructor creates a heap with specified number of elements.
+ * This can also take in a upcall functor and freelist (if 0, then
+ * defaults will be created).
+ *
+ * @param size size_t, the maximum number of timers that can be
+ * inserted into the new object.
+ * @param preallocated int (default 0), if non-0 then all the memory
+ * for the @c ACE_Timer_Node objects will be pre-allocated. This saves
+ * time and is more predictable (though it requires more space).
+ * Otherwise, timer nodes are allocated as needed.
+ */
+ ACE_Timer_Heap_T (size_t size,
+ int preallocated = 0,
+ FUNCTOR *upcall_functor = 0,
+ ACE_Free_List<ACE_Timer_Node_T <TYPE> > *freelist = 0);
+
+ /**
+ * Default constructor. @c upcall_functor is the instance of the
+ * FUNCTOR to be used by the queue. If @c upcall_functor is 0, Timer
+ * Heap will create a default FUNCTOR. @c freelist is the freelist of
+ * timer nodes. If 0, then a default freelist will be created. The default
+ * size will be ACE_DEFAULT_TIMERS and there will be no preallocation.
+ */
+ ACE_Timer_Heap_T (FUNCTOR *upcall_functor = 0,
+ ACE_Free_List<ACE_Timer_Node_T <TYPE> > *freelist = 0);
+
+ /// Destructor.
+ virtual ~ACE_Timer_Heap_T (void);
+
+ /// True if heap is empty, else false.
+ virtual int is_empty (void) const;
+
+ /// Returns the time of the earliest node in the Timer_Queue.
+ /// Must be called on a non-empty queue.
+ virtual const ACE_Time_Value &earliest_time (void) const;
+
+ /**
+ * Schedule a timer that may optionally auto-reset.
+ * Schedule <type> that will expire after <delay> amount of time,
+ * which is specified in absolute time. If it expires then <act> is
+ * passed in as the value to the <functor>. If <interval> is != to
+ * <ACE_Time_Value::zero> then it is used to reschedule the <type>
+ * automatically, using relative time to the current <gettimeofday>.
+ * This method returns a <timer_id> that uniquely identifies the the
+ * <type> entry in an internal list. This <timer_id> can be used to
+ * cancel the timer before it expires. The cancellation ensures
+ * that <timer_ids> are unique up to values of greater than 2
+ * billion timers. As long as timers don't stay around longer than
+ * this there should be no problems with accidentally deleting the
+ * wrong timer. Returns -1 on failure (which is guaranteed never to
+ * be a valid <timer_id>).
+ */
+ virtual long schedule (const TYPE &type,
+ const void *act,
+ const ACE_Time_Value &delay,
+ const ACE_Time_Value &interval = ACE_Time_Value::zero);
+
+ /**
+ * Resets the interval of the timer represented by <timer_id> to
+ * <interval>, which is specified in relative time to the current
+ * <gettimeofday>. If <interval> is equal to
+ * <ACE_Time_Value::zero>, the timer will become a non-rescheduling
+ * timer. Returns 0 if successful, -1 if not.
+ */
+ virtual int reset_interval (long timer_id,
+ const ACE_Time_Value &interval);
+
+ /**
+ * Cancel all timer associated with <type>. If <dont_call> is 0
+ * then the <functor> will be invoked. Returns number of timers
+ * cancelled.
+ */
+ virtual int cancel (const TYPE &type,
+ int dont_call_handle_close = 1);
+
+ /**
+ * Cancel the single timer that matches the <timer_id> value (which
+ * was returned from the <schedule> method). If act is non-NULL
+ * then it will be set to point to the ``magic cookie'' argument
+ * passed in when the timer was registered. This makes it possible
+ * to free up the memory and avoid memory leaks. If <dont_call> is
+ * 0 then the <functor> will be invoked. Returns 1 if cancellation
+ * succeeded and 0 if the <timer_id> wasn't found.
+ */
+ virtual int cancel (long timer_id,
+ const void **act = 0,
+ int dont_call_handle_close = 1);
+
+ /// Returns a pointer to this <ACE_Timer_Queue>'s iterator.
+ virtual ACE_Timer_Queue_Iterator_T<TYPE, FUNCTOR, ACE_LOCK> &iter (void);
+
+ /// Removes the earliest node from the queue and returns it. Note that
+ /// the timer is removed from the heap, but is not freed, and its ID
+ /// is not reclaimed. The caller is responsible for calling either
+ /// @c reschedule or @c free_node after this function returns. Thus,
+ /// this function is for support of @c ACE_Timer_Queue::expire and
+ /// should not be used unadvisedly in other conditions.
+ ACE_Timer_Node_T <TYPE> *remove_first (void);
+
+ /// Dump the state of an object.
+ virtual void dump (void) const;
+
+ /// Reads the earliest node from the queue and returns it.
+ virtual ACE_Timer_Node_T<TYPE> *get_first (void);
+
+protected:
+ /// Reschedule an "interval" <ACE_Timer_Node>.
+ virtual void reschedule (ACE_Timer_Node_T<TYPE> *);
+
+ /// Factory method that allocates a new node (uses operator new if
+ /// we're *not* preallocating, otherwise uses an internal freelist).
+ virtual ACE_Timer_Node_T<TYPE> *alloc_node (void);
+
+ /**
+ * Factory method that frees a previously allocated node (uses
+ * operator delete if we're *not* preallocating, otherwise uses an
+ * internal freelist).
+ */
+ virtual void free_node (ACE_Timer_Node_T<TYPE> *);
+
+private:
+ /// Remove and return the <slot>th <ACE_Timer_Node> and restore the
+ /// heap property.
+ ACE_Timer_Node_T<TYPE> *remove (size_t slot);
+
+ /// Insert <new_node> into the heap and restore the heap property.
+ void insert (ACE_Timer_Node_T<TYPE> *new_node);
+
+ /**
+ * Doubles the size of the heap and the corresponding timer_ids array.
+ * If preallocation is used, will also double the size of the
+ * preallocated array of ACE_Timer_Nodes.
+ */
+ void grow_heap (void);
+
+ /// Restore the heap property, starting at <slot>.
+ void reheap_up (ACE_Timer_Node_T<TYPE> *new_node,
+ size_t slot,
+ size_t parent);
+
+ /// Restore the heap property, starting at <slot>.
+ void reheap_down (ACE_Timer_Node_T<TYPE> *moved_node,
+ size_t slot,
+ size_t child);
+
+ /// Copy <moved_node> into the <slot> slot of <heap_> and move
+ /// <slot> into the corresponding slot in the <timer_id_> array.
+ void copy (int slot, ACE_Timer_Node_T<TYPE> *moved_node);
+
+ /**
+ * Returns a timer id that uniquely identifies this timer. This id
+ * can be used to cancel a timer via the <cancel (int)> method. The
+ * timer id returned from this method will never == -1 to avoid
+ * conflicts with other failure return values.
+ */
+ int timer_id (void);
+
+ /// Pops and returns a new timer id from the freelist.
+ int pop_freelist (void);
+
+ /// Pushes <old_id> onto the freelist.
+ void push_freelist (int old_id);
+
+ /// Maximum size of the heap.
+ size_t max_size_;
+
+ /// Current size of the heap.
+ size_t cur_size_;
+
+ /// Number of heap entries in transition (removed from the queue, but
+ /// not freed) and may be rescheduled or freed.
+ size_t cur_limbo_;
+
+ /// Iterator used to expire timers.
+ HEAP_ITERATOR *iterator_;
+
+ /**
+ * Current contents of the Heap, which is organized as a "heap" of
+ * <ACE_Timer_Node> *'s. In this context, a heap is a "partially
+ * ordered, almost complete" binary tree, which is stored in an
+ * array.
+ */
+ ACE_Timer_Node_T<TYPE> **heap_;
+
+ /**
+ * An array of "pointers" that allows each <ACE_Timer_Node> in the
+ * <heap_> to be located in O(1) time. Basically, <timer_id_[i]>
+ * contains the slot in the <heap_> array where an <ACE_Timer_Node>
+ * * with timer id <i> resides. Thus, the timer id passed back from
+ * <schedule> is really a slot into the <timer_ids> array. The
+ * <timer_ids_> array serves two purposes: negative values are
+ * indications of free timer IDs, whereas positive values are
+ * "pointers" into the <heap_> array for assigned timer IDs.
+ */
+ long *timer_ids_;
+
+ /// "Pointer" to the element in the <timer_ids_> array that was
+ /// last given out as a timer ID.
+ size_t timer_ids_curr_;
+
+ /// Index representing the lowest timer ID that has been freed. When
+ /// the timer_ids_next_ value wraps around, it starts back at this
+ /// point.
+ size_t timer_ids_min_free_;
+
+ /**
+ * If this is non-0, then we preallocate <max_size_> number of
+ * <ACE_Timer_Node> objects in order to reduce dynamic allocation
+ * costs. In auto-growing implementation, this points to the
+ * last array of nodes allocated.
+ */
+ ACE_Timer_Node_T<TYPE> *preallocated_nodes_;
+
+ /// This points to the head of the <preallocated_nodes_> freelist,
+ /// which is organized as a stack.
+ ACE_Timer_Node_T<TYPE> *preallocated_nodes_freelist_;
+
+ /// Set of pointers to the arrays of preallocated timer nodes.
+ /// Used to delete the allocated memory when required.
+ ACE_Unbounded_Set<ACE_Timer_Node_T<TYPE> *> preallocated_node_set_;
+
+ // = Don't allow these operations for now.
+ ACE_UNIMPLEMENTED_FUNC (ACE_Timer_Heap_T (const ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK> &))
+ ACE_UNIMPLEMENTED_FUNC (void operator= (const ACE_Timer_Heap_T<TYPE, FUNCTOR, ACE_LOCK> &))
+};
+
+#if defined (ACE_TEMPLATES_REQUIRE_SOURCE) && !defined(ACE_HAS_BROKEN_HPUX_TEMPLATES)
+#include "ace/Timer_Heap_T.cpp"
+#endif /* ACE_TEMPLATES_REQUIRE_SOURCE && !ACE_HAS_BROKEN_HPUX_TEMPLATES */
+
+#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA)
+#pragma implementation ("Timer_Heap_T.cpp")
+#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */
+
+#include "ace/post.h"
+#endif /* ACE_TIMER_HEAP_T_H */
diff --git a/ace/Timer/Timer_List.cpp b/ace/Timer/Timer_List.cpp
new file mode 100644
index 00000000000..3834178a0b0
--- /dev/null
+++ b/ace/Timer/Timer_List.cpp
@@ -0,0 +1,44 @@
+// $Id$
+
+#if !defined (ACE_TIMER_LIST_C)
+#define ACE_TIMER_LIST_C
+
+#include "ace/Timer_List.h"
+
+ACE_RCSID(ace, Timer_List, "$Id$")
+
+#if defined (ACE_HAS_BROKEN_HPUX_TEMPLATES)
+#include "ace/Timer_Hash.h"
+#include "ace/Timer_List_T.cpp"
+
+#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION)
+template class
+ ACE_Timer_List_T<
+ ACE_Event_Handler*,
+ ACE_Timer_Hash_Upcall<
+ ACE_Event_Handler*,
+ ACE_Event_Handler_Handle_Timeout_Upcall<ACE_Null_Mutex>,
+ ACE_Null_Mutex>,
+ ACE_Null_Mutex>;
+
+template class
+ACE_Timer_List_Iterator_T<
+ ACE_Event_Handler*,
+ ACE_Timer_Hash_Upcall<
+ ACE_Event_Handler*,
+ ACE_Event_Handler_Handle_Timeout_Upcall<ACE_Null_Mutex>,
+ ACE_Null_Mutex>,
+ ACE_Null_Mutex>;
+#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */
+#endif /* ACE_HAS_BROKEN_HPUX_TEMPLATES */
+
+#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION)
+template class ACE_Timer_List_T<ACE_Event_Handler *, ACE_Event_Handler_Handle_Timeout_Upcall<ACE_SYNCH_RECURSIVE_MUTEX>, ACE_SYNCH_RECURSIVE_MUTEX>;
+template class ACE_Timer_List_Iterator_T<ACE_Event_Handler *, ACE_Event_Handler_Handle_Timeout_Upcall<ACE_SYNCH_RECURSIVE_MUTEX>, ACE_SYNCH_RECURSIVE_MUTEX>;
+#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA)
+#pragma instantiate ACE_Timer_List_T<ACE_Event_Handler *, ACE_Event_Handler_Handle_Timeout_Upcall<ACE_SYNCH_RECURSIVE_MUTEX>, ACE_SYNCH_RECURSIVE_MUTEX>
+#pragma instantiate ACE_Timer_List_Iterator_T<ACE_Event_Handler *, ACE_Event_Handler_Handle_Timeout_Upcall<ACE_SYNCH_RECURSIVE_MUTEX>, ACE_SYNCH_RECURSIVE_MUTEX>
+#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */
+
+
+#endif /* ACE_TIMER_LIST_C */
diff --git a/ace/Timer/Timer_List.h b/ace/Timer/Timer_List.h
new file mode 100644
index 00000000000..a9586061307
--- /dev/null
+++ b/ace/Timer/Timer_List.h
@@ -0,0 +1,38 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Timer_List.h
+ *
+ * $Id$
+ *
+ * @author Doug Schmidt
+ */
+//=============================================================================
+
+
+#ifndef ACE_TIMER_LIST_H
+#define ACE_TIMER_LIST_H
+#include "ace/pre.h"
+
+#include "ace/Timer_List_T.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+// The following typedef are here for ease of use and backward
+// compatibility.
+
+typedef ACE_Timer_List_T<ACE_Event_Handler *,
+ ACE_Event_Handler_Handle_Timeout_Upcall<ACE_SYNCH_RECURSIVE_MUTEX>,
+ ACE_SYNCH_RECURSIVE_MUTEX>
+ ACE_Timer_List;
+
+typedef ACE_Timer_List_Iterator_T<ACE_Event_Handler *,
+ ACE_Event_Handler_Handle_Timeout_Upcall<ACE_SYNCH_RECURSIVE_MUTEX>,
+ ACE_SYNCH_RECURSIVE_MUTEX>
+ ACE_Timer_List_Iterator;
+
+#include "ace/post.h"
+#endif /* ACE_TIMER_LIST_H */
diff --git a/ace/Timer/Timer_List_T.cpp b/ace/Timer/Timer_List_T.cpp
new file mode 100644
index 00000000000..710521bcc05
--- /dev/null
+++ b/ace/Timer/Timer_List_T.cpp
@@ -0,0 +1,342 @@
+// $Id$
+
+#ifndef ACE_TIMER_LIST_T_C
+#define ACE_TIMER_LIST_T_C
+
+#include "ace/Timer_List_T.h"
+#include "ace/Log_Msg.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+ACE_RCSID(ace, Timer_List_T, "$Id$")
+
+// Default Constructor
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK>
+ACE_Timer_List_Iterator_T<TYPE, FUNCTOR, ACE_LOCK>::ACE_Timer_List_Iterator_T (ACE_Timer_List_T<TYPE, FUNCTOR, ACE_LOCK> &timer_list)
+ : timer_list_ (timer_list)
+{
+ this->first();
+ // Nothing
+}
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK>
+ACE_Timer_List_Iterator_T<TYPE, FUNCTOR, ACE_LOCK>::~ACE_Timer_List_Iterator_T (void)
+{
+}
+
+// Positions the iterator at the node right after the dummy node
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK> void
+ACE_Timer_List_Iterator_T<TYPE, FUNCTOR, ACE_LOCK>::first (void)
+{
+ this->position_ = this->timer_list_.head_->get_next ();
+}
+
+// Positions the iterator at the next node in the Timer Queue
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK> void
+ACE_Timer_List_Iterator_T<TYPE, FUNCTOR, ACE_LOCK>::next (void)
+{
+ // Make sure that if we are at the end, we don't wrap around
+ if (this->position_ != this->timer_list_.head_)
+ this->position_ = this->position_->get_next ();
+}
+
+// Returns true when we are at <head_>
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK> int
+ACE_Timer_List_Iterator_T<TYPE, FUNCTOR, ACE_LOCK>::isdone (void) const
+{
+ return this->position_ == this->timer_list_.head_;
+}
+
+// Returns the node at <position_> or 0 if we are at the end
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK> ACE_Timer_Node_T<TYPE> *
+ACE_Timer_List_Iterator_T<TYPE, FUNCTOR, ACE_LOCK>::item (void)
+{
+ if (this->position_ != this->timer_list_.head_)
+ return this->position_;
+ return 0;
+}
+
+// Return our instance of the iterator
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK> ACE_Timer_Queue_Iterator_T<TYPE, FUNCTOR, ACE_LOCK> &
+ACE_Timer_List_T<TYPE, FUNCTOR, ACE_LOCK>::iter (void)
+{
+ this->iterator_->first ();
+ return *this->iterator_;
+}
+
+// Create an empty list.
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK>
+ACE_Timer_List_T<TYPE, FUNCTOR, ACE_LOCK>::ACE_Timer_List_T (FUNCTOR *upcall_functor,
+ ACE_Free_List<ACE_Timer_Node_T <TYPE> > *freelist)
+ : ACE_Timer_Queue_T<TYPE, FUNCTOR, ACE_LOCK> (upcall_functor, freelist),
+ head_ (new ACE_Timer_Node_T<TYPE>),
+ timer_id_ (0)
+{
+ ACE_TRACE ("ACE_Timer_List_T::ACE_Timer_List");
+
+ this->head_->set_next (this->head_);
+ this->head_->set_prev (this->head_);
+
+ ACE_NEW (iterator_,
+ LIST_ITERATOR (*this));
+}
+
+
+// Checks if list is empty.
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK> int
+ACE_Timer_List_T<TYPE, FUNCTOR, ACE_LOCK>::is_empty (void) const
+{
+ ACE_TRACE ("ACE_Timer_List_T::is_empty");
+ return this->head_->get_next () == this->head_;
+}
+
+
+// Returns earliest time in a non-empty list.
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK> const ACE_Time_Value &
+ACE_Timer_List_T<TYPE, FUNCTOR, ACE_LOCK>::earliest_time (void) const
+{
+ ACE_TRACE ("ACE_Timer_List_T::earliest_time");
+ return this->head_->get_next ()->get_timer_value ();
+}
+
+
+// Remove all remaining items in the list.
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK>
+ACE_Timer_List_T<TYPE, FUNCTOR, ACE_LOCK>::~ACE_Timer_List_T (void)
+{
+ ACE_TRACE ("ACE_Timer_List_T::~ACE_Timer_List_T");
+ ACE_MT (ACE_GUARD (ACE_LOCK, ace_mon, this->mutex_));
+
+ delete iterator_;
+
+ for (ACE_Timer_Node_T<TYPE> *curr = this->head_->get_next ();
+ curr != this->head_;
+ )
+ {
+ ACE_Timer_Node_T<TYPE> *next = curr->get_next ();
+ this->upcall_functor ().deletion (*this,
+ next->get_type (),
+ next->get_act ());
+ this->free_node (curr);
+ curr = next;
+ }
+
+ // delete the dummy node
+ delete this->head_;
+}
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK> void
+ACE_Timer_List_T<TYPE, FUNCTOR, ACE_LOCK>::dump (void) const
+{
+ ACE_TRACE ("ACE_Timer_List_T::dump");
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+
+ size_t count = 0;
+
+ for (ACE_Timer_Node_T<TYPE> *curr = this->head_->get_next ();
+ curr != this->head_;
+ curr = curr->get_next ())
+ count++;
+
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\nsize_ = %d"), count));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\ntimer_id_ = %d"), this->timer_id_));
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+
+// Reschedule a periodic timer. This function must be called with the
+// lock held.
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK> void
+ACE_Timer_List_T<TYPE, FUNCTOR, ACE_LOCK>::reschedule (ACE_Timer_Node_T<TYPE> *expired)
+{
+ ACE_TRACE ("ACE_Timer_List_T::reschedule");
+
+ ACE_Timer_Node_T<TYPE> *after = this->head_->get_next ();
+
+ // Locate the proper position in the queue.
+
+ while (after != this->head_
+ && expired->get_timer_value () > after->get_timer_value ())
+ after = after->get_next ();
+
+ expired->set_next (after);
+ expired->set_prev (after->get_prev ());
+ after->get_prev ()->set_next (expired);
+ after->set_prev (expired);
+}
+
+
+// Insert a new handler that expires at time future_time; if interval
+// is > 0, the handler will be reinvoked periodically.
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK> long
+ACE_Timer_List_T<TYPE, FUNCTOR, ACE_LOCK>::schedule (const TYPE &type,
+ const void *act,
+ const ACE_Time_Value &future_time,
+ const ACE_Time_Value &interval)
+{
+ ACE_TRACE ("ACE_Timer_List_T::schedule");
+ ACE_MT (ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, -1));
+
+ // Place in the middle of the list where it belongs (i.e., sorted in
+ // ascending order of absolute time to expire).
+ ACE_Timer_Node_T<TYPE> *after = this->head_->get_next ();
+
+ while (after != this->head_
+ && future_time > after->get_timer_value ())
+ after = after->get_next ();
+
+ ACE_Timer_Node_T<TYPE> *temp = this->alloc_node ();
+
+ temp->set (type,
+ act,
+ future_time,
+ interval,
+ after->get_prev (),
+ after,
+ (long) temp);
+
+ after->get_prev ()->set_next (temp);
+ after->set_prev (temp);
+
+ return ACE_reinterpret_cast (long, temp);
+}
+
+// Locate and update the inteval on the timer_id
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK> int
+ACE_Timer_List_T<TYPE, FUNCTOR, ACE_LOCK>::reset_interval (long timer_id,
+ const ACE_Time_Value &interval)
+{
+ ACE_TRACE ("ACE_Timer_List_T::reset_interval");
+ ACE_MT (ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, -1));
+
+ // Make sure we are getting a valid <timer_id>, not an error
+ // returned by <schedule>.
+ if (timer_id == -1)
+ return -1;
+
+ ACE_Timer_Node_T<TYPE> *node =
+ ACE_reinterpret_cast (ACE_Timer_Node_T<TYPE> *,
+ timer_id);
+
+ node->set_interval (interval);
+
+ return 0;
+}
+
+// Locate and remove the single <ACE_Event_Handler> with a value of
+// <timer_id> from the timer queue.
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK> int
+ACE_Timer_List_T<TYPE, FUNCTOR, ACE_LOCK>::cancel (long timer_id,
+ const void **act,
+ int dont_call)
+{
+ ACE_TRACE ("ACE_Timer_List_T::cancel");
+ ACE_MT (ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, -1));
+
+ // Make sure we are getting a valid <timer_id>, not an error
+ // returned by schedule ()
+ if (timer_id == -1)
+ return 0;
+
+ ACE_Timer_Node_T<TYPE> *node =
+ ACE_reinterpret_cast (ACE_Timer_Node_T<TYPE> *,
+ timer_id);
+
+ // Check to see if the node looks like a true ACE_Timer_Node_T<TYPE>
+ if (timer_id == node->get_timer_id ())
+ {
+ node->get_next ()->set_prev (node->get_prev ());
+ node->get_prev ()->set_next (node->get_next ());
+
+ if (act != 0)
+ *act = node->get_act ();
+
+ if (dont_call == 0)
+ this->upcall_functor ().cancellation (*this,
+ node->get_type ());
+ this->free_node (node);
+ return 1;
+ }
+
+ // Wasn't valid
+ return 0;
+}
+
+
+// Locate and remove all values of <handler> from the timer queue.
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK> int
+ACE_Timer_List_T<TYPE, FUNCTOR, ACE_LOCK>::cancel (const TYPE &type,
+ int dont_call)
+{
+ ACE_TRACE ("ACE_Timer_List_T::cancel");
+ ACE_MT (ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, -1));
+
+ int number_of_cancellations = 0;
+
+ for (ACE_Timer_Node_T<TYPE> *curr = this->head_->get_next ();
+ curr != this->head_;
+ )
+ {
+ if (curr->get_type () == type)
+ {
+ number_of_cancellations++;
+
+ curr->get_prev ()->set_next (curr->get_next ());
+ curr->get_next ()->set_prev (curr->get_prev ());
+ ACE_Timer_Node_T<TYPE> *temp = curr;
+ curr = curr->get_next ();
+ this->free_node (temp);
+ }
+ else
+ curr = curr->get_next ();
+ }
+
+ if (dont_call == 0)
+ this->upcall_functor ().cancellation (*this, type);
+
+ return number_of_cancellations;
+}
+
+// Reads the first node on the list and returns it.
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK> ACE_Timer_Node_T<TYPE> *
+ACE_Timer_List_T<TYPE, FUNCTOR, ACE_LOCK>::get_first (void)
+{
+ ACE_TRACE ("ACE_Timer_List_T::get_first");
+
+ return this->head_->get_next ();
+}
+
+// Removes the first node on the list and returns it.
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK> ACE_Timer_Node_T<TYPE> *
+ACE_Timer_List_T<TYPE, FUNCTOR, ACE_LOCK>::remove_first (void)
+{
+ ACE_TRACE ("ACE_Timer_List_T::remove_first");
+
+ // remove the node and fix the pointers
+ ACE_Timer_Node_T<TYPE> *temp = this->head_->get_next ();
+ this->head_->set_next (temp->get_next ());
+ temp->get_next ()->set_prev (this->head_);
+
+ return temp;
+}
+
+#endif /* ACE_TIMER_LIST_T_C */
diff --git a/ace/Timer/Timer_List_T.h b/ace/Timer/Timer_List_T.h
new file mode 100644
index 00000000000..a863ce39a3c
--- /dev/null
+++ b/ace/Timer/Timer_List_T.h
@@ -0,0 +1,217 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Timer_List_T.h
+ *
+ * $Id$
+ *
+ * @author Douglas C. Schmidt <schmidt@cs.wustl.edu>
+ */
+//=============================================================================
+
+#ifndef ACE_TIMER_LIST_T_H
+#define ACE_TIMER_LIST_T_H
+#include "ace/pre.h"
+
+#include "ace/Timer_Queue_T.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+// Forward declaration.
+template <class TYPE, class FUNCTOR, class ACE_LOCK>
+class ACE_Timer_List_T;
+
+/**
+ * @class ACE_Timer_List_Iterator_T
+ *
+ * @brief Iterates over an <ACE_Timer_List>.
+ *
+ * This is a generic iterator that can be used to visit every
+ * node of a timer queue.
+ */
+template <class TYPE, class FUNCTOR, class ACE_LOCK>
+class ACE_Timer_List_Iterator_T : public ACE_Timer_Queue_Iterator_T <TYPE, FUNCTOR, ACE_LOCK>
+{
+public:
+ /// Constructor.
+ ACE_Timer_List_Iterator_T (ACE_Timer_List_T<TYPE, FUNCTOR, ACE_LOCK> &);
+
+ /// Destructor.
+ ~ACE_Timer_List_Iterator_T (void);
+
+ /// Positions the iterator at the earliest node in the Timer Queue
+ virtual void first (void);
+
+ /// Positions the iterator at the next node in the Timer Queue
+ virtual void next (void);
+
+ /// Returns true when there are no more nodes in the sequence
+ virtual int isdone (void) const;
+
+ /// Returns the node at the current position in the sequence
+ virtual ACE_Timer_Node_T<TYPE> *item (void);
+
+protected:
+ /// Pointer to the <ACE_Timer_List> that we are iterating over.
+ ACE_Timer_List_T<TYPE, FUNCTOR, ACE_LOCK> &timer_list_;
+
+ ACE_Timer_Node_T<TYPE> *position_;
+};
+
+/**
+ * @class ACE_Timer_List_T
+ *
+ * @brief Provides a simple implementation of timers.
+ *
+ * This implementation uses a linked list of absolute times.
+ * Therefore, in the average case, scheduling and canceling
+ * timers is O(N) (where N is the total number of timers) and
+ * expiring timers is O(K) (where K is the total number of timers
+ * that are < the current time of day).
+ * More clever implementations could use a delta-list, a heap,
+ * or timing wheels, etc. For instance, <ACE_Timer_Heap>
+ * is a subclass of <ACE_Timer_List> that implements a
+ * heap-based callout queue. For most applications, the
+ * <ACE_Timer_Heap> will perform substantially faster than the
+ * <ACE_Timer_List>.
+ */
+template <class TYPE, class FUNCTOR, class ACE_LOCK>
+class ACE_Timer_List_T : public ACE_Timer_Queue_T<TYPE, FUNCTOR, ACE_LOCK>
+{
+public:
+ /// Type of iterator
+ typedef ACE_Timer_List_Iterator_T<TYPE, FUNCTOR, ACE_LOCK> LIST_ITERATOR;
+
+ /// Iterator is a friend
+ friend class ACE_Timer_List_Iterator_T<TYPE, FUNCTOR, ACE_LOCK>;
+
+ /// Type inherited from
+ typedef ACE_Timer_Queue_T<TYPE, FUNCTOR, ACE_LOCK> INHERITED;
+
+ // = Initialization and termination methods.
+ /**
+ * Default constructor. <upcall_functor> is the instance of the
+ * FUNCTOR to be used by the list. If <upcall_functor> is 0, a
+ * default FUNCTOR will be created. <freelist> the freelist of
+ * timer nodes. If 0, then a default freelist will be created.
+ */
+ ACE_Timer_List_T (FUNCTOR *upcall_functor = 0,
+ ACE_Free_List<ACE_Timer_Node_T <TYPE> > *freelist = 0);
+
+ /// Destructor
+ virtual ~ACE_Timer_List_T (void);
+
+ /// True if queue is empty, else false.
+ virtual int is_empty (void) const;
+
+ /// Returns the time of the earlier node in the <ACE_Timer_List>.
+ /// Must be called on a non-empty queue.
+ virtual const ACE_Time_Value &earliest_time (void) const;
+
+ /**
+ * Schedule <type> that will expire after <delay> amount of time,
+ * which is specified in absolute time. If it expires then <act> is
+ * passed in as the value to the <functor>. If <interval> is != to
+ * <ACE_Time_Value::zero> then it is used to reschedule the <type>
+ * automatically, using relative time to the current <gettimeofday>.
+ * This method returns a <timer_id> that uniquely identifies the the
+ * <type> entry in an internal list. This <timer_id> can be used to
+ * cancel the timer before it expires. The cancellation ensures
+ * that <timer_ids> are unique up to values of greater than 2
+ * billion timers. As long as timers don't stay around longer than
+ * this there should be no problems with accidentally deleting the
+ * wrong timer. Returns -1 on failure (which is guaranteed never to
+ * be a valid <timer_id>).
+ */
+ virtual long schedule (const TYPE &type,
+ const void *act,
+ const ACE_Time_Value &delay,
+ const ACE_Time_Value &interval = ACE_Time_Value::zero);
+
+ /**
+ * Resets the interval of the timer represented by <timer_id> to
+ * <interval>, which is specified in relative time to the current
+ * <gettimeofday>. If <interval> is equal to
+ * <ACE_Time_Value::zero>, the timer will become a non-rescheduling
+ * timer. Returns 0 if successful, -1 if not.
+ */
+ virtual int reset_interval (long timer_id,
+ const ACE_Time_Value &interval);
+
+ /**
+ * Cancel all timer associated with <type>. If <dont_call> is 0
+ * then the <functor> will be invoked. Returns number of timers
+ * cancelled.
+ */
+ virtual int cancel (const TYPE &type,
+ int dont_call_handle_close = 1);
+
+ /**
+ * Cancel the single timer that matches the <timer_id> value (which
+ * was returned from the <schedule> method). If act is non-NULL
+ * then it will be set to point to the ``magic cookie'' argument
+ * passed in when the timer was registered. This makes it possible
+ * to free up the memory and avoid memory leaks. If <dont_call> is
+ * 0 then the <functor> will be invoked. Returns 1 if cancellation
+ * succeeded and 0 if the <timer_id> wasn't found.
+ */
+ virtual int cancel (long timer_id,
+ const void **act = 0,
+ int dont_call_handle_close = 1);
+
+ /// Returns a pointer to this <ACE_Timer_Queue>'s iterator.
+ virtual ACE_Timer_Queue_Iterator_T<TYPE, FUNCTOR, ACE_LOCK> &iter (void);
+
+ /// Removes the earliest node from the queue and returns it
+ virtual ACE_Timer_Node_T<TYPE> *remove_first (void);
+
+ /// Dump the state of an object.
+ virtual void dump (void) const;
+
+ /// Reschedule an "interval" <ACE_Timer_Node>. This should be private
+ /// but for now it needs to be public for <ACE_Timer_Hash_T>
+ virtual void reschedule (ACE_Timer_Node_T<TYPE> *);
+
+ /// Reads the earliest node from the queue and returns it.
+ virtual ACE_Timer_Node_T<TYPE> *get_first (void);
+
+protected:
+ /// Factory method that allocates a new node (uses operator new).
+/* virtual ACE_Timer_Node_T<TYPE> *alloc_node (void);
+
+ /// Factory method that frees a previously allocated node (uses
+ /// operator delete).
+ virtual void free_node (ACE_Timer_Node_T<TYPE> *);
+*/
+private:
+ /// Pointer to linked list of <ACE_Timer_Handles>.
+ ACE_Timer_Node_T<TYPE> *head_;
+
+ /// Iterator used to expire timers.
+ LIST_ITERATOR *iterator_;
+
+ /**
+ * Keeps track of the timer id that uniquely identifies each timer.
+ * This id can be used to cancel a timer via the <cancel (int)>
+ * method.
+ */
+ long timer_id_;
+
+ // = Don't allow these operations for now.
+ ACE_UNIMPLEMENTED_FUNC (ACE_Timer_List_T (const ACE_Timer_List_T<TYPE, FUNCTOR, ACE_LOCK> &))
+ ACE_UNIMPLEMENTED_FUNC (void operator= (const ACE_Timer_List_T<TYPE, FUNCTOR, ACE_LOCK> &))
+};
+
+#if defined (ACE_TEMPLATES_REQUIRE_SOURCE) && !defined(ACE_HAS_BROKEN_HPUX_TEMPLATES)
+#include "ace/Timer_List_T.cpp"
+#endif /* ACE_TEMPLATES_REQUIRE_SOURCE && !ACE_HAS_BROKEN_HPUX_TEMPLATES */
+
+#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA)
+#pragma implementation ("Timer_List_T.cpp")
+#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */
+
+#include "ace/post.h"
+#endif /* ACE_TIMER_LIST_T_H */
diff --git a/ace/Timer/Timer_Queue.cpp b/ace/Timer/Timer_Queue.cpp
new file mode 100644
index 00000000000..cfcfcd13ae6
--- /dev/null
+++ b/ace/Timer/Timer_Queue.cpp
@@ -0,0 +1,60 @@
+// $Id$
+
+#if !defined (ACE_TIMER_QUEUE_C)
+#define ACE_TIMER_QUEUE_C
+
+#include "ace/Containers.h"
+#include "ace/Timer_Queue.h"
+
+ACE_RCSID(ace, Timer_Queue, "$Id$")
+
+#if defined (ACE_HAS_BROKEN_HPUX_TEMPLATES)
+#include "ace/Timer_Hash.h"
+#include "ace/Timer_Queue_T.cpp"
+
+#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION)
+template class
+ ACE_Timer_Queue_T<
+ ACE_Event_Handler*,
+ ACE_Timer_Hash_Upcall<
+ ACE_Event_Handler*,
+ ACE_Event_Handler_Handle_Timeout_Upcall<ACE_Null_Mutex>,
+ ACE_Null_Mutex>,
+ ACE_Null_Mutex>;
+
+template class
+ ACE_Timer_Queue_Iterator_T<
+ ACE_Event_Handler*,
+ ACE_Timer_Hash_Upcall<
+ ACE_Event_Handler*,
+ ACE_Event_Handler_Handle_Timeout_Upcall<ACE_Null_Mutex>,
+ ACE_Null_Mutex>,
+ ACE_Null_Mutex>;
+#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */
+#endif /* ACE_HAS_BROKEN_HPUX_TEMPLATES */
+
+#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION)
+template class ACE_Unbounded_Set<ACE_Timer_Node_T<ACE_Event_Handler *> *>;
+template class ACE_Node<ACE_Timer_Node_T<ACE_Event_Handler *> *>;
+template class ACE_Unbounded_Set_Iterator<ACE_Timer_Node_T<ACE_Event_Handler *> *>;
+template class ACE_Timer_Node_Dispatch_Info_T<ACE_Event_Handler *>;
+template class ACE_Timer_Node_T<ACE_Event_Handler *>;
+template class ACE_Timer_Queue_T<ACE_Event_Handler *, ACE_Event_Handler_Handle_Timeout_Upcall<ACE_SYNCH_RECURSIVE_MUTEX>, ACE_SYNCH_RECURSIVE_MUTEX>;
+template class ACE_Timer_Queue_Iterator_T<ACE_Event_Handler *, ACE_Event_Handler_Handle_Timeout_Upcall<ACE_SYNCH_RECURSIVE_MUTEX>, ACE_SYNCH_RECURSIVE_MUTEX>;
+template class ACE_Event_Handler_Handle_Timeout_Upcall<ACE_SYNCH_RECURSIVE_MUTEX>;
+
+#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA)
+
+#pragma instantiate ACE_Unbounded_Set<ACE_Timer_Node_T<ACE_Event_Handler *> *>
+#pragma instantiate ACE_Node<ACE_Timer_Node_T<ACE_Event_Handler *> *>
+#pragma instantiate ACE_Unbounded_Set_Iterator<ACE_Timer_Node_T<ACE_Event_Handler *> *>
+#pragma instantiate ACE_Timer_Node_Dispatch_Info_T<ACE_Event_Handler *>
+#pragma instantiate ACE_Timer_Node_T<ACE_Event_Handler *>
+#pragma instantiate ACE_Timer_Queue_T<ACE_Event_Handler *, ACE_Event_Handler_Handle_Timeout_Upcall<ACE_SYNCH_RECURSIVE_MUTEX>, ACE_SYNCH_RECURSIVE_MUTEX>
+#pragma instantiate ACE_Timer_Queue_Iterator_T<ACE_Event_Handler *, ACE_Event_Handler_Handle_Timeout_Upcall<ACE_SYNCH_RECURSIVE_MUTEX>, ACE_SYNCH_RECURSIVE_MUTEX>
+#pragma instantiate ACE_Event_Handler_Handle_Timeout_Upcall<ACE_SYNCH_RECURSIVE_MUTEX>
+
+#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */
+
+
+#endif /* ACE_TIMER_QUEUE_C */
diff --git a/ace/Timer/Timer_Queue.h b/ace/Timer/Timer_Queue.h
new file mode 100644
index 00000000000..54a0a8f1137
--- /dev/null
+++ b/ace/Timer/Timer_Queue.h
@@ -0,0 +1,45 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Timer_Queue.h
+ *
+ * $Id$
+ *
+ * @author Douglas C. Schmidt <schmidt@cs.wustl.edu> and
+ * Irfan Pyarali <irfan@cs.wustl.edu>.
+ */
+//=============================================================================
+
+#ifndef ACE_TIMER_QUEUE_H
+#define ACE_TIMER_QUEUE_H
+#include "ace/pre.h"
+
+#include "ace/Synch.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "ace/Timer_Queue_T.h"
+
+// The following typedef are here for ease of use and backward
+// compatibility.
+typedef ACE_Timer_Node_Dispatch_Info_T<ACE_Event_Handler *>
+ ACE_Timer_Node_Dispatch_Info;
+
+typedef ACE_Timer_Node_T<ACE_Event_Handler *>
+ ACE_Timer_Node;
+
+typedef ACE_Timer_Queue_T<ACE_Event_Handler *,
+ ACE_Event_Handler_Handle_Timeout_Upcall<ACE_SYNCH_RECURSIVE_MUTEX>,
+ ACE_SYNCH_RECURSIVE_MUTEX>
+ ACE_Timer_Queue;
+
+typedef ACE_Timer_Queue_Iterator_T<ACE_Event_Handler *,
+ ACE_Event_Handler_Handle_Timeout_Upcall<ACE_SYNCH_RECURSIVE_MUTEX>,
+ ACE_SYNCH_RECURSIVE_MUTEX>
+ ACE_Timer_Queue_Iterator;
+
+#include "ace/post.h"
+#endif /* ACE_TIMER_QUEUE_H */
diff --git a/ace/Timer/Timer_Queue_Adapters.cpp b/ace/Timer/Timer_Queue_Adapters.cpp
new file mode 100644
index 00000000000..237e7349cbc
--- /dev/null
+++ b/ace/Timer/Timer_Queue_Adapters.cpp
@@ -0,0 +1,310 @@
+// $Id$
+
+#include "ace/Timer_Queue_Adapters.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#ifndef ACE_TIMER_QUEUE_ADAPTERS_C
+# define ACE_TIMER_QUEUE_ADAPTERS_C
+
+ACE_RCSID(ace, Timer_Queue_Adapters, "$Id$")
+
+# if !defined (__ACE_INLINE__)
+# include "ace/Timer_Queue_Adapters.i"
+# endif /* __ACE_INLINE__ */
+
+template <class TQ> TQ &
+ACE_Async_Timer_Queue_Adapter<TQ>::timer_queue (void)
+{
+ return this->timer_queue_;
+}
+
+template <class TQ> int
+ACE_Async_Timer_Queue_Adapter<TQ>::cancel (long timer_id,
+ const void **act)
+{
+ // Block designated signals.
+ ACE_Sig_Guard sg (&this->mask_);
+ ACE_UNUSED_ARG (sg);
+
+ return this->timer_queue_.cancel (timer_id, act);
+}
+
+template <class TQ> int
+ACE_Async_Timer_Queue_Adapter<TQ>::expire (void)
+{
+ // Block designated signals.
+ ACE_Sig_Guard sg (&this->mask_);
+ ACE_UNUSED_ARG (sg);
+
+ return this->timer_queue_.expire ();
+}
+
+template <class TQ> int
+ACE_Async_Timer_Queue_Adapter<TQ>::schedule_ualarm (void)
+{
+ ACE_Time_Value tv = this->timer_queue_.earliest_time ()
+ - ACE_OS::gettimeofday ();
+
+ // Beware of negative times and zero times (which cause problems for
+ // <ualarm>).
+ if (tv < ACE_Time_Value::zero)
+ tv = ACE_Time_Value (0, 1);
+
+ // @@ This code should be clever enough to avoid updating the
+ // <ualarm> if we haven't actually changed the earliest time.
+ // Schedule a new timer.
+ ACE_OS::ualarm (tv);
+ return 0;
+}
+
+template <class TQ> long
+ACE_Async_Timer_Queue_Adapter<TQ>::schedule (ACE_Event_Handler *eh,
+ const void *act,
+ const ACE_Time_Value &delay,
+ const ACE_Time_Value &interval)
+{
+ ACE_UNUSED_ARG (act);
+ ACE_UNUSED_ARG (interval);
+
+ // Block designated signals.
+ ACE_Sig_Guard sg (&this->mask_);
+ ACE_UNUSED_ARG (sg);
+
+ // @@ We still need to implement interval timers...
+ long tid = this->timer_queue_.schedule (eh, act, delay);
+
+ if (tid == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_LIB_TEXT ("%p\n"),
+ ACE_LIB_TEXT ("schedule_timer")),
+ -1);
+
+ if (this->schedule_ualarm () == -1)
+ return 0;
+
+ return tid;
+}
+
+template <class TQ>
+ACE_Async_Timer_Queue_Adapter<TQ>::ACE_Async_Timer_Queue_Adapter (ACE_Sig_Set *mask)
+ // If <mask> == 0, block *all* signals when the SIGARLM handler is
+ // running, else just block those in the mask.
+ : mask_ (mask)
+{
+ // The following code is necessary to selectively "block" certain
+ // signals when SIGALRM is running. Also, we always restart system
+ // calls that are interrupted by the signals.
+
+ ACE_Sig_Action sa ((ACE_SignalHandler) 0,
+ this->mask_,
+ SA_RESTART);
+
+ if (this->sig_handler_.register_handler (SIGALRM, this, &sa) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("%p\n"),
+ ACE_LIB_TEXT ("register_handler")));
+}
+
+// This is the signal handler function for the asynchronous timer
+// list. It gets invoked asynchronously when the SIGALRM signal
+// occurs.
+
+template <class TQ> int
+ACE_Async_Timer_Queue_Adapter<TQ>::handle_signal (int signum,
+ siginfo_t *,
+ ucontext_t *)
+{
+ switch (signum)
+ {
+ case SIGALRM:
+ {
+ // Expire the pending timers.
+
+ // @@ We need to figure out how to implement interval
+ // timers...
+ this->timer_queue_.expire ();
+
+ // Only schedule a new timer if there is one in the list.
+
+ // @@ This code should also become smarter to avoid
+ // unnecessary calls to ualarm().
+ if (this->timer_queue_.is_empty () == 0)
+ return this->schedule_ualarm ();
+ else
+ return 0;
+ /* NOTREACHED */
+ }
+ default:
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "unexpected signal %S\n",
+ signum),
+ -1);
+ /* NOTREACHED */
+ }
+}
+
+template<class TQ>
+ACE_Thread_Timer_Queue_Adapter<TQ>::ACE_Thread_Timer_Queue_Adapter (ACE_Thread_Manager *tm)
+ : ACE_Task_Base (tm),
+ condition_ (mutex_),
+ active_ (1), // Assume that we start in active mode.
+ thr_id_ (ACE_OS::NULL_thread)
+{
+}
+
+template<class TQ> ACE_SYNCH_MUTEX &
+ACE_Thread_Timer_Queue_Adapter<TQ>::mutex (void)
+{
+ return this->mutex_;
+}
+
+template<class TQ> long
+ACE_Thread_Timer_Queue_Adapter<TQ>::schedule
+ (ACE_Event_Handler* handler,
+ const void *act,
+ const ACE_Time_Value &delay,
+ const ACE_Time_Value &interval)
+{
+ ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, ace_mon, this->mutex_, -1);
+
+ long result = this->timer_queue_.schedule (handler, act, delay, interval);
+ this->condition_.signal ();
+ return result;
+}
+
+template<class TQ> int
+ACE_Thread_Timer_Queue_Adapter<TQ>::cancel (long timer_id,
+ const void **act)
+{
+ ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, ace_mon, this->mutex_, -1);
+
+ int result = this->timer_queue_.cancel (timer_id, act);
+ condition_.signal ();
+ return result;
+}
+
+template<class TQ> void
+ACE_Thread_Timer_Queue_Adapter<TQ>::deactivate (void)
+{
+ ACE_GUARD (ACE_SYNCH_MUTEX, ace_mon, this->mutex_);
+
+ this->active_ = 0;
+ this->condition_.signal ();
+}
+
+template<class TQ> int
+ACE_Thread_Timer_Queue_Adapter<TQ>::svc (void)
+{
+ ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, ace_mon, this->mutex_, -1);
+
+ this->thr_id_ = ACE_Thread::self ();
+
+ // Thread cancellation point, if ACE supports it.
+ //
+ // Note: This call generates a warning under Solaris because the header
+ // file /usr/include/pthread.h redefines the routine argument. This
+ // is a bug in the Solaris header files and has nothing to do with
+ // ACE.
+# if !defined (ACE_LACKS_PTHREAD_CANCEL)
+ ACE_PTHREAD_CLEANUP_PUSH (&this->condition_.mutex ());
+# endif /* ACE_LACKS_PTHREAD_CANCEL */
+
+ while (this->active_)
+ {
+# if defined (ACE_HAS_DEFERRED_TIMER_COMMANDS)
+ // Temporarily suspend ownership of the timer queue mutex in
+ // order to dispatch deferred execution commands. These
+ // commands are to be treated as executing in a context
+ // "external" to the timer queue adapter, and thus must compete
+ // separately for this lock.
+ mutex_.release ();
+ this->dispatch_commands ();
+
+ // Re-acquire ownership of the timer queue mutex in order to
+ // restore the "internal" timer queue adapter context
+ mutex_.acquire ();
+# endif /* ACE_HAS_DEFERRED_TIMER_COMMANDS */
+
+ // If the queue is empty, sleep until there is a change on it.
+ if (this->timer_queue_.is_empty ())
+ this->condition_.wait ();
+ else
+ {
+ // Compute the remaining time, being careful not to sleep
+ // for "negative" amounts of time.
+ ACE_Time_Value tv = this->timer_queue_.earliest_time ();
+
+ // ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("waiting until %u.%3.3u secs\n"),
+ // tv.sec(), tv.msec()));
+ this->condition_.wait (&tv);
+ }
+
+ // Expire timers anyway, at worst this is a no-op.
+ this->timer_queue_.expire ();
+ }
+
+ // Thread cancellation point, if ACE supports it.
+# if !defined (ACE_LACKS_PTHREAD_CANCEL)
+ ACE_PTHREAD_CLEANUP_POP (0);
+# endif /* ACE_LACKS_PTHREAD_CANCEL */
+
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("terminating dispatching thread\n")));
+ return 0;
+}
+
+
+# if defined (ACE_HAS_DEFERRED_TIMER_COMMANDS)
+
+// Enqueues a command object for execution just before waiting on the next
+// timer event. This allows deferred execution of commands that cannot
+// be performed in the timer event handler context, such as registering
+// or cancelling timers on platforms where the timer queue mutex is not
+// recursive.
+
+template<class TQ> int
+ACE_Thread_Timer_Queue_Adapter<TQ>::enqueue_command (ACE_Command_Base *cmd,
+ COMMAND_ENQUEUE_POSITION pos)
+{
+ // Serialize access to the command queue.
+ ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, ace_mon,
+ this->command_mutex_, -1);
+
+ if (pos == ACE_Thread_Timer_Queue_Adapter<TQ>::TAIL)
+ {
+ return command_queue_.enqueue_tail (cmd);
+ }
+ else
+ {
+ return command_queue_.enqueue_head (cmd);
+ }
+}
+
+
+// Dispatches all command objects enqueued in the most
+// recent event handler context.
+
+template<class TQ> int
+ACE_Thread_Timer_Queue_Adapter<TQ>::dispatch_commands (void)
+{
+ // Serialize access to the command queue.
+ ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, ace_mon,
+ this->command_mutex_, -1);
+
+ // loop through the enqueued commands
+ ACE_Command_Base *cmd = 0;
+ while (command_queue_.dequeue_head (cmd) == 0)
+ if (cmd)
+ {
+ cmd->execute ();
+ delete cmd;
+ }
+
+ return 0;
+}
+
+# endif /* ACE_HAS_DEFERRED_TIMER_COMMANDS */
+
+#endif /* ACE_TIMER_QUEUE_ADAPTERS_C*/
diff --git a/ace/Timer/Timer_Queue_Adapters.h b/ace/Timer/Timer_Queue_Adapters.h
new file mode 100644
index 00000000000..ef05e7f79f4
--- /dev/null
+++ b/ace/Timer/Timer_Queue_Adapters.h
@@ -0,0 +1,230 @@
+// -*- C++ -*-
+
+//=============================================================================
+/**
+ * @file Timer_Queue_Adapters.h
+ *
+ * $Id$
+ *
+ * @author Douglas C. Schmidt and Carlos O'Ryan
+ */
+//=============================================================================
+
+
+#ifndef ACE_TIMER_QUEUE_ADAPTERS_H
+#define ACE_TIMER_QUEUE_ADAPTERS_H
+#include "ace/pre.h"
+
+#include "ace/Task.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "ace/Signal.h"
+
+/**
+ * @class ACE_Async_Timer_Queue_Adapter
+ *
+ * @brief Adapts a <TQ> to be run asynchronously.
+ *
+ * This implementation uses the <ualarm> call, which generates
+ * the SIGARLM signal that is caught by this class.
+ */
+template <class TQ>
+class ACE_Export ACE_Async_Timer_Queue_Adapter : public ACE_Event_Handler
+{
+public:
+ typedef TQ TIMER_QUEUE;
+
+ /// Constructor
+ /**
+ * Register the SIGALRM handler. If <mask> == 0 then block all
+ * signals when <SIGALRM> is run. Otherwise, just block the signals
+ * indicated in <mask>.
+ */
+ ACE_Async_Timer_Queue_Adapter (ACE_Sig_Set *mask = 0);
+
+ /// Schedule the timer according to the semantics of the
+ /// <ACE_Timer_List>.
+ /**
+ * Tthis timer gets dispatched via a signal, rather than by a user
+ * calling <expire>. Note that interval timers are not implemented
+ * yet.
+ */
+ long schedule (ACE_Event_Handler *type,
+ const void *act,
+ const ACE_Time_Value &delay,
+ const ACE_Time_Value &interval = ACE_Time_Value::zero);
+
+ /// Cancel the <timer_id> and pass back the <act> if an address is
+ /// passed in.
+ int cancel (long timer_id, const void **act = 0);
+
+ /// Dispatch all timers whose values are <= <cur_time>. Returns the
+ /// number of timers canceled.
+ int expire (void);
+
+ /// Access the underlying <TIMER_QUEUE>.
+ TQ &timer_queue (void);
+
+private:
+ /// Perform the logic to compute the new ualarm(2) setting.
+ virtual int schedule_ualarm (void);
+
+ /// Called back by <SIGALRM> handler.
+ virtual int handle_signal (int signum, siginfo_t *, ucontext_t *);
+
+ /// Handler for the <SIGALRM> signal, so that we can access our state
+ /// without requiring any global variables.
+ ACE_Sig_Handler sig_handler_;
+
+ /// Implementation of the timer queue (e.g., <ACE_Timer_List>,
+ /// <ACE_Timer_Heap>, etc.).
+ TQ timer_queue_;
+
+ /// Mask of signals to be blocked when we're servicing <SIGALRM>.
+ ACE_Sig_Set mask_;
+};
+
+/**
+ * @class ACE_Thread_Timer_Queue_Adapter
+ *
+ * @brief Adapts a Timer_Queue using a separate thread for dispatching.
+ *
+ * This implementation of a Timer_Queue uses a separate thread to
+ * dispatch the timers. The base queue need not be thread safe,
+ * this class takes all the necessary locks.
+ *
+ * @note This is a case were template parameters will be useful, but
+ * (IMHO) the effort and portability problems discourage their
+ * use.
+ *
+ */
+template <class TQ>
+class ACE_Export ACE_Thread_Timer_Queue_Adapter : public ACE_Task_Base
+{
+public:
+
+ /// Trait for the underlying queue type.
+ typedef TQ TIMER_QUEUE;
+
+# if defined (ACE_HAS_DEFERRED_TIMER_COMMANDS)
+
+ /// Typedef for the position at which to enqueue a deferred execution command.
+ enum COMMAND_ENQUEUE_POSITION {HEAD, TAIL};
+
+# endif /* ACE_HAS_DEFERRED_TIMER_COMMANDS */
+
+ /// Creates the timer queue. Activation of the task is the user's
+ /// responsibility.
+ ACE_Thread_Timer_Queue_Adapter (ACE_Thread_Manager * = ACE_Thread_Manager::instance ());
+
+ /// Schedule the timer according to the semantics of the <TQ>; wakes
+ /// up the dispatching thread.
+ long schedule (ACE_Event_Handler *handler,
+ const void *act,
+ const ACE_Time_Value &delay,
+ const ACE_Time_Value &interval = ACE_Time_Value::zero);
+
+ /// Cancel the <timer_id> add return the <act> parameter if an
+ /// address is passed in. Also wakes up the dispatching thread.
+ int cancel (long timer_id, const void **act = 0);
+
+ /// Runs the dispatching thread.
+ virtual int svc (void);
+
+ /// Inform the dispatching thread that it should terminate.
+ virtual void deactivate (void);
+
+ /// Access the locking mechanism, useful for iteration.
+ ACE_SYNCH_MUTEX &mutex (void);
+
+ /// Access the implementation queue, useful for iteration.
+ TQ &timer_queue (void);
+
+ /// Return the thread id of our active object.
+ ACE_thread_t thr_id (void);
+
+ /**
+ * We override the default <activate> method so that we can ensure
+ * that only a single thread is ever spawned. Otherwise, too many
+ * weird things can happen...
+ */
+ virtual int activate (long flags = THR_NEW_LWP | THR_JOINABLE,
+ int n_threads = 1,
+ int force_active = 0,
+ long priority = ACE_DEFAULT_THREAD_PRIORITY,
+ int grp_id = -1,
+ ACE_Task_Base *task = 0,
+ ACE_hthread_t thread_handles[] = 0,
+ void *stack[] = 0,
+ size_t stack_size[] = 0,
+ ACE_thread_t thread_names[] = 0);
+
+# if defined (ACE_HAS_DEFERRED_TIMER_COMMANDS)
+
+ /**
+ * Enqueues a command object for execution just before waiting on the next
+ * timer event. This allows deferred execution of commands that cannot
+ * be performed in the timer event handler context, such as registering
+ * or cancelling timers on platforms where the timer queue mutex is not
+ * recursive.
+ */
+ int enqueue_command (ACE_Command_Base *command_,
+ COMMAND_ENQUEUE_POSITION pos = TAIL);
+
+# endif /* ACE_HAS_DEFERRED_TIMER_COMMANDS */
+
+private:
+
+# if defined (ACE_HAS_DEFERRED_TIMER_COMMANDS)
+
+ /// Dispatches all command objects enqueued in the most
+ /// recent event handler context.
+ int dispatch_commands (void);
+
+ /// Queue of commands for deferred execution.
+ ACE_Unbounded_Queue<ACE_Command_Base *> command_queue_;
+
+ /// The mutual exclusion mechanism for the command queue.
+ ACE_SYNCH_MUTEX command_mutex_;
+
+# endif /* ACE_HAS_DEFERRED_TIMER_COMMANDS */
+
+ /// The underlying Timer_Queue.
+ TQ timer_queue_;
+
+ /**
+ * The dispatching thread sleeps on this condition while waiting to
+ * dispatch the next timer; it is used to wake it up if there is a
+ * change on the timer queue.
+ */
+ ACE_SYNCH_CONDITION condition_;
+
+ /// The mutual exclusion mechanism which is required to use the
+ /// <condition_>.
+ ACE_SYNCH_MUTEX mutex_;
+
+ /// When deactivate is called this variable turns to false and the
+ /// dispatching thread is signalled, to terminate its main loop.
+ int active_;
+
+ /// Thread id of our active object task.
+ ACE_thread_t thr_id_;
+};
+
+#if defined (__ACE_INLINE__)
+# include "ace/Timer_Queue_Adapters.i"
+#endif /* __ACE_INLINE__ */
+
+#if defined (ACE_TEMPLATES_REQUIRE_SOURCE)
+# include "ace/Timer_Queue_Adapters.cpp"
+#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */
+
+#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA)
+# pragma implementation ("Timer_Queue_Adapters.cpp")
+#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */
+
+#include "ace/post.h"
+#endif /* ACE_TIMER_QUEUE_ADAPTERS_H */
diff --git a/ace/Timer/Timer_Queue_Adapters.i b/ace/Timer/Timer_Queue_Adapters.i
new file mode 100644
index 00000000000..621c9c08ef8
--- /dev/null
+++ b/ace/Timer/Timer_Queue_Adapters.i
@@ -0,0 +1,37 @@
+/* -*- C++ -*- */
+// $Id$
+
+template<class TQ> ACE_INLINE TQ &
+ACE_Thread_Timer_Queue_Adapter<TQ>::timer_queue (void)
+{
+ return this->timer_queue_;
+}
+
+template<class TQ> ACE_INLINE ACE_thread_t
+ACE_Thread_Timer_Queue_Adapter<TQ>::thr_id (void)
+{
+ return this->thr_id_;
+}
+
+template<class TQ> ACE_INLINE int
+ACE_Thread_Timer_Queue_Adapter<TQ>::activate (long flags,
+ int n_threads,
+ int force_active,
+ long priority,
+ int grp_id,
+ ACE_Task_Base *task,
+ ACE_hthread_t thread_handles[],
+ void *stack[],
+ size_t stack_size[],
+ ACE_thread_t thread_names[])
+{
+ // Macros to avoid "warning: unused parameter" type warning.
+ ACE_UNUSED_ARG (n_threads);
+ ACE_UNUSED_ARG (force_active);
+ ACE_UNUSED_ARG (thread_handles);
+
+ // Make sure that we only allow a single thread to be spawned for
+ // our adapter. Otherwise, too many weird things can happen.
+ return ACE_Task_Base::activate (flags, 1, 0, priority, grp_id, task, 0,
+ stack, stack_size, thread_names);
+}
diff --git a/ace/Timer/Timer_Queue_T.cpp b/ace/Timer/Timer_Queue_T.cpp
new file mode 100644
index 00000000000..166e35c60e6
--- /dev/null
+++ b/ace/Timer/Timer_Queue_T.cpp
@@ -0,0 +1,354 @@
+// $Id$
+
+#ifndef ACE_TIMER_QUEUE_T_C
+#define ACE_TIMER_QUEUE_T_C
+
+#include "ace/Synch.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "ace/Signal.h"
+#include "ace/Timer_Queue_T.h"
+#include "ace/Log_Msg.h"
+
+#if !defined (__ACE_INLINE__)
+#include "ace/Timer_Queue_T.i"
+#endif /* __ACE_INLINE__ */
+
+ACE_RCSID(ace, Timer_Queue_T, "$Id$")
+
+template <class TYPE> void
+ACE_Timer_Node_T<TYPE>::dump (void) const
+{
+ ACE_TRACE ("ACE_Timer_Node_T::dump");
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\nact_ = %x"), this->act_));
+ this->timer_value_.dump ();
+ this->interval_.dump ();
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\nprev_ = %x"), this->prev_));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\nnext_ = %x"), this->next_));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\ntimer_id_ = %d\n"), this->timer_id_));
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+template <class TYPE>
+ACE_Timer_Node_T<TYPE>::ACE_Timer_Node_T (void)
+{
+ ACE_TRACE ("ACE_Timer_Node_T::ACE_Timer_Node_T");
+}
+
+template <class TYPE>
+ACE_Timer_Node_T<TYPE>::~ACE_Timer_Node_T (void)
+{
+ ACE_TRACE ("ACE_Timer_Node_T::~ACE_Timer_Node_T");
+}
+
+
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK>
+ACE_Timer_Queue_Iterator_T<TYPE, FUNCTOR, ACE_LOCK>::ACE_Timer_Queue_Iterator_T (void)
+{
+}
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK>
+ACE_Timer_Queue_Iterator_T<TYPE, FUNCTOR, ACE_LOCK>::~ACE_Timer_Queue_Iterator_T (void)
+{
+}
+
+// Determines the minimum amount of time that the Reactor must wait
+// before timing out. This is computed as the smaller of (1) the
+// amount the caller requested when calling handle_events() and (2)
+// the earliest time registered in the Timer Queue (if any). Must be
+// called with an external lock held since it returns a pointer to a
+// Time_Value type stored in the Timer_Queue type itself. If some
+// external lock isn't held we'll have reentrancy problems!
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK> ACE_Time_Value *
+ACE_Timer_Queue_T<TYPE, FUNCTOR, ACE_LOCK>::calculate_timeout (ACE_Time_Value *max_wait_time)
+{
+ ACE_TRACE ("ACE_Timer_Queue_T::calculate_timeout");
+ ACE_MT (ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, max_wait_time));
+
+ if (this->is_empty ())
+ // Nothing on the Timer_Queue, so use whatever the caller gave us.
+ return max_wait_time;
+ else
+ {
+ ACE_Time_Value cur_time = this->gettimeofday ();
+
+ if (this->earliest_time () > cur_time)
+ {
+ // The earliest item on the Timer_Queue is still in the
+ // future. Therefore, use the smaller of (1) caller's wait
+ // time or (2) the delta time between now and the earliest
+ // time on the Timer_Queue.
+
+ this->timeout_ = this->earliest_time () - cur_time;
+ if (max_wait_time == 0 || *max_wait_time > timeout_)
+ return &this->timeout_;
+ else
+ return max_wait_time;
+ }
+ else
+ {
+ // The earliest item on the Timer_Queue is now in the past.
+ // Therefore, we've got to "poll" the Reactor, i.e., it must
+ // just check the descriptors and then dispatch timers, etc.
+ this->timeout_ = ACE_Time_Value::zero;
+ return &this->timeout_;
+ }
+ }
+}
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK> ACE_Time_Value *
+ACE_Timer_Queue_T<TYPE, FUNCTOR, ACE_LOCK>::calculate_timeout (ACE_Time_Value *max_wait_time,
+ ACE_Time_Value *the_timeout)
+{
+ ACE_TRACE ("ACE_Timer_Queue_T::calculate_timeout");
+
+ if (the_timeout == 0)
+ return 0;
+
+ if (this->is_empty ())
+ {
+ // Nothing on the Timer_Queue, so use whatever the caller gave us.
+ if (max_wait_time)
+ *the_timeout = *max_wait_time;
+ else
+ return 0;
+ }
+ else
+ {
+ ACE_Time_Value cur_time = this->gettimeofday ();
+
+ if (this->earliest_time () > cur_time)
+ {
+ // The earliest item on the Timer_Queue is still in the
+ // future. Therefore, use the smaller of (1) caller's wait
+ // time or (2) the delta time between now and the earliest
+ // time on the Timer_Queue.
+
+ *the_timeout = this->earliest_time () - cur_time;
+ if (!(max_wait_time == 0 || *max_wait_time > *the_timeout))
+ *the_timeout = *max_wait_time;
+ }
+ else
+ {
+ // The earliest item on the Timer_Queue is now in the past.
+ // Therefore, we've got to "poll" the Reactor, i.e., it must
+ // just check the descriptors and then dispatch timers, etc.
+ *the_timeout = ACE_Time_Value::zero;
+ }
+ }
+ return the_timeout;
+}
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK> void
+ACE_Timer_Queue_T<TYPE, FUNCTOR, ACE_LOCK>::dump (void) const
+{
+ ACE_TRACE ("ACE_Timer_Queue_T::dump");
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+ this->timeout_.dump ();
+ this->timer_skew_.dump ();
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK>
+ACE_Timer_Queue_T<TYPE, FUNCTOR, ACE_LOCK>::ACE_Timer_Queue_T (FUNCTOR *upcall_functor,
+ ACE_Free_List<ACE_Timer_Node_T <TYPE> > *freelist)
+ : gettimeofday_ (ACE_OS::gettimeofday),
+ delete_upcall_functor_ (upcall_functor == 0),
+ delete_free_list_ (freelist == 0),
+ timer_skew_ (0, ACE_TIMER_SKEW)
+{
+ ACE_TRACE ("ACE_Timer_Queue_T::ACE_Timer_Queue_T");
+
+ if (!freelist)
+ ACE_NEW (free_list_,
+ (ACE_Locked_Free_List<ACE_Timer_Node_T<TYPE>,ACE_Null_Mutex>));
+ else
+ free_list_ = freelist;
+
+ if (!upcall_functor)
+ ACE_NEW (upcall_functor_,
+ FUNCTOR);
+ else
+ upcall_functor_ = upcall_functor;
+}
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK>
+ACE_Timer_Queue_T<TYPE, FUNCTOR, ACE_LOCK>::~ACE_Timer_Queue_T (void)
+{
+ ACE_TRACE ("ACE_Timer_Queue_T::~ACE_Timer_Queue_T");
+
+ // Cleanup the functor and free_list on the way out
+ if (this->delete_upcall_functor_)
+ delete this->upcall_functor_;
+
+ if (this->delete_free_list_)
+ delete this->free_list_;
+}
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK> ACE_Timer_Node_T<TYPE> *
+ACE_Timer_Queue_T<TYPE, FUNCTOR, ACE_LOCK>::alloc_node (void)
+{
+ return this->free_list_->remove ();
+}
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK> void
+ACE_Timer_Queue_T<TYPE, FUNCTOR, ACE_LOCK>::free_node (ACE_Timer_Node_T<TYPE> *node)
+{
+ this->free_list_->add (node);
+}
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK> ACE_LOCK &
+ACE_Timer_Queue_T<TYPE, FUNCTOR, ACE_LOCK>::mutex (void)
+{
+ return this->mutex_;
+}
+
+
+// Run the <handle_timeout> method for all Timers whose values are <=
+// <cur_time>.
+template <class TYPE, class FUNCTOR, class ACE_LOCK> int
+ACE_Timer_Queue_T<TYPE, FUNCTOR, ACE_LOCK>::expire (const ACE_Time_Value &cur_time)
+{
+ ACE_TRACE ("ACE_Timer_Queue_T::expire");
+ ACE_MT (ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, -1));
+
+ // Keep looping while there are timers remaining and the earliest
+ // timer is <= the <cur_time> passed in to the method.
+
+ if (this->is_empty ())
+ return 0;
+
+ int number_of_timers_expired = 0;
+ int result = 0;
+
+ ACE_Timer_Node_Dispatch_Info_T<TYPE> info;
+
+ while ((result = this->dispatch_info_i (cur_time,
+ info)) != 0)
+ {
+ // call the functor
+ this->upcall (info.type_, info.act_, cur_time);
+
+ number_of_timers_expired++;
+
+ }
+
+ ACE_UNUSED_ARG (result);
+ return number_of_timers_expired;
+}
+
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK> int
+ACE_Timer_Queue_T<TYPE, FUNCTOR, ACE_LOCK>::dispatch_info_i (const ACE_Time_Value &cur_time,
+ ACE_Timer_Node_Dispatch_Info_T<TYPE> &info)
+{
+ ACE_TRACE ("ACE_Timer_Queue_T::dispatch_info_i");
+
+ if (this->is_empty ())
+ return 0;
+
+ ACE_Timer_Node_T<TYPE> *expired = 0;
+
+ if (this->earliest_time () <= cur_time)
+ {
+ expired = this->remove_first ();
+
+ // Get the dispatch info
+ expired->get_dispatch_info (info);
+
+ // Check if this is an interval timer.
+ if (expired->get_interval () > ACE_Time_Value::zero)
+ {
+ // Make sure that we skip past values that have already
+ // "expired".
+ do
+ expired->set_timer_value (expired->get_timer_value () + expired->get_interval ());
+ while (expired->get_timer_value () <= cur_time);
+
+ // Since this is an interval timer, we need to reschedule
+ // it.
+ this->reschedule (expired);
+ }
+ else
+ {
+ // Call the factory method to free up the node.
+ this->free_node (expired);
+ }
+
+ return 1;
+ }
+
+ return 0;
+}
+
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK> void
+ACE_Timer_Queue_T<TYPE, FUNCTOR, ACE_LOCK>::return_node (ACE_Timer_Node_T<TYPE> *node)
+{
+ ACE_MT (ACE_GUARD (ACE_LOCK, ace_mon, this->mutex_));
+ this->free_node (node);
+}
+
+
+template <class ACE_LOCK>
+ACE_Event_Handler_Handle_Timeout_Upcall<ACE_LOCK>::ACE_Event_Handler_Handle_Timeout_Upcall (void)
+{
+}
+
+template <class ACE_LOCK>
+ACE_Event_Handler_Handle_Timeout_Upcall<ACE_LOCK>::~ACE_Event_Handler_Handle_Timeout_Upcall (void)
+{
+}
+
+template <class ACE_LOCK> int
+ACE_Event_Handler_Handle_Timeout_Upcall<ACE_LOCK>::timeout (ACE_Timer_Queue_T<ACE_Event_Handler *,
+ ACE_Event_Handler_Handle_Timeout_Upcall<ACE_LOCK>,
+ ACE_LOCK> &timer_queue,
+ ACE_Event_Handler *handler,
+ const void *act,
+ const ACE_Time_Value &cur_time)
+{
+ // Upcall to the <handler>s handle_timeout method.
+ if (handler->handle_timeout (cur_time, act) == -1)
+ timer_queue.cancel (handler, 0); // 0 means "call handle_close()".
+
+ return 0;
+}
+
+template <class ACE_LOCK> int
+ACE_Event_Handler_Handle_Timeout_Upcall<ACE_LOCK>::cancellation (ACE_Timer_Queue_T<ACE_Event_Handler *,
+ ACE_Event_Handler_Handle_Timeout_Upcall<ACE_LOCK>,
+ ACE_LOCK> &timer_queue,
+ ACE_Event_Handler *handler)
+{
+ ACE_UNUSED_ARG (timer_queue);
+
+ // Upcall to the <handler>s handle_close method
+ handler->handle_close (ACE_INVALID_HANDLE,
+ ACE_Event_Handler::TIMER_MASK);
+ return 0;
+}
+
+template <class ACE_LOCK> int
+ACE_Event_Handler_Handle_Timeout_Upcall<ACE_LOCK>::deletion (ACE_Timer_Queue_T<ACE_Event_Handler *,
+ ACE_Event_Handler_Handle_Timeout_Upcall<ACE_LOCK>,
+ ACE_LOCK> &timer_queue,
+ ACE_Event_Handler *handler,
+ const void *arg)
+{
+ ACE_UNUSED_ARG (timer_queue);
+ ACE_UNUSED_ARG (handler);
+ ACE_UNUSED_ARG (arg);
+
+ // Does nothing
+
+ return 0;
+}
+
+#endif /* ACE_TIMER_QUEUE_T_C*/
diff --git a/ace/Timer/Timer_Queue_T.h b/ace/Timer/Timer_Queue_T.h
new file mode 100644
index 00000000000..55735ace482
--- /dev/null
+++ b/ace/Timer/Timer_Queue_T.h
@@ -0,0 +1,498 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Timer_Queue_T.h
+ *
+ * $Id$
+ *
+ * @author Doug Schmidt <schmidt@cs.wustl.edu>
+ * @author Irfan Pyarali <irfan@cs.wustl.edu> and
+ * @author Darrell Brunsch <brunsch@cs.wustl.edu>
+ */
+//=============================================================================
+
+#ifndef ACE_TIMER_QUEUE_T_H
+#define ACE_TIMER_QUEUE_T_H
+#include "ace/pre.h"
+
+#include "ace/Free_List.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "ace/Test_and_Set.h"
+
+/**
+ * @class ACE_Timer_Node_Dispatch_Info_T
+ *
+ * @brief Maintains generated dispatch information for Timer nodes.
+ *
+ */
+template <class TYPE>
+class ACE_Timer_Node_Dispatch_Info_T
+{
+public:
+ // The type of object held in the queue
+ TYPE type_;
+
+ /// Asynchronous completion token associated with the timer.
+ const void *act_;
+};
+
+/**
+ * @class ACE_Timer_Node_T
+ *
+ * @brief Maintains the state associated with a Timer entry.
+ */
+template <class TYPE>
+class ACE_Timer_Node_T
+{
+public:
+ /// Default constructor
+ ACE_Timer_Node_T (void);
+
+ /// Dtor.
+ ~ACE_Timer_Node_T (void);
+
+ /// Useful typedef ..
+ typedef ACE_Timer_Node_Dispatch_Info_T <TYPE> DISPATCH_INFO;
+
+ /// singly linked list
+ void set (const TYPE &type,
+ const void *a,
+ const ACE_Time_Value &t,
+ const ACE_Time_Value &i,
+ ACE_Timer_Node_T<TYPE> *n,
+ long timer_id);
+
+ /// doubly linked list version
+ void set (const TYPE &type,
+ const void *a,
+ const ACE_Time_Value &t,
+ const ACE_Time_Value &i,
+ ACE_Timer_Node_T<TYPE> *p,
+ ACE_Timer_Node_T<TYPE> *n,
+ long timer_id);
+
+ // = Accessors
+
+ /// Get the type.
+ TYPE &get_type (void);
+
+ /// Set the type.
+ void set_type (TYPE &type);
+
+ /// Get the asynchronous completion token.
+ const void *get_act (void);
+
+ /// set the asynchronous completion token.
+ void set_act (void *act);
+
+ /// get the timer value.
+ const ACE_Time_Value &get_timer_value (void) const;
+
+ /// set the timer value.
+ void set_timer_value (const ACE_Time_Value &timer_value);
+
+ /// get the timer interval.
+ const ACE_Time_Value &get_interval (void) const;
+
+ /// Set the timer interval.
+ void set_interval (const ACE_Time_Value &interval);
+
+ /// get the previous pointer.
+ ACE_Timer_Node_T<TYPE> *get_prev (void);
+
+ /// set the previous pointer.
+ void set_prev (ACE_Timer_Node_T<TYPE> *prev);
+
+ /// get the next pointer.
+ ACE_Timer_Node_T<TYPE> *get_next (void);
+
+ /// set the next pointer.
+ void set_next (ACE_Timer_Node_T<TYPE> *next);
+
+ /// get the timer_id.
+ long get_timer_id (void) const;
+
+ /// set the timer_id.
+ void set_timer_id (long timer_id);
+
+ /// Get the dispatch info. The dispatch information is got
+ /// through <info>. This form helps us in preventing allocation and
+ /// deleting data along the criticl path.
+ /// @@TODO: We may want to have a copying version too, so that our
+ /// interface will be complete..
+ void get_dispatch_info (ACE_Timer_Node_Dispatch_Info_T <TYPE> &info);
+
+
+ /// Dump the state of an TYPE.
+ void dump (void) const;
+
+private:
+ /// Type of object stored in the Queue
+ TYPE type_;
+
+ /// Asynchronous completion token associated with the timer.
+ const void *act_;
+
+ /// Time until the timer expires.
+ ACE_Time_Value timer_value_;
+
+ /// If this is a periodic timer this holds the time until the next
+ /// timeout.
+ ACE_Time_Value interval_;
+
+ /// Pointer to previous timer.
+ ACE_Timer_Node_T<TYPE> *prev_;
+
+ /// Pointer to next timer.
+ ACE_Timer_Node_T<TYPE> *next_;
+
+ /// Id of this timer (used to cancel timers before they expire).
+ long timer_id_;
+};
+
+/**
+ * @class ACE_Timer_Queue_Iterator_T
+ *
+ * @brief Generic interface for iterating over a subclass of
+ * <ACE_Timer_Queue>.
+ *
+ * This is a generic iterator that can be used to visit every
+ * node of a timer queue. Be aware that it isn't guaranteed
+ * that the transversal will be in order of timeout values.
+ */
+template <class TYPE, class FUNCTOR, class ACE_LOCK>
+class ACE_Timer_Queue_Iterator_T
+{
+public:
+ // = Initialization and termination methods.
+ /// Constructor.
+ ACE_Timer_Queue_Iterator_T (void);
+
+ /// Destructor.
+ virtual ~ACE_Timer_Queue_Iterator_T (void);
+
+ /// Positions the iterator at the earliest node in the Timer Queue
+ virtual void first (void) = 0;
+
+ /// Positions the iterator at the next node in the Timer Queue
+ virtual void next (void) = 0;
+
+ /// Returns true when there are no more nodes in the sequence
+ virtual int isdone (void) const = 0;
+
+ /// Returns the node at the current position in the sequence
+ virtual ACE_Timer_Node_T<TYPE> *item (void) = 0;
+};
+
+/**
+ * @class ACE_Timer_Queue_T
+ *
+ * @brief Provides an interface to timers.
+ *
+ * This is an abstract base class that provides hook for
+ * implementing specialized policies such as <ACE_Timer_List>
+ * and <ACE_Timer_Heap>.
+ */
+template <class TYPE, class FUNCTOR, class ACE_LOCK>
+class ACE_Timer_Queue_T
+{
+public:
+ /// Type of Iterator.
+ typedef ACE_Timer_Queue_Iterator_T<TYPE, FUNCTOR, ACE_LOCK> ITERATOR;
+
+ // = Initialization and termination methods.
+ /**
+ * Default constructor. <upcall_functor> is the instance of the
+ * FUNCTOR to be used by the queue. If <upcall_functor> is 0, Timer
+ * Queue will create a default FUNCTOR. <freelist> the freelist of
+ * timer nodes. If 0, then a default freelist will be created.
+ */
+ ACE_Timer_Queue_T (FUNCTOR *upcall_functor = 0,
+ ACE_Free_List<ACE_Timer_Node_T <TYPE> > *freelist = 0);
+
+ /// Destructor - make virtual for proper destruction of inherited
+ /// classes.
+ virtual ~ACE_Timer_Queue_T (void);
+
+ /// True if queue is empty, else false.
+ virtual int is_empty (void) const = 0;
+
+ /// Returns the time of the earlier node in the Timer_Queue. Must
+ /// be called on a non-empty queue.
+ virtual const ACE_Time_Value &earliest_time (void) const = 0;
+
+ /**
+ * Schedule <type> that will expire after <delay> amount of time,
+ * which is specified in absolute time. If it expires then <act> is
+ * passed in as the value to the <functor>. If <interval> is != to
+ * <ACE_Time_Value::zero> then it is used to reschedule the <type>
+ * automatically, using relative time to the current <gettimeofday>.
+ * This method returns a <timer_id> that uniquely identifies the the
+ * <type> entry in an internal list. This <timer_id> can be used to
+ * cancel the timer before it expires. The cancellation ensures
+ * that <timer_ids> are unique up to values of greater than 2
+ * billion timers. As long as timers don't stay around longer than
+ * this there should be no problems with accidentally deleting the
+ * wrong timer. Returns -1 on failure (which is guaranteed never to
+ * be a valid <timer_id>).
+ */
+ virtual long schedule (const TYPE &type,
+ const void *act,
+ const ACE_Time_Value &delay,
+ const ACE_Time_Value &interval = ACE_Time_Value::zero) = 0;
+
+ /**
+ * Resets the interval of the timer represented by <timer_id> to
+ * <interval>, which is specified in relative time to the current
+ * <gettimeofday>. If <interval> is equal to
+ * <ACE_Time_Value::zero>, the timer will become a non-rescheduling
+ * timer. Returns 0 if successful, -1 if not.
+ */
+ virtual int reset_interval (long timer_id,
+ const ACE_Time_Value &interval) = 0;
+
+ /**
+ * Cancel all timer associated with <type>. If
+ * <dont_call_handle_close> is 0 then the <functor> will be invoked,
+ * which typically invokes the <handle_close> hook. Returns number
+ * of timers cancelled.
+ */
+ virtual int cancel (const TYPE &type,
+ int dont_call_handle_close = 1) = 0;
+
+ /**
+ * Cancel the single timer that matches the <timer_id> value (which
+ * was returned from the <schedule> method). If act is non-NULL
+ * then it will be set to point to the ``magic cookie'' argument
+ * passed in when the timer was registered. This makes it possible
+ * to free up the memory and avoid memory leaks. If
+ * <dont_call_handle_close> is 0 then the <functor> will be invoked,
+ * which typically calls the <handle_close> hook. Returns 1 if
+ * cancellation succeeded and 0 if the <timer_id> wasn't found.
+ */
+ virtual int cancel (long timer_id,
+ const void **act = 0,
+ int dont_call_handle_close = 1) = 0;
+
+ /**
+ * Run the <functor> for all timers whose values are <= <cur_time>.
+ * This does not account for <timer_skew>. Returns the number of
+ * timers canceled.
+ */
+ virtual int expire (const ACE_Time_Value &current_time);
+
+ /**
+ * Get the dispatch information for a timer whose value is <= <cur_time>.
+ * This does not account for <timer_skew>. Returns 1 if
+ * there is a node whose value <= <cur_time> else returns a 0.
+ *
+ */
+ int dispatch_info (const ACE_Time_Value &current_time,
+ ACE_Timer_Node_Dispatch_Info_T<TYPE> &info);
+
+ /**
+ * Run the <functor> for all timers whose values are <=
+ * <ACE_OS::gettimeofday>. Also accounts for <timer_skew>.
+ *
+ * Depending on the resolution of the underlying OS the system calls
+ * like select()/poll() might return at time different than that is
+ * specified in the timeout. Suppose the OS guarantees a resolution of t ms.
+ * The timeline will look like
+ *
+ * A B
+ * | |
+ * V V
+ * |-------------|-------------|-------------|-------------|
+ * t t t t t
+ *
+ *
+ * If you specify a timeout value of A, then the timeout will not occur
+ * at A but at the next interval of the timer, which is later than
+ * that is expected. Similarly, if your timeout value is equal to B,
+ * then the timeout will occur at interval after B. Now depending upon the
+ * resolution of your timeouts and the accuracy of the timeouts
+ * needed for your application, you should set the value of
+ * <timer_skew>. In the above case, if you want the timeout A to fire
+ * no later than A, then you should specify your <timer_skew> to be
+ * A % t.
+ *
+ * The timeout value should be specified via the macro ACE_TIMER_SKEW
+ * in your config.h file. The default value is zero.
+ *
+ * Things get interesting if the t before the timeout value B is zero
+ * i.e your timeout is less than the interval. In that case, you are
+ * almost sure of not getting the desired timeout behaviour. Maybe you
+ * should look for a better OS :-)
+ *
+ * Returns the number of timers canceled.
+ */
+
+ /* virtual */ int expire (void);
+
+ /**
+ * Returns the current time of day. This method allows different
+ * implementations of the timer queue to use special high resolution
+ * timers.
+ */
+ /* virtual */ ACE_Time_Value gettimeofday (void);
+
+ /// Allows applications to control how the timer queue gets the time
+ /// of day.
+ void gettimeofday (ACE_Time_Value (*gettimeofday)(void));
+
+ /// Determine the next event to timeout. Returns <max> if there are
+ /// no pending timers or if all pending timers are longer than max.
+ virtual ACE_Time_Value *calculate_timeout (ACE_Time_Value *max);
+
+ /**
+ * Determine the next event to timeout. Returns <max> if there are
+ * no pending timers or if all pending timers are longer than max.
+ * <the_timeout> should be a pointer to storage for the timeout value,
+ * and this value is also returned.
+ */
+ virtual ACE_Time_Value *calculate_timeout (ACE_Time_Value *max,
+ ACE_Time_Value *the_timeout);
+
+ // = Set/get the timer skew for the Timer_Queue.
+ void timer_skew (const ACE_Time_Value &skew);
+ const ACE_Time_Value &timer_skew (void) const;
+
+ /// Synchronization variable used by the queue
+ ACE_LOCK &mutex (void);
+
+ /// Accessor to the upcall functor
+ FUNCTOR &upcall_functor (void);
+
+ /// Returns a pointer to this <ACE_Timer_Queue>'s iterator.
+ virtual ITERATOR &iter (void) = 0;
+
+ /// Removes the earliest node from the queue and returns it
+ virtual ACE_Timer_Node_T<TYPE> *remove_first (void) = 0;
+
+ /// Dump the state of a object.
+ virtual void dump (void) const;
+
+ /// Reads the earliest node from the queue and returns it.
+ virtual ACE_Timer_Node_T<TYPE> *get_first (void) = 0;
+
+ /// Method used to return a timer node to the queue's ownership
+ /// after it is returned by a method like <remove_first>.
+ virtual void return_node (ACE_Timer_Node_T<TYPE> *);
+
+
+ /// This method will call the <functor> with the <type>, <act> and
+ /// <time>
+ /* virtual */ void upcall (TYPE &type,
+ const void *act,
+ const ACE_Time_Value &cur_time);
+
+protected:
+ /// Reschedule an "interval" <ACE_Timer_Node>.
+ virtual void reschedule (ACE_Timer_Node_T<TYPE> *) = 0;
+
+ /// Factory method that allocates a new node.
+ virtual ACE_Timer_Node_T<TYPE> *alloc_node (void);
+
+ /// Factory method that frees a previously allocated node.
+ virtual void free_node (ACE_Timer_Node_T<TYPE> *);
+
+ /// Non-locking version of dispatch_info ()
+ int dispatch_info_i (const ACE_Time_Value &current_time,
+ ACE_Timer_Node_Dispatch_Info_T<TYPE> &info);
+
+ /// Synchronization variable for <ACE_Timer_Queue>.
+ /// NOTE: the right name would be lock_, but HP/C++ will choke on that!
+ ACE_LOCK mutex_;
+
+ /// Class that implements a free list
+ ACE_Free_List<ACE_Timer_Node_T<TYPE> > *free_list_;
+
+ /// Pointer to function that returns the current time of day.
+ ACE_Time_Value (*gettimeofday_)(void);
+
+ /// Upcall functor
+ FUNCTOR *upcall_functor_;
+
+ /// To delete or not to delete is the question?
+ int delete_upcall_functor_;
+
+ /// Flag to delete only if the class created the <free_list_>
+ int delete_free_list_;
+
+private:
+
+ /// Returned by <calculate_timeout>.
+ ACE_Time_Value timeout_;
+
+ /// Adjusts for timer skew in various clocks.
+ ACE_Time_Value timer_skew_;
+
+ // = Don't allow these operations for now.
+ ACE_UNIMPLEMENTED_FUNC (ACE_Timer_Queue_T (const ACE_Timer_Queue_T<TYPE, FUNCTOR, ACE_LOCK> &))
+ ACE_UNIMPLEMENTED_FUNC (void operator= (const ACE_Timer_Queue_T<TYPE, FUNCTOR, ACE_LOCK> &))
+};
+
+/**
+ * @class ACE_Event_Handler_Handle_Timeout_Upcall
+ *
+ * @brief Functor for Timer_Queues.
+ *
+ * This class implements the functor required by the Timer
+ * Queue to call <handle_timeout> on ACE_Event_Handlers.
+ */
+template <class ACE_LOCK>
+class ACE_Event_Handler_Handle_Timeout_Upcall
+{
+public:
+ typedef ACE_Timer_Queue_T<ACE_Event_Handler *,
+ ACE_Event_Handler_Handle_Timeout_Upcall<ACE_LOCK>,
+ ACE_LOCK>
+ TIMER_QUEUE;
+
+ // = Initialization and termination methods.
+ /// Constructor.
+ ACE_Event_Handler_Handle_Timeout_Upcall (void);
+
+ /// Destructor.
+ ~ACE_Event_Handler_Handle_Timeout_Upcall (void);
+
+ /// This method is called when the timer expires
+ int timeout (TIMER_QUEUE &timer_queue,
+ ACE_Event_Handler *handler,
+ const void *arg,
+ const ACE_Time_Value &cur_time);
+
+ /// This method is called when the timer is canceled
+ int cancellation (TIMER_QUEUE &timer_queue,
+ ACE_Event_Handler *handler);
+
+ /// This method is called when the timer queue is destroyed and
+ /// the timer is still contained in it
+ int deletion (TIMER_QUEUE &timer_queue,
+ ACE_Event_Handler *handler,
+ const void *arg);
+private:
+ // = Don't allow these operations for now.
+ ACE_UNIMPLEMENTED_FUNC (ACE_Event_Handler_Handle_Timeout_Upcall (const ACE_Event_Handler_Handle_Timeout_Upcall<ACE_LOCK> &))
+ ACE_UNIMPLEMENTED_FUNC (void operator= (const ACE_Event_Handler_Handle_Timeout_Upcall<ACE_LOCK> &))
+};
+
+#if defined (__ACE_INLINE__)
+#include "ace/Timer_Queue_T.i"
+#endif /* __ACE_INLINE__ */
+
+#if defined (ACE_TEMPLATES_REQUIRE_SOURCE) && !defined (ACE_HAS_BROKEN_HPUX_TEMPLATES)
+#include "ace/Timer_Queue_T.cpp"
+#endif /* ACE_TEMPLATES_REQUIRE_SOURCE && !ACE_HAS_BROKEN_HPUX_TEMPLATES */
+
+#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA)
+#pragma implementation ("Timer_Queue_T.cpp")
+#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */
+
+#include "ace/post.h"
+#endif /* ACE_TIMER_QUEUE_T_H */
diff --git a/ace/Timer/Timer_Queue_T.i b/ace/Timer/Timer_Queue_T.i
new file mode 100644
index 00000000000..8af63669a6f
--- /dev/null
+++ b/ace/Timer/Timer_Queue_T.i
@@ -0,0 +1,188 @@
+// $Id$
+
+/* -*- C++ -*- */
+
+template <class TYPE> ACE_INLINE void
+ACE_Timer_Node_T<TYPE>::set (const TYPE &type,
+ const void *a,
+ const ACE_Time_Value &t,
+ const ACE_Time_Value &i,
+ ACE_Timer_Node_T<TYPE> *n,
+ long timer_id)
+{
+ this->type_ = type;
+ this->act_ = a;
+ this->timer_value_ = t;
+ this->interval_ = i;
+ this->next_ = n;
+ this->timer_id_ = timer_id;
+}
+
+template <class TYPE> ACE_INLINE void
+ACE_Timer_Node_T<TYPE>::set (const TYPE &type,
+ const void *a,
+ const ACE_Time_Value &t,
+ const ACE_Time_Value &i,
+ ACE_Timer_Node_T<TYPE> *p,
+ ACE_Timer_Node_T<TYPE> *n,
+ long timer_id)
+{
+ this->type_ = type;
+ this->act_ = a;
+ this->timer_value_ = t;
+ this->interval_ = i;
+ this->prev_ = p;
+ this->next_ = n;
+ this->timer_id_ = timer_id;
+}
+
+template <class TYPE> ACE_INLINE TYPE &
+ACE_Timer_Node_T<TYPE>::get_type (void)
+{
+ return this->type_;
+}
+
+template <class TYPE> ACE_INLINE void
+ACE_Timer_Node_T<TYPE>::set_type (TYPE &type)
+{
+ this->type_ = type;
+}
+
+template <class TYPE> ACE_INLINE const void *
+ACE_Timer_Node_T<TYPE>::get_act (void)
+{
+ return this->act_;
+}
+
+template <class TYPE> ACE_INLINE void
+ACE_Timer_Node_T<TYPE>::set_act (void *act)
+{
+ this->act_ = act;
+}
+
+template <class TYPE> ACE_INLINE const ACE_Time_Value &
+ACE_Timer_Node_T<TYPE>::get_timer_value (void) const
+{
+ return this->timer_value_;
+}
+
+template <class TYPE> ACE_INLINE void
+ACE_Timer_Node_T<TYPE>::set_timer_value (const ACE_Time_Value &timer_value)
+{
+ this->timer_value_ = timer_value;
+}
+
+template <class TYPE> ACE_INLINE const ACE_Time_Value &
+ACE_Timer_Node_T<TYPE>::get_interval (void) const
+{
+ return this->interval_;
+}
+
+template <class TYPE> ACE_INLINE void
+ACE_Timer_Node_T<TYPE>::set_interval (const ACE_Time_Value &interval)
+{
+ this->interval_ = interval;
+}
+
+template <class TYPE> ACE_INLINE ACE_Timer_Node_T<TYPE> *
+ACE_Timer_Node_T<TYPE>::get_prev (void)
+{
+ return this->prev_;
+}
+
+template <class TYPE> ACE_INLINE void
+ACE_Timer_Node_T<TYPE>::set_prev (ACE_Timer_Node_T<TYPE> *prev)
+{
+ this->prev_ = prev;
+}
+
+template <class TYPE> ACE_INLINE ACE_Timer_Node_T<TYPE> *
+ACE_Timer_Node_T<TYPE>::get_next (void)
+{
+ return this->next_;
+}
+
+template <class TYPE> ACE_INLINE void
+ACE_Timer_Node_T<TYPE>::set_next (ACE_Timer_Node_T<TYPE> *next)
+{
+ this->next_ = next;
+}
+
+template <class TYPE> ACE_INLINE long
+ACE_Timer_Node_T<TYPE>::get_timer_id (void) const
+{
+ return this->timer_id_;
+}
+
+template <class TYPE> ACE_INLINE void
+ACE_Timer_Node_T<TYPE>::set_timer_id (long timer_id)
+{
+ this->timer_id_ = timer_id;
+}
+
+template <class TYPE> ACE_INLINE void
+ACE_Timer_Node_T<TYPE>::get_dispatch_info (ACE_Timer_Node_Dispatch_Info_T<TYPE> &info)
+{
+ // Yes, do a copy
+ info.type_ = this->type_;
+ info.act_ = this->act_;
+}
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK> ACE_INLINE void
+ACE_Timer_Queue_T<TYPE, FUNCTOR, ACE_LOCK>::timer_skew (const ACE_Time_Value &skew)
+{
+ timer_skew_ = skew;
+}
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK> ACE_INLINE const ACE_Time_Value &
+ACE_Timer_Queue_T<TYPE, FUNCTOR, ACE_LOCK>::timer_skew (void) const
+{
+ return timer_skew_;
+}
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK> ACE_INLINE int
+ACE_Timer_Queue_T<TYPE, FUNCTOR, ACE_LOCK>::expire (void)
+{
+ if (!this->is_empty ())
+ return this->expire (this->gettimeofday () + timer_skew_);
+ else
+ return 0;
+}
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK> int
+ACE_Timer_Queue_T<TYPE, FUNCTOR, ACE_LOCK>::dispatch_info (const ACE_Time_Value &cur_time,
+ ACE_Timer_Node_Dispatch_Info_T<TYPE> &info)
+{
+ ACE_TRACE ("ACE_Timer_Queue_T::dispatch_info");
+ ACE_MT (ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, 0));
+
+ return this->dispatch_info_i (cur_time, info);
+}
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK> ACE_INLINE void
+ACE_Timer_Queue_T<TYPE, FUNCTOR, ACE_LOCK>::upcall (TYPE &type,
+ const void *act,
+ const ACE_Time_Value &cur_time)
+{
+ this->upcall_functor ().timeout (*this, type, act, cur_time);
+}
+
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK> ACE_INLINE ACE_Time_Value
+ACE_Timer_Queue_T<TYPE, FUNCTOR, ACE_LOCK>::gettimeofday (void)
+{
+ // Invoke gettimeofday via pointer to function.
+ return this->gettimeofday_ ();
+}
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK> ACE_INLINE void
+ACE_Timer_Queue_T<TYPE, FUNCTOR, ACE_LOCK>::gettimeofday (ACE_Time_Value (*gettimeofday)(void))
+{
+ this->gettimeofday_ = gettimeofday;
+}
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK> ACE_INLINE FUNCTOR &
+ACE_Timer_Queue_T<TYPE, FUNCTOR, ACE_LOCK>::upcall_functor (void)
+{
+ return *this->upcall_functor_;
+}
diff --git a/ace/Timer/Timer_Wheel.cpp b/ace/Timer/Timer_Wheel.cpp
new file mode 100644
index 00000000000..de72afccb18
--- /dev/null
+++ b/ace/Timer/Timer_Wheel.cpp
@@ -0,0 +1,23 @@
+// $Id$
+
+#if !defined (ACE_TIMER_WHEEL_C)
+#define ACE_TIMER_WHEEL_C
+
+#include "ace/Timer_Wheel.h"
+
+#if defined (ACE_HAS_BROKEN_HPUX_TEMPLATES)
+#include "ace/Timer_Wheel_T.cpp"
+#endif /* ACE_HAS_BROKEN_HPUX_TEMPLATES */
+
+ACE_RCSID(ace, Timer_Wheel, "$Id$")
+
+#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION)
+template class ACE_Timer_Wheel_T<ACE_Event_Handler *, ACE_Event_Handler_Handle_Timeout_Upcall<ACE_SYNCH_RECURSIVE_MUTEX>, ACE_SYNCH_RECURSIVE_MUTEX>;
+template class ACE_Timer_Wheel_Iterator_T<ACE_Event_Handler *, ACE_Event_Handler_Handle_Timeout_Upcall<ACE_SYNCH_RECURSIVE_MUTEX>, ACE_SYNCH_RECURSIVE_MUTEX>;
+#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA)
+#pragma instantiate ACE_Timer_Wheel_T<ACE_Event_Handler *, ACE_Event_Handler_Handle_Timeout_Upcall<ACE_SYNCH_RECURSIVE_MUTEX>, ACE_SYNCH_RECURSIVE_MUTEX>
+#pragma instantiate ACE_Timer_Wheel_Iterator_T<ACE_Event_Handler *, ACE_Event_Handler_Handle_Timeout_Upcall<ACE_SYNCH_RECURSIVE_MUTEX>, ACE_SYNCH_RECURSIVE_MUTEX>
+#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */
+
+
+#endif /* ACE_TIMER_WHEEL_C */
diff --git a/ace/Timer/Timer_Wheel.h b/ace/Timer/Timer_Wheel.h
new file mode 100644
index 00000000000..5d37d0488dc
--- /dev/null
+++ b/ace/Timer/Timer_Wheel.h
@@ -0,0 +1,39 @@
+
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Timer_Wheel.h
+ *
+ * $Id$
+ *
+ * @author Darrell Brunsch (brunsch@cs.wustl.edu)
+ */
+//=============================================================================
+
+
+#ifndef ACE_TIMER_WHEEL_H
+#define ACE_TIMER_WHEEL_H
+#include "ace/pre.h"
+
+#include "ace/Timer_Wheel_T.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+// The following typedef are here for ease of use and backward
+// compatibility.
+
+typedef ACE_Timer_Wheel_T<ACE_Event_Handler *,
+ ACE_Event_Handler_Handle_Timeout_Upcall<ACE_SYNCH_RECURSIVE_MUTEX>,
+ ACE_SYNCH_RECURSIVE_MUTEX>
+ ACE_Timer_Wheel;
+
+typedef ACE_Timer_Wheel_Iterator_T<ACE_Event_Handler *,
+ ACE_Event_Handler_Handle_Timeout_Upcall<ACE_SYNCH_RECURSIVE_MUTEX>,
+ ACE_SYNCH_RECURSIVE_MUTEX>
+ ACE_Timer_Wheel_Iterator;
+
+#include "ace/post.h"
+#endif /* ACE_TIMER_WHEEL_H */
diff --git a/ace/Timer/Timer_Wheel_T.cpp b/ace/Timer/Timer_Wheel_T.cpp
new file mode 100644
index 00000000000..dc7ffe7e01e
--- /dev/null
+++ b/ace/Timer/Timer_Wheel_T.cpp
@@ -0,0 +1,820 @@
+// $Id$
+
+#ifndef ACE_TIMER_WHEEL_T_C
+#define ACE_TIMER_WHEEL_T_C
+
+#include "ace/Timer_Wheel_T.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "ace/High_Res_Timer.h"
+#include "ace/Log_Msg.h"
+
+ACE_RCSID(ace, Timer_Wheel_T, "$Id$")
+
+/**
+ * Just initializes the iterator with a ACE_Timer_Wheel_T and then calls
+ * first() to initialize the rest of itself.
+ *
+ * @param wheel A reference for a timer queue to iterate over
+ */
+template <class TYPE, class FUNCTOR, class ACE_LOCK>
+ACE_Timer_Wheel_Iterator_T<TYPE,
+ FUNCTOR,
+ ACE_LOCK>::ACE_Timer_Wheel_Iterator_T (
+ ACE_Timer_Wheel_T<TYPE, FUNCTOR, ACE_LOCK> &wheel
+ )
+ : timer_wheel_ (wheel)
+{
+ this->first();
+}
+
+
+/**
+ * Destructor, at this level does nothing.
+ */
+template <class TYPE, class FUNCTOR, class ACE_LOCK>
+ACE_Timer_Wheel_Iterator_T<TYPE,
+ FUNCTOR,
+ ACE_LOCK>::~ACE_Timer_Wheel_Iterator_T (void)
+{
+}
+
+
+/**
+ * Positions the iterator at the first position in the timing wheel
+ * that contains something. pos_ will be set to the position of this entry
+ * and list_item_ will point to the first entry in that position. Since
+ * this is an iterator,
+ *
+ * If the wheel is empty, pos_ will be equal timer_wheel_.wheel_size_ and
+ * list_item_ would be 0.
+ */
+template <class TYPE, class FUNCTOR, class ACE_LOCK> void
+ACE_Timer_Wheel_Iterator_T<TYPE, FUNCTOR, ACE_LOCK>::first (void)
+{
+ for (this->pos_ = 0;
+ this->pos_ < this->timer_wheel_.wheel_size_;
+ this->pos_++)
+ {
+ // Skip over empty entries
+ if (this->timer_wheel_.wheel_[this->pos_]->get_next ()
+ != this->timer_wheel_.wheel_[this->pos_])
+ {
+ this->list_item_ =
+ this->timer_wheel_.wheel_[this->pos_]->get_next ();
+ return;
+ }
+ }
+
+ // The queue is empty if we are here
+ this->list_item_ = 0;
+}
+
+
+/**
+ * Positions the iterator at the next node in list or goes to the next
+ * list
+ */
+template <class TYPE, class FUNCTOR, class ACE_LOCK> void
+ACE_Timer_Wheel_Iterator_T<TYPE, FUNCTOR, ACE_LOCK>::next (void)
+{
+ if (this->isdone ())
+ return;
+
+ this->list_item_ =
+ this->list_item_->get_next ();
+
+ // If there is no more in the current list, go to the next
+ if (this->list_item_ == this->timer_wheel_.wheel_[this->pos_])
+ {
+ for (this->pos_++;
+ this->pos_ < this->timer_wheel_.wheel_size_;
+ this->pos_++)
+ {
+ // Check for an empty entry
+ if (this->timer_wheel_.wheel_[this->pos_]->get_next ()
+ != this->timer_wheel_.wheel_[this->pos_])
+ {
+ this->list_item_ =
+ this->timer_wheel_.wheel_[this->pos_]->get_next ();
+ return;
+ }
+ }
+
+ this->list_item_ = 0;
+ }
+}
+
+
+/**
+ * @return True when we there isn't anymore items (when list_item_ == 0)
+ */
+template <class TYPE, class FUNCTOR, class ACE_LOCK> int
+ACE_Timer_Wheel_Iterator_T<TYPE, FUNCTOR, ACE_LOCK>::isdone (void) const
+{
+ return this->list_item_ == 0;
+}
+
+
+/**
+ * @return The node at the current position in the sequence or 0 if the wheel
+ * is empty
+ */
+template <class TYPE, class FUNCTOR, class ACE_LOCK> ACE_Timer_Node_T<TYPE> *
+ACE_Timer_Wheel_Iterator_T<TYPE, FUNCTOR, ACE_LOCK>::item (void)
+{
+ if (this->isdone ())
+ return 0;
+
+ return this->list_item_;
+}
+
+
+/**
+ * Constructor that sets up the timing wheel and also may preallocate
+ * some nodes on the free list
+ *
+ * @param wheelsize The number of lists in the timer wheel
+ * @param resolution The time resolution used by the hashing function
+ * @param prealloc The number of entries to prealloc in the free_list
+ * @param upcall_functor A pointer to a functor to use instead of the default
+ * @param freelist A pointer to a freelist to use instead of the default
+ */
+template <class TYPE, class FUNCTOR, class ACE_LOCK>
+ACE_Timer_Wheel_T<TYPE, FUNCTOR, ACE_LOCK>::ACE_Timer_Wheel_T (
+ size_t wheelsize,
+ size_t resolution,
+ size_t prealloc,
+ FUNCTOR *upcall_functor,
+ ACE_Free_List<ACE_Timer_Node_T <TYPE> > *freelist
+ )
+ : ACE_Timer_Queue_T<TYPE,FUNCTOR,ACE_LOCK> (upcall_functor, freelist),
+ wheel_size_ (wheelsize),
+ resolution_ (resolution),
+ earliest_pos_ (0)
+{
+ ACE_TRACE ("ACE_Timer_Wheel_T::ACE_Timer_Wheel_T");
+ size_t i;
+
+ this->gettimeofday (ACE_OS::gettimeofday);
+
+ // Create the timing wheel
+ ACE_NEW (this->wheel_,
+ ACE_Timer_Node_T<TYPE> *[wheelsize]);
+
+ // Create the dummy nodes
+ for (i = 0; i < wheelsize; i++)
+ {
+ ACE_Timer_Node_T<TYPE> *tempnode =
+ this->alloc_node ();
+ tempnode->set_next (tempnode);
+ tempnode->set_prev (tempnode);
+ this->wheel_[i] = tempnode;
+ }
+
+ // Do the preallocation
+ this->free_list_->resize (prealloc);
+
+ ACE_NEW (iterator_,
+ WHEEL_ITERATOR (*this));
+}
+
+
+/**
+ * Default Constructor that sets defaults for wheel_size_ and resolution_
+ * and doesn't do any preallocation.
+ *
+ * @param upcall_functor A pointer to a functor to use instead of the default
+ * @param freelist A pointer to a freelist to use instead of the default
+ */
+template <class TYPE, class FUNCTOR, class ACE_LOCK>
+ACE_Timer_Wheel_T<TYPE, FUNCTOR, ACE_LOCK>::ACE_Timer_Wheel_T (
+ FUNCTOR *upcall_functor,
+ ACE_Free_List<ACE_Timer_Node_T <TYPE> > *freelist
+ )
+ : ACE_Timer_Queue_T<TYPE,FUNCTOR,ACE_LOCK> (upcall_functor, freelist),
+ wheel_size_ (ACE_DEFAULT_TIMER_WHEEL_SIZE),
+ resolution_ (ACE_DEFAULT_TIMER_WHEEL_RESOLUTION),
+ earliest_pos_ (0)
+{
+ ACE_TRACE ("ACE_Timer_Wheel_T::ACE_Timer_Wheel_T");
+ size_t i;
+
+ this->gettimeofday (ACE_OS::gettimeofday);
+
+ // Create the timing wheel
+ ACE_NEW (this->wheel_,
+ ACE_Timer_Node_T<TYPE> *[this->wheel_size_]);
+
+ // Create the dummy nodes
+ for (i = 0;
+ i < this->wheel_size_;
+ i++)
+ {
+ ACE_Timer_Node_T<TYPE> *tempnode = this->alloc_node ();
+ tempnode->set_next (tempnode);
+ tempnode->set_prev (tempnode);
+ this->wheel_[i] = tempnode;
+ }
+
+ ACE_NEW (iterator_,
+ WHEEL_ITERATOR (*this));
+}
+
+// Destructor just cleans up its memory
+
+template <class TYPE, class FUNCTOR, class ACE_LOCK>
+ACE_Timer_Wheel_T<TYPE, FUNCTOR, ACE_LOCK>::~ACE_Timer_Wheel_T (void)
+{
+ ACE_TRACE ("ACE_Timer_Wheel_T::~ACE_Timer_Wheel_T");
+
+ delete iterator_;
+
+ for (size_t i = 0;
+ i < this->wheel_size_;
+ i++)
+ {
+ // delete nodes until only the dummy node is left
+ while (this->wheel_[i]->get_next () != this->wheel_[i])
+ {
+ ACE_Timer_Node_T<TYPE> *next =
+ this->wheel_[i]->get_next ();
+ this->wheel_[i]->set_next (next->get_next ());
+ next->get_next ()->set_prev (this->wheel_[i]);
+ this->upcall_functor ().deletion (*this,
+ next->get_type (),
+ next->get_act ());
+ this->free_node (next);
+ }
+
+ // and now delete the dummy node
+ delete this->wheel_[i];
+ }
+
+ // finally delete the wheel
+ delete [] this->wheel_;
+}
+
+
+/**
+ * Checks to see if <earliest_pos> points to a empty list (then it is empty).
+ *
+ * @return True if empty
+ */
+template <class TYPE, class FUNCTOR, class ACE_LOCK> int
+ACE_Timer_Wheel_T<TYPE, FUNCTOR, ACE_LOCK>::is_empty (void) const
+{
+ ACE_TRACE ("ACE_Timer_Wheel_T::is_empty");
+
+ return this->wheel_[this->earliest_pos_]->get_next ()
+ == this->wheel_[this->earliest_pos_];
+}
+
+
+/**
+ * @return First (earliest) node in the wheel_'s earliest_pos_ list
+ */
+template <class TYPE, class FUNCTOR, class ACE_LOCK> const ACE_Time_Value &
+ACE_Timer_Wheel_T<TYPE, FUNCTOR, ACE_LOCK>::earliest_time (void) const
+{
+ ACE_TRACE ("ACE_Timer_Wheel_T::earliest_time");
+
+ return this->wheel_[this->earliest_pos_]->get_next ()->get_timer_value ();
+}
+
+/**
+ * Creates a ACE_Timer_Node_T based on the input parameters. Then inserts
+ * the node into the wheel using reschedule (). Then returns a timer_id
+ * (which is actually a pointer to the actual timer_node).
+ *
+ * @param type The data of the timer node
+ * @param act Asynchronous Completion Token (AKA magic cookie)
+ * @param delay The time the timer is scheduled for (in absolute time)
+ * @param interval If not ACE_Time_Value::zero, then this is a periodic
+ * timer and interval is the time period
+ *
+ * @return Unique identifier (can be used to cancel the timer.
+ * -1 on failure.
+ */
+template <class TYPE, class FUNCTOR, class ACE_LOCK> long
+ACE_Timer_Wheel_T<TYPE, FUNCTOR, ACE_LOCK>::schedule (
+ const TYPE &type,
+ const void *act,
+ const ACE_Time_Value &delay,
+ const ACE_Time_Value &interval
+ )
+{
+ ACE_TRACE ("ACE_Timer_Wheel_T::schedule");
+ ACE_MT (ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, -1));
+
+ ACE_Timer_Node_T<TYPE> *tempnode = this->alloc_node ();
+
+ if (tempnode)
+ {
+ // Note that the timer_id is actually the pointer to the node
+
+ // Set the details of the node
+ tempnode->set (type,
+ act,
+ delay,
+ interval,
+ 0,
+ 0,
+ (long) tempnode);
+
+ // Reschedule will insert it into the correct position
+ this->reschedule (tempnode);
+
+ return tempnode->get_timer_id ();
+ }
+
+ // Failure return
+ errno = ENOMEM;
+ return -1;
+}
+
+
+/**
+ * Find the timer node by using the id as a pointer. Then use set_interval ()
+ * on the node to update the interval.
+ *
+ * @param timer_id The timer identifier
+ * @param interval The new interval
+ *
+ * @return 0 if successful, -1 if no.
+ */
+template <class TYPE, class FUNCTOR, class ACE_LOCK> int
+ACE_Timer_Wheel_T<TYPE, FUNCTOR, ACE_LOCK>::reset_interval (
+ long timer_id,
+ const ACE_Time_Value &interval
+ )
+{
+ ACE_TRACE ("ACE_Timer_Wheel_T::reset_interval");
+ ACE_MT (ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, -1));
+
+ // Make sure we are getting a valid <timer_id>, not an error
+ // returned by <schedule>.
+ if (timer_id == -1)
+ return -1;
+
+ ACE_Timer_Node_T<TYPE> *node =
+ ACE_reinterpret_cast (ACE_Timer_Node_T<TYPE> *,
+ timer_id);
+
+ // Check to see if the node looks like a true
+ // ACE_Timer_Node_T<TYPE>.
+ if (timer_id != node->get_timer_id ())
+ return -1;
+
+ node->set_interval (interval);
+ return 0;
+}
+
+
+/**
+ * Goes through every list in the wheel and whenever we find one with the
+ * correct type value, we remove it and continue. At the end make sure
+ * we reset the earliest time value in case the earliest timers were
+ * removed.
+ *
+ * @param type The value to search for.
+ * @param skip_close If this non-zero, the cancellation method of the
+ * functor will not be called for each cancelled timer.
+ *
+ * @return Number of timers cancelled
+ */
+template <class TYPE, class FUNCTOR, class ACE_LOCK> int
+ACE_Timer_Wheel_T<TYPE, FUNCTOR, ACE_LOCK>::cancel (const TYPE &type,
+ int skip_close)
+{
+ ACE_TRACE ("ACE_Timer_Wheel_T::cancel");
+ ACE_MT (ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, -1));
+
+ int number_of_cancellations = 0;
+ size_t i;
+
+ // Walk through the wheel
+ for (i = 0;
+ i < this->wheel_size_;
+ i++)
+ {
+
+ // Walk through the list.
+ for (ACE_Timer_Node_T<TYPE> *curr =
+ this->wheel_[i]->get_next ();
+ curr != this->wheel_[i];
+ )
+ {
+ if (curr->get_type () == type)
+ {
+ // Cancel it and remove it.
+ number_of_cancellations++;
+
+ // Detach it from the list
+ ACE_Timer_Node_T<TYPE> *tempnode = curr;
+ curr->get_prev ()->set_next (curr->get_next ());
+ curr->get_next ()->set_prev (curr->get_prev ());
+
+ // Go on to the next and delete the detached node
+ curr = curr->get_next ();
+ this->free_node (tempnode);
+ }
+ else
+ curr = curr->get_next ();
+ }
+ }
+
+ // Look for a new earliest time
+
+ // Defaults to zero.
+ ACE_Time_Value earliest_time;
+
+ // Check every entry in the table
+ for (i = 0; i < this->wheel_size_; i++)
+ {
+ // Skip empty entries
+ if (this->wheel_[i]->get_next () != this->wheel_[i])
+ {
+ // if initialization or if the time is earlier
+ if (earliest_time == ACE_Time_Value::zero
+ || this->wheel_[i]->get_timer_value () < earliest_time)
+ {
+ earliest_time =
+ this->wheel_[i]->get_next ()->get_timer_value ();
+ this->earliest_pos_ = i;
+ }
+ }
+ }
+
+ if (skip_close == 0)
+ this->upcall_functor ().cancellation (*this,
+ type);
+ return number_of_cancellations;
+}
+
+
+/**
+ * Cancels the single timer that is specified by the timer_id. In this
+ * case the timer_id is actually a pointer to the node, so we cast it
+ * to the node. This can be dangerous if the timer_id is made up
+ * (or deleted twice) so we do a little sanity check. Finally we update
+ * the earliest time in case the earliest timer was removed.
+ *
+ * @param timer_id Timer Identifier
+ * @param act Asychronous Completion Token (AKA magic cookie):
+ * If this is non-zero, stores the magic cookie of
+ * the cancelled timer here.
+ * @param skip_close If this non-zero, the cancellation method of the
+ * functor will not be called.
+ *
+ * @return 1 for sucess and 0 if the timer_id wasn't found (or was
+ * found to be invalid)
+ */
+template <class TYPE, class FUNCTOR, class ACE_LOCK> int
+ACE_Timer_Wheel_T<TYPE, FUNCTOR, ACE_LOCK>::cancel (long timer_id,
+ const void **act,
+ int skip_close)
+{
+ ACE_TRACE ("ACE_Timer_Wheel_T::cancel");
+ ACE_MT (ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, -1));
+
+ // Make sure we are getting a valid <timer_id>, not an error
+ // returned by <schedule>.
+ if (timer_id == -1)
+ return 0;
+
+ ACE_Timer_Node_T<TYPE> *node =
+ ACE_reinterpret_cast (ACE_Timer_Node_T<TYPE> *,
+ timer_id);
+
+ // Check to see if the node looks like a true ACE_Timer_Node_T<TYPE>.
+ if (timer_id == node->get_timer_id ())
+ {
+ node->get_next ()->set_prev (node->get_prev ());
+ node->get_prev ()->set_next (node->get_next ());
+
+ if (act != 0)
+ *act = node->get_act ();
+
+ if (skip_close == 0)
+ this->upcall_functor ().cancellation (*this,
+ node->get_type ());
+
+ // Find out what position it is in.
+ size_t pos = (node->get_timer_value ().usec () / this->resolution_)
+ % this->wheel_size_;
+
+ this->free_node (node);
+
+ // Get the new earliest time if we have to
+
+ if (pos == this->earliest_pos_)
+ {
+ ACE_Time_Value earliest_time; // defaults to zero
+
+ // Check every entry in the table
+ for (size_t i = 0; i < this->wheel_size_; i++)
+ {
+ // Skip empty entries
+ if (this->wheel_[i]->get_next () != this->wheel_[i])
+ {
+ // if initialization or if the time is earlier
+ if (earliest_time == ACE_Time_Value::zero
+ || this->wheel_[i]->get_timer_value () < earliest_time)
+ {
+ earliest_time =
+ this->wheel_[i]->get_next ()->get_timer_value ();
+ this->earliest_pos_ = i;
+ }
+ }
+ }
+ }
+
+ return 1;
+ }
+
+ // Didn't find it if we are here
+ return 0;
+}
+
+
+/**
+ * Dumps out the size of the wheel, the resolution, and the contents
+ * of the wheel.
+ */
+template <class TYPE, class FUNCTOR, class ACE_LOCK> void
+ACE_Timer_Wheel_T<TYPE, FUNCTOR, ACE_LOCK>::dump (void) const
+{
+ ACE_TRACE ("ACE_Timer_Wheel_T::dump");
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_LIB_TEXT ("\nwheel_size_ = %d"), this->wheel_size_));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_LIB_TEXT ("\nresolution_ = %d"), this->resolution_));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_LIB_TEXT ("\nwheel_ = \n")));
+
+ for (size_t i = 0; i < this->wheel_size_; i++)
+ {
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("%d\n"), i));
+ ACE_Timer_Node_T<TYPE> *temp = this->wheel_[i]->get_next ();
+ while (temp != this->wheel_[i])
+ {
+ temp->dump ();
+ temp = temp->get_next ();
+ }
+ }
+
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+
+/**
+ * Removes the earliest node and then find the new <earliest_pos_>
+ *
+ * @return The earliest timer node.
+ */
+template <class TYPE, class FUNCTOR, class ACE_LOCK> ACE_Timer_Node_T<TYPE> *
+ACE_Timer_Wheel_T<TYPE, FUNCTOR, ACE_LOCK>::remove_first (void)
+{
+ ACE_TRACE ("ACE_Timer_Wheel_T::remove_first");
+
+ // Remove the item
+ ACE_Timer_Node_T<TYPE> *temp =
+ this->wheel_[this->earliest_pos_]->get_next ();
+ temp->get_prev ()->set_next (temp->get_next ());
+ temp->get_next ()->set_prev (temp->get_prev ());
+
+ ACE_Time_Value earliest_time;
+
+ // Check every entry in the table for the new earliest item
+ for (size_t i = 0;
+ i < this->wheel_size_;
+ i++)
+ {
+ // Check for an empty entry
+ if (this->wheel_[i]->get_next () != this->wheel_[i])
+ {
+ // if initialization or if the time is earlier
+ if (earliest_time == ACE_Time_Value::zero
+ || this->wheel_[i]->get_timer_value () < earliest_time)
+ {
+ earliest_time =
+ this->wheel_[i]->get_next ()->get_timer_value ();
+ this->earliest_pos_ = i;
+ }
+ }
+ }
+
+ return temp;
+}
+
+
+/**
+ * Returns the earliest node without removing it
+ *
+ * @return The earliest timer node.
+ */
+template <class TYPE, class FUNCTOR, class ACE_LOCK> ACE_Timer_Node_T<TYPE> *
+ACE_Timer_Wheel_T<TYPE, FUNCTOR, ACE_LOCK>::get_first (void)
+{
+ ACE_TRACE ("ACE_Timer_Wheel_T::get_first");
+
+ return this->wheel_[this->earliest_pos_]->get_next ();
+}
+
+/**
+ * Takes an ACE_Timer_Node and inserts it into the correct position in
+ * the correct list. Also makes sure to update the earliest time.
+ *
+ * @param expired The timer node to reschedule
+ */
+template <class TYPE, class FUNCTOR, class ACE_LOCK> void
+ACE_Timer_Wheel_T<TYPE, FUNCTOR, ACE_LOCK>::reschedule (
+ ACE_Timer_Node_T<TYPE> *expired
+ )
+{
+ ACE_TRACE ("ACE_Timer_Wheel_T::reschedule");
+
+ size_t pos = (expired->get_timer_value ().usec () / this->resolution_)
+ % this->wheel_size_;
+
+ // See if we need to update the earliest time
+ if (this->is_empty ()
+ || expired->get_timer_value () < this->earliest_time ())
+ this->earliest_pos_ = pos;
+
+ // Insert time into dummy node.
+ this->wheel_[pos]->set_timer_value (expired->get_timer_value ());
+ ACE_Timer_Node_T<TYPE> *cursor =
+ this->wheel_[pos]->get_next ();
+
+ // Find position to insert
+ while (cursor->get_timer_value () < expired->get_timer_value ())
+ cursor = cursor->get_next ();
+
+ // Insert
+ expired->set_prev (cursor->get_prev ());
+ expired->set_next (cursor);
+ cursor->set_prev (expired);
+ expired->get_prev ()->set_next (expired);
+}
+
+/**
+ * @return The iterator
+ */
+template <class TYPE, class FUNCTOR, class ACE_LOCK>
+ACE_Timer_Queue_Iterator_T<TYPE, FUNCTOR, ACE_LOCK> &
+ACE_Timer_Wheel_T<TYPE, FUNCTOR, ACE_LOCK>::iter (void)
+{
+ this->iterator_->first ();
+ return *this->iterator_;
+}
+
+/**
+ * Dummy version of expire to get rid of warnings in Sun CC 4.2
+ * Just call the expire of the base class.
+ */
+template <class TYPE, class FUNCTOR, class ACE_LOCK> int
+ACE_Timer_Wheel_T<TYPE, FUNCTOR, ACE_LOCK>::expire ()
+{
+ return ACE_Timer_Queue_T<TYPE,FUNCTOR,ACE_LOCK>::expire ();
+}
+
+/**
+ * This is a specialized version of expire that is more suited for the
+ * internal data representation. Notice that we are still expiring
+ * timers in order, even though this can be really speeded up if we
+ * didn't worry about this.
+ *
+ * @param cur_time The time to expire timers up to.
+ *
+ * @return Number of timers expired
+ */
+template <class TYPE, class FUNCTOR, class ACE_LOCK> int
+ACE_Timer_Wheel_T<TYPE, FUNCTOR, ACE_LOCK>::expire (
+ const ACE_Time_Value &cur_time
+ )
+{
+ ACE_TRACE ("ACE_Timer_Wheel_T::expire");
+ ACE_MT (ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, -1));
+
+ int number_of_timers_expired = 0;
+ size_t i;
+
+ size_t earliest_pos = this->wheel_size_;
+ ACE_Time_Value earliest_time = cur_time;
+
+ size_t next_earliest_pos = this->wheel_size_;
+ ACE_Time_Value next_earliest_time;
+
+ // Find the earliest time and location
+ for (i = 0; i < this->wheel_size_; i++)
+ {
+ if (this->wheel_[i]->get_next () != this->wheel_[i]
+ && this->wheel_[i]->get_next ()->get_timer_value ()
+ <= earliest_time)
+ {
+ earliest_pos = i;
+ earliest_time = this->wheel_[i]->get_next ()->get_timer_value ();
+ }
+ }
+
+ // Check to see if the timer queue is empty
+ if (earliest_pos == this->wheel_size_)
+ return 0;
+
+ do
+ {
+ next_earliest_time = cur_time;
+ next_earliest_pos = this->wheel_size_;
+
+ // Find the next earliest position and time.
+ for (i = 0; i < this->wheel_size_; i++)
+ {
+ if (i != earliest_pos
+ && this->wheel_[i]->get_next () != this->wheel_[i]
+ && this->wheel_[i]->get_next ()->get_timer_value ()
+ <= next_earliest_time)
+ {
+ next_earliest_pos = i;
+ next_earliest_time =
+ this->wheel_[i]->get_next ()->get_timer_value ();
+ }
+ }
+
+ // Keep expiring timers until we need to move to the next list
+ while (this->wheel_[earliest_pos]->get_next ()
+ != this->wheel_[earliest_pos]
+ && this->wheel_[earliest_pos]->get_next ()->get_timer_value ()
+ <= next_earliest_time)
+ {
+ // Remove the first node in the earliest position
+ ACE_Timer_Node_T<TYPE> *expired =
+ this->wheel_[earliest_pos]->get_next ();
+ this->wheel_[earliest_pos]->set_next (expired->get_next ());
+ expired->get_next ()->set_prev (this->wheel_[earliest_pos]);
+
+ TYPE &type = expired->get_type ();
+ const void *act = expired->get_act ();
+ int reclaim = 1;
+
+ // Check if this is an interval timer.
+ if (expired->get_interval () > ACE_Time_Value::zero)
+ {
+ // Make sure that we skip past values that have already
+ // "expired".
+ do
+ expired->set_timer_value (expired->get_timer_value ()
+ + expired->get_interval ());
+ while (expired->get_timer_value () <= cur_time);
+
+ // Since this is an interval timer, we need to
+ // reschedule it.
+ this->reschedule (expired);
+ reclaim = 0;
+ }
+
+ // Call the functor.
+ this->upcall (type, act, cur_time);
+
+ if (reclaim)
+ // Free up the node and the token.
+ this->free_node (expired);
+
+ ++number_of_timers_expired;
+ }
+
+ earliest_pos = next_earliest_pos;
+ }
+ while (earliest_pos != this->wheel_size_);
+
+ // Look for a new earliest time
+
+ earliest_time = ACE_Time_Value::zero;
+
+ // Check every entry in the table
+ for (i = 0; i < this->wheel_size_; i++)
+ {
+ // Skip empty entries
+ if (this->wheel_[i]->get_next () != this->wheel_[i])
+ {
+ // if initialization or if the time is earlier
+ if (earliest_time == ACE_Time_Value::zero
+ || this->wheel_[i]->get_timer_value () < earliest_time)
+ {
+ earliest_time =
+ this->wheel_[i]->get_next ()->get_timer_value ();
+ this->earliest_pos_ = i;
+ }
+ }
+ }
+
+ return number_of_timers_expired;
+}
+
+#endif /* ACE_TIMER_WHEEL_T_C */
diff --git a/ace/Timer/Timer_Wheel_T.h b/ace/Timer/Timer_Wheel_T.h
new file mode 100644
index 00000000000..8548374433a
--- /dev/null
+++ b/ace/Timer/Timer_Wheel_T.h
@@ -0,0 +1,211 @@
+
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Timer_Wheel_T.h
+ *
+ * $Id$
+ *
+ * @author Darrell Brunsch <brunsch@cs.wustl.edu>
+ */
+//=============================================================================
+
+
+#ifndef ACE_TIMER_WHEEL_T_H
+#define ACE_TIMER_WHEEL_T_H
+#include "ace/pre.h"
+
+#include "ace/Timer_Queue_T.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+// Forward declaration
+template <class TYPE, class FUNCTOR, class ACE_LOCK>
+class ACE_Timer_Wheel_T;
+
+/**
+ * @class ACE_Timer_Wheel_Iterator_T
+ *
+ * @brief Iterates over an <ACE_Timer_Wheel>.
+ *
+ * This is a generic iterator that can be used to visit every
+ * node of a timer queue. Be aware that it doesn't transverse
+ * in the order of timeout values.
+ */
+template <class TYPE, class FUNCTOR, class ACE_LOCK>
+class ACE_Timer_Wheel_Iterator_T
+ : public ACE_Timer_Queue_Iterator_T <TYPE, FUNCTOR, ACE_LOCK>
+{
+public:
+ /// Constructor
+ ACE_Timer_Wheel_Iterator_T (ACE_Timer_Wheel_T<TYPE, FUNCTOR, ACE_LOCK> &);
+
+ /// Destructor
+ ~ACE_Timer_Wheel_Iterator_T (void);
+
+ /// Positions the iterator at the earliest node in the Timer Queue
+ virtual void first (void);
+
+ /// Positions the iterator at the next node in the Timer Queue
+ virtual void next (void);
+
+ /// Returns true when there are no more nodes in the sequence
+ virtual int isdone (void) const;
+
+ /// Returns the node at the current position in the sequence
+ virtual ACE_Timer_Node_T<TYPE> *item (void);
+
+protected:
+ /// Pointer to the <ACE_Timer_List> that we are iterating over.
+ ACE_Timer_Wheel_T<TYPE, FUNCTOR, ACE_LOCK> &timer_wheel_;
+
+ /// Current position in the timing wheel
+ size_t pos_;
+
+ /// Pointer to the position in the the <pos_>th list
+ ACE_Timer_Node_T<TYPE> *list_item_;
+};
+
+/**
+ * @class ACE_Timer_Wheel_T
+ *
+ * @brief Provides a Timing Wheel version of Timer Queue
+ *
+ * This implementation uses a hash table of ordered doubly-
+ * linked lists of absolute times. The other enhancements
+ * to Timer List include using the pointer to the node as the
+ * timer id (to speed up removing), adding a free list and
+ * the ability to preallocate nodes. Timer Wheel is based on
+ * the timing wheel implementation used in Adam M. Costello and
+ * George Varghese's paper "Redesigning the BSD Callout and
+ * Timer Facilities"
+ * (http://dworkin.wustl.edu/~varghese/PAPERS/newbsd.ps.Z)
+ */
+template <class TYPE, class FUNCTOR, class ACE_LOCK>
+class ACE_Timer_Wheel_T : public ACE_Timer_Queue_T<TYPE, FUNCTOR, ACE_LOCK>
+{
+public:
+ /// Type of iterator
+ typedef ACE_Timer_Wheel_Iterator_T<TYPE, FUNCTOR, ACE_LOCK> WHEEL_ITERATOR;
+
+ /// Iterator is a friend
+ friend class ACE_Timer_Wheel_Iterator_T<TYPE, FUNCTOR, ACE_LOCK>;
+
+ /// Type inherited from
+ typedef ACE_Timer_Queue_T<TYPE, FUNCTOR, ACE_LOCK> INHERITED;
+
+ /// Default constructor
+ ACE_Timer_Wheel_T (FUNCTOR *upcall_functor = 0,
+ ACE_Free_List<ACE_Timer_Node_T <TYPE> > *freelist = 0);
+
+ /// Constructor with opportunities to set the wheelsize and resolution
+ ACE_Timer_Wheel_T (size_t wheelsize,
+ size_t resolution,
+ size_t prealloc = 0,
+ FUNCTOR *upcall_functor = 0,
+ ACE_Free_List<ACE_Timer_Node_T <TYPE> > *freelist = 0);
+
+ /// Destructor
+ virtual ~ACE_Timer_Wheel_T (void);
+
+ /// True if queue is empty, else false.
+ virtual int is_empty (void) const;
+
+ /// Returns the time of the earlier node in the <ACE_Timer_Wheel>.
+ /// Must be called on a non-empty queue.
+ virtual const ACE_Time_Value &earliest_time (void) const;
+
+ /// Schedules a timer.
+ virtual long schedule (const TYPE &type,
+ const void *act,
+ const ACE_Time_Value &delay,
+ const ACE_Time_Value &interval
+ = ACE_Time_Value::zero);
+
+ /// Changes the interval of a timer (and can make it periodic or non
+ /// periodic by setting it to ACE_Time_Value::zero or not).
+ virtual int reset_interval (long timer_id,
+ const ACE_Time_Value &interval);
+
+ /// Cancel all timer associated with <type>. If <dont_call> is 0
+ /// then the <functor> will be invoked. Returns number of timers
+ /// cancelled.
+ virtual int cancel (const TYPE &type,
+ int dont_call_handle_close = 1);
+
+ // Cancel a timer, storing the magic cookie in act (if nonzero).
+ // Calls the functor if dont_call_handle_close is 0 and returns 1
+ // on success
+ virtual int cancel (long timer_id,
+ const void **act = 0,
+ int dont_call_handle_close = 1);
+
+ /// Run the <functor> for all timers whose values are <=
+ /// <ACE_OS::gettimeofday>. Also accounts for <timer_skew>. Returns
+ /// the number of timers canceled.
+ virtual int expire (void);
+
+ // Run the <functor> for all timers whose values are <= <cur_time>.
+ // This does not account for <timer_skew>. Returns the number of
+ // timers canceled.
+ int expire (const ACE_Time_Value &);
+
+ /// Returns a pointer to this <ACE_Timer_Queue_T>'s iterator.
+ virtual ACE_Timer_Queue_Iterator_T<TYPE, FUNCTOR, ACE_LOCK> &iter (void);
+
+ /// Removes the earliest node from the queue and returns it
+ virtual ACE_Timer_Node_T<TYPE> *remove_first (void);
+
+ /// Dump the state of an object.
+ virtual void dump (void) const;
+
+ /// Reads the earliest node from the queue and returns it.
+ virtual ACE_Timer_Node_T<TYPE> *get_first (void);
+
+private:
+ /// Reschedule an "interval" node
+ virtual void reschedule (ACE_Timer_Node_T<TYPE> *);
+
+ /// Timing Wheel.
+ ACE_Timer_Node_T<TYPE> **wheel_;
+
+ /// Size of the timing wheel.
+ size_t wheel_size_;
+
+ /// Resolution (in microsoconds) of the timing wheel.
+ size_t resolution_;
+
+ /// Index of the list with the earliest time
+ size_t earliest_pos_;
+
+ /// Keeps track of the size of the queue
+ long size_;
+
+ /// Iterator used to expire timers.
+ WHEEL_ITERATOR *iterator_;
+
+ /// Pointer to the freelist of <ACE_Timer_Node_T<TYPE>>.
+ ACE_Timer_Node_T<TYPE> *freelist_;
+
+ // = Don't allow these operations for now.
+ ACE_UNIMPLEMENTED_FUNC (
+ ACE_Timer_Wheel_T (const ACE_Timer_Wheel_T<TYPE, FUNCTOR, ACE_LOCK> &))
+ ACE_UNIMPLEMENTED_FUNC (
+ void operator= (const ACE_Timer_Wheel_T<TYPE, FUNCTOR, ACE_LOCK> &))
+};
+
+#if defined (ACE_TEMPLATES_REQUIRE_SOURCE)
+#if !defined (ACE_HAS_BROKEN_HPUX_TEMPLATES)
+#include "ace/Timer_Wheel_T.cpp"
+#endif /* !ACE_HAS_BROKEN_HPUX_TEMPLATES */
+#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */
+
+#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA)
+#pragma implementation ("Timer_Wheel_T.cpp")
+#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */
+
+#include "ace/post.h"
+#endif /* ACE_TIMER_WHEEL_T_H */
diff --git a/ace/Token/Local_Tokens.cpp b/ace/Token/Local_Tokens.cpp
new file mode 100644
index 00000000000..bca379f58ca
--- /dev/null
+++ b/ace/Token/Local_Tokens.cpp
@@ -0,0 +1,1446 @@
+// $Id$
+
+#include "ace/Thread.h"
+#include "ace/Local_Tokens.h"
+#include "ace/Token_Manager.h"
+
+#if !defined (__ACE_INLINE__)
+#include "ace/Local_Tokens.i"
+#endif /* __ACE_INLINE__ */
+
+#if defined (ACE_HAS_TOKENS_LIBRARY)
+
+ACE_RCSID(ace, Local_Tokens, "$Id$")
+
+void
+ACE_Tokens::dump (void) const
+{
+ ACE_TRACE ("ACE_Tokens::dump");
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("ACE_Tokens::dump:\n")
+ ACE_LIB_TEXT (" reference_cont_ = %d\n")
+ ACE_LIB_TEXT (" token_name_ = %s\n"),
+ reference_count_, token_name_));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("waiters_\n")));
+ this->waiters_.dump ();
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+ACE_Tokens::ACE_Tokens (void)
+ : visited_ (0),
+ reference_count_ (0)
+{
+ ACE_TRACE ("ACE_Tokens::ACE_Tokens");
+}
+
+void
+ACE_Tokens::make_owner (ACE_TPQ_Entry *caller)
+{
+ this->waiters_.remove (caller);
+ this->waiters_.enqueue (caller, 0);
+}
+
+#if defined (ACE_LACKS_INLINE_FUNCTIONS)
+ACE_Null_Token::ACE_Null_Token (void)
+{
+}
+
+ACE_Null_Token::~ACE_Null_Token (void)
+{
+}
+#endif /* ACE_LACKS_INLINE_FUNCTIONS */
+
+void
+ACE_TPQ_Entry::dump (void) const
+{
+ ACE_TRACE ("ACE_TPQ_Entry::dump");
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_LIB_TEXT ("ACE_TPQ_Entry::dump:\n")
+ ACE_LIB_TEXT (" nesting_level_ = %d\n")
+ ACE_LIB_TEXT (" client_id_ = %s\n"),
+ nesting_level_,
+ client_id_));
+
+ if (next_ != 0)
+ {
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("next:.\n")));
+ next_->dump ();
+ }
+
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("ACE_TPQ_Entry::dump end.\n")));
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+ACE_TPQ_Entry::ACE_TPQ_Entry (const ACE_Token_Proxy *new_proxy,
+ const ACE_TCHAR *client_id)
+ : cond_var_ (lock_),
+ next_ (0),
+ // This const typecast is safe.
+ proxy_ ((ACE_Token_Proxy *) new_proxy),
+ nesting_level_ (0),
+ sleep_hook_ (0)
+{
+ ACE_TRACE ("ACE_TPQ_Entry::ACE_TPQ_Entry");
+
+ if (client_id != 0)
+ this->client_id (client_id);
+ else
+ {
+ // Just make sure we have enough space.
+ ACE_TCHAR host_name[MAXHOSTNAMELEN];
+ ACE_TCHAR name[(sizeof host_name / sizeof (ACE_TCHAR)) + 256];
+ ACE_OS::hostname (host_name, sizeof host_name);
+
+ ACE_thread_t thread_id = ACE_Thread::self ();
+
+ // The cast is an attempt to get this to compile (and run,
+ // hopefully) regardless of the type of ACE_thread_t.
+ ACE_OS::sprintf (name,
+ ACE_LIB_TEXT ("/%s/%u/%lu"),
+ host_name,
+ ACE_static_cast (u_int, ACE_OS::getpid ()),
+ *ACE_reinterpret_cast (u_long *, &thread_id));
+
+ this->client_id (name);
+ }
+}
+
+ACE_TPQ_Entry::ACE_TPQ_Entry (void)
+ : cond_var_ (lock_),
+ proxy_ (0),
+ nesting_level_ (0),
+ sleep_hook_ (0)
+{
+ ACE_TRACE ("ACE_TPQ_Entry::ACE_TPQ_Entry null const.");
+}
+
+ACE_TPQ_Entry::ACE_TPQ_Entry (const ACE_TPQ_Entry &rhs)
+: cond_var_ (lock_)
+{
+ ACE_TRACE ("ACE_TPQ_Entry::ACE_TPQ_Entry copy const.");
+ *this = rhs;
+}
+
+ACE_TPQ_Entry::~ACE_TPQ_Entry (void)
+{
+ ACE_TRACE ("ACE_TPQ_Entry::~ACE_TPQ_Entry");
+}
+
+void
+ACE_TPQ_Entry::operator= (const ACE_TPQ_Entry& rhs)
+{
+ ACE_TRACE ("ACE_TPQ_Entry::operator=");
+ if (&rhs == this)
+ return;
+ this->proxy_ = rhs.proxy ();
+ this->nesting_level_ = rhs.nesting_level ();
+ this->client_id (rhs.client_id ());
+ this->sleep_hook_ = rhs.sleep_hook ();
+}
+
+void
+ACE_TPQ_Entry::client_id (const ACE_TCHAR *id)
+{
+ ACE_TRACE ("ACE_TPQ_Entry::client_id");
+
+ if (id == 0)
+ return;
+
+ ACE_OS::strsncpy (this->client_id_,
+ (ACE_TCHAR *) id,
+ ACE_MAXCLIENTIDLEN);
+}
+
+void
+ACE_TSS_TPQ_Entry::dump (void) const
+{
+ ACE_TRACE ("ACE_TSS_TPQ_Entry::dump");
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+#if defined (ACE_HAS_BROKEN_CONDITIONAL_STRING_CASTS)
+ ACE_DEBUG ((LM_DEBUG, (char *) "ACE_TSS_TPQ_Entry::dump:\n",
+ (char *) " client_id_ = %s\n",
+ (char *) client_id_ == 0 ? (char *) "0" : (char *) client_id_));
+#else /* ! defined (ACE_HAS_BROKEN_CONDITIONAL_STRING_CASTS) */
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("ACE_TSS_TPQ_Entry::dump:\n")
+ ACE_LIB_TEXT (" client_id_ = %s\n"),
+ client_id_ == 0 ? ACE_LIB_TEXT ("0") : client_id_));
+#endif /* ! defined (ACE_HAS_BROKEN_CONDITIONAL_STRING_CASTS) */
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("base:\n")));
+ ACE_TPQ_ENTRY::dump ();
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+ACE_TSS_TPQ_Entry::ACE_TSS_TPQ_Entry (const ACE_Token_Proxy *proxy,
+ const ACE_TCHAR *client_id)
+: proxy_ (proxy),
+ client_id_ (client_id)
+{
+ ACE_TRACE ("ACE_TSS_TPQ_Entry::ACE_TSS_TPQ_Entry");
+}
+
+ACE_TPQ_Entry *
+ACE_TSS_TPQ_Entry::make_TSS_TYPE (void) const
+{
+ ACE_TRACE ("ACE_TSS_TPQ_Entry::make_TSS_TYPE");
+ ACE_TPQ_Entry *temp;
+
+ ACE_NEW_RETURN (temp,
+ ACE_TPQ_Entry (this->proxy_,
+ this->client_id_),
+ 0);
+ return temp;
+}
+
+ACE_TSS_TPQ_Entry::operator ACE_TPQ_Entry * (void)
+{
+#if !defined (ACE_NO_TSS_TOKENS)
+ return (ACE_TPQ_Entry *) (*((ACE_TSS<ACE_TPQ_Entry> *) this));
+#else
+ // Not sure this is the right thing to do, but it seems to work.
+ // The base class ALSO has a proxy_ and client_id_ members (weird?)
+ // which don't get initialised. The following two lines make this
+ // the same as the subclass, so that the slicing works .
+ ACE_TPQ_ENTRY::proxy ((ACE_Token_Proxy *)(this->proxy_));
+ ACE_TPQ_ENTRY::client_id (this->client_id_);
+ return (ACE_TPQ_Entry *) this;;
+#endif /* !ACE_NO_TSS_TOKENS */
+}
+
+ACE_TPQ_Iterator::ACE_TPQ_Iterator (ACE_Token_Proxy_Queue &q)
+ : current_ (q.head_)
+{
+ ACE_TRACE ("ACE_TPQ_Iterator::ACE_TPQ_Iterator");
+}
+
+int
+ACE_TPQ_Iterator::next (ACE_TPQ_Entry *&next_item)
+{
+ ACE_TRACE ("ACE_TPQ_Iterator::next");
+
+ next_item = this->current_;
+
+ return current_ != 0;
+}
+
+int
+ACE_TPQ_Iterator::done (void) const
+{
+ ACE_TRACE ("ACE_TPQ_Iterator::done");
+
+ return this->current_ == 0;
+}
+
+void
+ACE_TPQ_Iterator::advance (void)
+{
+ ACE_TRACE ("ACE_TPQ_Iterator::advance");
+
+ if (current_ != 0)
+ this->current_ = this->current_->next_;
+}
+
+void
+ACE_TPQ_Iterator::dump (void) const
+{
+ ACE_TRACE ("ACE_TPQ_Iterator::dump");
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("ACE_TPQ_Iterator::dump:\n")
+ ACE_LIB_TEXT (" current_ = %d\n"),
+ (long) this->current_));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("head_ and tail_\n")));
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+void
+ACE_Token_Proxy_Queue::dump (void) const
+{
+ ACE_TRACE ("ACE_Token_Proxy_Queue::dump");
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("ACE_Token_Proxy_Queue::dump:\n")
+ ACE_LIB_TEXT (" size_ = %d\n"),
+ size_));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("head_ and tail_\n")));
+ if (this->head_ != 0)
+ this->head_->dump ();
+
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("ACE_Token_Proxy_Queue::dump end.\n")));
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+ACE_Token_Proxy_Queue::ACE_Token_Proxy_Queue (void)
+ : head_ (0),
+ tail_ (0),
+ size_ (0)
+{
+ ACE_TRACE ("ACE_Token_Proxy_Queue::ACE_Token_Proxy_Queue");
+}
+
+void
+ACE_Token_Proxy_Queue::enqueue (ACE_TPQ_Entry *tpq,
+ int position)
+{
+ ACE_TRACE ("ACE_Token_Proxy_Queue::enqueue");
+ tpq->next_ = 0;
+
+ ++this->size_;
+
+ if (this->head_ == 0)
+ {
+ // make tpq the entire list
+ this->head_ = this->tail_ = tpq;
+ return;
+ }
+
+ if (position == 0)
+ {
+ // make head of list
+ tpq->next_ = this->head_;
+ this->head_ = tpq;
+ return;
+ }
+
+ if (position == -1)
+ {
+ // stick at back of list
+ this->tail_->next_ = tpq;
+ this->tail_ = tpq;
+ return;
+ }
+
+ // walk through list to insertion point
+ ACE_TPQ_Entry *temp = head_;
+
+ for (int x = position;
+ x > 1;
+ --x)
+ {
+ // end of queue?
+ if (temp->next_ == 0)
+ break;
+ // advance pointer
+ else
+ temp = temp->next_;
+ }
+
+ // insert new tpq after temp
+ tpq->next_ = temp->next_;
+ temp->next_ = tpq;
+}
+
+void
+ACE_Token_Proxy_Queue::dequeue (void)
+{
+ ACE_TRACE ("ACE_Token_Proxy_Queue::dequeue");
+
+ if (head_ == 0)
+ return;
+
+ ACE_TPQ_Entry *temp = this->head_;
+
+ this->head_ = this->head_->next_;
+
+ temp->next_ = 0;
+
+ --this->size_;
+
+ if (this->head_ == 0 && this->size_ != 0)
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("incorrect size = %d\n"),
+ this->size_));
+}
+
+/*
+int
+ACE_Token_Proxy_Queue::member (const ACE_TCHAR *id)
+{
+ ACE_TRACE ("ACE_Token_Proxy_Queue::member");
+
+ for (ACE_TPQ_Entry *temp = this->head_;
+ temp != 0;
+ temp = temp->next_)
+ if (ACE_OS::strcmp (temp->client_id (), id) == 0)
+ // We found it!
+ return 1;
+
+ // We didn't find it :-(
+ return 0;
+}
+*/
+
+void
+ACE_Token_Proxy_Queue::remove (const ACE_TPQ_Entry *remove_me)
+{
+ ACE_TRACE ("ACE_Token_Proxy_Queue::remove");
+ // sanity
+ if ((remove_me == 0) || (this->head_ == 0))
+ return;
+
+ // is it the head?
+ if (this->head_ == remove_me) // pointer comparison.
+ {
+ this->head_ = this->head_->next_;
+ if (this->head_ == 0)
+ this->tail_ = 0;
+
+ --this->size_;
+ return;
+ }
+
+ ACE_TPQ_Entry *temp = this->head_;
+ ACE_TPQ_Entry *previous = 0;
+
+ // is it in the middle or tail?
+ while (temp != 0)
+ {
+ if (temp == remove_me)
+ {
+ // previous should never be null since the first if
+ // conditional should always be false
+ previous->next_ = temp->next_;
+ // is it the tail?
+ if (this->tail_ == temp)
+ this->tail_ = previous;
+
+ --this->size_;
+ return;
+ }
+
+ previous = temp;
+ temp = temp->next_;
+ }
+
+ // it wasn't in the list.
+ return;
+}
+
+void
+ACE_Mutex_Token::dump (void) const
+{
+ ACE_TRACE ("ACE_Mutex_Token::dump");
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("ACE_Mutex_Token::dump:\n")));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("lock_\n")));
+ lock_.dump ();
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("base:\n")));
+ ACE_Tokens::dump ();
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("ACE_Mutex_Token::dump end.\n")));
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+ACE_Mutex_Token::ACE_Mutex_Token (const ACE_TCHAR *name)
+{
+ ACE_TRACE ("ACE_Mutex_Token::ACE_Mutex_Token");
+
+ ACE_OS::strsncpy (this->token_name_,
+ name,
+ ACE_MAXTOKENNAMELEN);
+}
+
+ACE_Mutex_Token::~ACE_Mutex_Token (void)
+{
+ ACE_TRACE ("ACE_Mutex_Token::~ACE_Mutex_Token");
+}
+
+int
+ACE_Mutex_Token::acquire (ACE_TPQ_Entry *caller,
+ int ignore_deadlock,
+ int notify)
+{
+ ACE_TRACE ("ACE_Mutex_Token::acquire");
+ // We need to acquire two locks. This one to ensure that only one
+ // thread uses this token at a time.
+ ACE_GUARD_RETURN (ACE_TOKEN_CONST::MUTEX, ace_mon1, this->lock_, -1);
+ // This one to ensure an atomic transaction across all tokens. Note
+ // that this order is crucial too. It's resource coloring for other
+ // threads which may be calling this same token.
+ ACE_GUARD_RETURN (ACE_TOKEN_CONST::MUTEX, ace_mon2, ACE_Token_Manager::instance ()->mutex (), -1);
+
+ // Does _anyone_ own the token?
+ if (this->owner () == 0)
+ {
+ // there are no waiters, so queue as the first waiter (the owner.)
+ this->waiters_.enqueue (caller, -1);
+ return 0; // success
+ }
+
+ // Does the caller already own it?
+ if (this->is_owner (caller->client_id ()))
+ {
+ // Recursive acquisition.
+ caller->nesting_level (1);
+ return 0; // success
+ }
+
+ // Check for deadlock.
+ if (!ignore_deadlock
+ && ACE_Token_Manager::instance ()->check_deadlock (caller->proxy ()) == 1)
+ {
+ errno = EDEADLK;
+ ACE_RETURN (-1);
+ }
+
+ // Someone owns it. Sorry, you're getting queued up at the end of
+ // the waiter queue.
+ this->waiters_.enqueue (caller, -1);
+
+ if (notify)
+ this->owner ()->call_sleep_hook ();
+
+ errno = EWOULDBLOCK;
+ ACE_RETURN (-1);
+
+ ACE_NOTREACHED (return -1);
+}
+
+int
+ACE_Mutex_Token::tryacquire (ACE_TPQ_Entry *caller)
+{
+ ACE_TRACE ("ACE_Mutex_Token::tryacquire");
+ // We need to acquire two locks. This one to ensure that only one
+ // thread uses this token at a time.
+ ACE_GUARD_RETURN (ACE_TOKEN_CONST::MUTEX, ace_mon1, this->lock_, -1);
+ // This one to ensure an atomic transaction across all tokens. Note
+ // that this order is crucial too. It's resource coloring for other
+ // threads which may be calling this same token.
+ ACE_GUARD_RETURN (ACE_TOKEN_CONST::MUTEX, ace_mon2, ACE_Token_Manager::instance ()->mutex (), -1);
+
+ // Does _anyone_ own the token?
+ if (this->owner () == 0)
+ {
+ this->waiters_.enqueue (caller, -1);
+ return 0; // success
+ }
+ // Does the caller already own it?
+ if (this->is_owner (caller->client_id ()))
+ {
+ // recursive acquisition
+ caller->nesting_level (1);
+ return 0; // success
+ }
+ else
+ // Someone owns it. Fail.
+ {
+ errno = EWOULDBLOCK;
+ ACE_RETURN (-1);
+ }
+
+ ACE_NOTREACHED (return -1);
+}
+
+int
+ACE_Mutex_Token::renew (ACE_TPQ_Entry *caller,
+ int requeue_position)
+{
+ ACE_TRACE ("ACE_Mutex_Token::renew");
+ ACE_GUARD_RETURN (ACE_TOKEN_CONST::MUTEX, ace_mon, this->lock_, -1);
+
+ // Verify that the caller is the owner.
+ if (this->is_owner (caller->client_id ()) == 0)
+ {
+ errno = EACCES;
+ ACE_RETURN (-1);
+ }
+
+ // The caller is the owner, so check to see if there are any
+ // waiters. If not, we just keep the token. == 1 means that there
+ // is only the owner.
+ if (this->waiters_.size () == 1 || requeue_position == 0)
+ return 0;
+
+ // Requeue the caller.
+ this->waiters_.dequeue ();
+
+ this->waiters_.enqueue (caller, requeue_position);
+
+ // Notify new owner.
+ if (this->owner () != 0)
+ this->owner ()->proxy ()->token_acquired (this->owner ());
+
+ // Tell the caller that the operation would block.
+ errno = EWOULDBLOCK;
+ ACE_RETURN (-1);
+
+ ACE_NOTREACHED (return -1);
+}
+
+// Release the current holder of the token (which had
+// better be the caller's thread!).
+
+int
+ACE_Mutex_Token::release (ACE_TPQ_Entry *caller)
+{
+ ACE_TRACE ("ACE_Mutex_Token::release");
+ ACE_GUARD_RETURN (ACE_TOKEN_CONST::MUTEX, ace_mon, this->lock_, -1);
+
+ // Does anyone own the token?
+ if (this->owner () == 0)
+ {
+ errno = EACCES;
+ ACE_RETURN (-1);
+ }
+
+ // Is the caller the owner.
+ if (this->is_owner (caller->client_id ()))
+ {
+ // Check the nesting level.
+ if (caller->nesting_level () > 0)
+ caller->nesting_level (-1);
+ else
+ {
+ this->waiters_.dequeue ();
+ // Notify new owner.
+ if (this->owner () != 0)
+ this->owner ()->proxy ()->token_acquired (this->owner ());
+ }
+ }
+ else
+ this->remove (caller);
+
+ return 0;
+}
+
+int
+ACE_Mutex_Token::owners (OWNER_STACK &stack,
+ const ACE_TCHAR *id)
+{
+ ACE_TRACE ("ACE_Mutex_Token::owners");
+ if (this->owner () != 0)
+ {
+ stack.push (this->owner ());
+ // If an <id> is specified, return whether it is the owner being
+ // returned.
+ if (id != 0)
+ return this->owner ()->equal_client_id (id);
+ }
+
+ return 0;
+}
+
+int
+ACE_Mutex_Token::is_waiting_for (const ACE_TCHAR *id)
+{
+ ACE_TRACE ("ACE_Mutex_Token::is_waiting_for");
+ // If there is no owner, or <id> is the owner, return false.
+ if ((this->owner () == 0) || this->is_owner (id))
+ return 0;
+
+ // Step through each waiter looking for <id>.
+ ACE_TPQ_Iterator iterator (waiters_);
+ iterator.advance ();
+ for (ACE_TPQ_Entry *temp = 0;
+ iterator.next (temp) != 0;
+ iterator.advance ())
+ {
+ if (temp->equal_client_id (id))
+ return 1;
+ }
+
+ return 0;
+}
+
+int
+ACE_Mutex_Token::is_owner (const ACE_TCHAR *id)
+{
+ ACE_TRACE ("ACE_Mutex_Token::is_owner");
+ // If there is an owner, return whether it is <id>.
+ if ((this->owner () != 0) &&
+ this->owner ()->equal_client_id (id))
+ return 1;
+ else
+ return 0;
+}
+
+void
+ACE_RW_Token::dump (void) const
+{
+ ACE_TRACE ("ACE_RW_Token::dump");
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("ACE_RW_Token::dump:\n")
+ ACE_LIB_TEXT ("num_writers_ = %d\n"), num_writers_));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("lock_\n")));
+ this->lock_.dump ();
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("base:\n")));
+ ACE_Tokens::dump ();
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("ACE_RW_Token::dump end.\n")));
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+ACE_RW_Token::ACE_RW_Token (const ACE_TCHAR *name)
+: num_writers_ (0)
+{
+ ACE_TRACE ("ACE_RW_Token::ACE_RW_Token");
+
+ ACE_OS::strsncpy (this->token_name_,
+ name,
+ ACE_MAXTOKENNAMELEN);
+}
+
+ACE_RW_Token::~ACE_RW_Token (void)
+{
+ ACE_TRACE ("ACE_RW_Token::~ACE_RW_Token");
+}
+
+int
+ACE_RW_Token::acquire (ACE_TPQ_Entry *caller,
+ int ignore_deadlock,
+ int notify)
+{
+ ACE_TRACE ("ACE_RW_Token::acquire");
+ // We need to acquire two locks. This one to ensure that only one
+ // thread uses this token at a time.
+ ACE_GUARD_RETURN (ACE_TOKEN_CONST::MUTEX, ace_mon1, this->lock_, -1);
+ // This one to ensure an atomic transaction across all tokens. Note
+ // that this order is crucial too. It's resource coloring for other
+ // threads which may be calling this same token.
+ ACE_GUARD_RETURN (ACE_TOKEN_CONST::MUTEX, ace_mon2, ACE_Token_Manager::instance ()->mutex (), -1);
+
+ if (caller->proxy ()->type () == ACE_RW_Token::WRITER)
+ this->num_writers_++;
+
+ // Does _anyone_ own the token?
+ if (this->owner () == 0)
+ {
+ // There are no waiters, so queue as the first waiter (the owner).
+ this->waiters_.enqueue (caller, -1);
+ return 0;
+ }
+
+ // Check for recursive acquisition.
+ if (this->is_owner (caller->client_id ()))
+ {
+ caller->nesting_level (1);
+ return 0; // Success.
+ }
+
+ // Reader.
+ if (caller->proxy ()->type () == ACE_RW_Token::READER)
+ {
+ // Are there any writers?
+ if (this->num_writers_ == 0)
+ {
+ // Queue the caller at the end of the queue.
+ this->waiters_.enqueue (caller, -1);
+ return 0;
+ }
+ // Else failure.
+ }
+
+ // Failure code.
+
+ // Check for deadlock.
+ if (!ignore_deadlock &&
+ ACE_Token_Manager::instance ()->check_deadlock (caller->proxy ()) == 1)
+ {
+ if (caller->proxy ()->type () == ACE_RW_Token::WRITER)
+ this->num_writers_--;
+ errno = EDEADLK;
+ ACE_RETURN (-1);
+ }
+
+ // Queue the caller at the end of the queue.
+ this->waiters_.enqueue (caller, -1);
+
+ if (notify)
+ {
+ // If it's a writer, just notify it.
+ if (this->owner ()->proxy ()->type () == ACE_RW_Token::WRITER)
+ this->owner ()->call_sleep_hook ();
+ else
+ {
+ // Call back all reader owners.
+ ACE_TPQ_Entry *temp = this->owner ();
+ do
+ {
+ temp->call_sleep_hook ();
+ temp = temp->next_;
+ }
+ while (temp != 0 &&
+ temp->proxy ()->type () == ACE_RW_Token::READER);
+ }
+ }
+
+ errno = EWOULDBLOCK;
+ ACE_RETURN (-1);
+
+ ACE_NOTREACHED (return -1);
+}
+
+int
+ACE_RW_Token::tryacquire (ACE_TPQ_Entry *caller)
+{
+ ACE_TRACE ("ACE_RW_Token::tryacquire");
+ // We need to acquire two locks. This one to ensure that only one
+ // thread uses this token at a time.
+ ACE_GUARD_RETURN (ACE_TOKEN_CONST::MUTEX, ace_mon1, this->lock_, -1);
+ // This one to ensure an atomic transaction across all tokens. Note
+ // that this order is crucial too. It's resource coloring for other
+ // threads which may be calling this same token.
+ ACE_GUARD_RETURN (ACE_TOKEN_CONST::MUTEX, ace_mon2, ACE_Token_Manager::instance ()->mutex (), -1);
+
+ if (caller->proxy ()->type () == ACE_RW_Token::WRITER)
+ {
+ this->num_writers_++;
+ }
+
+ // Does _anyone_ own the token?
+ if (this->owner () == 0)
+ {
+ // There are no waiters, so queue as the first waiter (the owner).
+ this->waiters_.enqueue (caller, -1);
+ return 0;
+ }
+
+ // Check for recursive acquisition.
+ if (this->is_owner (caller->client_id ()))
+ {
+ caller->nesting_level (1);
+ return 0; // Success.
+ }
+
+ // Reader.
+ if (caller->proxy ()->type () == ACE_RW_Token::READER)
+ {
+ // Are there any writers?
+ if (this->num_writers_ == 0)
+ {
+ // queue the caller at the end of the queue.
+ this->waiters_.enqueue (caller, -1);
+ return 0;
+ }
+ // Else, fail.
+ }
+ else // Writer.
+ // We're going to fail, so decrement the num_writers.
+ {
+ this->num_writers_--;
+ }
+
+
+ errno = EWOULDBLOCK;
+ ACE_RETURN (-1);
+
+ ACE_NOTREACHED (return -1);
+}
+
+int
+ACE_RW_Token::renew (ACE_TPQ_Entry *caller,
+ int requeue_position)
+{
+ ACE_TRACE ("ACE_RW_Token::renew");
+ ACE_GUARD_RETURN (ACE_TOKEN_CONST::MUTEX, ace_mon, this->lock_, -1);
+
+ // Werify that the caller is the owner
+ if (this->is_owner (caller->client_id ()) == 0)
+ {
+ errno = EACCES;
+ ACE_RETURN (-1);
+ }
+
+ // The caller is the owner, so check to see if there are any
+ // waiters. If not, we just keep the token.
+ if (this->waiters_.size () == 1 || requeue_position == 0)
+ return 0;
+
+ // There are waiters, so remove the caller.
+ this->remove (caller);
+
+ // Requeue the caller.
+ this->waiters_.enqueue (caller, requeue_position);
+
+ if (caller->proxy ()->type () == ACE_RW_Token::READER)
+ {
+ // If the caller got queued before any writers, the caller is
+ // still the owner.
+ if (this->is_owner (caller->client_id ()))
+ return 0; // success
+ // else fallthrough and return would block.
+ }
+ // Writers will always have to block since waiters_.size () == 1 or
+ // requeue_position == 0.
+
+ // Get a new owner.
+ this->notify_new_owner (caller);
+
+ // Tell the caller that the operation would block.
+ errno = EWOULDBLOCK;
+ ACE_RETURN (-1);
+
+ ACE_NOTREACHED (return -1);
+}
+
+int
+ACE_RW_Token::release (ACE_TPQ_Entry *caller)
+{
+ ACE_TRACE ("ACE_RW_Token::release");
+ ACE_GUARD_RETURN (ACE_TOKEN_CONST::MUTEX, ace_mon, this->lock_, -1);
+
+ // Check for errors.
+ if ((this->owner () == 0) ||
+ (this->is_owner (caller->client_id ()) == 0))
+ {
+ errno = EACCES;
+ ACE_RETURN (-1);
+ }
+
+ if (caller->proxy ()->type () == ACE_RW_Token::WRITER)
+ num_writers_--;
+
+ // Recursive release.
+ if (caller->nesting_level () > 0)
+ {
+ caller->nesting_level (-1);
+ return 0;
+ }
+
+ // Remove the caller and notify the new owner(s).
+ this->remove (caller);
+ this->notify_new_owner (caller);
+
+ return 0;
+}
+
+void
+ACE_RW_Token::notify_new_owner (ACE_TPQ_Entry *old_owner)
+{
+ ACE_TRACE ("ACE_RW_Token::notify_new_owner");
+
+ if (this->owner () == 0)
+ return;
+
+ if (this->owner ()->proxy ()->type () == ACE_RW_Token::READER)
+ {
+ if (old_owner->proxy ()->type () == ACE_RW_Token::READER)
+ // the owners already know that they're owners
+ return;
+
+ // The current owner is a reader and the previous owner was a
+ // writer, so notify all waiting readers up to the first writer.
+ // call back all reader owners.
+ ACE_TPQ_Iterator iterator (waiters_);
+ for (ACE_TPQ_Entry *temp = 0;
+ iterator.next (temp) != 0;
+ iterator.advance ())
+ {
+ if (temp->proxy ()->type () == WRITER)
+ // We've gone through all the readers.
+ break;
+
+ temp->proxy ()->token_acquired (temp);
+ }
+ }
+ else // writer
+ this->owner ()->proxy ()->token_acquired (this->owner ());
+}
+
+
+int
+ACE_RW_Token::owners (OWNER_STACK &stack,
+ const ACE_TCHAR *id)
+{
+ ACE_TRACE ("ACE_RW_Token::owners");
+
+ if (this->owner () == 0)
+ return 0;
+
+ int id_is_owner = 0;
+
+ // The first waiter is a writer, so there is only one owner.
+ if (this->owner ()->proxy ()->type () == WRITER)
+ {
+ stack.push (this->owner ());
+ // If an <id> is specified, return whether it is the owner being
+ // returned.
+ if ((id != 0) &&
+ (ACE_OS::strcmp (id, this->owner ()->client_id ()) == 0))
+ id_is_owner = 1;
+ }
+ // The first waiter is a reader, so there can be multiple owning
+ // readers.
+ else
+ {
+ ACE_TPQ_Iterator iterator (waiters_);
+ for (ACE_TPQ_Entry *temp = 0;
+ iterator.next (temp) != 0;
+ iterator.advance ())
+ {
+ if (temp->proxy ()->type () == WRITER)
+ // We've gone through all the readers.
+ break;
+
+ stack.push (temp);
+
+ if (!id_is_owner && (id != 0) &&
+ (ACE_OS::strcmp (id, temp->client_id ()) == 0))
+ id_is_owner = 1;
+ }
+ }
+
+ return id_is_owner;
+}
+
+int
+ACE_RW_Token::is_waiting_for (const ACE_TCHAR *id)
+{
+ ACE_TRACE ("ACE_RW_Token::is_waiting_for");
+ // If there is no owner, or <id> is the owner, return false.
+ if ((this->owner () == 0) ||
+ this->is_owner (id))
+ return 0;
+
+ // Step through each waiter looking for <id>.
+ ACE_TPQ_Iterator iterator (waiters_);
+ iterator.advance ();
+ for (ACE_TPQ_Entry *temp = 0;
+ iterator.next (temp) != 0;
+ iterator.advance ())
+ {
+ if (temp->equal_client_id (id))
+ return 1;
+ }
+
+ return 0;
+}
+
+int
+ACE_RW_Token::is_owner (const ACE_TCHAR *id)
+{
+ ACE_TRACE ("ACE_RW_Token::is_owner");
+ // If there is no owner, return false.
+ if (this->owner () == 0)
+ return 0;
+
+ // A writer owns us.
+ if (this->owner ()->proxy ()->type () == ACE_RW_Token::WRITER)
+ return this->owner ()->equal_client_id (id);
+
+ // Readers own us.
+ // Step through each owning reader looking for <id>.
+ ACE_TPQ_Iterator iterator (waiters_);
+ for (ACE_TPQ_Entry *temp = 0;
+ iterator.next (temp) != 0;
+ iterator.advance ())
+ {
+ if (temp->proxy ()->type () != ACE_RW_Token::READER)
+ break;
+
+ if (temp->equal_client_id (id))
+ return 1;
+ }
+
+ return 0;
+}
+
+void
+ACE_Token_Proxy::dump (void) const
+{
+ ACE_TRACE ("ACE_Token_Proxy::dump");
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("ACE_Token_Proxy::dump:\n")
+ ACE_LIB_TEXT (" type = %d\n")
+ ACE_LIB_TEXT (" ignore_deadlock_ = %d\n")
+ ACE_LIB_TEXT (" debug_ = %d\n"),
+ (int) this->type (), ignore_deadlock_, debug_));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("mutex_, and waiter_\n")));
+
+ if (this->token_ != 0)
+ this->token_->dump ();
+
+ this->waiter_.dump ();
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("ACE_Token_Proxy::dump end.\n")));
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+const ACE_TCHAR *
+ACE_Token_Proxy::client_id (void) const
+{
+ ACE_TRACE ("ACE_Token_Proxy::client_id");
+ // Thread-specific.
+ ACE_Token_Proxy *nc_this =
+ ACE_const_cast (ACE_Token_Proxy *, this);
+ const ACE_TPQ_Entry *temp =
+ nc_this->waiter_.operator->();
+ const ACE_TCHAR *id = temp->client_id ();
+
+ if (id == 0)
+ return ACE_LIB_TEXT ("ERROR NO CLIENT ID");
+ else
+ return id;
+}
+
+void
+ACE_Token_Proxy::client_id (const ACE_TCHAR *client_id)
+{
+ ACE_TRACE ("ACE_Token_Proxy::client_id");
+ this->waiter_->client_id (client_id);
+}
+
+const ACE_TCHAR *
+ACE_Token_Proxy::owner_id (void)
+{
+ ACE_TRACE ("ACE_Token_Proxy::owner_id");
+ return this->token_->owner_id ();
+}
+
+const ACE_TCHAR *
+ACE_Token_Proxy::name (void) const
+{
+ ACE_TRACE ("ACE_Token_Proxy::name");
+ return this->token_->name ();
+}
+
+ACE_Token_Proxy::ACE_Token_Proxy (void)
+: token_ (0),
+ waiter_ (this, 0)
+{
+ ACE_TRACE ("ACE_Token_Proxy::ACE_Token_Proxy");
+}
+
+// Notice the token_ (0). Do *not* copy the token pointer. This must
+// be obtained through the token manager. Also, we don't copy any
+// waiter info. A copied Proxy does *not* inherit client_id.
+
+ACE_Token_Proxy::ACE_Token_Proxy (const ACE_Token_Proxy &)
+ : token_ (0),
+ waiter_ (this, 0)
+{
+ ACE_TRACE ("ACE_Token_Proxy::ACE_Token_Proxy");
+}
+
+// @@ should I do a mutex_->release ()?
+ACE_Token_Proxy::~ACE_Token_Proxy (void)
+{
+ ACE_TRACE ("ACE_Token_Proxy::~ACE_Token_Proxy");
+
+ if (token_ != 0)
+ // notify token manager that we are done with it so it can
+ // free it if necessary
+ ACE_Token_Manager::instance ()->release_token (token_);
+}
+
+int
+ACE_Token_Proxy::open (const ACE_TCHAR *token_name,
+ int ignore_deadlock,
+ int debug)
+{
+ ACE_TRACE ("ACE_Token_Proxy::open");
+
+ // Store some parameters.
+ this->ignore_deadlock_ = ignore_deadlock;
+ this->debug_ = debug;
+
+ // Used in case a name was not specified.
+ ACE_TCHAR name[BUFSIZ];
+
+ // We must have a name.
+ if (token_name == 0)
+ {
+ ACE_OS::sprintf (name, ACE_LIB_TEXT ("token %lx"),
+ ACE_reinterpret_cast (long, this));
+ token_name = name;
+ }
+
+ // Get or create the underlying token. The Token Manager will call
+ // us back to set token_.
+ ACE_Token_Manager::instance ()->get_token (this, token_name);
+
+ // Check for failed get or failed new.
+ if (this->token_ == 0)
+ {
+ errno = ENOMEM;
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_LIB_TEXT ("Can't allocate mutex")), -1);
+ }
+
+ return 0;
+}
+
+int
+ACE_Token_Proxy::acquire (int notify,
+ void (*sleep_hook)(void *),
+ ACE_Synch_Options &options)
+{
+ ACE_TRACE ("ACE_Token_Proxy::acquire");
+ if (this->token_ == 0)
+ {
+ errno = ENOENT;
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_LIB_TEXT ("Not open.\n")), -1);
+ }
+
+ // Make sure no one calls our token_acquired until we have a chance
+ // to sleep first! If after we call an EWOULDBLOCK
+ // mutex_->acquire() below, but before we enter handle_options to
+ // wait on the cond_var, a thread tries to give take us off the
+ // waiter queue and signal us, IT WILL FIRST HAVE TO ACQUIRE THIS
+ // cond_var.mutex (). _This_ is why we acquire it.
+ this->waiter_->cond_var_.mutex ().acquire ();
+
+ this->waiter_->sleep_hook (sleep_hook);
+
+ if (this->token_->acquire (this->waiter_, this->ignore_deadlock_, notify) == -1)
+ // acquire failed
+ {
+ switch (errno)
+ {
+ case EDEADLK :
+ if (!ignore_deadlock_)
+ {
+ waiter_->cond_var_.mutex ().release ();
+ errno = EDEADLK;
+ ACE_RETURN (-1);
+ }
+ // Else, fallthrough and block!
+
+ case EWOULDBLOCK :
+ if (this->debug_)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_LIB_TEXT ("(%t) waiting for %s, owner is %s, ")
+ ACE_LIB_TEXT ("total waiters == %d\n"),
+ this->name (),
+ this->token_->owner_id (),
+ token_->no_of_waiters ()));
+
+ // no error, but would block, if error, return error (-1),
+ // otherwise, return whether we called the holder or not.
+ int return_value;
+ if (this->handle_options (options,
+ waiter_->cond_var_) == -1)
+ return_value = -1;
+ else
+ return_value = notify == 1;
+
+ errno = EWOULDBLOCK;
+ ACE_RETURN (return_value);
+
+ default :
+ waiter_->cond_var_.mutex ().release ();
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_LIB_TEXT ("%p\n"),
+ ACE_LIB_TEXT ("Token Proxy acquire.")),
+ -1);
+ }
+ }
+ else
+ // we have the token
+ {
+ if (debug_)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_LIB_TEXT ("(%t) acquired %s\n"),
+ this->name ()));
+ waiter_->cond_var_.mutex ().release ();
+ }
+
+ return 0;
+}
+
+int
+ACE_Token_Proxy::tryacquire (void (*sleep_hook)(void *))
+{
+ ACE_TRACE ("ACE_Token_Proxy::tryacquire");
+ if (this->token_ == 0)
+ {
+ errno = ENOENT;
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_LIB_TEXT ("Not open.\n")),
+ -1);
+ }
+
+ this->waiter_->sleep_hook (sleep_hook);
+
+ return this->token_->tryacquire (waiter_);
+}
+
+int
+ACE_Token_Proxy::renew (int requeue_position,
+ ACE_Synch_Options &options)
+{
+ ACE_TRACE ("ACE_Token_Proxy::renew");
+ if (this->token_ == 0)
+ {
+ errno = ENOENT;
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_LIB_TEXT ("Not open.\n")),
+ -1);
+ }
+
+ // Make sure no one calls our token_acquired until we have a chance
+ // to sleep first!
+ this->waiter_->cond_var_.mutex ().acquire ();
+
+ if (this->token_->renew (this->waiter_, requeue_position) == -1)
+ {
+ // check for error
+ if (errno != EWOULDBLOCK)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_LIB_TEXT ("%p renew failed\n"), ACE_LIB_TEXT ("ACE_Token_Proxy")), -1);
+
+ if (this->debug_)
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("(%t) renew blocking for %s, owner is %s\n"),
+ this->name (),
+ token_->owner_id ()));
+
+ // no error, but would block, so block or return
+ return this->handle_options (options, waiter_->cond_var_);
+ }
+ else
+ // we have the token
+ {
+ if (this->debug_)
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("(%t) renewed %s\n"),
+ this->name ()));
+ waiter_->cond_var_.mutex ().release ();
+ return 0;
+ }
+}
+
+int
+ACE_Token_Proxy::handle_options (ACE_Synch_Options &options,
+ ACE_TOKEN_CONST::COND_VAR &cv)
+{
+ // Some operation failed with EWOULDBLOCK.
+ ACE_TRACE ("ACE_Token_Proxy::handle_options");
+
+ if (options[ACE_Synch_Options::USE_REACTOR] == 1)
+ // Asynchronous.
+ {
+ // Save/restore errno.
+ ACE_Errno_Guard error (errno);
+ cv.mutex ().release ();
+ ACE_RETURN (-1);
+ }
+ else
+ // Synchronous.
+ {
+ // Block on condition variable.
+ while (cv.wait ((ACE_Time_Value *) options.time_value ()) == -1)
+ {
+ // Note, this should obey whatever thread-specific
+ // interrupt policy is currently in place...
+ if (errno == EINTR)
+ continue;
+ // We come here if a timeout occurs or some serious
+ // ACE_Condition object error.
+ cv.mutex ().release ();
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_LIB_TEXT ("condition variable wait")
+ ACE_LIB_TEXT (" bombed.")), -1);
+ }
+
+ if (this->debug_)
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("(%t) unblocking.\n"),
+ this->client_id ()));
+ cv.mutex ().release ();
+ return 0; // operation succeeded
+ }
+}
+
+int
+ACE_Token_Proxy::release (ACE_Synch_Options &)
+{
+ ACE_TRACE ("ACE_Token_Proxy::release");
+
+ if (this->token_ == 0)
+ {
+ errno = ENOENT;
+ if (debug_)
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("Must open before releasing.\n")));
+ ACE_RETURN (-1);
+ }
+
+ if (this->token_->release (waiter_) != 0)
+ {
+ // Release failed.
+ this->token_->remove (this->waiter_);
+ if (debug_)
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("(%t) %p.\n"), ACE_LIB_TEXT ("release failed")));
+ return -1;
+ }
+ else
+ {
+ if (this->debug_)
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("(%t) released %s, owner is %s\n"),
+ this->name (),
+ token_->owner_id ()));
+
+ return 0;
+ }
+}
+
+int
+ACE_Token_Proxy::remove (ACE_Synch_Options &)
+{
+ ACE_TRACE ("ACE_Token_Proxy::remove");
+ return 0;
+}
+
+void
+ACE_Token_Proxy::sleep_hook (void)
+{
+ ACE_TRACE ("ACE_Token_Proxy::sleep_hook");
+ // Somebody wants our token! (Let'em wait...)
+ return;
+}
+
+void
+ACE_Token_Proxy::token_acquired (ACE_TPQ_Entry *e)
+{
+ ACE_TRACE ("ACE_Token_Proxy::token_acquired");
+ e->cond_var_.mutex ().acquire ();
+ // We've been taken off the waiters list and given the token!
+ // This implementation signals the internal condition
+ // variable. Thus, if asynchronous acquires are used, this must be
+ // overriden to do something more useful!
+ e->cond_var_.signal ();
+ e->cond_var_.mutex ().release ();
+
+ return;
+}
+
+ACE_Token_Name::ACE_Token_Name (const ACE_TCHAR *token_name)
+{
+ ACE_TRACE ("ACE_Token_Name::ACE_Token_Name");
+ this->name (token_name);
+}
+
+ACE_Token_Name::ACE_Token_Name (const ACE_Token_Name &rhs)
+{
+ ACE_TRACE ("ACE_Token_Name::ACE_Token_Name");
+ this->name (rhs.name ());
+}
+
+ACE_Token_Name::~ACE_Token_Name ()
+{
+ ACE_TRACE ("ACE_Token_Name::~ACE_Token_Name");
+}
+
+void
+ACE_Token_Name::dump (void) const
+{
+ ACE_TRACE ("ACE_Token_Name::dump");
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+#if defined (ACE_HAS_BROKEN_CONDITIONAL_STRING_CASTS)
+ ACE_DEBUG ((LM_DEBUG, (char *) "ACE_Token_Name::dump:\n",
+ (char *) " token_name_ = %s\n",
+ (char *) token_name_ == 0 ? (char *) "no name" : (char *) token_name_));
+#else /* ! defined (ACE_HAS_BROKEN_CONDITIONAL_STRING_CASTS) */
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("ACE_Token_Name::dump:\n")
+ ACE_LIB_TEXT (" token_name_ = %s\n"),
+ token_name_ == 0 ? ACE_LIB_TEXT ("no name") : token_name_));
+#endif /* ! defined (ACE_HAS_BROKEN_CONDITIONAL_STRING_CASTS) */
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+
+#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION)
+#if !defined (ACE_NO_TSS_TOKENS)
+template class ACE_TSS <ACE_TPQ_Entry>;
+#endif /* ACE_NO_TSS_TOKENS */
+template class ACE_Unbounded_Stack <ACE_TPQ_Entry *>;
+template class ACE_Node <ACE_TPQ_Entry *>;
+#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA)
+#if !defined (ACE_NO_TSS_TOKENS)
+#pragma instantiate ACE_TSS <ACE_TPQ_Entry>
+#endif /* ACE_NO_TSS_TOKENS */
+#pragma instantiate ACE_Unbounded_Stack <ACE_TPQ_Entry *>
+#pragma instantiate ACE_Node <ACE_TPQ_Entry *>
+#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */
+
+#endif /* ACE_HAS_TOKENS_LIBRARY */
diff --git a/ace/Token/Local_Tokens.h b/ace/Token/Local_Tokens.h
new file mode 100644
index 00000000000..6660d8b2028
--- /dev/null
+++ b/ace/Token/Local_Tokens.h
@@ -0,0 +1,1098 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Local_Tokens.h
+ *
+ * $Id$
+ *
+ * @author Karl-Heinz Dorn <kdorn@erlh.siemens.de>
+ * @author Douglas C. Schmidt <schmidt@cs.wustl.edu>
+ * @author and Tim Harrison <harrison@cs.wustl.edu>
+ *
+ * This file contains definitions for the following classes:
+ *
+ * public:
+ * 7. ACE_Token_Proxy
+ * 8. ACE_Null_Token : public ACE_Token_Proxy
+ * 9. ACE_Local_Mutex : public ACE_Token_Proxy
+ * *. ACE_Local_RLock : public ACE_Local_Mutex
+ * &. ACE_Local_WLock : public ACE_Local_Mutex
+ * private:
+ * 1. ACE_TOKEN_CONST
+ * 3. ACE_TPQ_Entry
+ * b. ACE_TSS_TPQ_Entry
+ * c. ACE_TPQ_Iterator
+ * 4. ACE_Token_Proxy_Queue
+ * 5. ACE_Tokens
+ * 6. ACE_Mutex_Token : public ACE_Tokens
+ * 12. ACE_RW_Token : public ACE_Tokens
+ * a. ACE_Token_Name
+ *
+ * Note that the locking classes defined in this file are *not*
+ * intended to be used as general-purpose synchronization
+ * mechanisms, such as mutexes or semaphores. Instead, you should
+ * use the <ACE_Recursive_Thread_Mutex>, <ACE_Thread_Mutex>,
+ * <ACE_Thread_Semaphore>, etc., that are defined in
+ * $ACE_ROOT/ace/Synch.h and $ACE_ROOT/ace/Synch_T.h or the
+ * <ACE_Token> that's defined in $ACE_ROOT/ace/Token.h.
+ *
+ *
+ */
+//=============================================================================
+
+#ifndef ACE_LOCAL_MUTEX_H
+#define ACE_LOCAL_MUTEX_H
+#include "ace/pre.h"
+
+#include "ace/Synch_T.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "ace/Containers.h"
+#include "ace/Synch_Options.h"
+#include "ace/Map_Manager.h"
+#include "ace/Log_Msg.h"
+
+#if defined (ACE_HAS_TOKENS_LIBRARY)
+
+#if !(defined (ACE_HAS_THREADS) && defined (ACE_HAS_THREAD_SPECIFIC_STORAGE))
+# define ACE_NO_TSS_TOKENS 1
+#endif /* !(defined (ACE_HAS_THREADS) && defined (ACE_HAS_THREAD_SPECIFIC_STORAGE)) */
+
+// 1.
+/**
+ * @class ACE_TOKEN_CONST
+ *
+ * @brief Not a public interface.
+ *
+ * Constant definitions and typdefs for Token library. Mostly,
+ * this class is necessary to fight the compiler with order of
+ * declaration errors.
+ */
+class ACE_Export ACE_TOKEN_CONST
+{
+public:
+#if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0)
+ // ACE platform supports some form of threading.
+ typedef ACE_Condition_Thread_Mutex COND_VAR;
+ typedef ACE_Thread_Mutex MUTEX;
+ typedef ACE_Guard<ACE_Thread_Mutex> GUARD;
+#else
+ typedef ACE_Null_Condition COND_VAR;
+ typedef ACE_Null_Mutex MUTEX;
+ typedef ACE_Guard<ACE_Null_Mutex> GUARD;
+#endif /* ACE_HAS_THREADS */
+};
+
+// Forward decl.
+class ACE_Token_Proxy;
+
+// 3..
+/**
+ * @class ACE_TPQ_Entry
+ *
+ * @brief Token Proxy Queue entry. Used in the ACE_Token_Proxy_Queue
+ *
+ * Not a public interface.
+ */
+class ACE_Export ACE_TPQ_Entry
+{
+friend class ACE_Token_Manager;
+public:
+ typedef void (*PTVF) (void *);
+
+ /// Null constructor.
+ ACE_TPQ_Entry (void);
+
+ /// Construction.
+ ACE_TPQ_Entry (const ACE_Token_Proxy *proxy,
+ const ACE_TCHAR *client_id);
+
+ /// Copy constructor.
+ ACE_TPQ_Entry (const ACE_TPQ_Entry &rhs);
+
+ /// Death.
+ ~ACE_TPQ_Entry (void);
+
+ /// Copy operator use by the queue.
+ void operator= (const ACE_TPQ_Entry &rhs);
+
+ // = Set/get top of the queue.
+ ACE_Token_Proxy *proxy (void) const;
+ void proxy (ACE_Token_Proxy *);
+
+ // = Delta/get nesting level of the entry.
+ int nesting_level (void) const;
+ void nesting_level (int delta);
+
+ // = Set/get client_id of the entry.
+ const ACE_TCHAR *client_id (void) const;
+ void client_id (const ACE_TCHAR *);
+
+ /// Returns 1 if <id> == client id. Does not check for <id> == 0.
+ int equal_client_id (const ACE_TCHAR *id);
+
+ /// One method for arg and sleep_hook.
+ void set (void (*sleep_hook)(void *));
+
+ // = Set/get sleep hook of the entry.
+ void sleep_hook (void (*sh)(void *));
+ PTVF sleep_hook (void) const;
+
+ /// Call the sleep hook function or method passing arg.
+ void call_sleep_hook (void);
+
+ /// Dump the state of the class.
+ void dump (void) const;
+
+ // = Used to block the thread if an acquire fails with EWOULDBLOCK.
+ ACE_TOKEN_CONST::COND_VAR cond_var_;
+ ACE_TOKEN_CONST::MUTEX lock_;
+
+ /// Pointer to next in list.
+ ACE_TPQ_Entry *next_;
+
+ // = Get/set whether this client is blocked waiting for a token.
+ int waiting (void) const;
+ void waiting (int w);
+
+private:
+ /// This client is waiting for a token.
+ int waiting_;
+
+ /// Proxy.
+ ACE_Token_Proxy *proxy_;
+
+ /// Nesting level.
+ int nesting_level_;
+
+ /// Arg.
+ void *arg_;
+
+ /// Client id.
+ ACE_TCHAR client_id_[ACE_MAXCLIENTIDLEN];
+
+ /// Sleep hook.
+ void (*sleep_hook_)(void *);
+};
+
+// b..
+#if defined (ACE_NO_TSS_TOKENS)
+typedef ACE_TPQ_Entry ACE_TPQ_ENTRY;
+#else
+typedef ACE_TSS<ACE_TPQ_Entry> ACE_TPQ_ENTRY;
+#endif /* ACE_NO_TSS_TOKENS */
+
+/**
+ * @class ACE_TSS_TPQ_Entry
+ *
+ * @brief ACE_TSS_TPQ_Entry
+ *
+ * Not a public interface.
+ */
+class ACE_Export ACE_TSS_TPQ_Entry : public ACE_TPQ_ENTRY
+{
+public:
+ /// These are passed to the constructor of ACE_TPQ_Entry in
+ /// make_TSS_TYPE
+ ACE_TSS_TPQ_Entry (const ACE_Token_Proxy *proxy,
+ const ACE_TCHAR *client_id);
+
+ /// Destructor.
+ virtual ~ACE_TSS_TPQ_Entry (void);
+
+ /// Allows us to pass args to the construction of the TSS object.
+ virtual ACE_TPQ_Entry *make_TSS_TYPE (void) const;
+
+ /// Operator overloading and inheritence don't mix.
+ operator ACE_TPQ_Entry *(void);
+
+ /// Dump the state of the class.
+ void dump (void) const;
+
+#if defined (ACE_NO_TSS_TOKENS)
+ ACE_TPQ_Entry *operator-> (void)
+ {
+ return (ACE_TPQ_Entry *) this;
+ }
+#endif /* ACE_NO_TSS_TOKENS */
+
+private:
+ /// Private: should not be used
+ ACE_TSS_TPQ_Entry (const ACE_TSS_TPQ_Entry &);
+ void operator= (const ACE_TSS_TPQ_Entry &);
+
+ // = These are passed to the constructor of ACE_TPQ_Entry in
+ // make_TSS_TYPE
+ /// Proxy.
+ /// Client_id.
+ const ACE_Token_Proxy *proxy_;
+ const ACE_TCHAR *client_id_;
+};
+
+class ACE_Token_Proxy_Queue;
+
+// c..
+/**
+ * @class ACE_TPQ_Iterator
+ *
+ * @brief Iterates through ACE_Token_Proxy_Queues.
+ *
+ * Not a public interface.
+ */
+class ACE_Export ACE_TPQ_Iterator
+{
+public:
+ /// Construction.
+ ACE_TPQ_Iterator (ACE_Token_Proxy_Queue &q);
+
+ /// Destructor.
+ ~ACE_TPQ_Iterator (void);
+
+ /// Pass back the <next_item>.
+ int next (ACE_TPQ_Entry *&next_item);
+
+ /// Returns 1 when all items have been seen, else 0.
+ int done (void) const;
+
+ /// Move forward by one element in the queue.
+ void advance (void);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+private:
+ ACE_TPQ_Entry *current_;
+};
+
+// 4..
+/**
+ * @class ACE_Token_Proxy_Queue
+ *
+ * @brief Token waiter list.
+ *
+ * Not a public interface.
+ * This queue holds all the token proxies waiting for ownership
+ * of a token. Along with the proxy reference, it also stores
+ * the nesting level, client id, and a magic cookie from the
+ * proxy. This queue stores the ACE_TPQ_Entries by pointer
+ * values. It DOES NOT make copies. Thus, the user is
+ * responsible to ensure that the TPQ's stick around. This is
+ * motivated by the need to reduce dynamic memory allocation.
+ */
+class ACE_Export ACE_Token_Proxy_Queue
+{
+public:
+ friend class ACE_TPQ_Iterator;
+
+ /// Construction.
+ ACE_Token_Proxy_Queue (void);
+
+ /// Destructor
+ ~ACE_Token_Proxy_Queue (void);
+
+ /**
+ * Enqueue a proxy, nesting level, client_id, and a magic cookie at
+ * the given position in the list. If the position is -1, we
+ * enqueue at the end of the list (I think).
+ */
+ void enqueue (ACE_TPQ_Entry* new_entry,
+ int position);
+
+ /// Top of the queue.
+ const ACE_TPQ_Entry* head (void);
+
+// int member (const ACE_TCHAR *id);
+ // Is this id in the waiter list?
+
+ /// Remove the top waiter.
+ void dequeue (void);
+
+ /// Remove the waiter whose proxy ref matches remove_me.
+ void remove (const ACE_TPQ_Entry *remove_me);
+
+ /// The number of waiters.
+ int size (void);
+
+ /// Dump the state of the class.
+ void dump (void) const;
+
+protected:
+ /**
+ * Head.
+ * Tail.
+ * Size.
+ */
+ ACE_TPQ_Entry *head_;
+ ACE_TPQ_Entry *tail_;
+ int size_;
+};
+
+// 5..
+/**
+ * @class ACE_Tokens
+ *
+ * @brief Abstract representation of ACE tokens.
+ *
+ * Not a public interface.
+ * Currently, I don't see a reason for providing an abstract
+ * interface at this level of the library. As of yet, no one
+ * uses <ACE_Tokens< derivatives through this abstract interface
+ * except for <ACE_Token_Manager>. It only uses the statistical
+ * methods which are shared by all Tokens. For that reason, it
+ * still makes since to have a common base class. However,
+ * acquire, renew, and release do not need to have matching
+ * interfaces throughout all Tokens.
+ * To add a new type of token (e.g. semaphore), this class must
+ * be subtyped to define the new semantics. See
+ * <ACE_Token_Manager> for details.
+ */
+class ACE_Export ACE_Tokens
+{
+public:
+
+ /// Null constructor.
+ ACE_Tokens (void);
+
+ /// Destructor
+ virtual ~ACE_Tokens (void);
+
+ /// No implementation.
+ virtual int acquire (ACE_TPQ_Entry *caller,
+ int ignore_deadlock,
+ int notify) = 0;
+
+ /// No implementation.
+ virtual int tryacquire (ACE_TPQ_Entry *caller) = 0;
+
+ /// No implementation.
+ virtual int renew (ACE_TPQ_Entry *caller,
+ int requeue_position) = 0;
+
+ /// No implementation.
+ virtual int release (ACE_TPQ_Entry *caller) = 0;
+
+ /// Move the caller to the front of the waiter list. This is for use
+ /// with remote mutexes and shadow mutexes.
+ void make_owner (ACE_TPQ_Entry *caller);
+
+ /// Remove the caller from the waiter list.
+ void remove (ACE_TPQ_Entry *caller);
+
+ // = Accessor methods.
+
+ /// Stack of owners.
+ typedef ACE_Unbounded_Stack<ACE_TPQ_Entry *> OWNER_STACK;
+
+ /// Returns a stack of the current owners. Returns -1 on error, 0 on
+ /// success. If <id> is non-zero, returns 1 if id is an owner.
+ virtual int owners (OWNER_STACK &o, const ACE_TCHAR *id) = 0;
+
+ /// Returns 1 if <id> is waiting for this token. 0 otherwise.
+ virtual int is_waiting_for (const ACE_TCHAR *id) = 0;
+
+ /// Returns 1 if <id> is an owner of this token. 0 otherwise.
+ virtual int is_owner (const ACE_TCHAR *id) = 0;
+
+ /// Return the queue of waiters.
+ virtual ACE_Token_Proxy_Queue *waiters (void);
+
+ /// Return the number of proxies that are currently waiting to get
+ /// the token.
+ virtual int no_of_waiters (void);
+
+ /// The current owner.
+ const ACE_TCHAR *owner_id (void);
+
+ /// Token name.
+ const ACE_TCHAR* name (void);
+
+ // = Reference counting. These are only called by the
+ // Token_Manager.
+ void inc_reference (void);
+ int dec_reference (void);
+
+ /// Dump the state of the class.
+ void dump (void) const;
+
+ /**
+ * These are the Token types supported by the library at ship time.
+ * There is no restriction on the number of Token types added by
+ * "3rd parties." These are only necessary for the Token Server.
+ */
+ enum TOKEN_TYPES { MUTEX, RWLOCK };
+
+ /**
+ * Provides a manual RTTI mechanism. This method is used only by
+ * ACE_Token_Request so that the type of a token can be sent to a
+ * remote Token Server.
+ */
+ virtual int type (void) const = 0;
+
+ // = The following methods allow the deadlock detection algorithm to
+ // check if this token has been visited.
+
+ /// Mark or unmark the token as visited.
+ void visit (int v);
+
+ /// Check if the token has been visited.
+ int visited (void);
+
+ /// All the data of the current owner.
+ ACE_TPQ_Entry *owner (void);
+
+protected:
+
+ /// For the deadlock detection algorithm.
+ int visited_;
+
+ /// Reference count.
+ int reference_count_;
+
+ /// List of client's owning and waiting the token.
+ ACE_Token_Proxy_Queue waiters_;
+
+ /// Name of token.
+ ACE_TCHAR token_name_[ACE_MAXTOKENNAMELEN];
+};
+
+class ACE_Local_Mutex;
+
+// 6..
+/**
+ * @class ACE_Mutex_Token
+ *
+ * @brief Class that acquires, renews, and releases a process-local
+ * synchronization token.
+ *
+ * Not a public interface.
+ * This class is a more general-purpose synchronization mechanism
+ * than SunOS 5.x mutexes. For example, it implements "recursive
+ * mutex" semantics, where a thread that owns the token can
+ * reacquire it without deadlocking. In addition, threads that
+ * are blocked awaiting the token are serviced in strict FIFO
+ * order as other threads release the token (SunOS 5.x mutexes
+ * don't strictly enforce an acquisition order).
+ */
+class ACE_Export ACE_Mutex_Token : public ACE_Tokens
+{
+public:
+ /// life
+ ACE_EXPLICIT ACE_Mutex_Token (const ACE_TCHAR* name);
+
+ /// death
+ virtual ~ACE_Mutex_Token (void);
+
+ // = Synchronization operations.
+ // With acquire, renew, and release, the caller must be specified so
+ // that multiple proxies (e.g. ACE_Local_Mutex) can use the same
+ // token.
+
+ /**
+ * Returns 0 on success, -1 on failure with <ACE_Log_Msg::errnum> as
+ * the reason. If errnum == EWOULDBLOCK, and notify == 1,
+ * <ACE_Token_Proxy::sleep_hook> has been called on the current
+ * owner of the token. If ignore_deadlock is passed as 1 and errnum
+ * == EDEADLK, then deadlock was detected via ace_token_manager.
+ */
+ virtual int acquire (ACE_TPQ_Entry *caller,
+ int ignore_deadlock,
+ int notify);
+
+ /// same as acquire, but fails if would block
+ virtual int tryacquire (ACE_TPQ_Entry *caller);
+
+ /**
+ * An optimized method that efficiently reacquires the token if no
+ * other threads are waiting. This is useful for situations where
+ * you don't want to degrade the quality of service if there are
+ * other threads waiting to get the token. If <requeue_position> ==
+ * -1 and there are other threads waiting to obtain the token we are
+ * queued at the end of the list of waiters. If <requeue_position>
+ * > -1 then it indicates how many entries to skip over before
+ * inserting our thread into the list of waiters (e.g.,
+ * <requeue_position> == 0 means "insert at front of the queue").
+ * Renew has the rather odd semantics such that if there are other
+ * waiting threads it will give up the token even if the
+ * nesting_level_ > 1. I'm not sure if this is really the right
+ * thing to do (since it makes it possible for shared data to be
+ * changed unexpectedly) so use with caution... Returns 0 on
+ * success, -1 on failure with <ACE_Log_Msg::errnum> as the reason.
+ * If errnum == EWOULDBLOCK, and notify == 1,
+ * <ACE_Token_Proxy::sleep_hook> has been called on the current
+ * owner of the token.
+ */
+ virtual int renew (ACE_TPQ_Entry *caller,
+ int requeue_position);
+
+ /**
+ * Relinquish the token. If there are any waiters then the next one
+ * in line gets it. If the caller is not the owner, caller is
+ * removed from the waiter list.
+ */
+ virtual int release (ACE_TPQ_Entry *caller);
+
+ /// Dump the state of the class.
+ void dump (void) const;
+
+ /// Returns ACE_Tokens::MUTEX.
+ virtual int type (void) const;
+
+ /// Returns a stack of the current owners. Returns -1 on error, 0 on
+ /// success. If <id> is non-zero, returns 1 if id is an owner.
+ virtual int owners (OWNER_STACK &o, const ACE_TCHAR *id);
+
+ /// Returns 1 if <id> is waiting for this token. 0 otherwise.
+ virtual int is_waiting_for (const ACE_TCHAR *id);
+
+ /// Returns 1 if <id> is an owner of this token. 0 otherwise.
+ virtual int is_owner (const ACE_TCHAR *id);
+
+private:
+ /// ACE_Mutex_Token used to lock internal data structures.
+ ACE_TOKEN_CONST::MUTEX lock_;
+};
+
+// 12..
+/**
+ * @class ACE_RW_Token
+ *
+ * @brief Class that acquires, renews, and releases a process-local
+ * synchronization token.
+ *
+ * Not a public interface.
+ * This class is a more general-purpose synchronization mechanism
+ * than SunOS 5.x mutexes. For example, it implements "recursive
+ * mutex" semantics, where a thread that owns the token can
+ * reacquire it without deadlocking. In addition, threads that are
+ * blocked awaiting the token are serviced in strict FIFO order as
+ * other threads release the token (SunOS 5.x mutexes don't strictly
+ * enforce an acquisition order).
+ */
+class ACE_Export ACE_RW_Token : public ACE_Tokens
+{
+public:
+ /// Life.
+ ACE_EXPLICIT ACE_RW_Token (const ACE_TCHAR* name);
+
+ /// Death.
+ virtual ~ACE_RW_Token (void);
+
+ // = Synchronization operations.
+ // With acquire, renew, and release, the caller must be specified so
+ // that multiple proxies (e.g. ACE_Local_Mutex) can use the same
+ // token.
+
+ /**
+ * Returns 0 on success, -1 on failure with <ACE_Log_Msg::errnum> as
+ * the reason. If errnum == EWOULDBLOCK, and notify == 1,
+ * <ACE_Token_Proxy::sleep_hook> has been called on the current
+ * owner of the token. If ignore_deadlock is passed as 1 and errnum
+ * == EDEADLK, then deadlock was detected via ace_token_manager.
+ */
+ virtual int acquire (ACE_TPQ_Entry *caller,
+ int ignore_deadlock,
+ int notify);
+
+ /// same as acquire except fails on would block
+ virtual int tryacquire (ACE_TPQ_Entry *caller);
+
+ /**
+ * An optimized method that efficiently reacquires the token if no
+ * other threads are waiting. This is useful for situations where
+ * you don't want to degrade the quality of service if there are
+ * other threads waiting to get the token. If <requeue_position> ==
+ * -1 and there are other threads waiting to obtain the token we are
+ * queued at the end of the list of waiters. If <requeue_position>
+ * > -1 then it indicates how many entries to skip over before
+ * inserting our thread into the list of waiters (e.g.,
+ * <requeue_position> == 0 means "insert at front of the queue").
+ * Renew has the rather odd semantics such that if there are other
+ * waiting threads it will give up the token even if the
+ * nesting_level_ > 1. I'm not sure if this is really the right
+ * thing to do (since it makes it possible for shared data to be
+ * changed unexpectedly) so use with caution... Returns 0 on
+ * success, -1 on failure with <ACE_Log_Msg::errnum> as the reason.
+ * If errnum == EWOULDBLOCK, and notify == 1,
+ * <ACE_Token_Proxy::sleep_hook> has been called on the current
+ * owner of the token.
+ */
+ virtual int renew (ACE_TPQ_Entry *caller,
+ int requeue_position);
+
+ /**
+ * Relinquish the token. If there are any waiters then the next one
+ * in line gets it. If the caller is not the owner, caller is
+ * removed from the waiter list.
+ */
+ virtual int release (ACE_TPQ_Entry *caller);
+
+ /// Dump the state of the class.
+ void dump (void) const;
+
+ /// These are the types that proxies can be.
+ enum PROXY_TYPE { READER, WRITER };
+
+ /// Returns READER or WRITER.
+ virtual int type (void) const;
+
+ /// Returns a stack of the current owners. Returns -1 on error, 0 on
+ /// success. If <id> is non-zero, returns 1 if id is an owner.
+ virtual int owners (OWNER_STACK &o, const ACE_TCHAR *id);
+
+ /// Returns 1 if <id> is waiting for this token. 0 otherwise.
+ virtual int is_waiting_for (const ACE_TCHAR *id);
+
+ /// Returns 1 if <id> is an owner of this token. 0 otherwise.
+ virtual int is_owner (const ACE_TCHAR *id);
+
+protected:
+ /// the number of waiting writers.
+ int num_writers_;
+
+ /// ACE_Mutex_Token used to lock internal data structures.
+ ACE_TOKEN_CONST::MUTEX lock_;
+
+ /// Sets the new owner.
+ void notify_new_owner (ACE_TPQ_Entry *caller);
+};
+
+// a..
+/**
+ * @class ACE_Token_Name
+ *
+ * @brief Allows Token_Manger to identify tokens.
+ *
+ * For now, this is just a string. We need a string class
+ * anyway to use in <ACE_Map_Manager>. Having this class
+ * (instead of <ACE_SString>) allows us to easily change if
+ * needed. For instance, we may choose to identify tokens by
+ * name and *type* in the future.
+ */
+class ACE_Export ACE_Token_Name
+{
+public:
+ /// Construction.
+ ACE_Token_Name (const ACE_TCHAR *token_name = 0);
+
+ /// Copy construction.
+ ACE_Token_Name (const ACE_Token_Name &rhs);
+
+ /// Death.
+ virtual ~ACE_Token_Name (void);
+
+ /// Copy.
+ void operator= (const ACE_Token_Name &rhs);
+
+ /// Comparison.
+ int operator== (const ACE_Token_Name &rhs) const;
+
+ /// Token name.
+ const ACE_TCHAR *name (void) const;
+
+ /// Token name.
+ void name (const ACE_TCHAR *new_name);
+
+ /// Dump the state of the class.
+ void dump (void) const;
+
+private:
+ /// Name of the token.
+ ACE_TCHAR token_name_[ACE_MAXTOKENNAMELEN];
+};
+
+// 7..
+/**
+ * @class ACE_Token_Proxy
+ *
+ * @brief Abstract representation of ACE tokens.
+ *
+ * Interface for all Tokens in ACE. This class implements the
+ * synchronization needed for tokens (condition variables etc.)
+ * The algorithms for the operations (acquire, release, etc.)
+ * operate on the generic ACE_Tokens interface. Thus, the _type_
+ * of token (mutex, rwlock) can be set at construction of
+ * ACE_Token_Proxy. You can use all Tokens in ACE through the
+ * ACE_Token_Proxy by passing the proper values at construction.
+ * Alternatively, there are class definitions which "know" how to
+ * do this (ACE_Local_Mutex, ACE_Local_RLock, ACE_Local_WLock).
+ * To add a new type of token (e.g. semaphore), this class is not
+ * changed. See ACE_Token_Manager for details.
+ * Tokens (e.g. ACE_Mutex_Token) assume that it can always call
+ * <ACE_Token_Proxy::token_acquired> on a new token owner. This
+ * is not a problem for synchronous use of token proxies (that is,
+ * when acquires block until successful.) However, for
+ * implementations of the Token Server, which may use asynch
+ * operations, the proxy can not go away after an acquire until
+ * the token is acquired. This is not really a problem, but
+ * should be understood.
+ */
+class ACE_Export ACE_Token_Proxy
+{
+public:
+ friend class ACE_Token_Manager;
+ friend class ACE_Token_Invariant_Manager; // For testing.
+
+ // Initialization and termination methods.
+ /// Construction.
+ ACE_Token_Proxy (void);
+
+ /// Death.
+ virtual ~ACE_Token_Proxy (void);
+
+ /**
+ * <name> is the string uniquely identifying the token.
+ * <ignore_deadlock> can be 1 to disable deadlock notifications.
+ * <debug> prints debug messages.
+ */
+ virtual int open (const ACE_TCHAR *name,
+ int ignore_deadlock = 0,
+ int debug = 0);
+
+ // = The following methods have implementations which are
+ // independent of the token semantics (mutex, rwlock, etc.) They
+ // forward operations to the underlying token and perform the
+ // necessary blocking semantics for operations (condition variables
+ // etc.) This allows reuse of the blocking code as well as having
+ // multiple proxies to the same token.
+
+ /// Calls acquire on the token. Blocks the calling thread if would
+ /// block.
+ virtual int acquire (int notify = 0,
+ void (*sleep_hook)(void *) = 0,
+ ACE_Synch_Options &options =
+ ACE_Synch_Options::defaults);
+
+ /// Calls renew on the token. Blocks the calling thread if would
+ /// block.
+ virtual int renew (int requeue_position = -1,
+ ACE_Synch_Options &options =
+ ACE_Synch_Options::defaults);
+
+ /// Calls renew on the token.
+ virtual int tryacquire (void (*sleep_hook)(void *) = 0);
+
+ /// Calls release on the token.
+ virtual int release (ACE_Synch_Options &options =
+ ACE_Synch_Options::defaults);
+
+ /// Calls remove on the token.
+ virtual int remove (ACE_Synch_Options &options =
+ ACE_Synch_Options::defaults);
+
+ /// Since the locking mechanism doesn't support read locks then this
+ /// just calls <acquire>.
+ virtual int acquire_read (int notify = 0,
+ void (*sleep_hook)(void *) = 0,
+ ACE_Synch_Options &options =
+ ACE_Synch_Options::defaults);
+
+ /// Since the locking mechanism doesn't support write locks then this
+ /// just calls <acquire>.
+ virtual int acquire_write (int notify = 0,
+ void (*sleep_hook)(void *) = 0,
+ ACE_Synch_Options &options =
+ ACE_Synch_Options::defaults);
+
+ /// Since the locking mechanism doesn't support read locks then this
+ /// just calls <tryacquire>.
+ virtual int tryacquire_read (void (*sleep_hook)(void *) = 0);
+
+ /// Since the locking mechanism doesn't support write locks then this
+ /// just calls <tryacquire>.
+ virtual int tryacquire_write (void (*sleep_hook)(void *) = 0);
+
+ // = Utility methods.
+
+ /// Get the client id of the proxy. This is implemented as
+ /// thread-specific data.
+ virtual const ACE_TCHAR *client_id (void) const;
+
+ /**
+ * Set the client_id for the calling thread. I strongly recommend
+ * that this not be used unless you really know what you're doing.
+ * I use this in the Token Server, and it caused many headaches.
+ */
+ virtual void client_id (const ACE_TCHAR *client_id);
+
+ /**
+ * Return the name of the token. This is important for use within
+ * the token servers (local and remote) as well as with token
+ * collections. So, all derivations of ACE_Token_Proxy must be able to
+ * stringify some name. The name must uniquely identify a token.
+ * So, for instance, the token within the reactor should probably be
+ * called "Reactor Token."
+ */
+ virtual const ACE_TCHAR *name (void) const;
+
+ /**
+ * This should really be called <someone_waiting>. This is called
+ * by ACE_Token_xx's when another proxy enters the waiting list and
+ * requests that the current token holder be notified.
+ */
+ virtual void sleep_hook (void);
+
+ /// This is called when a queued (waiting) proxy is removed from the
+ /// waiters list and given the token.
+ virtual void token_acquired (ACE_TPQ_Entry *);
+
+ /// the client id of the current token holder
+ virtual const ACE_TCHAR *owner_id (void);
+
+ /// Return a dynamically allocated clone of the derived class.
+ virtual ACE_Token_Proxy *clone (void) const = 0;
+
+ /// Dump the state of the class.
+ void dump (void) const;
+
+ /**
+ * This method can be used be Tokens (e.g. Readers/Writer Tokens) to
+ * distinguish between Proxy types. For instance a Reader proxy
+ * should return a different type value than a Writer proxy. The
+ * default implementation returns 0.
+ */
+ virtual int type (void) const;
+
+protected:
+ /// Duplication.
+ ACE_Token_Proxy (const ACE_Token_Proxy &);
+
+ /// If this is set, we ignore deadlock.
+ int ignore_deadlock_;
+
+ /// Print a bunch of debug messages.
+ int debug_;
+
+ /// Reference to the actual logical token. Many ACE_Local_Mutex
+ /// proxies can reference the same ACE_Mutex_Token.
+ ACE_Tokens *token_;
+
+ /// Handles cond_var waits.
+ int handle_options (ACE_Synch_Options &options,
+ ACE_TOKEN_CONST::COND_VAR &cv);
+
+ /// Waiter info used for asynchronous transactions.
+ ACE_TSS_TPQ_Entry waiter_;
+
+ /// Make the correct type of ACE_Tokens. This is called by the Token
+ /// Manager.
+ virtual ACE_Tokens *create_token (const ACE_TCHAR *name) = 0;
+};
+
+// 8..
+/**
+ * @class ACE_Null_Token
+ *
+ * @brief No op class for nonthreaded platform protocols.
+ */
+class ACE_Export ACE_Null_Token : public ACE_Token_Proxy
+{
+public:
+#if defined (ACE_LACKS_INLINE_FUNCTIONS)
+ // @@ Hopefully, we can remove this ridicules ifdef when CE's compiler becomes more normal.
+ /// Construction.
+ ACE_Null_Token (void);
+
+ /// Destructor
+ ~ACE_Null_Token (void);
+#endif /* ACE_LACKS_INLINE_FUNCTION */
+
+ /// Acquire.
+ virtual int acquire (int /* notify */ = 0,
+ void (* /* sleep_hook */ )(void *) = 0,
+ ACE_Synch_Options & /* options */ =
+ ACE_Synch_Options::defaults) { return 0; }
+
+ /// Renew.
+ virtual int renew (int /* requeue_position */ = -1,
+ ACE_Synch_Options & /* options */ =
+ ACE_Synch_Options::defaults) { return 0; }
+
+ /// Try acquire.
+ virtual int tryacquire (void (* /* sleep_hook */)(void *) = 0) { return 0; }
+
+ /// Release.
+ virtual int release (ACE_Synch_Options & /* options */ =
+ ACE_Synch_Options::defaults) { return 0; }
+
+ /// Remove.
+ virtual int remove (ACE_Synch_Options & /* options */ =
+ ACE_Synch_Options::defaults) { return 0; }
+
+ /// Return a dynamically allocated clone of the derived class.
+ virtual ACE_Token_Proxy *clone (void) const { return new ACE_Null_Token; }
+
+ /// Dump the state of the class.
+ void dump (void) const;
+
+ /// Do not allow the Token Manager to create us.
+ virtual ACE_Tokens *create_token (const ACE_TCHAR *) { return 0; }
+};
+
+// 9..
+/**
+ * @class ACE_Local_Mutex
+ *
+ * @brief Class that acquires, renews, and releases a synchronization
+ * token local to the process.
+ *
+ * This class is a more general-purpose synchronization mechanism
+ * than SunOS 5.x mutexes. For example, it implements "recursive
+ * mutex" semantics, where a thread that owns the token can
+ * reacquire it without deadlocking. In addition, threads that
+ * are blocked awaiting the token are serviced in strict FIFO
+ * order as other threads release the token (SunOS 5.x mutexes
+ * don't strictly enforce an acquisition order). Lastly,
+ * ACE_Local_Mutex performs deadlock detection on acquire calls.
+ * The interfaces for acquire, tryacquire, renew, release,
+ * etc. are defined in ACE_Token_Proxy. The semantics for
+ * ACE_Local_Mutex are that of a mutex.
+ */
+class ACE_Export ACE_Local_Mutex : public ACE_Token_Proxy
+{
+public:
+ /**
+ * <token_name> uniquely id's the token.
+ * <ignore_deadlock> will allow deadlock to occur (useful for
+ * testing). <debug> prints a bunch of messages.
+ */
+ ACE_Local_Mutex (const ACE_TCHAR *token_name = 0,
+ int ignore_deadlock = 0,
+ int debug = 0);
+
+ /// Destructor
+ ~ACE_Local_Mutex (void);
+
+ /// Dump the state of the class.
+ void dump (void) const;
+
+ /// Return deep copy.
+ virtual ACE_Token_Proxy *clone (void) const;
+
+protected:
+ /// Return a new ACE_Local_Mutex.
+ virtual ACE_Tokens *create_token (const ACE_TCHAR *name);
+};
+
+// *.
+/**
+ * @class ACE_Local_RLock
+ *
+ * @brief Class that acquires, renews, and releases a readers lock that
+ * is local to the process.
+ *
+ * This class implements the reader interface to canonical
+ * readers/writer locks. Multiple readers can hold the lock
+ * simultaneously when no writers have the lock. Alternatively,
+ * when a writer holds the lock, no other participants (readers
+ * or writers) may hold the lock. This class is a more
+ * general-purpose synchronization mechanism than SunOS 5.x
+ * RLocks. For example, it implements "recursive RLock"
+ * semantics, where a thread that owns the token can reacquire it
+ * without deadlocking. In addition, threads that are blocked
+ * awaiting the token are serviced in strict FIFO order as other
+ * threads release the token (SunOS 5.x RLockes don't strictly
+ * enforce an acquisition order).
+ * The interfaces for acquire, tryacquire, renew, release,
+ * etc. are defined in ACE_Token_Proxy. The semantics for
+ * ACE_Local_RLock are that of a readers/writers lock. Acquire
+ * for this class implies a reader acquisition. That is,
+ * multiple clients may acquire a lock for read only.
+ */
+class ACE_Export ACE_Local_RLock : public ACE_Token_Proxy
+{
+public:
+ // = Initialization and termination.
+
+ /**
+ * <token_name> uniquely id's the token.
+ * <ignore_deadlock> will allow deadlock to occur (useful for
+ * testing). <debug> prints a bunch of messages.
+ */
+ ACE_Local_RLock (const ACE_TCHAR *token_name = 0,
+ int ignore_deadlock = 0,
+ int debug = 0);
+
+ /// Destructor
+ ~ACE_Local_RLock (void);
+
+ /// Dump the state of the class.
+ void dump (void) const;
+
+ /// Returns ACE_RW_Token::RLOCK.
+ virtual int type (void) const;
+
+ /// Return deep copy.
+ virtual ACE_Token_Proxy *clone (void) const;
+
+protected:
+ /// Return a new ACE_Local_Mutex.
+ virtual ACE_Tokens *create_token (const ACE_TCHAR *name);
+};
+
+// *.
+/**
+ * @class ACE_Local_WLock
+ *
+ * @brief Class that acquires, renews, and releases a writer lock that
+ * is local to the process.
+ *
+ * This class implements the writer interface to canonical
+ * readers/writer locks. Multiple readers can hold the lock
+ * simultaneously when no writers have the lock. Alternatively,
+ * when a writer holds the lock, no other participants (readers
+ * or writers) may hold the lock. This class is a more
+ * general-purpose synchronization mechanism than SunOS 5.x
+ * WLock. For example, it implements "recursive WLock"
+ * semantics, where a thread that owns the token can reacquire it
+ * without deadlocking. In addition, threads that are blocked
+ * awaiting the token are serviced in strict FIFO order as other
+ * threads release the token (SunOS 5.x WLocks don't strictly
+ * enforce an acquisition order).
+ * The interfaces for acquire, tryacquire, renew, release,
+ * etc. are defined in ACE_Token_Proxy. The semantics for
+ * ACE_Local_WLock are that of a readers/writers lock. Acquire
+ * for this class implies a writer acquisition. That is, only
+ * one client may hold the lock for writing.
+ */
+class ACE_Export ACE_Local_WLock : public ACE_Token_Proxy
+{
+public:
+ // = Initialization and termination.
+
+ /**
+ * <token_name> uniquely id's the token.
+ * <ignore_deadlock> will allow deadlock to occur (useful for
+ * testing). <debug> prints a bunch of messages.
+ */
+ ACE_Local_WLock (const ACE_TCHAR *token_name = 0,
+ int ignore_deadlock = 0,
+ int debug = 0);
+
+ /// Destructor
+ ~ACE_Local_WLock (void);
+
+ /// Dump the state of the class.
+ void dump (void) const;
+
+ /// Returns ACE_RW_Token::WLOCK.
+ virtual int type (void) const;
+
+ /// Return deep copy.
+ virtual ACE_Token_Proxy *clone (void) const;
+
+protected:
+ /// Return a new ACE_Local_Mutex.
+ ACE_Tokens *create_token (const ACE_TCHAR *name);
+};
+
+#endif /* ACE_HAS_TOKENS_LIBRARY */
+
+#if defined (__ACE_INLINE__)
+#include "ace/Local_Tokens.i"
+#endif /* __ACE_INLINE__ */
+#include "ace/post.h"
+#endif /* ACE_LOCAL_MUTEX_H */
diff --git a/ace/Token/Local_Tokens.i b/ace/Token/Local_Tokens.i
new file mode 100644
index 00000000000..01594e0dec2
--- /dev/null
+++ b/ace/Token/Local_Tokens.i
@@ -0,0 +1,458 @@
+/* -*- C++ -*- */
+// $Id$
+
+#if defined (ACE_HAS_TOKENS_LIBRARY)
+
+ACE_INLINE int
+ACE_Token_Proxy::type (void) const
+{
+ ACE_TRACE ("ACE_Token_Proxy::type");
+ return 0;
+}
+
+ACE_INLINE int
+ACE_Token_Proxy::acquire_read (int notify,
+ void (*sleep_hook)(void *),
+ ACE_Synch_Options &options)
+{
+ return this->acquire (notify,
+ sleep_hook,
+ options);
+}
+
+ACE_INLINE int
+ACE_Token_Proxy::acquire_write (int notify,
+ void (*sleep_hook)(void *),
+ ACE_Synch_Options &options)
+{
+ return this->acquire (notify,
+ sleep_hook,
+ options);
+}
+
+ACE_INLINE int
+ACE_Token_Proxy::tryacquire_read (void (*sleep_hook)(void *))
+{
+ return this->tryacquire (sleep_hook);
+}
+
+ACE_INLINE int
+ACE_Token_Proxy::tryacquire_write (void (*sleep_hook)(void *))
+{
+ return this->tryacquire (sleep_hook);
+}
+
+// ************************************************************
+
+ACE_INLINE int
+ACE_Token_Proxy_Queue::size (void)
+{
+ ACE_TRACE ("ACE_Token_Proxy_Queue::size");
+ return this->size_;
+}
+
+// ************************************************************
+
+ACE_INLINE int
+ACE_TPQ_Entry::waiting (void) const
+{
+ ACE_TRACE ("ACE_TPQ_Entry::waiting");
+ return waiting_;
+}
+
+ACE_INLINE void
+ACE_TPQ_Entry::waiting (int v)
+{
+ ACE_TRACE ("ACE_TPQ_Entry::waiting");
+ waiting_ = v;
+}
+
+ACE_INLINE const ACE_TCHAR *
+ACE_TPQ_Entry::client_id (void) const
+{
+ ACE_TRACE ("ACE_TPQ_Entry::client_id");
+ return this->client_id_;
+}
+
+ACE_INLINE ACE_Token_Proxy *
+ACE_TPQ_Entry::proxy (void) const
+{
+ ACE_TRACE ("ACE_TPQ_Entry::proxy");
+ return this->proxy_;
+}
+
+ACE_INLINE void
+ACE_TPQ_Entry::proxy (ACE_Token_Proxy *proxy)
+{
+ ACE_TRACE ("ACE_TPQ_Entry::proxy");
+ this->proxy_ = proxy;
+}
+
+ACE_INLINE
+ACE_TSS_TPQ_Entry::~ACE_TSS_TPQ_Entry (void)
+{
+}
+
+ACE_INLINE
+ACE_TPQ_Iterator::~ACE_TPQ_Iterator (void)
+{
+}
+
+ACE_INLINE
+ACE_Token_Proxy_Queue::~ACE_Token_Proxy_Queue (void)
+{
+}
+
+ACE_INLINE
+ACE_Tokens::~ACE_Tokens (void)
+{
+}
+
+ACE_INLINE void
+ACE_Tokens::remove (ACE_TPQ_Entry *caller)
+{
+ this->waiters_.remove (caller);
+}
+
+ACE_INLINE int
+ACE_Tokens::dec_reference (void)
+{
+ ACE_TRACE ("ACE_Tokens::dec_reference");
+ if (this->reference_count_ == 0)
+ {
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("dec_reference already zero")));
+ return 0;
+ }
+
+ return --this->reference_count_;
+}
+
+ACE_INLINE void
+ACE_Tokens::inc_reference (void)
+{
+ ACE_TRACE ("ACE_Tokens::inc_reference");
+ ++this->reference_count_;
+}
+
+ACE_INLINE ACE_Token_Proxy_Queue *
+ACE_Tokens::waiters ()
+{
+ ACE_TRACE ("ACE_Tokens::waiters");
+ return &this->waiters_;
+}
+
+ACE_INLINE int
+ACE_Tokens::no_of_waiters ()
+{
+ ACE_TRACE ("ACE_Tokens::no_of_waiters");
+ return this->waiters_.size ();
+}
+
+ACE_INLINE const ACE_TPQ_Entry *
+ACE_Token_Proxy_Queue::head (void)
+{
+ ACE_TRACE ("ACE_Token_Proxy_Queue::head");
+ if (this->head_ == 0)
+ return 0;
+ else
+ return this->head_;
+}
+
+// **************************************************
+// **************************************************
+// **************************************************
+
+ACE_INLINE void
+ACE_Tokens::visit (int v)
+{
+ ACE_TRACE ("ACE_Tokens::visit");
+ visited_ = v;
+}
+
+ACE_INLINE int
+ACE_Tokens::visited (void)
+{
+ ACE_TRACE ("ACE_Tokens::visited");
+ return visited_;
+}
+
+ACE_INLINE ACE_TPQ_Entry *
+ACE_Tokens::owner (void)
+{
+ ACE_TRACE ("ACE_Tokens::owner");
+ return (ACE_TPQ_Entry *) this->waiters_.head ();
+}
+
+ACE_INLINE const ACE_TCHAR*
+ACE_Tokens::owner_id ()
+{
+ ACE_TRACE ("ACE_Tokens::owner_id");
+ if (this->owner () == 0)
+ return ACE_LIB_TEXT ("no owner");
+ else
+ return this->owner ()->client_id ();
+}
+
+ACE_INLINE const ACE_TCHAR*
+ACE_Tokens::name (void)
+{
+ ACE_TRACE ("ACE_Tokens::name");
+ return this->token_name_;
+}
+
+#if 0
+ACE_INLINE ACE_Token_Proxy *
+ACE_Tokens::current_owner (void)
+{
+ ACE_TRACE ("ACE_Tokens::current_owner");
+ // ACE_GUARD_RETURN ???
+
+ if (this->owner () == 0)
+ return 0;
+ else
+ return this->owner ()->proxy ();
+}
+#endif /* 0 */
+
+// ************************************************************
+
+ACE_INLINE int
+ACE_Mutex_Token::type (void) const
+{
+ ACE_TRACE ("ACE_Mutex_Token::type");
+ return (int) ACE_Tokens::MUTEX;
+}
+
+// ************************************************************
+
+ACE_INLINE int
+ACE_RW_Token::type (void) const
+{
+ ACE_TRACE ("ACE_RW_Token::type");
+ return (int) ACE_Tokens::RWLOCK;
+}
+
+// ************************************************************
+
+ACE_INLINE int
+ACE_TPQ_Entry::nesting_level (void) const
+{
+ ACE_TRACE ("ACE_TPQ_Entry::nesting_level");
+ return this->nesting_level_;
+}
+
+ACE_INLINE void
+ACE_TPQ_Entry::nesting_level (int delta)
+{
+ ACE_TRACE ("ACE_TPQ_Entry::nesting_level");
+ this->nesting_level_ += delta;
+}
+
+ACE_INLINE ACE_TPQ_Entry::PTVF
+ACE_TPQ_Entry::sleep_hook (void) const
+{
+ ACE_TRACE ("ACE_TPQ_Entry::sleep_hook");
+ return this->sleep_hook_;
+}
+
+ACE_INLINE void
+ACE_TPQ_Entry::sleep_hook (void (*sh)(void *))
+{
+ ACE_TRACE ("ACE_TPQ_Entry::sleep_hook");
+ this->sleep_hook_ = sh;
+}
+
+ACE_INLINE void
+ACE_TPQ_Entry::call_sleep_hook (void)
+{
+ ACE_TRACE ("ACE_TPQ_Entry::call_sleep_hook");
+
+ // if a function has been registered, call it.
+ if (this->sleep_hook () != 0)
+ this->sleep_hook () ((void *) this->proxy ());
+ else
+ // otherwise, call back the sleep_hook method
+ this->proxy ()->sleep_hook ();
+}
+
+ACE_INLINE int
+ACE_TPQ_Entry::equal_client_id (const ACE_TCHAR *id)
+{
+ ACE_TRACE ("ACE_TPQ_Entry::equal_client_id");
+ return (ACE_OS::strcmp (this->client_id (), id) == 0);
+}
+
+// ************************************************************
+// ************************************************************
+// ************************************************************
+
+ACE_INLINE
+ACE_Local_Mutex::ACE_Local_Mutex (const ACE_TCHAR *token_name,
+ int ignore_deadlock,
+ int debug)
+{
+ ACE_TRACE ("ACE_Local_Mutex::ACE_Local_Mutex");
+ this->open (token_name, ignore_deadlock, debug);
+}
+
+ACE_INLINE void
+ACE_Token_Name::name (const ACE_TCHAR *new_name)
+{
+ ACE_TRACE ("ACE_Token_Name::name");
+
+ if (new_name == 0)
+ new_name = ACE_LIB_TEXT ("no name");
+
+ int n = ACE_OS::strlen (new_name) + 1;
+
+ if (n >= ACE_MAXTOKENNAMELEN)
+ n = ACE_MAXTOKENNAMELEN - 1;
+
+ ACE_OS::strsncpy (this->token_name_, (ACE_TCHAR *) new_name, n);
+}
+
+ACE_INLINE const ACE_TCHAR*
+ACE_Token_Name::name (void) const
+{
+ ACE_TRACE ("ACE_Token_Name::name");
+ return this->token_name_;
+}
+
+ACE_INLINE ACE_Token_Proxy *
+ACE_Local_Mutex::clone (void) const
+{
+ ACE_Token_Proxy *temp = 0;
+ ACE_NEW_RETURN (temp,
+ ACE_Local_Mutex (token_->name (),
+ ignore_deadlock_,
+ debug_),
+ 0);
+ return temp;
+}
+
+ACE_INLINE ACE_Tokens *
+ACE_Local_Mutex::create_token (const ACE_TCHAR *name)
+{
+ ACE_Tokens *temp = 0;
+ ACE_NEW_RETURN (temp,
+ ACE_Mutex_Token (name),
+ 0);
+ return temp;
+}
+
+ACE_INLINE
+ACE_Local_Mutex::~ACE_Local_Mutex (void)
+{
+}
+
+// ************************************************************
+
+ACE_INLINE
+ACE_Local_RLock::ACE_Local_RLock (const ACE_TCHAR *token_name,
+ int ignore_deadlock,
+ int debug)
+{
+ ACE_TRACE ("ACE_Local_RLock::ACE_Local_RLock");
+ this->open (token_name, ignore_deadlock, debug);
+}
+
+ACE_INLINE
+ACE_Local_RLock::~ACE_Local_RLock (void)
+{
+}
+
+ACE_INLINE ACE_Tokens *
+ACE_Local_RLock::create_token (const ACE_TCHAR *name)
+{
+ ACE_Tokens *temp = 0;
+ ACE_NEW_RETURN (temp,
+ ACE_RW_Token (name),
+ 0);
+ return temp;
+}
+
+ACE_INLINE int
+ACE_Local_RLock::type (void) const
+{
+ return ACE_RW_Token::READER;
+}
+
+ACE_INLINE ACE_Token_Proxy *
+ACE_Local_RLock::clone (void) const
+{
+ ACE_Token_Proxy *temp = 0;
+ ACE_NEW_RETURN (temp,
+ ACE_Local_RLock (token_->name (),
+ ignore_deadlock_,
+ debug_),
+ 0);
+ return temp;
+}
+
+// ************************************************************
+
+ACE_INLINE
+ACE_Local_WLock::ACE_Local_WLock (const ACE_TCHAR *token_name,
+ int ignore_deadlock,
+ int debug)
+{
+ ACE_TRACE ("ACE_Local_WLock::ACE_Local_WLock");
+ this->open (token_name, ignore_deadlock, debug);
+}
+
+ACE_INLINE
+ACE_Local_WLock::~ACE_Local_WLock (void)
+{
+}
+
+ACE_INLINE ACE_Tokens *
+ACE_Local_WLock::create_token (const ACE_TCHAR *name)
+{
+ ACE_Tokens *temp = 0;
+ ACE_NEW_RETURN (temp,
+ ACE_RW_Token (name),
+ 0);
+ return temp;
+}
+
+ACE_INLINE int
+ACE_Local_WLock::type (void) const
+{
+ return ACE_RW_Token::WRITER;
+}
+
+ACE_INLINE ACE_Token_Proxy *
+ACE_Local_WLock::clone (void) const
+{
+ ACE_Token_Proxy *temp = 0;
+ ACE_NEW_RETURN (temp,
+ ACE_Local_WLock (token_->name (),
+ ignore_deadlock_,
+ debug_),
+ 0);
+ return temp;
+}
+
+// ************************************************************
+
+
+ACE_INLINE void
+ACE_Token_Name::operator= (const ACE_Token_Name &rhs)
+{
+ ACE_TRACE ("ACE_Token_Name::operator=");
+ if (&rhs == this)
+ return;
+ else
+ this->name (rhs.name ());
+}
+
+ACE_INLINE int
+ACE_Token_Name::operator== (const ACE_Token_Name &rhs) const
+{
+ ACE_TRACE ("ACE_Token_Name::operator==");
+
+ // the name and type must be the same
+ return (ACE_OS::strcmp (this->token_name_, rhs.name ()) == 0);
+}
+
+#endif /* ACE_HAS_TOKENS_LIBRARY */
diff --git a/ace/Token/Remote_Tokens.cpp b/ace/Token/Remote_Tokens.cpp
new file mode 100644
index 00000000000..86aec7547d8
--- /dev/null
+++ b/ace/Token/Remote_Tokens.cpp
@@ -0,0 +1,438 @@
+// Remote_Tokens.cpp
+// $Id$
+
+#include "ace/Remote_Tokens.h"
+#include "ace/Singleton.h"
+
+#if !defined (__ACE_INLINE__)
+#include "ace/Remote_Tokens.i"
+#endif /* __ACE_INLINE__ */
+
+#if defined (ACE_HAS_TOKENS_LIBRARY)
+
+ACE_RCSID(ace, Remote_Tokens, "$Id$")
+
+#if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0)
+#define ACE_TSS_CONNECTION_MUTEX ACE_Thread_Mutex
+#else
+#define ACE_TSS_CONNECTION_MUTEX ACE_Null_Mutex
+#endif /* ACE_MT_SAFE */
+
+// Make a typedef to simplify access to the Singleton below.
+typedef ACE_Singleton<ACE_TSS_Connection, ACE_TSS_CONNECTION_MUTEX> ACE_Token_Connections;
+
+// Initialize the statics from ACE_TSS_Connection;
+ACE_INET_Addr ACE_TSS_Connection::server_address_;
+
+// ************************************************************
+
+void
+ACE_TSS_Connection::set_server_address (const ACE_INET_Addr &server_address)
+{
+ ACE_TRACE ("ACE_TSS_Connection::set_server_address");
+ server_address_ = server_address;
+}
+
+// Necessary to make some compilers work...
+ACE_TSS_Connection::ACE_TSS_Connection (void)
+{
+ ACE_TRACE ("ACE_TSS_Connection::ACE_TSS_Connection");
+}
+
+ACE_TSS_Connection::~ACE_TSS_Connection (void)
+{
+ ACE_TRACE ("ACE_TSS_Connection::~ACE_TSS_Connection");
+}
+
+ACE_SOCK_Stream *
+ACE_TSS_Connection::get_connection (void)
+{
+ return ACE_TSS<ACE_SOCK_Stream>::operator-> ();
+}
+
+ACE_SOCK_Stream *
+ACE_TSS_Connection::make_TSS_TYPE (void) const
+{
+ ACE_TRACE ("ACE_TSS_Connection::make_TSS_TYPE");
+
+ ACE_SOCK_Connector connector;
+ ACE_SOCK_Stream *stream = 0;
+
+ ACE_NEW_RETURN (stream,
+ ACE_SOCK_Stream,
+ 0);
+
+ if (connector.connect (*stream, server_address_) == -1)
+ {
+ delete stream;
+ errno = ECONNREFUSED;
+ return 0;
+ }
+
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("ACE_TSS_Connection new connection\n")));
+ return stream;
+}
+
+ACE_TSS_Connection::operator ACE_SOCK_Stream *(void)
+{
+ return this->get_connection ();
+}
+
+void
+ACE_TSS_Connection::dump (void) const
+{
+ ACE_TRACE ("ACE_TSS_Connection::dump");
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("ACE_TSS_Connection::dump:\n")));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("server_address_\n")));
+ server_address_.dump ();
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("base:\n")));
+ ACE_TSS<ACE_SOCK_Stream>::dump ();
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+ACE_Remote_Token_Proxy::ACE_Remote_Token_Proxy (void)
+{
+ ACE_TRACE ("ACE_Remote_Token_Proxy::ACE_Remote_Token_Proxy");
+}
+
+ACE_Remote_Token_Proxy::~ACE_Remote_Token_Proxy (void)
+{
+ ACE_TRACE ("ACE_Remote_Token_Proxy::~ACE_Remote_Token_Proxy");
+}
+
+int
+ACE_Remote_Token_Proxy::open (const ACE_TCHAR *name,
+ int ignore_deadlock,
+ int debug)
+{
+ ACE_TRACE ("ACE_Remote_Token_Proxy::open");
+ ignore_shadow_deadlock_ = ignore_deadlock;
+ return ACE_Token_Proxy::open (name, 0, debug);
+}
+
+void
+ACE_Remote_Token_Proxy::set_server_address (const ACE_INET_Addr &server_address)
+{
+ ACE_TRACE ("ACE_Remote_Token_Proxy::set_server_address");
+ ACE_Token_Connections::instance ()->set_server_address (server_address);
+}
+
+int
+ACE_Remote_Token_Proxy::initiate_connection (void)
+{
+ ACE_TRACE ("ACE_Remote_Token_Proxy::initiate_connection");
+ if (token_ == 0)
+ {
+ errno = ENOENT;
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_LIB_TEXT ("ACE_Remote_Token_Proxy not open.\n")), -1);
+ }
+
+ ACE_SOCK_Stream *peer = ACE_Token_Connections::instance ()->get_connection ();
+ return peer == 0 ? 0 : 1;
+}
+
+// Do the work of sending a request and getting a reply.
+
+int
+ACE_Remote_Token_Proxy::request_reply (ACE_Token_Request &request,
+ ACE_Synch_Options &)
+{
+ ACE_TRACE ("ACE_Remote_Token_Proxy::request_reply");
+ void *buffer;
+ ssize_t length;
+
+ if ((length = request.encode (buffer)) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_LIB_TEXT ("%p\n"), ACE_LIB_TEXT ("encode failed")), -1);
+
+ ACE_SOCK_Stream *peer = ACE_Token_Connections::instance ()->get_connection ();
+
+ if (peer == 0)
+ return -1;
+
+ // Transmit request via a blocking send.
+
+ if (peer->send_n (buffer, length) != length)
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_LIB_TEXT ("%p\n"), ACE_LIB_TEXT ("send_n failed")), -1);
+ else
+ {
+ ACE_Token_Reply reply;
+
+ // Receive reply via blocking read.
+
+ if (peer->recv (&reply, sizeof reply) != sizeof reply)
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_LIB_TEXT ("%p\n"), ACE_LIB_TEXT ("recv failed")), -1);
+
+ if (reply.decode () == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_LIB_TEXT ("%p\n"), ACE_LIB_TEXT ("decode failed")), -1);
+
+ errno = int (reply.errnum ());
+ if (errno != 0)
+ ACE_RETURN (-1);
+ else
+ return 0;
+ }
+}
+
+int
+ACE_Remote_Token_Proxy::acquire (int notify,
+ void (*sleep_hook)(void *),
+ ACE_Synch_Options &options)
+{
+ ACE_TRACE ("ACE_Remote_Token_Proxy::acquire");
+
+ // First grab the local shadow mutex.
+ if (ACE_Token_Proxy::acquire (notify,
+ sleep_hook,
+ ACE_Synch_Options::asynch) == -1)
+ {
+ // Acquire failed, deal with it...
+ switch (errno)
+ {
+ case EWOULDBLOCK :
+ // Whoah, we detected wouldblock via the shadow mutex!
+ if (debug_)
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("(%t) shadow: acquire will block, owner is %s\n"),
+ this->token_->owner_id ()));
+ // No error, but would block,
+ break;
+
+ case EDEADLK :
+ if (debug_)
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("(%t) shadow: deadlock detected\n")));
+
+ if (ignore_shadow_deadlock_)
+ break;
+ else
+ {
+ errno = EDEADLK;
+ ACE_RETURN (-1);
+ }
+
+ default :
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_LIB_TEXT ("(%t) %p shadow acquire failed\n"),
+ ACE_LIB_TEXT ("ACE_Remote_Token_Proxy")),
+ -1);
+ }
+ }
+
+ ACE_Token_Request request (token_->type (),
+ this->type (),
+ ACE_Token_Request::ACQUIRE,
+ this->name (),
+ this->client_id (),
+ options);
+
+ request.notify (notify);
+
+ int result = this->request_reply (request, options);
+
+ if (result == -1)
+ {
+ // Update the local shadow copy.
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("error on remote acquire, releasing shadow mutex.\n")));
+ ACE_Token_Proxy::release ();
+ }
+ else
+ {
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("(%t) acquired %s remotely.\n"), this->name ()));
+ // Our shadow call may have failed. However, it's still a race
+ // to the remote server. If we beat the client which holds the
+ // local token, we need to fix things locally to reflect the
+ // actual ownership. All that should happen is that our waiter
+ // is moved to the front of the waiter list.
+ token_->make_owner (waiter_);
+ }
+
+ return result;
+}
+
+int
+ACE_Remote_Token_Proxy::tryacquire (void (*sleep_hook)(void *))
+{
+ ACE_TRACE ("ACE_Remote_Token_Proxy::tryacquire");
+
+ // If we can detect locally that the tryacquire will fail, there is
+ // no need to go remote.
+ if (ACE_Token_Proxy::tryacquire (sleep_hook) == -1)
+ {
+ if (debug_)
+ {
+ // Save/restore errno.
+ ACE_Errno_Guard error (errno);
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_LIB_TEXT ("shadow try acquire failed\n")));
+ }
+
+ return -1;
+ }
+
+ ACE_Token_Request request (token_->type (),
+ this->type (),
+ ACE_Token_Request::TRY_ACQUIRE,
+ this->name (),
+ this->client_id (),
+ ACE_Synch_Options::synch);
+
+ return this->request_reply (request,
+ ACE_Synch_Options::synch);
+}
+
+int
+ACE_Remote_Token_Proxy::renew (int requeue_position,
+ ACE_Synch_Options &options)
+{
+ ACE_TRACE ("ACE_Remote_Token_Proxy::renew");
+
+ if (ACE_Token_Proxy::renew (requeue_position,
+ ACE_Synch_Options::asynch) == -1)
+ {
+ // Check for error.
+ if (errno != EWOULDBLOCK)
+ return -1;
+ else if (debug_)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_LIB_TEXT ("(%t) shadow: renew would block. owner %s.\n"),
+ this->token_->owner_id ()));
+ }
+
+ ACE_Token_Request request (token_->type (),
+ this->type (),
+ ACE_Token_Request::RENEW,
+ this->name (),
+ this->client_id (),
+ options);
+
+ request.requeue_position (requeue_position);
+
+ int result = this->request_reply (request, options);
+
+ if (result == -1)
+ {
+ {
+ // Save/restore errno.
+ ACE_Errno_Guard error (errno);
+ ACE_Token_Proxy::release ();
+ }
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_LIB_TEXT ("%p error on remote renew, releasing shadow mutex.\n"),
+ ACE_LIB_TEXT ("ACE_Remote_Token_Proxy")), -1);
+ }
+ else
+ {
+ if (debug_)
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("(%t) renewed %s remotely.\n"), this->name ()));
+ // Make sure that the local shadow reflects our new ownership.
+ token_->make_owner (waiter_);
+ return result;
+ }
+}
+
+int
+ACE_Remote_Token_Proxy::release (ACE_Synch_Options &options)
+{
+ ACE_TRACE ("ACE_Remote_Token_Proxy::release");
+
+ ACE_Token_Request request (token_->type (),
+ this->type (),
+ ACE_Token_Request::RELEASE,
+ this->name (),
+ this->client_id (),
+ options);
+
+ int result = this->request_reply (request, options);
+ if (result == 0)
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("(%t) released %s remotely.\n"), this->name ()));
+
+ // whether success or failure, we're going to release the shadow.
+ // If race conditions exist such that we are no longer the owner,
+ // this release will perform a remove.
+ if (ACE_Token_Proxy::release () == -1)
+ ACE_ERROR ((LM_ERROR, ACE_LIB_TEXT ("(%t) shadow: release failed\n")));
+
+ return result;
+}
+
+int
+ACE_Remote_Token_Proxy::remove (ACE_Synch_Options &)
+{
+ ACE_TRACE ("ACE_Remote_Token_Proxy::remove");
+ return 0;
+}
+
+void
+ACE_Remote_Token_Proxy::token_acquired (ACE_TPQ_Entry *)
+{
+ ACE_TRACE ("ACE_Remote_Token_Proxy::token_acquired");
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("(%t) shadow token %s acquired\n"),
+ this->client_id (),
+ this->name ()));
+ // ACE_Token_Proxy::token_acquired (vp);
+}
+
+const ACE_TCHAR*
+ACE_Remote_Token_Proxy::owner_id (void)
+{
+ ACE_TRACE ("ACE_Remote_Token_Proxy::owner_id");
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("owner_id called\n")));
+ // @@ special operation
+ return 0;
+}
+
+void
+ACE_Remote_Token_Proxy::dump (void) const
+{
+ ACE_TRACE ("ACE_Remote_Token_Proxy::dump");
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("ACE_Tokens::dump:\n")
+ ACE_LIB_TEXT (" ignore_shadow_deadlock_ = %d\n"),
+ ignore_shadow_deadlock_));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("base:\n")));
+ ACE_Token_Proxy::dump ();
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+void
+ACE_Remote_Mutex::dump (void) const
+{
+ ACE_TRACE ("ACE_Remote_Mutex::dump");
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("ACE_Remote_Mutex::dump:\n")));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("base:\n")));
+ ACE_Remote_Token_Proxy::dump ();
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+void
+ACE_Remote_RLock::dump (void) const
+{
+ ACE_TRACE ("ACE_Remote_RLock::dump");
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("ACE_Remote_RLock::dump:\n")));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("base:\n")));
+ ACE_Remote_Token_Proxy::dump ();
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+void
+ACE_Remote_WLock::dump (void) const
+{
+ ACE_TRACE ("ACE_Remote_WLock::dump");
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("ACE_Remote_WLock::dump:\n")));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("base:\n")));
+ ACE_Remote_Token_Proxy::dump ();
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION)
+template class ACE_TSS <ACE_SOCK_Stream>;
+template class ACE_Singleton <ACE_TSS_Connection, ACE_TSS_CONNECTION_MUTEX>;
+#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA)
+#pragma instantiate ACE_TSS <ACE_SOCK_Stream>
+#pragma instantiate ACE_Singleton <ACE_TSS_Connection, ACE_TSS_CONNECTION_MUTEX>
+#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */
+
+#endif /* ACE_HAS_TOKENS_LIBRARY */
diff --git a/ace/Token/Remote_Tokens.h b/ace/Token/Remote_Tokens.h
new file mode 100644
index 00000000000..6ec934027cb
--- /dev/null
+++ b/ace/Token/Remote_Tokens.h
@@ -0,0 +1,316 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Remote_Tokens.h
+ *
+ * $Id$
+ *
+ * @author Douglas C. Schmidt (schmidt@cs.wustl.edu)
+ * @author Tim Harrison (harrison@cs.wustl.edu)
+ */
+//=============================================================================
+
+#ifndef ACE_REMOTE_MUTEX_H
+#define ACE_REMOTE_MUTEX_H
+#include "ace/pre.h"
+
+#include "ace/INET_Addr.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "ace/SOCK_Connector.h"
+#include "ace/SOCK_Stream.h"
+#include "ace/Synch_Options.h"
+#include "ace/Local_Tokens.h"
+#include "ace/Token_Request_Reply.h"
+
+#if defined (ACE_HAS_TOKENS_LIBRARY)
+
+/**
+ * @class ACE_Remote_Token_Proxy
+ *
+ * @brief Proxy for acquiring, renewing, and releasing a distributed
+ * synchronization token.
+ *
+ * The Remote_Token_Proxy class implements the mechanisms for
+ * distributed token operations. It is similar to the
+ * ACE_Token_Proxy.
+ * = BUGS
+ * Distributed sleep_hooks have not been implemented. <owner_id>
+ * is not implemented.
+ */
+class ACE_Export ACE_Remote_Token_Proxy : public ACE_Token_Proxy
+{
+public:
+ /// Null construction.
+ ACE_Remote_Token_Proxy (void);
+
+ /// Death.
+ virtual ~ACE_Remote_Token_Proxy (void);
+
+ /**
+ * Same as Token_Proxy. <name> is the string uniquely identifying
+ * the token. <ignore_deadlock> can be 1 to disable deadlock
+ * notifications. <debug> prints debug messages.
+ */
+ int open (const ACE_TCHAR *name,
+ int ignore_deadlock = 0,
+ int debug = 0);
+
+
+ /**
+ * Open a connection with the token server. This only need be used
+ * when the user wishes to explicitly open a connection to check if
+ * the server exists. Connections are stored in the
+ * ACE_Token_Connections singleton as thread-specific data. That
+ * is, every thread has only one connection that is used for all
+ * remote tokens.
+ */
+ int initiate_connection (void);
+
+ /**
+ * Acquire the distributed token. If notify is specified and the
+ * token is already held, the owner is notified. options contains
+ * the timeout value for the acquire call. The timer is kept at the
+ * token server. Asynchronous operations are not supported.
+ * Returns 0 on success, -1 on failure with <errno> == problem.
+ */
+ virtual int acquire (int notify = 0,
+ void (*sleep_hook)(void *) = 0,
+ ACE_Synch_Options &options =
+ ACE_Synch_Options::synch);
+
+ /**
+ * Try to acquire the distributed token. If the token is already
+ * held, the call returns without queueing the caller as a waiter.
+ * Returns 0 on success (the token was acquired), and -1 with
+ * EWOULDBLOCK if the token was already held.
+ */
+ virtual int tryacquire (void (*sleep_hook)(void *) = 0);
+
+ /**
+ * Renew the token by offering to release it if there are any other
+ * waiters, otherwise get the token back immediately. This renew
+ * has the same semantics as ACE_Local_Mutex release. It is
+ * semantically equivalent to <release> followed by <acquire>, but
+ * it is faster. options contains the timeout value used if renew
+ * blocks. As with acquire, the timer is maintained at the token
+ * server. If there are waiters and requeue_position == -1, the
+ * caller is queued at the rear of the waiter list. Otherwise,
+ * requeue_position specifies the number of waiters to "let by"
+ * before reacquiring the token (effectively, the position in the
+ * waiter list.)
+ */
+ virtual int renew (int requeue_position = 0,
+ ACE_Synch_Options &options =
+ ACE_Synch_Options::synch);
+
+ /**
+ * Release the distributed token. Similar to ACE_Local_Mutex, if the
+ * caller is not the owner, it is removed from the waiter list (if
+ * applicable.) Returns 0 on success, -1 on failure with <errno> ==
+ * problem.
+ */
+ virtual int release (ACE_Synch_Options &options =
+ ACE_Synch_Options::synch);
+
+ /// Become interface compliant for ACE_Guard<>. This has no
+ /// functionality.
+ virtual int remove (ACE_Synch_Options &options =
+ ACE_Synch_Options::synch);
+
+ /// Override the default to do nothing.
+ virtual void token_acquired (ACE_TPQ_Entry *);
+
+ /// the client id of the current token holder
+ virtual const ACE_TCHAR* owner_id (void);
+
+ /**
+ * sets the server address for all instances of ACE_Remote_Token_Proxy
+ * If this isn't called, the environment variable TOKEN_SERVER is
+ * checked for the server address. If that is not specified, all
+ * ACE_Remote_** operations will fail.
+ */
+ static void set_server_address (const ACE_INET_Addr &server_address);
+
+ /// Dump the state of the class.
+ void dump (void) const;
+
+protected:
+
+ /// if shadows report deadlock, go remote anyway
+ int ignore_shadow_deadlock_;
+
+ /// Perform the request and wait for the reply.
+ int request_reply (ACE_Token_Request &request,
+ ACE_Synch_Options &options);
+};
+
+/**
+ * @class ACE_Remote_Mutex
+ *
+ * @brief Proxy for acquiring, renewing, and releasing a distributed
+ * mutex.
+ *
+ * This is the remote equivalent to ACE_Local_Mutex. The
+ * Remote_Mutex class offers methods for acquiring, renewing, and
+ * releasing a distributed synchronization mutex. Similar to
+ * ACE_Local_Mutex, ACE_Remote_Token_Proxy offers recursive
+ * acquisition, FIFO waiter ordering, and deadlock detection. It
+ * depends on the Token Server for its distributed synchronization
+ * semantics.
+ */
+class ACE_Export ACE_Remote_Mutex : public ACE_Remote_Token_Proxy
+{
+public:
+ /// Null creation. Remote_Token_Proxy::open must be called.
+ ACE_Remote_Mutex (void);
+
+ /// Calls Remote_Token_Proxy::open for you.
+ ACE_Remote_Mutex (const ACE_TCHAR *token_name,
+ int ignore_deadlock = 0,
+ int debug = 0);
+
+ /// Dump the state of the class.
+ void dump (void) const;
+
+ /// Return deep copy.
+ virtual ACE_Token_Proxy *clone (void) const;
+
+protected:
+ /// Make the correct type of ACE_Tokens. This is called by the Token
+ /// Manager.
+ virtual ACE_Tokens *create_token (const ACE_TCHAR *name);
+};
+
+/**
+ * @class ACE_Remote_RLock
+ *
+ * @brief Proxy for acquiring, renewing, and releasing a distributed
+ * readers lock.
+ *
+ * This is the remote equivalent to ACE_Local_RLock. Multiple
+ * readers can hold the lock simultaneously when no writers have
+ * the lock. Alternatively, when a writer holds the lock, no other
+ * participants (readers or writers) may hold the lock.
+ * ACE_Remote_RLock depends on the ACE Token Server for its
+ * distributed synchronization semantics.
+ */
+class ACE_Export ACE_Remote_RLock : public ACE_Remote_Token_Proxy
+{
+public:
+ ACE_Remote_RLock (void);
+
+ ACE_Remote_RLock (const ACE_TCHAR *token_name,
+ int ignore_deadlock = 0,
+ int debug = 0);
+
+ ACE_Remote_RLock (const ACE_Remote_RLock &mutex);
+
+ /// Dump the state of the class.
+ void dump (void) const;
+
+ /// Returns ACE_RW_Token::RLOCK;
+ virtual int type (void) const;
+
+ /// Return deep copy.
+ virtual ACE_Token_Proxy *clone (void) const;
+
+protected:
+ /// Make the correct type of ACE_Tokens. This is called by the Token
+ /// Manager.
+ virtual ACE_Tokens *create_token (const ACE_TCHAR *name);
+};
+
+/**
+ * @class ACE_Remote_WLock
+ *
+ * @brief Proxy for acquiring, renewing, and releasing a distributed
+ * writers lock.
+ *
+ * Shields applications from details of interacting with the
+ * ACE_Token_Server. The token_name_ is just the string that the
+ * Token Server uses to identify the token. The client_id_ (also
+ * used by the Token Server,) identifies the owner of the token and
+ * is used for deadlock detection.
+ */
+class ACE_Export ACE_Remote_WLock : public ACE_Remote_Token_Proxy
+{
+public:
+ ACE_Remote_WLock (void);
+
+ ACE_Remote_WLock (const ACE_TCHAR *token_name,
+ int ignore_deadlock = 0,
+ int debug = 0);
+
+ ACE_Remote_WLock (const ACE_Remote_WLock &mutex);
+
+ /// Dump the state of the class.
+ void dump (void) const;
+
+ /// Returns ACE_RW_Token::WLOCK;
+ virtual int type (void) const;
+
+ /// Return deep copy.
+ virtual ACE_Token_Proxy *clone (void) const;
+
+protected:
+ /// Make the correct type of ACE_Tokens. This is called by the Token
+ /// Manager.
+ virtual ACE_Tokens *create_token (const ACE_TCHAR *name);
+};
+
+/**
+ * @class ACE_TSS_Connection
+ *
+ * @brief Class for providing a connection per thread.
+ *
+ * ACE_TSS_Connection provides a single access point for all
+ * threads to access thread-specific connections. This prevents
+ * resource-sharing problems such as thread serialization.
+ */
+class ACE_Export ACE_TSS_Connection : public ACE_TSS<ACE_SOCK_Stream>
+{
+public:
+ // Necessary to make some compilers work...
+ ACE_TSS_Connection (void);
+ ~ACE_TSS_Connection (void);
+
+ /// retrieve the thread's connection
+ ACE_SOCK_Stream *get_connection (void);
+
+ /// Factory Method that creates a new SOCK Stream.
+ virtual ACE_SOCK_Stream *make_TSS_TYPE (void) const;
+
+ /// inheritence and operator overloading don't mix. Redefine this
+ /// from ACE_TSS so that we can use it.
+ operator ACE_SOCK_Stream *(void);
+
+ /// Set the server address.
+ static void set_server_address (const ACE_INET_Addr &server_address);
+
+ /// Dump the state of the class.
+ void dump (void) const;
+
+protected:
+ /// The address of the Token Server used by all instances of
+ /// Token_Proxy.
+ static ACE_INET_Addr server_address_;
+
+private:
+ /// Private: should not be used
+ ACE_TSS_Connection (const ACE_TSS_Connection &);
+ void operator= (const ACE_TSS_Connection &);
+};
+
+#endif /* ACE_HAS_TOKENS_LIBRARY */
+
+#if defined (__ACE_INLINE__)
+#include "ace/Remote_Tokens.i"
+#endif /* __ACE_INLINE__ */
+
+#include "ace/post.h"
+#endif /* ACE_REMOTE_TOKEN_H */
diff --git a/ace/Token/Remote_Tokens.i b/ace/Token/Remote_Tokens.i
new file mode 100644
index 00000000000..f0cc90e5105
--- /dev/null
+++ b/ace/Token/Remote_Tokens.i
@@ -0,0 +1,122 @@
+/* -*- C++ -*- */
+// $Id$
+
+#if defined (ACE_HAS_TOKENS_LIBRARY)
+
+ACE_INLINE
+ACE_Remote_Mutex::ACE_Remote_Mutex (void)
+{
+ ACE_TRACE ("ACE_Remote_Mutex::ACE_Remote_Mutex");
+}
+
+ACE_INLINE
+ACE_Remote_Mutex::ACE_Remote_Mutex (const ACE_TCHAR *token_name,
+ int ignore_deadlock,
+ int debug)
+{
+ ACE_TRACE ("ACE_Remote_Mutex::ACE_Remote_Mutex");
+ this->open (token_name, ignore_deadlock, debug);
+}
+
+ACE_INLINE ACE_Token_Proxy *
+ACE_Remote_Mutex::clone (void) const
+{
+ ACE_Token_Proxy *temp;
+ ACE_NEW_RETURN (temp,
+ ACE_Remote_Mutex (this->name (),
+ ignore_deadlock_,
+ debug_),
+ 0);
+ return temp;
+}
+
+ACE_INLINE ACE_Tokens *
+ACE_Remote_Mutex::create_token (const ACE_TCHAR *name)
+{
+ ACE_Tokens *temp;
+ ACE_NEW_RETURN (temp,
+ ACE_Mutex_Token (name),
+ 0);
+ return temp;
+}
+
+// ************************************************************
+
+ACE_INLINE
+ACE_Remote_RLock::ACE_Remote_RLock (const ACE_TCHAR *token_name,
+ int ignore_deadlock,
+ int debug)
+{
+ ACE_TRACE ("ACE_Remote_RLock::ACE_Remote_RLock");
+ this->open (token_name, ignore_deadlock, debug);
+}
+
+ACE_INLINE ACE_Tokens *
+ACE_Remote_RLock::create_token (const ACE_TCHAR *name)
+{
+ ACE_Tokens *temp = 0;
+ ACE_NEW_RETURN (temp,
+ ACE_RW_Token (name),
+ 0);
+ return temp;
+}
+
+ACE_INLINE int
+ACE_Remote_RLock::type (void) const
+{
+ return ACE_RW_Token::READER;
+}
+
+ACE_INLINE ACE_Token_Proxy *
+ACE_Remote_RLock::clone (void) const
+{
+ ACE_Token_Proxy *temp = 0;
+ ACE_NEW_RETURN (temp,
+ ACE_Remote_RLock (this->name (),
+ ignore_deadlock_,
+ debug_),
+ 0);
+ return temp;
+}
+
+// ************************************************************
+
+ACE_INLINE
+ACE_Remote_WLock::ACE_Remote_WLock (const ACE_TCHAR *token_name,
+ int ignore_deadlock,
+ int debug)
+{
+ ACE_TRACE ("ACE_Remote_WLock::ACE_Remote_WLock");
+ this->open (token_name, ignore_deadlock, debug);
+}
+
+
+ACE_INLINE ACE_Tokens *
+ACE_Remote_WLock::create_token (const ACE_TCHAR *name)
+{
+ ACE_Tokens *temp = 0;
+ ACE_NEW_RETURN (temp,
+ ACE_RW_Token (name),
+ 0);
+ return temp;
+}
+
+ACE_INLINE int
+ACE_Remote_WLock::type (void) const
+{
+ return ACE_RW_Token::WRITER;
+}
+
+ACE_INLINE ACE_Token_Proxy *
+ACE_Remote_WLock::clone (void) const
+{
+ ACE_Token_Proxy *temp = 0;
+ ACE_NEW_RETURN (temp,
+ ACE_Remote_WLock (this->name (),
+ ignore_deadlock_,
+ debug_),
+ 0);
+ return temp;
+}
+
+#endif /* ACE_HAS_TOKENS_LIBRARY */
diff --git a/ace/Token/Token_Collection.cpp b/ace/Token/Token_Collection.cpp
new file mode 100644
index 00000000000..e362d9e2aed
--- /dev/null
+++ b/ace/Token/Token_Collection.cpp
@@ -0,0 +1,302 @@
+// $Id$
+
+#include "ace/Token_Collection.h"
+
+#if !defined (__ACE_INLINE__)
+#include "ace/Token_Collection.i"
+#endif /* __ACE_INLINE__ */
+
+#if defined (ACE_HAS_TOKENS_LIBRARY)
+
+ACE_RCSID(ace, Token_Collection, "$Id$")
+
+ACE_Token_Collection::ACE_Token_Collection (int debug,
+ const ACE_TCHAR *name)
+: debug_ (debug)
+{
+ ACE_TRACE ("ACE_Token_Collection::ACE_Token_Collection");
+
+ if (name == 0)
+ name = ACE_LIB_TEXT ("no name");
+
+ ACE_OS::strsncpy (this->name_,
+ ACE_const_cast (ACE_TCHAR *,
+ name),
+ ACE_MAXTOKENNAMELEN);
+}
+
+int
+ACE_Token_Collection::insert (ACE_Token_Proxy &new_token)
+{
+ ACE_TRACE ("ACE_Token_Collection::insert");
+
+ TOKEN_NAME name (new_token.name ());
+
+ // Check if the new_proxy is already in the list.
+ if (collection_.find (name) == 1)
+ // One already exists, so fail.
+ return -1;
+
+ // Clone the new token.
+ ACE_Token_Proxy *temp = new_token.clone ();
+
+ if (collection_.bind (name, temp) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_LIB_TEXT ("bind failed\n")), -1);
+ return 0;
+}
+
+int
+ACE_Token_Collection::extract (const ACE_TCHAR *token_name, ACE_Token_Proxy *&proxy)
+{
+ ACE_TRACE ("ACE_Token_Collection::extract");
+ TOKEN_NAME name (token_name);
+ return collection_.unbind (token_name, proxy);
+}
+
+ACE_Token_Proxy *
+ACE_Token_Collection::is_member (const ACE_TCHAR *token_name)
+{
+ ACE_TRACE ("ACE_Token_Collection::is_member");
+ TOKEN_NAME name (token_name);
+ ACE_Token_Proxy *temp;
+ // Get the token from the collection.
+ return collection_.find (name, temp) == -1 ? 0 : temp;
+}
+
+int
+ACE_Token_Collection::is_member (const ACE_Token_Proxy &token)
+{
+ ACE_TRACE ("ACE_Token_Collection::is_member");
+ TOKEN_NAME token_name (token.name ());
+ return collection_.find (token_name) == 0;
+}
+
+int
+ACE_Token_Collection::acquire (int notify,
+ void (*sleep_hook)(void *),
+ ACE_Synch_Options &options)
+{
+ ACE_TRACE ("ACE_Token_Collection::acquire");
+
+ COLLECTION_ITERATOR iterator (collection_);
+
+ for (COLLECTION_ENTRY *temp = 0;
+ iterator.next (temp) != 0;
+ iterator.advance ())
+ {
+ if (debug_)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_LIB_TEXT ("collection acquiring %s\n"),
+ temp->int_id_->name ()));
+ if (temp->int_id_->acquire (notify,
+ sleep_hook,
+ options) == -1)
+ {
+ // Save/restore errno.
+ ACE_Errno_Guard error (errno);
+ this->release ();
+ ACE_RETURN (-1);
+ }
+ }
+
+ return 0;
+}
+
+int
+ACE_Token_Collection::acquire (const ACE_TCHAR *token_name,
+ int notify,
+ void (*sleep_hook)(void *),
+ ACE_Synch_Options &options)
+{
+ ACE_TRACE ("ACE_Token_Collection::acquire");
+ TOKEN_NAME name (token_name);
+ ACE_Token_Proxy *temp;
+ // Get the token from the collection.
+ int result = collection_.find (name, temp);
+ // did we find it?
+ if (result == -1)
+ return result;
+ // perform the operation
+ return temp->acquire (notify, sleep_hook, options);
+}
+
+
+int
+ACE_Token_Collection::tryacquire (const ACE_TCHAR *token_name,
+ void (*sleep_hook)(void *))
+{
+ ACE_TRACE ("ACE_Token_Collection::tryacquire");
+ TOKEN_NAME name (token_name);
+ ACE_Token_Proxy *temp;
+ // Get the token from the collection.
+ int result = collection_.find (name, temp);
+ // did we find it?
+ if (result == -1)
+ return result;
+
+ // perform the operation
+ return temp->tryacquire (sleep_hook);
+}
+
+int
+ACE_Token_Collection::tryacquire (void (*sleep_hook)(void *))
+{
+ ACE_TRACE ("ACE_Token_Collection::tryacquire");
+
+ COLLECTION_ITERATOR iterator (collection_);
+
+ for (COLLECTION_ENTRY *temp = 0;
+ iterator.next (temp) != 0;
+ iterator.advance ())
+ {
+ if (debug_)
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("collection acquiring %s\n"),
+ temp->int_id_->name ()));
+ // We will fail if _any_ token is not free.
+ if (temp->int_id_->tryacquire (sleep_hook) == -1)
+ return -1;
+ }
+
+ return 0;
+}
+
+int
+ACE_Token_Collection::renew (int requeue_position,
+ ACE_Synch_Options &options)
+{
+ ACE_TRACE ("ACE_Token_Collection::renew");
+
+ COLLECTION_ITERATOR iterator (collection_);
+
+ for (COLLECTION_ENTRY *temp = 0;
+ iterator.next (temp) != 0;
+ iterator.advance ())
+ {
+ if (debug_)
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("collection renewing %s\n"),
+ temp->int_id_->name ()));
+ if (temp->int_id_->renew (requeue_position, options) == -1)
+ return -1;
+ }
+
+ return 0;
+}
+
+int
+ACE_Token_Collection::renew (const ACE_TCHAR *token_name,
+ int requeue_position,
+ ACE_Synch_Options &options)
+{
+ ACE_TRACE ("ACE_Token_Collection::renew");
+ TOKEN_NAME name (token_name);
+ ACE_Token_Proxy *temp;
+
+ // Get the token from the collection.
+ int result = collection_.find (name, temp);
+
+ // Did we find it?
+ if (result == -1)
+ ACE_ERROR_RETURN ((LM_DEBUG, ACE_LIB_TEXT ("%p %s\n"),
+ ACE_LIB_TEXT ("not in collection "),
+ token_name), -1);
+ // perform the operation
+ return temp->renew (requeue_position, options);
+}
+
+int
+ACE_Token_Collection::release (ACE_Synch_Options &)
+
+{
+ ACE_TRACE ("ACE_Token_Collection::release");
+ COLLECTION_ITERATOR iterator (collection_);
+
+ for (COLLECTION_ENTRY *temp = 0;
+ iterator.next (temp) != 0;
+ iterator.advance ())
+ {
+ if (debug_)
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("collection releasing %s\n"),
+ temp->int_id_->name ()));
+ temp->int_id_->release ();
+ }
+
+ return 0;
+}
+
+int
+ACE_Token_Collection::release (const ACE_TCHAR *token_name,
+ ACE_Synch_Options &options)
+{
+ ACE_TRACE ("ACE_Token_Collection::release");
+ TOKEN_NAME name (token_name);
+ ACE_Token_Proxy *temp;
+ // get the token from the collection
+ int result = collection_.find (name, temp);
+ // did we find it?
+ if (result != 0)
+ return result;
+ // perform the operation
+ return temp->release (options);
+}
+
+ACE_Token_Collection::~ACE_Token_Collection (void)
+{
+ ACE_TRACE ("ACE_Token_Collection::~ACE_Token_Collection");
+ COLLECTION_ITERATOR iterator (collection_);
+
+ for (COLLECTION_ENTRY *temp = 0;
+ iterator.next (temp) != 0;
+ iterator.advance ())
+ {
+ delete temp->int_id_;
+ // The ext_id_'s delete themselves when the array of
+ // COLLECTION_ENTRYs goes away.
+ }
+}
+
+
+// This method doesn't mean anything for a collection.
+ACE_Token_Proxy *
+ACE_Token_Collection::clone (void) const
+{
+ ACE_TRACE ("ACE_Token_Collection::clone");
+ return (ACE_Token_Proxy *) 0;
+}
+
+// This method doesn't mean anything for a collection.
+ACE_Tokens *
+ACE_Token_Collection::create_token (const ACE_TCHAR *)
+{
+ ACE_TRACE ("ACE_Token_Collection::create_token");
+ return (ACE_Tokens *) 0;
+}
+
+void
+ACE_Token_Collection::dump (void) const
+{
+ ACE_TRACE ("ACE_Token_Collection::dump");
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("ACE_Token_Collection::dump:\n")
+ ACE_LIB_TEXT (" debug_ = %d\n"), debug_));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("collection_\n")));
+ collection_.dump ();
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("base:\n")));
+ ACE_Token_Proxy::dump ();
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION)
+template class ACE_Map_Manager<ACE_Token_Name, ACE_Token_Proxy *, ACE_Null_Mutex>;
+template class ACE_Map_Iterator_Base<ACE_Token_Name, ACE_Token_Proxy *, ACE_Null_Mutex>;
+template class ACE_Map_Iterator<ACE_Token_Name, ACE_Token_Proxy *, ACE_Null_Mutex>;
+template class ACE_Map_Reverse_Iterator<ACE_Token_Name, ACE_Token_Proxy *, ACE_Null_Mutex>;
+template class ACE_Map_Entry<ACE_Token_Name, ACE_Token_Proxy *>;
+#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA)
+#pragma instantiate ACE_Map_Manager<ACE_Token_Name, ACE_Token_Proxy *, ACE_Null_Mutex>
+#pragma instantiate ACE_Map_Iterator_Base<ACE_Token_Name, ACE_Token_Proxy *, ACE_Null_Mutex>
+#pragma instantiate ACE_Map_Iterator<ACE_Token_Name, ACE_Token_Proxy *, ACE_Null_Mutex>
+#pragma instantiate ACE_Map_Reverse_Iterator<ACE_Token_Name, ACE_Token_Proxy *, ACE_Null_Mutex>
+#pragma instantiate ACE_Map_Entry<ACE_Token_Name, ACE_Token_Proxy *>
+#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */
+
+#endif /* ACE_HAS_TOKENS_LIBRARY */
diff --git a/ace/Token/Token_Collection.h b/ace/Token/Token_Collection.h
new file mode 100644
index 00000000000..3c6e4297214
--- /dev/null
+++ b/ace/Token/Token_Collection.h
@@ -0,0 +1,234 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Token_Collection.h
+ *
+ * $Id$
+ *
+ * The ACE_Token class offers methods for acquiring, renewing,
+ * and releasing a synchronization token on a per-token basis. The
+ * ACE_Token_Collection offers an interface for performing
+ * operations on groups of tokens as a whole, or on a single token
+ * within the collection.
+ *
+ * The atomic group operations are not yet implemented.
+ *
+ *
+ * @author Douglas C. Schmidt (schmidt@cs.wustl.edu)
+ * @author Tim Harrison (harrison@cs.wustl.edu)
+ */
+//=============================================================================
+
+#ifndef ACE_TOKEN_COLLECTION_H
+#define ACE_TOKEN_COLLECTION_H
+#include "ace/pre.h"
+
+#include "ace/Map_Manager.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "ace/Local_Tokens.h"
+#include "ace/SString.h"
+
+#if defined (ACE_HAS_TOKENS_LIBRARY)
+
+/**
+ * @class ACE_Token_Collection
+ *
+ * @brief Allows atomic token group operations AND
+ * provides a ACE_Token manager interface.
+ *
+ * There are two types of operations offered by
+ * ACE_Token_Collection. The first is atomic operations on
+ * collections of Token_Proxies. In this respect, the
+ * ACE_Token_Collection can be thought of as a single token
+ * consisting of multiple Token_Proxies. The second role of the
+ * ACE_Token_Collection is as a ACE_Token manager.
+ * ACE_Token_Collection allows individual operations on single
+ * members of a collection of Token_Proxies. This provides a
+ * single access point for operations on multiple tokens.
+ */
+class ACE_Export ACE_Token_Collection : public ACE_Token_Proxy
+{
+
+ // = BUGS
+ // Although ACE_Token_Collection inherits from ACE_Token_Proxy, it
+ // can not be including in a collection. This is because <clone>
+ // returns zero for now.
+public:
+ /**
+ * <debug> print out verbose debugging messages. <name> will give a
+ * name to the collection. Collections don't really need names, but
+ * are sometimes useful for debugging.
+ */
+ ACE_Token_Collection (int debug = 0,
+ const ACE_TCHAR *name = 0);
+
+// Collection Management operations
+
+ int insert (ACE_Token_Proxy &token);
+
+ // Insert a Token into the collection. All ACE_Token type
+ // operations performed on the collection will also be performed on
+ // the new_proxy until it is removed. Note that no operations
+ // performed prior to the insertion will be performed. Returns: 0
+ // on success, -1 on failure with <errno> == problem. If a token
+ // proxy already exists in the collection with the same name, the
+ // insertion will fail. Also, <token> is copied. Note that during
+ // the copy, client_id's are *not* inherited. The client ID of the
+ // thread using the collection will be used. Client ID's can be
+ // changed explicity on each proxy using is_member.
+
+ /**
+ * removes the ACE_Token matching the given token_name from the
+ * collection. On success, extract returns 0. On failure
+ * (token_name was not in the collection,) extract returns -1. On
+ * success, the state of the token found is copied into proxy.
+ * The returned ACE_Token_Proxy* must be deleted by the user.
+ */
+ int extract (const ACE_TCHAR *token_name, ACE_Token_Proxy *&proxy);
+
+ /// returns the proxy if true. 0 otherwise.
+ ACE_Token_Proxy *is_member (const ACE_TCHAR *token_name);
+
+ /**
+ * Is the specified token in the collection?
+ * 1, yes.
+ * 0, no.
+ */
+ int is_member (const ACE_Token_Proxy &token);
+
+// = Collective operation semantics.
+
+// For acquire, renew, and release, there are two interfaces. Once
+// interface allows an operation on a single token in the
+// collection. The collective interfaces perform atomic operations
+// on the entire collection. For instance, a collective acquire
+// will perform an acquire for each and every token in the
+// collection or the operation will fail. Currently, these
+// operations are performed with no ordering heuristics. That is,
+// the Collection steps through the tokens in the order they were
+// inserted. For each one it performs the operation (acquire,
+// renew, or release).
+
+ /**
+ * Acquire "atomically" all resources in the collection. This is
+ * only successfull if all tokens in the collection could be
+ * acquired. options contains the blocking semantics, timeout
+ * value, etc. Returns: 0 on success, -1 on failure with <errno> ==
+ * problem. If and error or deadlock occurs for one of the tokens,
+ * all the tokens will be released and the method will return -1.
+ * Note that returning on detection of deadlock prevents livelock
+ * between competing collections. If a collection returns after
+ * detecting deadlock, it is the application's responsibility to not
+ * to blindly loop on the collection::acquire operation. In other
+ * words, once the collection reports deadlock, it is out of our
+ * hands.
+ */
+ virtual int acquire (int notify = 0,
+ void (*sleep_hook)(void *) = 0,
+ ACE_Synch_Options &options =
+ ACE_Synch_Options::defaults);
+
+ /// Acquire the token corresponding to <token_name>. The other
+ /// parameters are passed to <token>::acquire.
+ virtual int acquire (const ACE_TCHAR *token_name,
+ int notify = 0,
+ void (*sleep_hook)(void *) = 0,
+ ACE_Synch_Options &options =
+ ACE_Synch_Options::defaults);
+
+ /// Try to acquire all tokens in collection.
+ virtual int tryacquire (void (*sleep_hook)(void *) = 0);
+
+ /// Try to acquire <token_name>.
+ virtual int tryacquire (const ACE_TCHAR *token_name,
+ void (*sleep_hook)(void *) = 0);
+
+ /**
+ * Renews "atomically" all resources in the collection. This is
+ * only successfull if all tokens in the collection could be
+ * renewed. options contains the blocking semantics, timeout
+ * value, etc. Returns: 0 on success, -1 on failure with <errno> ==
+ * problem.
+ */
+ virtual int renew (int requeue_position = 0,
+ ACE_Synch_Options &options =
+ ACE_Synch_Options::defaults);
+
+
+ /// Renew the token corresponding to <token_name>. The other
+ /// parameters are passed to <token>::renew.
+ virtual int renew (const ACE_TCHAR *token_name,
+ int requeue_position = 0,
+ ACE_Synch_Options &options =
+ ACE_Synch_Options::defaults);
+
+ /**
+ * Releases "atomically" all resources in the collection. This is
+ * only successfull if all tokens in the collection could be
+ * released. options contains the blocking semantics, timeout
+ * value, etc. Returns: 0 on success, -1 on failure with <errno> ==
+ * problem.
+ */
+ virtual int release (ACE_Synch_Options &options =
+ ACE_Synch_Options::defaults);
+
+
+ /// Release the token corresponding to <token_name>. The other
+ /// parameters are passed to <token>::release.
+ virtual int release (const ACE_TCHAR *token_name,
+ ACE_Synch_Options &options =
+ ACE_Synch_Options::defaults);
+
+ ~ACE_Token_Collection (void);
+
+ /// Dump the state of the class.
+ void dump (void) const;
+
+ /// Return the name of the collection. Not very functionally
+ /// important, but sometimes a useful debugging tool.
+ virtual const ACE_TCHAR *name (void) const;
+
+protected:
+
+ typedef ACE_Token_Name TOKEN_NAME;
+
+ /// COLLECTION maintains a mapping from token names to ACE_Tokens*
+ typedef ACE_Map_Manager<TOKEN_NAME, ACE_Token_Proxy *, ACE_Null_Mutex>
+ COLLECTION;
+
+ /// Allows iterations through collection_
+ typedef ACE_Map_Iterator<TOKEN_NAME, ACE_Token_Proxy *, ACE_Null_Mutex>
+ COLLECTION_ITERATOR;
+
+ /// Allows iterations through collection_
+ typedef ACE_Map_Entry<TOKEN_NAME, ACE_Token_Proxy *>
+ COLLECTION_ENTRY;
+
+ /// COLLECTION maintains a mapping from token names to ACE_Tokens*.
+ COLLECTION collection_;
+
+ /// Whether to print out debug messages or not.
+ int debug_;
+
+ /// Name of the collection.
+ ACE_TCHAR name_[ACE_MAXTOKENNAMELEN];
+
+ // = I'm not sure what these mean, but they have to be defined since they're
+ // pure virtual in ACE_Token_Proxy.
+ virtual ACE_Token_Proxy *clone (void) const;
+ virtual ACE_Tokens *create_token (const ACE_TCHAR *name);
+};
+
+#endif /* ACE_HAS_TOKENS_LIBRARY */
+
+#if defined (__ACE_INLINE__)
+#include "ace/Token_Collection.i"
+#endif /* __ACE_INLINE__ */
+
+#include "ace/post.h"
+#endif /* ACE_TOKEN_COLLECTION_H */
diff --git a/ace/Token/Token_Collection.i b/ace/Token/Token_Collection.i
new file mode 100644
index 00000000000..fcab4df9b09
--- /dev/null
+++ b/ace/Token/Token_Collection.i
@@ -0,0 +1,12 @@
+/* -*- C++ -*- */
+// $Id$
+
+#if defined (ACE_HAS_TOKENS_LIBRARY)
+
+ACE_INLINE const ACE_TCHAR *
+ACE_Token_Collection::name (void) const
+{
+ return name_;
+}
+
+#endif /* ACE_HAS_TOKENS_LIBRARY */
diff --git a/ace/Token/Token_Invariants.cpp b/ace/Token/Token_Invariants.cpp
new file mode 100644
index 00000000000..e709e1ea65b
--- /dev/null
+++ b/ace/Token/Token_Invariants.cpp
@@ -0,0 +1,368 @@
+// $Id$
+
+#include "ace/Token_Invariants.h"
+#include "ace/Object_Manager.h"
+
+#if defined (ACE_HAS_TOKENS_LIBRARY)
+
+ACE_RCSID(ace, Token_Invariants, "$Id$")
+
+ACE_Token_Invariant_Manager *ACE_Token_Invariant_Manager::instance_ = 0;
+
+ACE_Token_Invariant_Manager *
+ACE_Token_Invariant_Manager::instance (void)
+{
+ ACE_TRACE ("ACE_Token_Invariant_Manager::instance");
+
+ // Perform the Double-Check pattern...
+ if (instance_ == 0)
+ {
+ ACE_MT (ACE_TOKEN_CONST::MUTEX *lock =
+ ACE_Managed_Object<ACE_TOKEN_CONST::MUTEX>::get_preallocated_object
+ (ACE_Object_Manager::ACE_TOKEN_INVARIANTS_CREATION_LOCK);
+ ACE_GUARD_RETURN (ACE_TOKEN_CONST::MUTEX, ace_mon, *lock, 0));
+
+ if (instance_ == 0)
+ {
+ ACE_NEW_RETURN (instance_,
+ ACE_Token_Invariant_Manager,
+ 0);
+ // Register for destruction with ACE_Object_Manager.
+ ACE_Object_Manager::at_exit (instance_);
+ }
+ }
+
+ return instance_;
+}
+
+ACE_Token_Invariant_Manager::ACE_Token_Invariant_Manager (void)
+{
+ ACE_TRACE ("ACE_Token_Invariant_Manager::ACE_Token_Invariant_Manager");
+}
+
+int
+ACE_Token_Invariant_Manager::mutex_acquired (const ACE_TCHAR *token_name)
+{
+ ACE_TRACE ("ACE_Token_Invariant_Manager::mutex_acquired");
+
+ ACE_GUARD_RETURN (ACE_TOKEN_CONST::MUTEX, ace_mon, this->lock_, -1);
+
+ ACE_Mutex_Invariants *inv = 0;
+ if (this->get_mutex (token_name, inv) == -1)
+ return -1;
+
+ return inv->acquired ();
+}
+
+int
+ACE_Token_Invariant_Manager::acquired (const ACE_Token_Proxy *proxy)
+{
+ ACE_TRACE ("ACE_Token_Invariant_Manager::acquired");
+
+ // Reach into the proxy to find the token type.
+ if (proxy->token_->type () == ACE_Tokens::MUTEX)
+ return this->mutex_acquired (proxy->name ());
+ else // ACE_Tokens::RWLOCK.
+ {
+ if (proxy->type () == ACE_RW_Token::READER)
+ return this->reader_acquired (proxy->name ());
+ else // ACE_RW_Token::WRITER.
+ return this->writer_acquired (proxy->name ());
+ }
+}
+
+void
+ACE_Token_Invariant_Manager::releasing (const ACE_Token_Proxy *proxy)
+{
+ ACE_TRACE ("ACE_Token_Invariant_Manager::releasing");
+
+ // Reach into the proxy to find the token type.
+ if (proxy->token_->type () == ACE_Tokens::MUTEX)
+ this->mutex_releasing (proxy->name ());
+ else // ACE_Tokens::RWLOCK.
+ this->rwlock_releasing (proxy->name ());
+}
+
+void
+ACE_Token_Invariant_Manager::mutex_releasing (const ACE_TCHAR *token_name)
+{
+ ACE_TRACE ("ACE_Token_Invariant_Manager::mutex_releasing");
+ ACE_GUARD (ACE_TOKEN_CONST::MUTEX, ace_mon, this->lock_);
+
+ ACE_Mutex_Invariants *inv = 0;
+ if (this->get_mutex (token_name, inv) == 0)
+ inv->releasing ();
+}
+
+int
+ACE_Token_Invariant_Manager::reader_acquired (const ACE_TCHAR *token_name)
+{
+ ACE_TRACE ("ACE_Token_Invariant_Manager::reader_acquired");
+ ACE_GUARD_RETURN (ACE_TOKEN_CONST::MUTEX, ace_mon, this->lock_, -1);
+
+ ACE_RWLock_Invariants *inv = 0;
+ if (this->get_rwlock (token_name, inv) == -1)
+ return -1;
+
+ return inv->reader_acquired ();
+}
+
+int
+ACE_Token_Invariant_Manager::writer_acquired (const ACE_TCHAR *token_name)
+{
+ ACE_TRACE ("ACE_Token_Invariant_Manager::writer_acquired");
+
+ ACE_GUARD_RETURN (ACE_TOKEN_CONST::MUTEX, ace_mon, this->lock_, -1);
+
+ ACE_RWLock_Invariants *inv = 0;
+ if (this->get_rwlock (token_name, inv) == -1)
+ return -1;
+
+ return inv->writer_acquired ();
+}
+
+void
+ACE_Token_Invariant_Manager::rwlock_releasing (const ACE_TCHAR *token_name)
+{
+ ACE_TRACE ("ACE_Token_Invariant_Manager::rwlock_releasing");
+
+ ACE_GUARD (ACE_TOKEN_CONST::MUTEX, ace_mon, this->lock_);
+
+ ACE_RWLock_Invariants *inv = 0;
+ if (this->get_rwlock (token_name, inv) == 0)
+ inv->releasing ();
+}
+
+void
+ACE_Token_Invariant_Manager::dump (void) const
+{
+ ACE_TRACE ("ACE_Token_Invariant_Manager::dump");
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("mutex_collection_:\n")));
+ mutex_collection_.dump ();
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("rwlock_collection_:\n")));
+ rwlock_collection_.dump ();
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+
+int
+ACE_Token_Invariant_Manager::get_mutex (const ACE_TCHAR *token_name,
+ ACE_Mutex_Invariants *&inv)
+{
+ ACE_TRACE ("ACE_Token_Invariant_Manager::get_mutex");
+ TOKEN_NAME name (token_name);
+ if (mutex_collection_.find (name, inv) == -1)
+ // We did not find one in the collection.
+ {
+ ACE_Mutex_Invariants *new_invariant;
+
+ ACE_NEW_RETURN (new_invariant,
+ ACE_Mutex_Invariants,
+ -1);
+ if (mutex_collection_.bind (name, new_invariant) == -1)
+ {
+ delete new_invariant;
+ return -1;
+ }
+
+ if (mutex_collection_.find (name, inv) == -1)
+ // We did not find one in the collection.
+ return -1;
+ }
+
+ return 0;
+}
+
+int
+ACE_Token_Invariant_Manager::get_rwlock (const ACE_TCHAR *token_name,
+ ACE_RWLock_Invariants *&inv)
+{
+ ACE_TRACE ("ACE_Token_Invariant_Manager::get_rwlock");
+ TOKEN_NAME name (token_name);
+ if (rwlock_collection_.find (name, inv) == -1)
+ // We did not find one in the collection.
+ {
+ ACE_RWLock_Invariants *new_invariant;
+
+ ACE_NEW_RETURN (new_invariant,
+ ACE_RWLock_Invariants,
+ -1);
+ if (rwlock_collection_.bind (name, new_invariant) == -1)
+ return -1;
+
+ if (rwlock_collection_.find (name, inv) == -1)
+ // We did not find one in the collection.
+ return -1;
+ }
+
+ return 0;
+}
+
+
+ACE_Token_Invariant_Manager::~ACE_Token_Invariant_Manager (void)
+{
+ ACE_TRACE ("ACE_Token_Invariant_Manager::~ACE_Token_Invariant_Manager");
+ MUTEX_COLLECTION_ITERATOR iterator (mutex_collection_);
+
+ for (MUTEX_COLLECTION_ENTRY *temp = 0;
+ iterator.next (temp) != 0;
+ iterator.advance ())
+ delete temp->int_id_;
+
+ RWLOCK_COLLECTION_ITERATOR iterator2 (rwlock_collection_);
+
+ for (RWLOCK_COLLECTION_ENTRY *temp2 = 0;
+ iterator2.next (temp2) != 0;
+ iterator2.advance ())
+ delete temp2->int_id_;
+}
+
+// **************************************************
+// **************************************************
+// **************************************************
+
+ACE_Mutex_Invariants::ACE_Mutex_Invariants (void)
+: owners_ (0)
+{
+}
+
+int
+ACE_Mutex_Invariants::acquired (void)
+{
+ if (++owners_ > 1)
+ {
+ owners_ = 42;
+ return 0;
+ }
+ else
+ return 1;
+}
+
+void
+ACE_Mutex_Invariants::releasing (void)
+{
+ if (owners_ == 1)
+ --owners_;
+}
+
+ACE_Mutex_Invariants::ACE_Mutex_Invariants (const ACE_Mutex_Invariants &rhs)
+: owners_ (rhs.owners_)
+{
+}
+
+void
+ACE_Mutex_Invariants::operator= (const ACE_Mutex_Invariants &rhs)
+{
+ owners_ = rhs.owners_;
+}
+
+void
+ACE_Mutex_Invariants::dump (void) const
+{
+ ACE_TRACE ("ACE_Mutex_Invariants::dump");
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("owners_ = %d\n"), owners_));
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+// **************************************************
+// **************************************************
+// **************************************************
+
+ACE_RWLock_Invariants::ACE_RWLock_Invariants (void)
+: writers_ (0),
+ readers_ (0)
+{
+}
+
+int
+ACE_RWLock_Invariants::writer_acquired (void)
+{
+ if (readers_ > 0)
+ {
+ writers_ = readers_ = 42;
+ return 0;
+ }
+ else if (++writers_ > 1)
+ {
+ writers_ = readers_ = 42;
+ return 0;
+ }
+ else
+ return 1;
+}
+
+int
+ACE_RWLock_Invariants::reader_acquired (void)
+{
+ if (writers_ > 0)
+ {
+ writers_ = readers_ = 42;
+ return 0;
+ }
+ else
+ {
+ ++readers_;
+ return 1;
+ }
+}
+
+void
+ACE_RWLock_Invariants::releasing (void)
+{
+ if (writers_ == 1)
+ writers_ = 0;
+ else if (readers_ > 0)
+ --readers_;
+}
+
+ACE_RWLock_Invariants::ACE_RWLock_Invariants (const ACE_RWLock_Invariants &rhs)
+: writers_ (rhs.writers_),
+ readers_ (rhs.readers_)
+{
+}
+
+void
+ACE_RWLock_Invariants::operator= (const ACE_RWLock_Invariants &rhs)
+{
+ writers_ = rhs.writers_;
+ readers_ = rhs.readers_;
+}
+
+void
+ACE_RWLock_Invariants::dump (void) const
+{
+ ACE_TRACE ("ACE_RWLock_Invariants::dump");
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("writers_ = %d\n"),
+ "readers_ = %d\n",
+ writers_, readers_));
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION)
+template class ACE_Map_Manager<ACE_Token_Name, ACE_Mutex_Invariants *, ACE_Null_Mutex>;
+template class ACE_Map_Iterator_Base<ACE_Token_Name, ACE_Mutex_Invariants *, ACE_Null_Mutex>;
+template class ACE_Map_Iterator<ACE_Token_Name, ACE_Mutex_Invariants *, ACE_Null_Mutex>;
+template class ACE_Map_Reverse_Iterator<ACE_Token_Name, ACE_Mutex_Invariants *, ACE_Null_Mutex>;
+template class ACE_Map_Entry<ACE_Token_Name, ACE_Mutex_Invariants *>;
+template class ACE_Map_Manager<ACE_Token_Name, ACE_RWLock_Invariants *, ACE_Null_Mutex>;
+template class ACE_Map_Iterator_Base<ACE_Token_Name, ACE_RWLock_Invariants *, ACE_Null_Mutex>;
+template class ACE_Map_Iterator<ACE_Token_Name, ACE_RWLock_Invariants *, ACE_Null_Mutex>;
+template class ACE_Map_Reverse_Iterator<ACE_Token_Name, ACE_RWLock_Invariants *, ACE_Null_Mutex>;
+template class ACE_Map_Entry<ACE_Token_Name, ACE_RWLock_Invariants *>;
+#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA)
+#pragma instantiate ACE_Map_Manager<ACE_Token_Name, ACE_Mutex_Invariants *, ACE_Null_Mutex>
+#pragma instantiate ACE_Map_Iterator_Base<ACE_Token_Name, ACE_Mutex_Invariants *, ACE_Null_Mutex>
+#pragma instantiate ACE_Map_Iterator<ACE_Token_Name, ACE_Mutex_Invariants *, ACE_Null_Mutex>
+#pragma instantiate ACE_Map_Reverse_Iterator<ACE_Token_Name, ACE_Mutex_Invariants *, ACE_Null_Mutex>
+#pragma instantiate ACE_Map_Entry<ACE_Token_Name, ACE_Mutex_Invariants *>
+#pragma instantiate ACE_Map_Manager<ACE_Token_Name, ACE_RWLock_Invariants *, ACE_Null_Mutex>
+#pragma instantiate ACE_Map_Iterator_Base<ACE_Token_Name, ACE_RWLock_Invariants *, ACE_Null_Mutex>
+#pragma instantiate ACE_Map_Iterator<ACE_Token_Name, ACE_RWLock_Invariants *, ACE_Null_Mutex>
+#pragma instantiate ACE_Map_Reverse_Iterator<ACE_Token_Name, ACE_RWLock_Invariants *, ACE_Null_Mutex>
+#pragma instantiate ACE_Map_Entry<ACE_Token_Name, ACE_RWLock_Invariants *>
+#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */
+
+#endif /* ACE_HAS_TOKENS_LIBRARY */
diff --git a/ace/Token/Token_Invariants.h b/ace/Token/Token_Invariants.h
new file mode 100644
index 00000000000..e5c10ebaed6
--- /dev/null
+++ b/ace/Token/Token_Invariants.h
@@ -0,0 +1,228 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Token_Invariants.h
+ *
+ * $Id$
+ *
+ * @author Tim Harrison (harrison@cs.wustl.edu)
+ *
+ * Allows applications to test that invariants are always
+ * satisfied. Can test mutexes and readers/writer locks. Does
+ * not test recursive acquisition.
+ *
+ *
+ */
+//=============================================================================
+
+#ifndef ACE_TOKEN_INVARIANTS_H
+#define ACE_TOKEN_INVARIANTS_H
+#include "ace/pre.h"
+
+#include "ace/Synch.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "ace/Map_Manager.h"
+#include "ace/Local_Tokens.h"
+
+#if defined (ACE_HAS_TOKENS_LIBRARY)
+
+/**
+ * @class ACE_Mutex_Invariants
+ *
+ * @brief Mutex Invariants
+ * = INVARIANTS
+ * 1. Only one owner at a time.
+ */
+class ACE_Export ACE_Mutex_Invariants
+{
+public:
+ /// Default construction.
+ ACE_Mutex_Invariants (void);
+
+ /// Returns 1 on success, 0 when an invariant has been violated and
+ /// -1 on error.
+ int acquired (void);
+
+ /// Updates internal database.
+ void releasing (void);
+
+ // = Map_Manager operations.
+
+ /// Copy construction.
+ ACE_Mutex_Invariants (const ACE_Mutex_Invariants &rhs);
+
+ /// Copy.
+ void operator= (const ACE_Mutex_Invariants &rhs);
+
+ /// Dump the state of the class.
+ void dump (void) const;
+
+private:
+ /// Number of owners. This had better be 0 >= owners_ <= 1;
+ int owners_;
+};
+
+/**
+ * @class ACE_RWLock_Invariants
+ *
+ * @brief RWLock Invariants
+ *
+ * Preserve the following invariants:
+ * -# Only one writer at a time.
+ * -# If there is an owning writer, there are no owning readers.
+ */
+class ACE_Export ACE_RWLock_Invariants
+{
+public:
+ /// Default construction.
+ ACE_RWLock_Invariants (void);
+
+ /// Returns 1 on success, 0 when an invariant has been violated and
+ /// -1 on error.
+ int writer_acquired (void);
+
+ /// Returns 1 on success, 0 when an invariant has been violated and
+ /// -1 on error.
+ int reader_acquired (void);
+
+ /// Updates internal database.
+ void releasing (void);
+
+ // = Map_Manager operations.
+
+ /// Copy construction.
+ ACE_RWLock_Invariants (const ACE_RWLock_Invariants &rhs);
+
+ /// Copy.
+ void operator= (const ACE_RWLock_Invariants &rhs);
+
+ /// Dump the state of the class.
+ void dump (void) const;
+
+private:
+ /// Number of owning writers.
+ int writers_;
+
+ /// Number of owning readers.
+ int readers_;
+};
+
+/**
+ * @class ACE_Token_Invariant_Manager
+ *
+ * @brief Token Invariants
+ *
+ * The Token Invariant Manager allows applications to test that
+ * invariants are always satisfied. Currently, Token_Invariants
+ * can test mutexes and readers/writer locks. Does not test
+ * recursive acquisition.
+ * Note that this class does not ever clean its database. Until
+ * destroyed, it's size will forever increase.
+ */
+class ACE_Export ACE_Token_Invariant_Manager : public ACE_Cleanup
+{
+public:
+
+ /// Singleton access point.
+ static ACE_Token_Invariant_Manager *instance (void);
+
+ // = Polymorphic methods. Just pass in the proxy and the method
+ // figures out the type of the token.
+
+ /// Returns 1 on success, 0 when an invariant has been violated and
+ /// -1 on error.
+ int acquired (const ACE_Token_Proxy *proxy);
+
+ /// Updates internal database.
+ void releasing (const ACE_Token_Proxy *proxy);
+
+ // = Explicit methods. These to not require actual proxies in order
+ // to test a scenario.
+
+ /// Returns 1 on success, 0 when an invariant has been violated and
+ /// -1 on error.
+ int mutex_acquired (const ACE_TCHAR *token_name);
+
+ /// Updates internal database.
+ void mutex_releasing (const ACE_TCHAR *token_name);
+
+ /// Returns 1 on success, 0 when an invariant has been violated and
+ /// -1 on error.
+ int reader_acquired (const ACE_TCHAR *token_name);
+
+ /// Returns 1 on success, 0 when an invariant has been violated and
+ /// -1 on error.
+ int writer_acquired (const ACE_TCHAR *token_name);
+
+ /// Updates internal database.
+ void rwlock_releasing (const ACE_TCHAR *token_name);
+
+ /// Dump the state of the class.
+ void dump (void) const;
+
+ // = The following two method should be in the protected part of the
+ // class. Bugs with certain compilers preclude this.
+ /// Prevent non-singleton construction.
+ ACE_Token_Invariant_Manager (void);
+
+ /// Destruction.
+ virtual ~ACE_Token_Invariant_Manager (void);
+
+protected:
+ /// Return or create.
+ int get_mutex (const ACE_TCHAR *token_name,
+ ACE_Mutex_Invariants *&inv);
+
+ /// Return or create.
+ int get_rwlock (const ACE_TCHAR *token_name,
+ ACE_RWLock_Invariants *&inv);
+
+ /// ACE_Mutex_Token used to lock internal data structures.
+ ACE_TOKEN_CONST::MUTEX lock_;
+
+ /// This may be changed to a template type.
+ typedef ACE_Token_Name TOKEN_NAME;
+
+ /// COLLECTION maintains a mapping from token names to mutexes.
+ typedef ACE_Map_Manager<TOKEN_NAME, ACE_Mutex_Invariants *, ACE_Null_Mutex>
+ MUTEX_COLLECTION;
+
+ /// Allows iterations through collection.
+ typedef ACE_Map_Iterator<TOKEN_NAME, ACE_Mutex_Invariants *, ACE_Null_Mutex>
+ MUTEX_COLLECTION_ITERATOR;
+
+ /// Allows iterations through collection.
+ typedef ACE_Map_Entry<TOKEN_NAME, ACE_Mutex_Invariants *>
+ MUTEX_COLLECTION_ENTRY;
+
+ /// MUTEX_COLLECTION maintains a mapping from token names to mutexes.
+ MUTEX_COLLECTION mutex_collection_;
+
+ /// COLLECTION maintains a mapping from token names to mutexes.
+ typedef ACE_Map_Manager<TOKEN_NAME, ACE_RWLock_Invariants *, ACE_Null_Mutex>
+ RWLOCK_COLLECTION;
+
+ /// Allows iterations through collection.
+ typedef ACE_Map_Iterator<TOKEN_NAME, ACE_RWLock_Invariants *, ACE_Null_Mutex>
+ RWLOCK_COLLECTION_ITERATOR;
+
+ /// Allows iterations through collection.
+ typedef ACE_Map_Entry<TOKEN_NAME, ACE_RWLock_Invariants *>
+ RWLOCK_COLLECTION_ENTRY;
+
+ /// MUTEX_COLLECTION maintains a mapping from token names to mutexes.
+ RWLOCK_COLLECTION rwlock_collection_;
+
+ /// Singleton pointer.
+ static ACE_Token_Invariant_Manager *instance_;
+};
+
+#endif /* ACE_HAS_TOKENS_LIBRARY */
+
+#include "ace/post.h"
+#endif /* ACE_TOKEN_INVARIANTS_H */
diff --git a/ace/Token/Token_Manager.cpp b/ace/Token/Token_Manager.cpp
new file mode 100644
index 00000000000..13e21c361fc
--- /dev/null
+++ b/ace/Token/Token_Manager.cpp
@@ -0,0 +1,280 @@
+// $Id$
+
+#include "ace/Token_Manager.h"
+#include "ace/Object_Manager.h"
+
+#if !defined (__ACE_INLINE__)
+#include "ace/Token_Manager.i"
+#endif /* __ACE_INLINE__ */
+
+#if defined (ACE_HAS_TOKENS_LIBRARY)
+
+ACE_RCSID(ace, Token_Manager, "$Id$")
+
+// singleton token manager
+ACE_Token_Manager *ACE_Token_Manager::token_manager_ = 0;
+
+ACE_Token_Manager::ACE_Token_Manager ()
+{
+ ACE_TRACE ("ACE_Token_Manager::ACE_Token_Manager");
+}
+
+ACE_Token_Manager::~ACE_Token_Manager ()
+{
+ ACE_TRACE ("ACE_Token_Manager::~ACE_Token_Manager");
+
+ COLLECTION_ITERATOR iterator (collection_);
+
+ for (COLLECTION_ENTRY *temp = 0;
+ iterator.next (temp) != 0;
+ iterator.advance ())
+ {
+ // @ should I be doing an unbind here?
+ delete temp->int_id_;
+ // The ext_id_'s delete themselves when the array of
+ // COLLECTION_ENTRYs goes away.
+ }
+}
+
+ACE_Token_Manager *
+ACE_Token_Manager::instance (void)
+{
+ ACE_TRACE ("ACE_Token_Manager::instance");
+
+ // This first check is to avoid acquiring the mutex in the common
+ // case. Double-Check pattern rules.
+ if (token_manager_ == 0)
+ {
+#if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0)
+ ACE_TOKEN_CONST::MUTEX *lock =
+ ACE_Managed_Object<ACE_TOKEN_CONST::MUTEX>::get_preallocated_object
+ (ACE_Object_Manager::ACE_TOKEN_MANAGER_CREATION_LOCK);
+ ACE_GUARD_RETURN (ACE_TOKEN_CONST::MUTEX, ace_mon, *lock, 0);
+#endif /* ACE_MT_SAFE */
+
+ if (token_manager_ == 0)
+ {
+ ACE_NEW_RETURN (token_manager_,
+ ACE_Token_Manager,
+ 0);
+ // Register for destruction with ACE_Object_Manager.
+ ACE_Object_Manager::at_exit (token_manager_);
+ }
+ }
+
+ return token_manager_;
+}
+
+void
+ACE_Token_Manager::get_token (ACE_Token_Proxy *proxy,
+ const ACE_TCHAR *token_name)
+{
+ ACE_TRACE ("ACE_Token_Manager::get_token");
+ // Hmm. I think this makes sense. We perform our own locking here
+ // (see safe_acquire.) We have to make sure that only one thread
+ // uses the collection at a time.
+
+ ACE_GUARD (ACE_TOKEN_CONST::MUTEX, ace_mon, this->lock_);
+
+ TOKEN_NAME name (token_name);
+
+ if (collection_.find (name, proxy->token_) == -1)
+ // We did not find one in the collection.
+ {
+ // Make one.
+ proxy->token_ = proxy->create_token (token_name);
+
+ // Put it in the collection.
+ if (collection_.bind (name, proxy->token_) == -1)
+ {
+ delete proxy->token_;
+ proxy->token_ = 0;
+ }
+ }
+
+ if (proxy->token_ != 0)
+ proxy->token_->inc_reference ();
+
+ // We may be returning proxy->token_ == 0 if new failed, caller must
+ // check.
+}
+
+// 0. check_deadlock (TOKEN)
+// 1. if TOKEN->visited (), return 0.
+// 2. mark TOKEN visited.
+// 3. get ALL_OWNERS
+// 4. if CLIENT in ALL_OWNERS, return *DEADLOCK*.
+// 5. for each OWNER in ALL_OWNERS,
+// 6. if OWNER is not waiting for a NEW_TOKEN, continue.
+// 7. else, if check_deadlock (NEW_TOKEN) == 1, return *DEADLOCK*
+// 8. return 0.
+
+int
+ACE_Token_Manager::check_deadlock (ACE_Token_Proxy *proxy)
+{
+ ACE_TRACE ("ACE_Token_Manager::check_deadlock");
+
+ // Start the recursive deadlock detection algorithm.
+ int result = this->check_deadlock (proxy->token_, proxy);
+
+ // Whether or not we detect deadlock, we have to unmark all tokens
+ // for the next time.
+ COLLECTION_ITERATOR iterator (collection_);
+ for (COLLECTION_ENTRY *temp = 0;
+ iterator.next (temp) != 0;
+ iterator.advance ())
+ temp->int_id_->visit (0);
+
+ return result;
+}
+
+int
+ACE_Token_Manager::check_deadlock (ACE_Tokens *token, ACE_Token_Proxy *proxy)
+{
+ ACE_TRACE ("ACE_Token_Manager::check_deadlock");
+
+ if (token->visited ())
+ return 0;
+
+ token->visit (1);
+
+ ACE_Tokens::OWNER_STACK owners;
+
+ int is_owner = token->owners (owners, proxy->client_id ());
+
+ switch (is_owner)
+ {
+ case -1:
+ // Error.
+ return -1;
+ case 1:
+ // The caller is an owner, so we have a deadlock situation.
+ if (debug_)
+ {
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("(%t) Deadlock detected.\n")));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("%s owns %s and is waiting for %s.\n"),
+ proxy->client_id (),
+ token->name (),
+ proxy->token_->name ()));
+ }
+
+ return 1;
+ case 0:
+ default:
+ // Recurse on each owner.
+ while (!owners.is_empty ())
+ {
+ ACE_TPQ_Entry *e;
+ owners.pop (e);
+ // If the owner is waiting on another token, recurse.
+ ACE_Tokens *twf = this->token_waiting_for (e->client_id ());
+ if ((twf != 0) &&
+ (this->check_deadlock (twf, proxy) == 1))
+ {
+ if (debug_)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_LIB_TEXT ("%s owns %s and is waiting for %s.\n"),
+ e->client_id (),
+ token->name (),
+ twf->name ()));
+ }
+ return 1;
+ }
+ // else, check the next owner.
+ }
+
+ // We've checked all the owners and found no deadlock.
+ return 0;
+ }
+}
+
+
+ACE_Tokens *
+ACE_Token_Manager::token_waiting_for (const ACE_TCHAR *client_id)
+{
+ COLLECTION_ITERATOR iterator (collection_);
+ for (COLLECTION_ENTRY *temp = 0;
+ iterator.next (temp) != 0;
+ iterator.advance ())
+ {
+ if (temp->int_id_->is_waiting_for (client_id))
+ return temp->int_id_;
+ }
+
+ // nothing was found, return NULL.
+ return 0;
+}
+
+// Notify the token manager that a token is has been released. If
+// as a result, there is no owner of the token, the token is
+// deleted.
+void
+ACE_Token_Manager::release_token (ACE_Tokens *&token)
+{
+ ACE_TRACE ("ACE_Token_Manager::release_token");
+ // again, let's perform our own locking here.
+
+ ACE_GUARD (ACE_TOKEN_CONST::MUTEX, ace_mon, this->lock_);
+
+ if (token->dec_reference () == 0)
+ {
+ // No one has the token, so we can delete it and remove it from
+ // our collection. First, let's get it from the collection.
+ TOKEN_NAME token_name (token->name ());
+
+ ACE_Tokens *temp;
+
+ if (collection_.unbind (token_name, temp) == -1)
+ // we did not find one in the collection
+ {
+ errno = ENOENT;
+ ACE_ERROR ((LM_ERROR, ACE_LIB_TEXT ("Token Manager could not release %s:%d\n"),
+ token->name (), token->type ()));
+ // @@ bad
+ }
+ else
+ // we found it
+ {
+ // sanity pointer comparison. The token referenced by the
+ // proxy better be the one we found in the list.
+ ACE_ASSERT (token == temp);
+ delete token; // or delete temp
+ // we set their token to zero. if the calling proxy is
+ // still going to be used, it had better check it's token
+ // value before calling a method on it!
+ token = 0;
+ }
+ }
+ // else
+ // someone is still interested in the token, so keep it around.
+}
+
+void
+ACE_Token_Manager::dump (void) const
+{
+ ACE_TRACE ("ACE_Token_Manager::dump");
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("ACE_Token_Manager::dump:\n")));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("lock_\n")));
+ lock_.dump ();
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("collection_\n")));
+ collection_.dump ();
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION)
+template class ACE_Map_Manager <ACE_Token_Name, ACE_Tokens *, ACE_Null_Mutex>;
+template class ACE_Map_Iterator_Base<ACE_Token_Name, ACE_Tokens *, ACE_Null_Mutex>;
+template class ACE_Map_Iterator<ACE_Token_Name, ACE_Tokens *, ACE_Null_Mutex>;
+template class ACE_Map_Reverse_Iterator<ACE_Token_Name, ACE_Tokens *, ACE_Null_Mutex>;
+template class ACE_Map_Entry <ACE_Token_Name, ACE_Tokens *>;
+#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA)
+#pragma instantiate ACE_Map_Manager <ACE_Token_Name, ACE_Tokens *, ACE_Null_Mutex>
+#pragma instantiate ACE_Map_Iterator_Base<ACE_Token_Name, ACE_Tokens *, ACE_Null_Mutex>
+#pragma instantiate ACE_Map_Iterator<ACE_Token_Name, ACE_Tokens *, ACE_Null_Mutex>
+#pragma instantiate ACE_Map_Reverse_Iterator<ACE_Token_Name, ACE_Tokens *, ACE_Null_Mutex>
+#pragma instantiate ACE_Map_Entry <ACE_Token_Name, ACE_Tokens *>
+#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */
+
+#endif /* ACE_HAS_TOKENS_LIBRARY */
diff --git a/ace/Token/Token_Manager.h b/ace/Token/Token_Manager.h
new file mode 100644
index 00000000000..aec44e08ae3
--- /dev/null
+++ b/ace/Token/Token_Manager.h
@@ -0,0 +1,135 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Token_Manager.h
+ *
+ * $Id$
+ *
+ * @author Tim Harrison (harrison@cs.wustl.edu)
+ */
+//=============================================================================
+
+#ifndef ACE_TOKEN_MANAGER_H
+#define ACE_TOKEN_MANAGER_H
+#include "ace/pre.h"
+
+#include "ace/Synch.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "ace/Map_Manager.h"
+#include "ace/Local_Tokens.h"
+
+#if defined (ACE_HAS_TOKENS_LIBRARY)
+
+class ACE_Local_Mutex;
+class ACE_Mutex_Token;
+
+/**
+ * @class ACE_Token_Manager
+ *
+ * @brief Manages all tokens in a process space.
+ *
+ * Factory: Proxies use the token manager to obtain token
+ * references. This allows multiple proxies to reference the same
+ * logical token.
+ * Deadlock detection: Tokens use the manager to check for
+ * deadlock situations during acquires.
+ */
+class ACE_Export ACE_Token_Manager : public ACE_Cleanup
+{
+
+ // To add a new type of token (e.g. semaphore), do the following
+ // steps: 1. Create a new derivation of ACE_Token. This class
+ // defines the semantics of the new Token. 2. Create a
+ // derivation of ACE_Token_Manager. You will only need to
+ // redefine make_mutex.
+public:
+ ACE_Token_Manager (void);
+ virtual ~ACE_Token_Manager (void);
+
+ // Set/get a pointer to token manager singleton.
+ static ACE_Token_Manager *instance (void);
+ void instance (ACE_Token_Manager *);
+
+ /**
+ * The Token manager uses ACE_Token_Proxy::token_id_ to look for
+ * an existing token. If none is found, the Token Manager calls
+ * ACE_Token_Proxy::create_token to create a new one. When
+ * finished, sets ACE_Token_Proxy::token_. <token_name> uniquely
+ * id's the token name.
+ */
+ void get_token (ACE_Token_Proxy *, const ACE_TCHAR *token_name);
+
+ /**
+ * returns 1 if the acquire will _not_ cause deadlock.
+ * returns 0 if the acquire _will_ cause deadlock.
+ * this method ignores recursive acquisition. That is, it will not
+ * report deadlock if the client holding the token requests the
+ * token again. Thus, it assumes recursive mutexes.
+ */
+ int check_deadlock (ACE_Token_Proxy *proxy);
+ int check_deadlock (ACE_Tokens *token, ACE_Token_Proxy *proxy);
+
+ /// notify the token manager that a token has been released. If as a
+ /// result, there is no owner of the token, the token is deleted.
+ void release_token (ACE_Tokens *&token);
+
+ /**
+ * This is to allow Tokens to perform atomic transactions. The
+ * typical usage is to acquire this mutex, check for a safe_acquire,
+ * perform some queueing (if need be) and then release the lock.
+ * This is necessary since safe_acquire is implemented in terms of
+ * the Token queues.
+ */
+ ACE_TOKEN_CONST::MUTEX &mutex (void);
+
+ /// Dump the state of the class.
+ void dump (void) const;
+
+ /// Turn debug mode on/off.
+ void debug (int d);
+
+private:
+ /// Whether to print debug messages or not.
+ int debug_;
+
+ /// pointer to singleton token manager.
+ static ACE_Token_Manager *token_manager_;
+
+ /// return the token that the given client_id is waiting for, if any
+ ACE_Tokens *token_waiting_for (const ACE_TCHAR *client_id);
+
+ /// ACE_Mutex_Token used to lock internal data structures.
+ ACE_TOKEN_CONST::MUTEX lock_;
+
+ /// This may be changed to a template type.
+ typedef ACE_Token_Name TOKEN_NAME;
+
+ /// COLLECTION maintains a mapping from token names to ACE_Tokens*
+ typedef ACE_Map_Manager<TOKEN_NAME, ACE_Tokens *, ACE_Null_Mutex>
+ COLLECTION;
+
+ /// Allows iterations through collection_
+ typedef ACE_Map_Iterator<TOKEN_NAME, ACE_Tokens *, ACE_Null_Mutex>
+ COLLECTION_ITERATOR;
+
+ /// Allows iterations through collection_
+ typedef ACE_Map_Entry<TOKEN_NAME, ACE_Tokens *>
+ COLLECTION_ENTRY;
+
+ /// COLLECTION maintains a mapping from token names to ACE_Tokens*.
+ COLLECTION collection_;
+};
+
+#endif /* ACE_HAS_TOKENS_LIBRARY */
+
+#if defined (__ACE_INLINE__)
+#include "ace/Token_Manager.i"
+#endif /* __ACE_INLINE__ */
+
+#include "ace/post.h"
+#endif /* ACE_TOKEN_MANAGER_H */
diff --git a/ace/Token/Token_Manager.i b/ace/Token/Token_Manager.i
new file mode 100644
index 00000000000..2ef2d7e1f53
--- /dev/null
+++ b/ace/Token/Token_Manager.i
@@ -0,0 +1,20 @@
+/* -*- C++ -*- */
+// $Id$
+
+#if defined (ACE_HAS_TOKENS_LIBRARY)
+
+ACE_INLINE ACE_TOKEN_CONST::MUTEX &
+ACE_Token_Manager::mutex (void)
+{
+ ACE_TRACE ("ACE_Token_Manager::mutex");
+ return lock_;
+}
+
+ACE_INLINE void
+ACE_Token_Manager::debug (int d)
+{
+ ACE_TRACE ("ACE_Token_Manager::debug");
+ debug_ = d;
+}
+
+#endif /* ACE_HAS_TOKENS_LIBRARY */
diff --git a/ace/Token/Token_Request_Reply.cpp b/ace/Token/Token_Request_Reply.cpp
new file mode 100644
index 00000000000..9fecb01e443
--- /dev/null
+++ b/ace/Token/Token_Request_Reply.cpp
@@ -0,0 +1,178 @@
+// $Id$
+
+#include "ace/Token_Request_Reply.h"
+
+#if !defined (__ACE_INLINE__)
+#include "ace/Token_Request_Reply.i"
+#endif /* __ACE_INLINE__ */
+
+#if defined (ACE_HAS_TOKENS_LIBRARY)
+
+ACE_RCSID(ace, Token_Request_Reply, "$Id$")
+
+// Default "do nothing" constructor.
+
+ACE_Token_Request::ACE_Token_Request (void)
+ : token_name_ (0),
+ client_id_ (0)
+{
+}
+
+// Create a ACE_Token_Request message.
+
+ACE_Token_Request::ACE_Token_Request (int token_type,
+ int proxy_type,
+ ACE_UINT32 operation_type,
+ const ACE_TCHAR token_name[],
+ const ACE_TCHAR client_id[],
+ const ACE_Synch_Options &options)
+{
+ this->token_type (token_type);
+ this->proxy_type (proxy_type);
+ this->operation_type (operation_type);
+ this->requeue_position (0); // to avoid Purify UMR
+ this->notify (0); // to avoid Purify UMR
+ transfer_.arg_ = 0; // to avoid Purify UMR
+ ACE_OS::memset (transfer_.data_, 0, sizeof transfer_.data_); // to avoid Purify UMR
+ this->token_name (token_name, client_id);
+ this->options (options);
+}
+
+// Encode the transfer buffer into network byte order
+// so that it can be sent to the server.
+
+int
+ACE_Token_Request::encode (void *&buf)
+{
+ buf = (void *) &this->transfer_;
+ return this->length ();
+}
+
+// Decode the transfer buffer into host byte byte order
+// so that it can be used by the server.
+
+int
+ACE_Token_Request::decode (void)
+{
+ this->token_name_ = this->transfer_.data_;
+
+ options_.set (transfer_.use_timeout_ == 1 ? ACE_Synch_Options::USE_TIMEOUT : 0,
+ ACE_Time_Value (transfer_.sec_, transfer_.usec_),
+ (void *) transfer_.arg_);
+
+ // Decode the variable-sized portion.
+ int token_len = ACE_OS::strlen (this->token_name_);
+
+ // Check to make sure this->tokenName_ isn't too long!
+ if (token_len >= ACE_MAXTOKENNAMELEN)
+ {
+ errno = ENAMETOOLONG;
+ return -1;
+ }
+ else // Skip this->tokenName_ + '\0' + ':'.
+ this->client_id_ =
+ &this->token_name_[(token_len + 2) * sizeof (ACE_TCHAR)];
+
+ // Fixed size header
+ // token_name_ plus '\0'
+ // ':'
+ // client_id_ plus '\0'
+ size_t data_size = ACE_TOKEN_REQUEST_HEADER_SIZE
+ + ACE_OS::strlen (this->token_name_) + 1
+ + ACE_OS::strlen (this->client_id_) + 1
+ + 1;
+
+ // Make sure the message was correctly received and framed.
+ return this->length () == data_size ? 0 : -1;
+}
+
+// Print out the current values of the ACE_Token_Request.
+
+void
+ACE_Token_Request::dump (void) const
+{
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("*******\nlength = %d\ntoken name = %s\nclient id = %s\n"),
+ this->length (), this->token_name (), this->client_id ()));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("type = ")));
+
+ if (this->token_type () == ACE_Tokens::MUTEX)
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("MUTEX\n")));
+ else // == ACE_Tokens::RWLOCK
+ {
+ if (this->proxy_type () == ACE_RW_Token::READER)
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("RLOCK\n")));
+ else // == WRITER
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("WLOCK\n")));
+ }
+
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("operation = ")));
+ switch (this->operation_type ())
+ {
+ case ACE_Token_Request::ACQUIRE:
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("ACQUIRE\n")));
+ break;
+ case ACE_Token_Request::RELEASE:
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("RELEASE\n")));
+ break;
+ case ACE_Token_Request::RENEW:
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("RENEW\n")));
+ break;
+ default:
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("<unknown operation type> = %d\n"), this->operation_type ()));
+ break;
+ }
+
+ if (this->options ()[ACE_Synch_Options::USE_TIMEOUT] == 0)
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("blocking forever\n")));
+ else
+ {
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("waiting for %d secs and %d usecs\n"),
+ this->options ().timeout ().sec (), this->options ().timeout ().usec ()));
+ }
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+// ************************************************************
+// ************************************************************
+// ************************************************************
+
+// Create a ACE_Token_Reply message.
+
+ACE_Token_Reply::ACE_Token_Reply (void) // Type of reply.
+{
+ this->arg (0);
+ this->errnum (0);
+ this->length (sizeof (Transfer));
+}
+
+// Encode the transfer buffer into network byte order
+// so that it can be sent to the client.
+
+int
+ACE_Token_Reply::encode (void *&buf)
+{
+ buf = (void *) &this->transfer_;
+ return this->length ();
+}
+
+// Decode the transfer buffer into host byte order
+// so that it can be used by the client.
+
+int
+ACE_Token_Reply::decode (void)
+{
+ return 0;
+}
+
+// Print out current values of the ACE_Token_Reply object.
+
+void
+ACE_Token_Reply::dump (void) const
+{
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("*******\nlength = %d\nerrnum = %d"),
+ this->length (), this->errnum ()));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("arg = %d"), this->arg ()));
+}
+
+#endif /* ACE_HAS_TOKENS_LIBRARY */
diff --git a/ace/Token/Token_Request_Reply.h b/ace/Token/Token_Request_Reply.h
new file mode 100644
index 00000000000..1c3aa88d09c
--- /dev/null
+++ b/ace/Token/Token_Request_Reply.h
@@ -0,0 +1,247 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Token_Request_Reply.h
+ *
+ * $Id$
+ *
+ * Define the format used to exchange messages between the
+ * ACE_Token Server and its clients.
+ *
+ *
+ * @author Douglas C. Schmidt (schmidt@cs.wustl.edu)
+ * @author Tim Harrison (harrison@cs.wustl.edu)
+ */
+//=============================================================================
+
+
+#ifndef ACE_TOKEN_REQUEST_REPLY_H
+#define ACE_TOKEN_REQUEST_REPLY_H
+#include "ace/pre.h"
+
+#include "ace/Local_Tokens.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "ace/Time_Value.h"
+
+#if defined (ACE_HAS_TOKENS_LIBRARY)
+
+// Specifies the size of the fixed length portion of
+// the Transfer structure in ACE_Token_Request
+#define ACE_TOKEN_REQUEST_HEADER_SIZE 40
+
+/**
+ * @class ACE_Token_Request
+ *
+ * @brief Message format for delivering requests to the ACE_Token Server.
+ *
+ * This class is implemented to minimize data copying.
+ * In particular, all marshaling is done in situ...
+ */
+class ACE_Export ACE_Token_Request
+{
+public:
+ /// Operation types.
+ enum OPERATION
+ {
+ /// Acquire the token.
+ ACQUIRE,
+ /// Release the token.
+ RELEASE,
+ /// Renew the token.
+ RENEW,
+ /// Remove the token.
+ REMOVE,
+ // Try to acquire the token.
+ TRY_ACQUIRE
+ };
+
+ /// Default constructor.
+ ACE_Token_Request (void);
+
+ /**
+ * token_type - MUTEX, RWLOCK
+ * proxy_type - MUTEX, RLOCK, WLOCK (acquires mean different things)
+ * operation - method
+ * token_name
+ * client_id
+ * options - we check USE_TIMEOUT and use the arg.
+ */
+ ACE_Token_Request (int token_type,
+ int proxy_type,
+ ACE_UINT32 operation,
+ const ACE_TCHAR token_name[],
+ const ACE_TCHAR client_id[],
+ const ACE_Synch_Options &options);
+
+ // = Set/get the length of the encoded/decoded message.
+ ACE_UINT32 length (void) const;
+ void length (ACE_UINT32);
+
+ // = Set/get the type of proxy
+ int proxy_type (void) const;
+ void proxy_type (int proxy_type);
+
+ // = Set/get the type of token
+ int token_type (void) const;
+ void token_type (int token_type);
+
+ // = Set/get the type of the operation.
+ ACE_UINT32 operation_type (void) const;
+ void operation_type (ACE_UINT32);
+
+ // = Set/get the requeue position. These should be used when renew
+ // is the operation type.
+ ACE_UINT32 requeue_position (void) const;
+ void requeue_position (ACE_UINT32);
+
+ // = Set/get notify. These should be used when acquire is the operation type.
+ ACE_UINT32 notify (void) const;
+ void notify (ACE_UINT32);
+
+ // = Set/get the timeout.
+ ACE_Synch_Options &options (void) const;
+ void options (const ACE_Synch_Options &options);
+
+ // = Set/get the name of the token and the client id. The set
+ // method is combined to make it easier on us. We're copying the
+ // names as a contiguous buffer.
+ ACE_TCHAR *token_name (void) const;
+ ACE_TCHAR *client_id (void) const;
+ void token_name (const ACE_TCHAR *token_name, const ACE_TCHAR *client_id);
+
+ /// Encode the message before transmission.
+ int encode (void *&);
+
+ /// Decode message after reception. This must be called to set the
+ /// internal options.
+ int decode (void);
+
+ /// Print out the values of the message for debugging purposes.
+ void dump (void) const;
+
+private:
+ // = The 5 fields in the <Transfer> struct are transmitted to the server.
+ // The remaining 2 fields are not tranferred -- they are used only on
+ // the server-side to simplify lookups.
+
+ struct Transfer
+ {
+ ACE_UINT32 length_;
+ // Length of entire request.
+
+ ACE_UINT32 token_type_;
+ // Type of the request (i.e., MUTEX, RLOCK, WLOCK...
+
+ ACE_UINT32 proxy_type_;
+ // Type of the request (i.e., MUTEX, RLOCK, WLOCK...
+
+ ACE_UINT32 operation_type_;
+ // Type of the request (i.e., <ACQUIRE>, <RELEASE>, <RENEW>, and <REMOVE>).
+
+ ACE_UINT32 requeue_position_;
+ // this only makes sense when operation type is renew
+
+ ACE_UINT32 notify_;
+ // this only makes sense when operation type is renew
+
+ // = ACE_Synch_Options stuff
+
+ ACE_UINT32 use_timeout_;
+ // Indicates if we should block forever. If 1, then <secTimeout_>
+ // and <usecTimeout_> indicates how long we should wait. If 0,
+ // then we block forever.
+
+ ACE_UINT32 sec_;
+ // Max seconds willing to wait for token if not blocking forever.
+
+ ACE_UINT32 usec_;
+ // Max micro seconds to wait for token if not blocking forever.
+
+ ACE_UINT32 arg_;
+ // value returned in <Token_Reply::arg>;
+
+ ACE_TCHAR data_[ACE_MAXTOKENNAMELEN + ACE_MAXCLIENTIDLEN + 3];
+ // The data portion contains the <tokenName_> including a 0 terminator,
+ // a ':', then the <clientId> including a 0 terminator
+ } transfer_;
+
+ /// Pointer to the beginning of the token name in this->data_.
+ ACE_TCHAR *token_name_;
+
+ /// Pointer to the beginning of the client id in this->data_;
+ ACE_TCHAR *client_id_;
+
+ /// Holds arg, sec, usec, etc.
+ ACE_Synch_Options options_;
+};
+
+/**
+ * @class ACE_Token_Reply
+ *
+ * @brief Message format for delivering replies from the ACE_Token Server.
+ *
+ * This class is implemented to minimize data copying.
+ * In particular, all marshaling is done in situ...
+ */
+class ACE_Export ACE_Token_Reply
+{
+public:
+ /// Default constructor.
+ ACE_Token_Reply (void);
+
+ // = Set/get the length of the encoded/decoded message.
+ ACE_UINT32 length (void) const;
+ void length (ACE_UINT32);
+
+ // = Set/get the errno of a reply.
+ ACE_UINT32 errnum (void) const;
+ void errnum (ACE_UINT32);
+
+ // = Set/get the arg of a reply.
+ ACE_UINT32 arg (void) const;
+ void arg (ACE_UINT32);
+
+ /// Encode the message before transfer.
+ int encode (void *&);
+
+ /// Decode a message after reception.
+ int decode (void);
+
+ /// Print out the values of the message for debugging purposes.
+ void dump (void) const;
+
+private:
+ // = The 2 fields in the <Transfer> struct are transmitted to the server.
+
+ struct Transfer
+ {
+ ACE_UINT32 length_;
+ // Length of entire reply.
+
+ ACE_UINT32 errno_;
+ // Indicates why error occurred if <this->type_> == <FAILURE>.
+ // Typical reasons include:
+ // <EWOULDBLOCK> (if client requested a non-blocking check for the token).
+ // <ETIME> (if the client timed out after waiting for the token).
+ // <ENOLCK> (if the token lock was removed out from underneath a waiter).
+ // <EACCES> (attempt to renew a token that isn't owned by the client).
+
+ ACE_UINT32 arg_;
+ // magic cookie
+
+ } transfer_;
+};
+
+#endif /* ACE_HAS_TOKENS_LIBRARY */
+
+#if defined (__ACE_INLINE__)
+#include "ace/Token_Request_Reply.i"
+#endif /* __ACE_INLINE__ */
+
+#include "ace/post.h"
+#endif /* ACE_TOKEN_REQUEST_REPLY_H */
diff --git a/ace/Token/Token_Request_Reply.i b/ace/Token/Token_Request_Reply.i
new file mode 100644
index 00000000000..e1c8ace3ad5
--- /dev/null
+++ b/ace/Token/Token_Request_Reply.i
@@ -0,0 +1,196 @@
+/* -*- C++ -*- */
+// $Id$
+
+#if defined (ACE_HAS_TOKENS_LIBRARY)
+
+// = Set/get the length of the encoded/decoded message.
+
+ACE_INLINE ACE_UINT32
+ACE_Token_Request::length (void) const
+{
+ return ntohl (this->transfer_.length_);
+}
+
+ACE_INLINE void
+ACE_Token_Request::length (ACE_UINT32 l)
+{
+ this->transfer_.length_ = htonl (l);
+}
+
+// = Set/get the type of the message.
+ACE_INLINE int
+ACE_Token_Request::token_type (void) const
+{
+ return (int) ntohl (this->transfer_.token_type_);
+}
+
+ACE_INLINE void
+ACE_Token_Request::token_type (int t)
+{
+ this->transfer_.token_type_ = htonl ((ACE_UINT32) t);
+}
+
+// = Set/get the type of the message.
+ACE_INLINE int
+ACE_Token_Request::proxy_type (void) const
+{
+ return (int) ntohl (this->transfer_.proxy_type_);
+}
+
+ACE_INLINE void
+ACE_Token_Request::proxy_type (int t)
+{
+ this->transfer_.proxy_type_ = htonl ((ACE_UINT32) t);
+}
+
+// = Set/get the type of the message.
+ACE_INLINE ACE_UINT32
+ACE_Token_Request::operation_type (void) const
+{
+ return ntohl (this->transfer_.operation_type_);
+}
+
+ACE_INLINE void
+ACE_Token_Request::operation_type (ACE_UINT32 t)
+{
+ this->transfer_.operation_type_ = htonl (t);
+}
+
+// = Set/get the requeue position
+ACE_INLINE ACE_UINT32
+ACE_Token_Request::requeue_position (void) const
+{
+ return ntohl (this->transfer_.requeue_position_);
+}
+
+ACE_INLINE void
+ACE_Token_Request::requeue_position (ACE_UINT32 rq)
+{
+ this->transfer_.requeue_position_ = htonl (rq);
+}
+
+// = Set/get the requeue position
+ACE_INLINE ACE_UINT32
+ACE_Token_Request::notify (void) const
+{
+ return ntohl (this->transfer_.notify_);
+}
+
+ACE_INLINE void
+ACE_Token_Request::notify (ACE_UINT32 rq)
+{
+ this->transfer_.notify_ = htonl (rq);
+}
+
+// = Set/get the blocking semantics.
+ACE_INLINE ACE_Synch_Options &
+ACE_Token_Request::options (void) const
+{
+ return (ACE_Synch_Options &) options_;
+}
+
+ACE_INLINE void
+ACE_Token_Request::options (const ACE_Synch_Options &opt)
+{
+ // fight the friggin const from hell
+ ACE_Synch_Options *options = (ACE_Synch_Options *) &opt;
+
+ transfer_.use_timeout_ = options->operator[](ACE_Synch_Options::USE_TIMEOUT);
+ if (transfer_.use_timeout_ == 1)
+ {
+ transfer_.usec_ = options->timeout ().usec ();
+ transfer_.sec_ = options->timeout ().sec ();
+ }
+ else
+ {
+ transfer_.usec_ = 0;
+ transfer_.sec_ = 0;
+ }
+}
+
+// = Set/get the name of the token.
+ACE_INLINE ACE_TCHAR *
+ACE_Token_Request::token_name (void) const
+{
+ return token_name_;
+}
+
+ACE_INLINE void
+ACE_Token_Request::token_name (const ACE_TCHAR *token_name,
+ const ACE_TCHAR *client_id)
+{
+ size_t token_name_length = ACE_OS::strlen (token_name) + 1; // Add 1 for '\0'.
+ size_t client_id_length = ACE_OS::strlen (client_id) + 1; // Add 1 for '\0'.
+
+ // Set up pointers and copy token_name and client_id into request.
+ token_name_ = this->transfer_.data_;
+ client_id_ = &this->token_name_[token_name_length + 1]; // Add 1 for ':';
+ client_id_[-1] = ACE_LIB_TEXT (':'); // Insert the ':' before this->clientId_.
+
+ (void) ACE_OS::memcpy (this->token_name_,
+ token_name,
+ token_name_length * sizeof (ACE_TCHAR));
+ (void) ACE_OS::memcpy (this->client_id_,
+ client_id,
+ client_id_length * sizeof (ACE_TCHAR));
+
+ // Fixed length header size
+ size_t len = ACE_TOKEN_REQUEST_HEADER_SIZE;
+
+ // ... then add in the amount of the variable-sized portion.
+ len += token_name_length + client_id_length + 1;
+
+ this->length (len);
+}
+
+// = Set/get the id of the client.
+ACE_INLINE ACE_TCHAR *
+ACE_Token_Request::client_id (void) const
+{
+ return this->client_id_;
+}
+
+// ************************************************************
+// ************************************************************
+// ************************************************************
+
+// = Set/get the length of the encoded/decoded message.
+ACE_INLINE ACE_UINT32
+ACE_Token_Reply::length (void) const
+{
+ return ntohl (this->transfer_.length_);
+}
+
+ACE_INLINE void
+ACE_Token_Reply::length (ACE_UINT32 l)
+{
+ this->transfer_.length_ = htonl (l);
+}
+
+// = Set/get the errno of a failed reply.
+ACE_INLINE ACE_UINT32
+ACE_Token_Reply::errnum (void) const
+{
+ return ntohl (this->transfer_.errno_);
+}
+
+ACE_INLINE void
+ACE_Token_Reply::errnum (ACE_UINT32 e)
+{
+ this->transfer_.errno_ = htonl (e);
+}
+
+// = Set/get the length of the encoded/decoded message.
+ACE_INLINE ACE_UINT32
+ACE_Token_Reply::arg (void) const
+{
+ return ntohl (this->transfer_.arg_);
+}
+
+ACE_INLINE void
+ACE_Token_Reply::arg (ACE_UINT32 arg)
+{
+ this->transfer_.arg_ = htonl (arg);
+}
+
+#endif /* ACE_HAS_TOKENS_LIBRARY */
diff --git a/ace/Utils/ARGV.cpp b/ace/Utils/ARGV.cpp
new file mode 100644
index 00000000000..8fb4668518d
--- /dev/null
+++ b/ace/Utils/ARGV.cpp
@@ -0,0 +1,344 @@
+// ARGV.cpp
+// $Id$
+
+// Transforms a string BUF into an ARGV-style vector of strings.
+
+#include "ace/ARGV.h"
+#include "ace/Log_Msg.h"
+
+#if !defined (__ACE_INLINE__)
+#include "ace/ARGV.i"
+#endif /* __ACE_INLINE__ */
+
+ACE_RCSID(ace, ARGV, "$Id$")
+
+ACE_ALLOC_HOOK_DEFINE (ACE_ARGV)
+
+void
+ACE_ARGV::dump (void) const
+{
+ ACE_TRACE ("ACE_ARGV::dump");
+
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("argc_ = %d"), this->argc_));
+
+ ACE_ARGV *this_obj = ACE_const_cast (ACE_ARGV *, this);
+
+ for (size_t i = 0; i < this->argc_; i++)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_LIB_TEXT ("\nargv_[%i] = %s"),
+ i,
+ this_obj->argv ()[i]));
+
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\nbuf = %s\n"), this->buf_));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\n")));
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+// Creates this->argv_ out of this->buf_. New memory is allocated for
+// each element of the array. This is used by the array-to-string
+// style constructor and for creating this->argv_ when in iterative
+// mode.
+
+int
+ACE_ARGV::string_to_argv (void)
+{
+ ACE_TRACE ("ACE_ARGV::string_to_argv");
+
+ return ACE_OS::string_to_argv (this->buf_,
+ this->argc_,
+ this->argv_,
+ this->substitute_env_args_);
+}
+
+int
+ACE_ARGV::argv_to_string (ACE_TCHAR **argv, ACE_TCHAR *&buf)
+{
+ return ACE_OS::argv_to_string (argv, buf);
+}
+
+ACE_ARGV::ACE_ARGV (const ACE_TCHAR buf[],
+ int substitute_env_args)
+ : substitute_env_args_ (substitute_env_args),
+ state_ (TO_PTR_ARRAY),
+ argc_ (0),
+ argv_ (0),
+ buf_ (0),
+ length_ (0),
+ queue_ ()
+{
+ ACE_TRACE ("ACE_ARGV::ACE_ARGV ACE_TCHAR[] to ACE_TCHAR *[]");
+
+ if (buf == 0 || buf[0] == 0)
+ return;
+
+ // Make an internal copy of the string.
+ ACE_NEW (this->buf_,
+ ACE_TCHAR[ACE_OS::strlen (buf) + 1]);
+ ACE_OS::strcpy (this->buf_, buf);
+
+ // Create this->argv_.
+ if (this->string_to_argv () == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("%p\n"),
+ ACE_LIB_TEXT ("string_to_argv")));
+}
+
+ACE_ARGV::ACE_ARGV (ACE_TCHAR *argv[],
+ int substitute_env_args)
+ : substitute_env_args_ (substitute_env_args),
+ state_ (TO_STRING),
+ argc_ (0),
+ argv_ (0),
+ buf_ (0),
+ length_ (0),
+ queue_ ()
+{
+ ACE_TRACE ("ACE_ARGV::ACE_ARGV ACE_TCHAR*[] to ACE_TCHAR[]");
+
+ if (argv == 0 || argv[0] == 0)
+ return;
+
+ int buf_len = 0;
+
+ // Determine the length of the buffer.
+
+ for (int i = 0; argv[i] != 0; i++)
+ {
+#if !defined (ACE_LACKS_ENV)
+ ACE_TCHAR *temp = 0;
+
+ // Account for environment variables.
+ if (this->substitute_env_args_
+ && (argv[i][0] == '$'
+ && (temp = ACE_OS::getenv (&argv[i][1])) != 0))
+ buf_len += ACE_OS::strlen (temp);
+ else
+#endif /* !ACE_LACKS_ENV */
+ buf_len += ACE_OS::strlen (argv[i]);
+
+ // Add one for the extra space between each string.
+ buf_len++;
+ }
+
+ // Step through all argv params and copy each one into buf; separate
+ // each param with white space.
+
+ ACE_NEW (this->buf_,
+ ACE_TCHAR[buf_len + 1]);
+
+ ACE_TCHAR *end = this->buf_;
+ int j;
+
+ for (j = 0; argv[j] != 0; j++)
+ {
+#if !defined (ACE_LACKS_ENV)
+ ACE_TCHAR *temp = 0;
+
+ // Account for environment variables.
+ if (this->substitute_env_args_
+ && (argv[j][0] == '$'
+ && (temp = ACE_OS::getenv (&argv[j][1])) != 0))
+ end = ACE_OS::strecpy (end, temp);
+ else
+#endif /* ACE_LACKS_ENV */
+ end = ACE_OS::strecpy (end, argv[j]);
+
+ // Replace the null char that strecpy copies with white space as
+ // a separator.
+ *(end - 1) = ACE_LIB_TEXT (' ');
+ }
+
+ // Remember how many arguments there are
+ this->argc_ = j;
+
+ // Null terminate the string.
+ *end = '\0';
+}
+
+ACE_ARGV::ACE_ARGV (ACE_TCHAR *first_argv[],
+ ACE_TCHAR *second_argv[],
+ int substitute_env_args)
+ : substitute_env_args_ (substitute_env_args),
+ state_ (TO_STRING),
+ argc_ (0),
+ argv_ (0),
+ buf_ (0),
+ length_ (0),
+ queue_ ()
+{
+ ACE_TRACE ("ACE_ARGV::ACE_ARGV ACE_TCHAR*[] + ACE_TCHAR *[] to ACE_TCHAR[]");
+
+ int first_argc;
+ int second_argc;
+
+ ACE_TCHAR *first_buf;
+ ACE_TCHAR *second_buf;
+
+ // convert the first argv to a string
+ first_argc = this->argv_to_string (first_argv,first_buf);
+
+ // convert the second argv to a string
+ second_argc = this->argv_to_string (second_argv,second_buf);
+
+ // Add the number of arguments in both the argvs.
+ this->argc_ = first_argc + second_argc;
+
+ int buf_len = ACE_OS::strlen (first_buf) + ACE_OS::strlen (second_buf) + 1;
+
+ // Allocate memory to the lenght of the combined argv string.
+ ACE_NEW (this->buf_,
+ ACE_TCHAR[buf_len + 1]);
+
+ // copy the first argv string to the buffer
+ ACE_OS::strcpy (this->buf_,first_buf);
+
+ // concatenate the second argv string to the buffer
+ ACE_OS::strcat (this->buf_,second_buf);
+
+ // Delete the first and second buffers
+
+ delete [] first_buf;
+
+ delete [] second_buf;
+}
+
+
+ACE_ARGV::ACE_ARGV (int substitute_env_args)
+ : substitute_env_args_ (substitute_env_args),
+ state_ (ITERATIVE),
+ argc_ (0),
+ argv_ (0),
+ buf_ (0),
+ length_ (0),
+ queue_ ()
+{
+ ACE_TRACE ("ACE_ARGV::ACE_ARGV Iterative");
+
+ // Nothing to do yet -- the user puts in arguments via add ()
+}
+
+int
+ACE_ARGV::add (const ACE_TCHAR *next_arg)
+{
+ // Only allow this to work in the "iterative" verion -- the
+ // ACE_ARGVs created with the one argument constructor.
+ if (this->state_ != ITERATIVE)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+
+ // Put the new argument at the end of the queue.
+ if (this->queue_.enqueue_tail ((ACE_TCHAR *) next_arg) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_LIB_TEXT ("Can't add more to ARGV queue")),
+ -1);
+
+ this->length_ += ACE_OS::strlen (next_arg);
+
+ this->argc_++;
+
+ // Wipe argv_ and buf_ away so that they will be recreated if the
+ // user calls argv () or buf ().
+ if (this->argv_ != 0)
+ {
+ for (int i = 0; this->argv_[i] != 0; i++)
+ ACE_OS::free ((void *) this->argv_[i]);
+
+ delete [] this->argv_;
+ this->argv_ = 0;
+ }
+
+ delete [] this->buf_;
+ this->buf_ = 0;
+
+ return 0;
+}
+
+int
+ACE_ARGV::add (ACE_TCHAR *argv[])
+{
+ for (int i = 0; argv[i] != 0; i++)
+ if (this->add (argv[i]) == -1)
+ return -1;
+
+ return 0;
+}
+
+// Free up argv_ and buf_
+
+ACE_ARGV::~ACE_ARGV (void)
+{
+ ACE_TRACE ("ACE_ARGV::~ACE_ARGV");
+
+ if (this->argv_ != 0)
+ for (int i = 0; this->argv_[i] != 0; i++)
+ ACE_OS::free ((void *) this->argv_[i]);
+
+ delete [] this->argv_;
+ delete [] this->buf_;
+}
+
+// Create buf_ out of the queue_. This is only used in the
+// "iterative" mode.
+
+int
+ACE_ARGV::create_buf_from_queue (void)
+{
+ ACE_TRACE ("ACE_ARGV::create_buf_from_queue");
+
+ // If the are no arguments, don't do anything
+ if (this->argc_ <= 0)
+ return -1;
+
+ delete [] this->buf_;
+
+ ACE_NEW_RETURN (this->buf_,
+ ACE_TCHAR[this->length_ + this->argc_],
+ -1);
+
+ // Get an iterator over the queue
+ ACE_Unbounded_Queue_Iterator<ACE_TCHAR *> iter (this->queue_);
+
+ ACE_TCHAR **arg;
+ ACE_TCHAR *ptr = this->buf_;
+ size_t len;
+ int more = 0;
+
+ while (!iter.done ())
+ {
+ // Get next argument from the queue.
+ iter.next (arg);
+
+ more = iter.advance ();
+
+ len = ACE_OS::strlen (*arg);
+
+ // Copy the argument into buf_
+ ACE_OS::memcpy ((void *) ptr,
+ (const void *) (*arg),
+ len * sizeof (ACE_TCHAR));
+ // Move the pointer down.
+ ptr += len;
+
+ // Put in an argument separating space.
+ if (more != 0)
+ *ptr++ = ' ';
+ }
+
+ // Put in the NUL terminator
+ *ptr = '\0';
+
+ return 0;
+}
+
+#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION)
+template class ACE_Unbounded_Queue<ACE_TCHAR *>;
+template class ACE_Unbounded_Queue_Iterator<ACE_TCHAR *>;
+template class ACE_Node<ACE_TCHAR *>;
+#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA)
+#pragma instantiate ACE_Unbounded_Queue<ACE_TCHAR *>
+#pragma instantiate ACE_Unbounded_Queue_Iterator<ACE_TCHAR *>
+#pragma instantiate ACE_Node<ACE_TCHAR *>
+#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */
diff --git a/ace/Utils/ARGV.h b/ace/Utils/ARGV.h
new file mode 100644
index 00000000000..613af430fed
--- /dev/null
+++ b/ace/Utils/ARGV.h
@@ -0,0 +1,169 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file ARGV.h
+ *
+ * $Id$
+ *
+ * @author Doug Schmidt <schmidt@cs.wustl.edu>
+ * @author Everett Anderson
+ */
+//=============================================================================
+
+#ifndef ACE_ARGUMENT_VECTOR_H
+#define ACE_ARGUMENT_VECTOR_H
+#include "ace/pre.h"
+
+#include "ace/ACE.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "ace/Unbounded_Queue.h"
+
+/**
+ * @class ACE_ARGV
+ *
+ * @brief Transforms a string <buf> into an <argv> style vector of
+ * strings or an <argv> style vector of string <buf>, performing
+ * environment variable substitutions if necessary.
+ */
+class ACE_Export ACE_ARGV
+{
+public:
+ // = Initialization and termination.
+ /**
+ * Converts <buf> into an <argv>-style vector of strings. If
+ * <substitute_env_args> is enabled then we'll substitute the
+ * environment variables for each $ENV encountered in the string.
+ * The subscript and <argv> operations are not allowed on an
+ * ACE_ARGV created this way.
+ */
+ ACE_ARGV (const ACE_TCHAR buf[],
+ int substitute_env_args = 1);
+
+ /**
+ * Converts <argv> into a linear string. If <substitute_env_args>
+ * is enabled then we'll substitute the environment variables for
+ * each $ENV encountered in the string. The <buf> operation is not
+ * allowed on an ACE_ARGV created this way.
+ */
+ ACE_ARGV (ACE_TCHAR *argv[],
+ int substitute_env_args = 1);
+
+ /**
+ * Creates an ACE_ARGV which is the concatenation of the first_argv
+ * and the second argv. The argv arguments should be null pointer
+ * terminated.
+ */
+ ACE_ARGV (ACE_TCHAR *first_argv[],
+ ACE_TCHAR *second_argv[],
+ int substitute_env_args =1);
+
+ /**
+ * Entry point for creating an ACE_TCHAR *[] command line
+ * iteratively via the <add> method. When this constructor is used,
+ * the <ITERATIVE> state is enabled. The <argv> and <buf> methods
+ * are allowed, and the result is recreated when called multiple
+ * times. The subscript operator is not allowed.
+ */
+ ACE_ARGV (int substitute_env_args = 1);
+
+ /// Destructor.
+ ~ACE_ARGV (void);
+
+ // = Accessor arguments.
+ /// Returns the <index>th string in the ARGV array.
+ const ACE_TCHAR *operator[] (size_t index);
+
+ /**
+ * Returns the <argv> array. Caller should not delete this memory
+ * since the <ARGV> destructor will delete it. If the caller
+ * modifies the array in the iterative mode, the changes are not
+ * saved to the queue.
+ */
+ ACE_TCHAR **argv (void);
+
+ /// Returns <argc>.
+ size_t argc (void) const;
+
+ /// Returns the <buf>. Caller should not delete this memory since
+ /// the <ARGV> destructor will delete it.
+ const ACE_TCHAR *buf (void);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+ /// Add another argument. This only works in the <ITERATIVE> state.
+ /// Note that this method does not copy <next_arg>, but instead
+ /// assumes ownership of it. Returns -1 on failure and 0 on success.
+ int add (const ACE_TCHAR *next_arg);
+
+ /**
+ * Add another <argv> array. The <argv> parameter must be NULL
+ * terminated. This only works in the <ITERATIVE> state. Returns
+ * -1 on failure and 0 on success.
+ */
+ int add (ACE_TCHAR *argv[]);
+
+ /// What state is this ACE_ARGV in?
+ int state (void) const;
+
+ // These are the states possible via the different constructors.
+ enum States
+ {
+ /// ACE_ARGV converts buf[] to ACE_TCHAR *argv[]
+ TO_STRING = 1,
+ /// ACE_ARGV converts ACE_TCHAR *argv[] to buf[]
+ TO_PTR_ARRAY = 2,
+ /// Builds buf[] or ACE_TCHAR *argv[] iteratively with <add>.
+ ITERATIVE = 3
+ };
+
+private:
+
+ /// Creates buf_ from the queue, deletes previous buf_.
+ int create_buf_from_queue (void);
+
+ /// Converts buf_ into the ACE_TCHAR *argv[] format.
+ int string_to_argv (void);
+
+ /// Returns the string created from argv in buf and
+ /// returns the number of arguments.
+ int argv_to_string (ACE_TCHAR **argv, ACE_TCHAR *&buf);
+
+ /// Replace args with environment variable values?
+ int substitute_env_args_;
+
+ /// Current state marker.
+ int state_;
+
+ /// Number of arguments in the ARGV array.
+ size_t argc_;
+
+ /// The array of string arguments.
+ ACE_TCHAR **argv_;
+
+ /// Buffer containing the <argv> contents.
+ ACE_TCHAR *buf_;
+
+ /// Total length of the arguments in the queue, not counting
+ /// separating spaces
+ size_t length_;
+
+ /// Queue which keeps user supplied arguments. This is only
+ /// active in the "iterative" mode.
+ ACE_Unbounded_Queue<ACE_TCHAR *> queue_;
+};
+
+#if defined (__ACE_INLINE__)
+#include "ace/ARGV.i"
+#endif /* __ACE_INLINE__ */
+
+#include "ace/post.h"
+#endif /* ACE_ARGUMENT_VECTOR_H */
diff --git a/ace/Utils/ARGV.i b/ace/Utils/ARGV.i
new file mode 100644
index 00000000000..f45bdf4b125
--- /dev/null
+++ b/ace/Utils/ARGV.i
@@ -0,0 +1,68 @@
+/* -*- C++ -*- */
+// $Id$
+
+// Return the number of args
+ACE_INLINE size_t
+ACE_ARGV::argc (void) const
+{
+ ACE_TRACE ("ACE_ARGV::argc");
+ return this->argc_;
+}
+
+// Return the state of this ACE_ARGV
+ACE_INLINE int
+ACE_ARGV::state(void) const
+{
+ ACE_TRACE ("ACE_ARGV::state");
+ return this->state_;
+}
+
+// Return the arguments in a space-separated string
+ACE_INLINE const ACE_TCHAR *
+ACE_ARGV::buf (void)
+{
+ ACE_TRACE ("ACE_ARGV::buf");
+
+ if (this->buf_ == 0 && this->state_ == ITERATIVE)
+ this->create_buf_from_queue ();
+
+ return (const ACE_TCHAR *) this->buf_;
+}
+
+// Return the arguments in an entry-per-argument array
+
+ACE_INLINE ACE_TCHAR **
+ACE_ARGV::argv (void)
+{
+ ACE_TRACE ("ACE_ARGV::argv");
+
+ // Try to create the argv_ if it isn't there
+ if (this->argv_ == 0)
+ {
+ if (this->state_ == ITERATIVE && this->buf_ == 0)
+ this->create_buf_from_queue ();
+
+ // Convert buf_ to argv_
+ if (this->string_to_argv () == -1)
+ return (ACE_TCHAR **) 0;
+ }
+
+ return (ACE_TCHAR **) this->argv_;
+}
+
+// Subscript operator.
+
+ACE_INLINE const ACE_TCHAR *
+ACE_ARGV::operator[] (size_t i)
+{
+ ACE_TRACE ("ACE_ARGV::operator[]");
+
+ // Don't go out of bounds.
+ if (i >= this->argc_)
+ return 0;
+
+ return (const ACE_TCHAR *) this->argv ()[i];
+}
+
+
+
diff --git a/ace/Utils/Active_Map_Manager.cpp b/ace/Utils/Active_Map_Manager.cpp
new file mode 100644
index 00000000000..d68fab4243a
--- /dev/null
+++ b/ace/Utils/Active_Map_Manager.cpp
@@ -0,0 +1,9 @@
+// $Id$
+
+#include "ace/Utils/Active_Map_Manager.h"
+
+ACE_RCSID(ace, Active_Map_Manager, "$Id$")
+
+#if !defined (__ACE_INLINE__)
+#include "ace/Utils/Active_Map_Manager.i"
+#endif /* __ACE_INLINE__ */
diff --git a/ace/Utils/Active_Map_Manager.cpp~ b/ace/Utils/Active_Map_Manager.cpp~
new file mode 100644
index 00000000000..a01fb45d9b0
--- /dev/null
+++ b/ace/Utils/Active_Map_Manager.cpp~
@@ -0,0 +1,10 @@
+// $Id$
+
+#include "ace/Active_Map_Manager.h"
+
+ACE_RCSID(ace, Active_Map_Manager, "$Id$")
+
+#if !defined (__ACE_INLINE__)
+#include "ace/Active_Map_Manager.i"
+#endif /* __ACE_INLINE__ */
+
diff --git a/ace/Utils/Active_Map_Manager.h b/ace/Utils/Active_Map_Manager.h
new file mode 100644
index 00000000000..97bad2802ae
--- /dev/null
+++ b/ace/Utils/Active_Map_Manager.h
@@ -0,0 +1,106 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Active_Map_Manager.h
+ *
+ * $Id$
+ *
+ * @author Irfan Pyarali
+ */
+//=============================================================================
+
+
+#ifndef ACE_ACTIVE_MAP_MANAGER_H
+#define ACE_ACTIVE_MAP_MANAGER_H
+#include "ace/pre.h"
+
+#include "ace/OS/OS.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+/**
+ * @class ACE_Active_Map_Manager_Key
+ *
+ * @brief Key used in the Active Object Map.
+ *
+ * This key keeps information of the index and the generation
+ * count of the slot it represents. Since the index information
+ * is part of the key, lookups are super fast and predictable,
+ */
+class ACE_Export ACE_Active_Map_Manager_Key
+{
+public:
+ /// Default constructor.
+ ACE_Active_Map_Manager_Key (void);
+
+ /**
+ * Constructor given the <slot_index> and <slot_generation> number.
+ * This is useful once the user has somehow recovered the
+ * <slot_index> and <slot_generation> number from the client.
+ */
+ ACE_Active_Map_Manager_Key (ACE_UINT32 slot_index,
+ ACE_UINT32 slot_generation);
+
+ /// Get/Set the <slot_index>.
+ ACE_UINT32 slot_index (void) const;
+ void slot_index (ACE_UINT32 i);
+
+ /// Get/Set the <slot_generation> number.
+ ACE_UINT32 slot_generation (void) const;
+ void slot_generation (ACE_UINT32 g);
+
+ /// Size required to store information about active key.
+ static size_t size (void);
+
+ /// Recover state of active key from <data>. User must make sure
+ /// that <data> encoded using the <encode> method.
+ void decode (const void *data);
+
+ /// Encode state of the active key into <data>. <data> must be as
+ /// big as the value returned from <size>.
+ void encode (void *data) const;
+
+ /// Compare keys.
+ int operator== (const ACE_Active_Map_Manager_Key &rhs) const;
+ int operator!= (const ACE_Active_Map_Manager_Key &rhs) const;
+
+ // = This really should be protected but because of template
+ // friends, they are not.
+
+ /// Increment the <slot_generation> number.
+ void increment_slot_generation_count (void);
+
+private:
+
+ /**
+ * @brief Data for the Active Object Map Key.
+ *
+ * This separate structure makes it easier to manage copying
+ * the index and the generation to and from the user buffer.
+ *
+ */
+ struct key_data
+ {
+ /// Slot index in the active map.
+ ACE_UINT32 slot_index_;
+
+ /// Slot generation number of <slot_index_> slot in the active map.
+ ACE_UINT32 slot_generation_;
+ };
+
+ /// Data for the Active Object Map Key.
+ key_data key_data_;
+};
+
+#if defined (__ACE_INLINE__)
+#include "ace/Utils/Active_Map_Manager.i"
+#endif /* __ACE_INLINE__ */
+
+// Include the templates here.
+#include "ace/Utils/Active_Map_Manager_T.h"
+
+#include "ace/post.h"
+#endif /* ACE_ACTIVE_MAP_MANAGER_H */
diff --git a/ace/Utils/Active_Map_Manager.h~ b/ace/Utils/Active_Map_Manager.h~
new file mode 100644
index 00000000000..1911e6c7e2e
--- /dev/null
+++ b/ace/Utils/Active_Map_Manager.h~
@@ -0,0 +1,106 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Active_Map_Manager.h
+ *
+ * $Id$
+ *
+ * @author Irfan Pyarali
+ */
+//=============================================================================
+
+
+#ifndef ACE_ACTIVE_MAP_MANAGER_H
+#define ACE_ACTIVE_MAP_MANAGER_H
+#include "ace/pre.h"
+
+#include "ace/OS.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+/**
+ * @class ACE_Active_Map_Manager_Key
+ *
+ * @brief Key used in the Active Object Map.
+ *
+ * This key keeps information of the index and the generation
+ * count of the slot it represents. Since the index information
+ * is part of the key, lookups are super fast and predictable,
+ */
+class ACE_Export ACE_Active_Map_Manager_Key
+{
+public:
+ /// Default constructor.
+ ACE_Active_Map_Manager_Key (void);
+
+ /**
+ * Constructor given the <slot_index> and <slot_generation> number.
+ * This is useful once the user has somehow recovered the
+ * <slot_index> and <slot_generation> number from the client.
+ */
+ ACE_Active_Map_Manager_Key (ACE_UINT32 slot_index,
+ ACE_UINT32 slot_generation);
+
+ /// Get/Set the <slot_index>.
+ ACE_UINT32 slot_index (void) const;
+ void slot_index (ACE_UINT32 i);
+
+ /// Get/Set the <slot_generation> number.
+ ACE_UINT32 slot_generation (void) const;
+ void slot_generation (ACE_UINT32 g);
+
+ /// Size required to store information about active key.
+ static size_t size (void);
+
+ /// Recover state of active key from <data>. User must make sure
+ /// that <data> encoded using the <encode> method.
+ void decode (const void *data);
+
+ /// Encode state of the active key into <data>. <data> must be as
+ /// big as the value returned from <size>.
+ void encode (void *data) const;
+
+ /// Compare keys.
+ int operator== (const ACE_Active_Map_Manager_Key &rhs) const;
+ int operator!= (const ACE_Active_Map_Manager_Key &rhs) const;
+
+ // = This really should be protected but because of template
+ // friends, they are not.
+
+ /// Increment the <slot_generation> number.
+ void increment_slot_generation_count (void);
+
+private:
+
+ /**
+ * @brief Data for the Active Object Map Key.
+ *
+ * This separate structure makes it easier to manage copying
+ * the index and the generation to and from the user buffer.
+ *
+ */
+ struct key_data
+ {
+ /// Slot index in the active map.
+ ACE_UINT32 slot_index_;
+
+ /// Slot generation number of <slot_index_> slot in the active map.
+ ACE_UINT32 slot_generation_;
+ };
+
+ /// Data for the Active Object Map Key.
+ key_data key_data_;
+};
+
+#if defined (__ACE_INLINE__)
+#include "ace/Active_Map_Manager.i"
+#endif /* __ACE_INLINE__ */
+
+// Include the templates here.
+#include "ace/Active_Map_Manager_T.h"
+
+#include "ace/post.h"
+#endif /* ACE_ACTIVE_MAP_MANAGER_H */
diff --git a/ace/Utils/Active_Map_Manager.i b/ace/Utils/Active_Map_Manager.i
new file mode 100644
index 00000000000..486a595b2be
--- /dev/null
+++ b/ace/Utils/Active_Map_Manager.i
@@ -0,0 +1,87 @@
+// $Id$
+
+ACE_INLINE
+ACE_Active_Map_Manager_Key::ACE_Active_Map_Manager_Key (void)
+{
+ // If you change ~0, please change ACE_Map_Manager::free_list_id()
+ // accordingly.
+ this->key_data_.slot_index_ = ~0;
+ this->key_data_.slot_generation_ = 0;
+}
+
+ACE_INLINE
+ACE_Active_Map_Manager_Key::ACE_Active_Map_Manager_Key (ACE_UINT32 slot_index,
+ ACE_UINT32 slot_generation)
+{
+ this->key_data_.slot_index_ = slot_index;
+ this->key_data_.slot_generation_ = slot_generation;
+}
+
+ACE_INLINE ACE_UINT32
+ACE_Active_Map_Manager_Key::slot_index (void) const
+{
+ return this->key_data_.slot_index_;
+}
+
+ACE_INLINE ACE_UINT32
+ACE_Active_Map_Manager_Key::slot_generation (void) const
+{
+ return this->key_data_.slot_generation_;
+}
+
+ACE_INLINE int
+ACE_Active_Map_Manager_Key::operator== (const ACE_Active_Map_Manager_Key &rhs) const
+{
+ return
+ this->key_data_.slot_index_ == rhs.key_data_.slot_index_ &&
+ this->key_data_.slot_generation_ == rhs.key_data_.slot_generation_;
+}
+
+ACE_INLINE int
+ACE_Active_Map_Manager_Key::operator!= (const ACE_Active_Map_Manager_Key &rhs) const
+{
+ return !this->operator== (rhs);
+}
+
+ACE_INLINE void
+ACE_Active_Map_Manager_Key::slot_index (ACE_UINT32 i)
+{
+ this->key_data_.slot_index_ = i;
+}
+
+ACE_INLINE void
+ACE_Active_Map_Manager_Key::slot_generation (ACE_UINT32 g)
+{
+ this->key_data_.slot_generation_ = g;
+}
+
+ACE_INLINE void
+ACE_Active_Map_Manager_Key::increment_slot_generation_count (void)
+{
+ ++this->key_data_.slot_generation_;
+}
+
+/* static */
+ACE_INLINE size_t
+ACE_Active_Map_Manager_Key::size (void)
+{
+ return sizeof (ACE_UINT32) + sizeof (ACE_UINT32);
+}
+
+ACE_INLINE void
+ACE_Active_Map_Manager_Key::decode (const void *data)
+{
+ // Copy the information from the user buffer into the key.
+ ACE_OS::memcpy (&this->key_data_,
+ data,
+ sizeof this->key_data_);
+}
+
+ACE_INLINE void
+ACE_Active_Map_Manager_Key::encode (void *data) const
+{
+ // Copy the key data to the user buffer.
+ ACE_OS::memcpy (data,
+ &this->key_data_,
+ sizeof this->key_data_);
+}
diff --git a/ace/Utils/Active_Map_Manager_T.cpp b/ace/Utils/Active_Map_Manager_T.cpp
new file mode 100644
index 00000000000..61fd31c4677
--- /dev/null
+++ b/ace/Utils/Active_Map_Manager_T.cpp
@@ -0,0 +1,20 @@
+// $Id$
+
+#ifndef ACE_ACTIVE_MAP_MANAGER_T_C
+#define ACE_ACTIVE_MAP_MANAGER_T_C
+
+#include "ace/Utils/Active_Map_Manager_T.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#if !defined (__ACE_INLINE__)
+#include "ace/Utils/Active_Map_Manager_T.i"
+#endif /* __ACE_INLINE__ */
+
+ACE_RCSID(ace, Active_Map_Manager_T, "$Id$")
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Active_Map_Manager)
+
+#endif /* ACE_ACTIVE_MAP_MANAGER_T_C */
diff --git a/ace/Utils/Active_Map_Manager_T.h b/ace/Utils/Active_Map_Manager_T.h
new file mode 100644
index 00000000000..22cb24bd7ee
--- /dev/null
+++ b/ace/Utils/Active_Map_Manager_T.h
@@ -0,0 +1,205 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Active_Map_Manager_T.h
+ *
+ * $Id$
+ *
+ * @author Irfan Pyarali
+ */
+//=============================================================================
+
+
+#ifndef ACE_ACTIVE_MAP_MANAGER_T_H
+#define ACE_ACTIVE_MAP_MANAGER_T_H
+#include "ace/pre.h"
+
+#include "ace/Utils/Templates/Map_Manager.h"
+#include "ace/Utils/Active_Map_Manager.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+/**
+ * @class ACE_Active_Map_Manager
+ *
+ * @brief Define a map abstraction that associates system generated
+ * keys with user specified values.
+ *
+ * Since the key is system generated, searches are very fast and
+ * take a constant amount of time.
+ */
+template <class T>
+class ACE_Active_Map_Manager : public ACE_Map_Manager<ACE_Active_Map_Manager_Key, T, ACE_Null_Mutex>
+{
+public:
+
+ // = Traits.
+ typedef ACE_Active_Map_Manager_Key key_type;
+ typedef T mapped_type;
+
+ typedef ACE_Map_Entry<ACE_Active_Map_Manager_Key, T> ENTRY;
+ typedef ACE_Map_Iterator<ACE_Active_Map_Manager_Key, T, ACE_Null_Mutex> ITERATOR;
+ typedef ACE_Map_Reverse_Iterator<ACE_Active_Map_Manager_Key, T, ACE_Null_Mutex> REVERSE_ITERATOR;
+
+ typedef ENTRY entry;
+ typedef ITERATOR iterator;
+ typedef REVERSE_ITERATOR reverse_iterator;
+
+ // = Initialization and termination methods.
+ /// Initialize a <Active_Map_Manager> with the <ACE_DEFAULT_MAP_SIZE>.
+ ACE_Active_Map_Manager (ACE_Allocator *alloc = 0);
+
+ /// Initialize a <Active_Map_Manager> with <size> entries.
+ ACE_Active_Map_Manager (size_t size,
+ ACE_Allocator *alloc = 0);
+
+ /// Close down a <Active_Map_Manager> and release dynamically
+ /// allocated resources.
+ ~ACE_Active_Map_Manager (void);
+
+ /// Initialize a <Active_Map_Manager> with size <length>.
+ int open (size_t length = ACE_DEFAULT_MAP_SIZE,
+ ACE_Allocator *alloc = 0);
+
+ /// Close down a <Active_Map_Manager> and release dynamically
+ /// allocated resources.
+ int close (void);
+
+ /// Add <value> to the map, and the corresponding key produced by the
+ /// Active_Map_Manager is returned through <key>.
+ int bind (const T &value,
+ ACE_Active_Map_Manager_Key &key);
+
+ /// Add <value> to the map. The user does not care about the
+ /// corresponding key produced by the Active_Map_Manager.
+ int bind (const T &value);
+
+ /**
+ * Reserves a slot in the internal structure and returns the key and
+ * a pointer to the value. User should place their <value> into
+ * <*internal_value>. This method is useful in reducing the number
+ * of copies required in some cases. Note that <internal_value> is
+ * only a temporary pointer and will change when the map resizes.
+ * Therefore, the user should use the pointer immediately and not
+ * hold on to it.
+ */
+ int bind (ACE_Active_Map_Manager_Key &key,
+ T *&internal_value);
+
+ /// Reassociate <key> with <value>. The function fails if <key> is
+ /// not in the map.
+ int rebind (const ACE_Active_Map_Manager_Key &key,
+ const T &value);
+
+ /**
+ * Reassociate <key> with <value>, storing the old value into the
+ * "out" parameter <old_value>. The function fails if <key> is not
+ * in the map.
+ */
+ int rebind (const ACE_Active_Map_Manager_Key &key,
+ const T &value,
+ T &old_value);
+
+ /**
+ * Reassociate <key> with <value>, storing the old key and value
+ * into the "out" parameter <old_key> and <old_value>. The function
+ * fails if <key> is not in the map.
+ */
+ int rebind (const ACE_Active_Map_Manager_Key &key,
+ const T &value,
+ ACE_Active_Map_Manager_Key &old_key,
+ T &old_value);
+
+ /// Locate <value> associated with <key>.
+ int find (const ACE_Active_Map_Manager_Key &key,
+ T &value) const;
+
+ /// Is <key> in the map?
+ int find (const ACE_Active_Map_Manager_Key &key) const;
+
+ /**
+ * Locate <value> associated with <key>. The value is returned via
+ * <internal_value> and hence a copy is saved. Note that
+ * <internal_value> is only a temporary pointer and will change when
+ * the map resizes. Therefore, the user should use the pointer
+ * immediately and not hold on to it.
+ */
+ int find (const ACE_Active_Map_Manager_Key &key,
+ T *&internal_value) const;
+
+ // Creates a key. User should place their <value> into
+ // <*internal_value>. This method is useful in reducing the number
+ // of copies required in some cases.
+
+ /// Remove <key> from the map.
+ int unbind (const ACE_Active_Map_Manager_Key &key);
+
+ /// Remove <key> from the map, and return the <value> associated with
+ /// <key>.
+ int unbind (const ACE_Active_Map_Manager_Key &key,
+ T &value);
+
+ /**
+ * Locate <value> associated with <key>. The value is returned via
+ * <internal_value> and hence a copy is saved. Note that
+ * <internal_value> is only a temporary pointer and will change when
+ * the map resizes or when this slot is reused. Therefore, the user
+ * should use the pointer immediately and not hold on to it.
+ */
+ int unbind (const ACE_Active_Map_Manager_Key &key,
+ T *&internal_value);
+
+ /// Return the current size of the map.
+ size_t current_size (void) const;
+
+ /// Return the total size of the map.
+ size_t total_size (void) const;
+
+ /// Returns a key that cannot be found in the map.
+ static const ACE_Active_Map_Manager_Key npos (void);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ // = STL styled iterator factory functions.
+
+ /// Return forward iterator.
+ ACE_Map_Iterator<ACE_Active_Map_Manager_Key, T, ACE_Null_Mutex> begin (void);
+ ACE_Map_Iterator<ACE_Active_Map_Manager_Key, T, ACE_Null_Mutex> end (void);
+
+ /// Return reverse iterator.
+ ACE_Map_Reverse_Iterator<ACE_Active_Map_Manager_Key, T, ACE_Null_Mutex> rbegin (void);
+ ACE_Map_Reverse_Iterator<ACE_Active_Map_Manager_Key, T, ACE_Null_Mutex> rend (void);
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+protected:
+
+ /// Private base class
+ typedef ACE_Map_Manager<ACE_Active_Map_Manager_Key, T, ACE_Null_Mutex> ACE_AMM_BASE;
+
+private:
+
+ // = Disallow these operations.
+ ACE_UNIMPLEMENTED_FUNC (void operator= (const ACE_Active_Map_Manager<T> &))
+ ACE_UNIMPLEMENTED_FUNC (ACE_Active_Map_Manager (const ACE_Active_Map_Manager<T> &))
+};
+
+#if defined (__ACE_INLINE__)
+#include "ace/Utils/Active_Map_Manager_T.i"
+#endif /* __ACE_INLINE__ */
+
+#if defined (ACE_TEMPLATES_REQUIRE_SOURCE)
+#include "ace/Utils/Active_Map_Manager_T.cpp"
+#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */
+
+#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA)
+#pragma implementation ("Active_Map_Manager_T.cpp")
+#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */
+
+#include "ace/post.h"
+#endif /* ACE_ACTIVE_MAP_MANAGER_T_H */
diff --git a/ace/Utils/Active_Map_Manager_T.h~ b/ace/Utils/Active_Map_Manager_T.h~
new file mode 100644
index 00000000000..b91d2fec51a
--- /dev/null
+++ b/ace/Utils/Active_Map_Manager_T.h~
@@ -0,0 +1,205 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Active_Map_Manager_T.h
+ *
+ * $Id$
+ *
+ * @author Irfan Pyarali
+ */
+//=============================================================================
+
+
+#ifndef ACE_ACTIVE_MAP_MANAGER_T_H
+#define ACE_ACTIVE_MAP_MANAGER_T_H
+#include "ace/pre.h"
+
+#include "ace/Map_Manager.h"
+#include "ace/Active_Map_Manager.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+/**
+ * @class ACE_Active_Map_Manager
+ *
+ * @brief Define a map abstraction that associates system generated
+ * keys with user specified values.
+ *
+ * Since the key is system generated, searches are very fast and
+ * take a constant amount of time.
+ */
+template <class T>
+class ACE_Active_Map_Manager : public ACE_Map_Manager<ACE_Active_Map_Manager_Key, T, ACE_Null_Mutex>
+{
+public:
+
+ // = Traits.
+ typedef ACE_Active_Map_Manager_Key key_type;
+ typedef T mapped_type;
+
+ typedef ACE_Map_Entry<ACE_Active_Map_Manager_Key, T> ENTRY;
+ typedef ACE_Map_Iterator<ACE_Active_Map_Manager_Key, T, ACE_Null_Mutex> ITERATOR;
+ typedef ACE_Map_Reverse_Iterator<ACE_Active_Map_Manager_Key, T, ACE_Null_Mutex> REVERSE_ITERATOR;
+
+ typedef ENTRY entry;
+ typedef ITERATOR iterator;
+ typedef REVERSE_ITERATOR reverse_iterator;
+
+ // = Initialization and termination methods.
+ /// Initialize a <Active_Map_Manager> with the <ACE_DEFAULT_MAP_SIZE>.
+ ACE_Active_Map_Manager (ACE_Allocator *alloc = 0);
+
+ /// Initialize a <Active_Map_Manager> with <size> entries.
+ ACE_Active_Map_Manager (size_t size,
+ ACE_Allocator *alloc = 0);
+
+ /// Close down a <Active_Map_Manager> and release dynamically
+ /// allocated resources.
+ ~ACE_Active_Map_Manager (void);
+
+ /// Initialize a <Active_Map_Manager> with size <length>.
+ int open (size_t length = ACE_DEFAULT_MAP_SIZE,
+ ACE_Allocator *alloc = 0);
+
+ /// Close down a <Active_Map_Manager> and release dynamically
+ /// allocated resources.
+ int close (void);
+
+ /// Add <value> to the map, and the corresponding key produced by the
+ /// Active_Map_Manager is returned through <key>.
+ int bind (const T &value,
+ ACE_Active_Map_Manager_Key &key);
+
+ /// Add <value> to the map. The user does not care about the
+ /// corresponding key produced by the Active_Map_Manager.
+ int bind (const T &value);
+
+ /**
+ * Reserves a slot in the internal structure and returns the key and
+ * a pointer to the value. User should place their <value> into
+ * <*internal_value>. This method is useful in reducing the number
+ * of copies required in some cases. Note that <internal_value> is
+ * only a temporary pointer and will change when the map resizes.
+ * Therefore, the user should use the pointer immediately and not
+ * hold on to it.
+ */
+ int bind (ACE_Active_Map_Manager_Key &key,
+ T *&internal_value);
+
+ /// Reassociate <key> with <value>. The function fails if <key> is
+ /// not in the map.
+ int rebind (const ACE_Active_Map_Manager_Key &key,
+ const T &value);
+
+ /**
+ * Reassociate <key> with <value>, storing the old value into the
+ * "out" parameter <old_value>. The function fails if <key> is not
+ * in the map.
+ */
+ int rebind (const ACE_Active_Map_Manager_Key &key,
+ const T &value,
+ T &old_value);
+
+ /**
+ * Reassociate <key> with <value>, storing the old key and value
+ * into the "out" parameter <old_key> and <old_value>. The function
+ * fails if <key> is not in the map.
+ */
+ int rebind (const ACE_Active_Map_Manager_Key &key,
+ const T &value,
+ ACE_Active_Map_Manager_Key &old_key,
+ T &old_value);
+
+ /// Locate <value> associated with <key>.
+ int find (const ACE_Active_Map_Manager_Key &key,
+ T &value) const;
+
+ /// Is <key> in the map?
+ int find (const ACE_Active_Map_Manager_Key &key) const;
+
+ /**
+ * Locate <value> associated with <key>. The value is returned via
+ * <internal_value> and hence a copy is saved. Note that
+ * <internal_value> is only a temporary pointer and will change when
+ * the map resizes. Therefore, the user should use the pointer
+ * immediately and not hold on to it.
+ */
+ int find (const ACE_Active_Map_Manager_Key &key,
+ T *&internal_value) const;
+
+ // Creates a key. User should place their <value> into
+ // <*internal_value>. This method is useful in reducing the number
+ // of copies required in some cases.
+
+ /// Remove <key> from the map.
+ int unbind (const ACE_Active_Map_Manager_Key &key);
+
+ /// Remove <key> from the map, and return the <value> associated with
+ /// <key>.
+ int unbind (const ACE_Active_Map_Manager_Key &key,
+ T &value);
+
+ /**
+ * Locate <value> associated with <key>. The value is returned via
+ * <internal_value> and hence a copy is saved. Note that
+ * <internal_value> is only a temporary pointer and will change when
+ * the map resizes or when this slot is reused. Therefore, the user
+ * should use the pointer immediately and not hold on to it.
+ */
+ int unbind (const ACE_Active_Map_Manager_Key &key,
+ T *&internal_value);
+
+ /// Return the current size of the map.
+ size_t current_size (void) const;
+
+ /// Return the total size of the map.
+ size_t total_size (void) const;
+
+ /// Returns a key that cannot be found in the map.
+ static const ACE_Active_Map_Manager_Key npos (void);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ // = STL styled iterator factory functions.
+
+ /// Return forward iterator.
+ ACE_Map_Iterator<ACE_Active_Map_Manager_Key, T, ACE_Null_Mutex> begin (void);
+ ACE_Map_Iterator<ACE_Active_Map_Manager_Key, T, ACE_Null_Mutex> end (void);
+
+ /// Return reverse iterator.
+ ACE_Map_Reverse_Iterator<ACE_Active_Map_Manager_Key, T, ACE_Null_Mutex> rbegin (void);
+ ACE_Map_Reverse_Iterator<ACE_Active_Map_Manager_Key, T, ACE_Null_Mutex> rend (void);
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+protected:
+
+ /// Private base class
+ typedef ACE_Map_Manager<ACE_Active_Map_Manager_Key, T, ACE_Null_Mutex> ACE_AMM_BASE;
+
+private:
+
+ // = Disallow these operations.
+ ACE_UNIMPLEMENTED_FUNC (void operator= (const ACE_Active_Map_Manager<T> &))
+ ACE_UNIMPLEMENTED_FUNC (ACE_Active_Map_Manager (const ACE_Active_Map_Manager<T> &))
+};
+
+#if defined (__ACE_INLINE__)
+#include "ace/Active_Map_Manager_T.i"
+#endif /* __ACE_INLINE__ */
+
+#if defined (ACE_TEMPLATES_REQUIRE_SOURCE)
+#include "ace/Active_Map_Manager_T.cpp"
+#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */
+
+#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA)
+#pragma implementation ("Active_Map_Manager_T.cpp")
+#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */
+
+#include "ace/post.h"
+#endif /* ACE_ACTIVE_MAP_MANAGER_T_H */
diff --git a/ace/Utils/Active_Map_Manager_T.i b/ace/Utils/Active_Map_Manager_T.i
new file mode 100644
index 00000000000..981594c3dfc
--- /dev/null
+++ b/ace/Utils/Active_Map_Manager_T.i
@@ -0,0 +1,303 @@
+// $Id$
+
+template <class T> ACE_INLINE int
+ACE_Active_Map_Manager<T>::bind (ACE_Active_Map_Manager_Key &key,
+ T *&internal_value)
+{
+ ACE_UINT32 slot_index;
+ int result = this->next_free (slot_index);
+
+ if (result == 0)
+ {
+ // Move from free list to occupied list
+ this->move_from_free_list_to_occupied_list (slot_index);
+
+ // Reset the key.
+ this->search_structure_[slot_index].ext_id_.increment_slot_generation_count ();
+ this->search_structure_[slot_index].ext_id_.slot_index (slot_index);
+
+ // Copy the key for the user.
+ key = this->search_structure_[slot_index].ext_id_;
+
+ // This is where the user should place the value.
+ internal_value = &this->search_structure_[slot_index].int_id_;
+
+ // Update the current size.
+ ++this->cur_size_;
+ }
+
+ return result;
+}
+
+template <class T> ACE_INLINE int
+ACE_Active_Map_Manager<T>::bind (const T &value,
+ ACE_Active_Map_Manager_Key &key)
+{
+ T *internal_value = 0;
+ int result = this->bind (key,
+ internal_value);
+
+ if (result == 0)
+ {
+ // Store new value.
+ *internal_value = value;
+ }
+
+ return result;
+}
+
+template <class T> ACE_INLINE int
+ACE_Active_Map_Manager<T>::bind (const T &value)
+{
+ ACE_Active_Map_Manager_Key key;
+ return this->bind (value, key);
+}
+
+template <class T> ACE_INLINE int
+ACE_Active_Map_Manager<T>::find (const ACE_Active_Map_Manager_Key &key,
+ T *&internal_value) const
+{
+ ACE_UINT32 slot_index = key.slot_index ();
+ ACE_UINT32 slot_generation = key.slot_generation ();
+
+ if (slot_index > this->total_size_ ||
+#if defined (ACE_HAS_LAZY_MAP_MANAGER)
+ this->search_structure_[slot_index].free_ ||
+#endif /* ACE_HAS_LAZY_MAP_MANAGER */
+ this->search_structure_[slot_index].ext_id_.slot_generation () != slot_generation ||
+ this->search_structure_[slot_index].ext_id_.slot_index () ==
+ (ACE_UINT32)this->free_list_id ())
+ {
+ return -1;
+ }
+ else
+ {
+ // This is where the user value is.
+ internal_value = &this->search_structure_[slot_index].int_id_;
+ }
+
+ return 0;
+}
+
+template <class T> ACE_INLINE int
+ACE_Active_Map_Manager<T>::find (const ACE_Active_Map_Manager_Key &key) const
+{
+ T *internal_value = 0;
+ return this->find (key,
+ internal_value);
+}
+
+template <class T> ACE_INLINE int
+ACE_Active_Map_Manager<T>::find (const ACE_Active_Map_Manager_Key &key,
+ T &value) const
+{
+ T *internal_value = 0;
+ int result = this->find (key,
+ internal_value);
+
+ if (result == 0)
+ value = *internal_value;
+
+ return result;
+}
+
+template <class T> ACE_INLINE int
+ACE_Active_Map_Manager<T>::rebind (const ACE_Active_Map_Manager_Key &key,
+ const T &value)
+{
+ int result = this->find (key);
+
+ if (result == 0)
+ {
+ // Store new value.
+ this->search_structure_[key.slot_index ()].int_id_ = value;
+ }
+
+ return result;
+}
+
+template <class T> ACE_INLINE int
+ACE_Active_Map_Manager<T>::rebind (const ACE_Active_Map_Manager_Key &key,
+ const T &value,
+ T &old_value)
+{
+ int result = this->find (key);
+
+ if (result == 0)
+ {
+ // Copy old value.
+ old_value = this->search_structure_[key.slot_index ()].int_id_;
+
+ // Store new value.
+ this->search_structure_[key.slot_index ()].int_id_ = value;
+ }
+
+ return result;
+}
+
+template <class T> ACE_INLINE int
+ACE_Active_Map_Manager<T>::rebind (const ACE_Active_Map_Manager_Key &key,
+ const T &value,
+ ACE_Active_Map_Manager_Key &old_key,
+ T &old_value)
+{
+ int result = this->find (key);
+
+ if (result == 0)
+ {
+ // Copy old key.
+ old_key = this->search_structure_[key.slot_index ()].ext_id_;
+
+ // Copy old value.
+ old_value = this->search_structure_[key.slot_index ()].int_id_;
+
+ // Store new value.
+ this->search_structure_[key.slot_index ()].int_id_ = value;
+ }
+
+ return result;
+}
+
+template <class T> ACE_INLINE int
+ACE_Active_Map_Manager<T>::unbind (const ACE_Active_Map_Manager_Key &key,
+ T *&internal_value)
+{
+ int result = this->find (key,
+ internal_value);
+
+ if (result == 0)
+ {
+ ACE_UINT32 slot_index = key.slot_index ();
+
+#if defined (ACE_HAS_LAZY_MAP_MANAGER)
+
+ //
+ // In the case of lazy map managers, the movement of free slots
+ // from the occupied list to the free list is delayed until we
+ // run out of free slots in the free list.
+ //
+
+ this->search_structure_[slot_index].free_ = 1;
+
+#else
+
+ // Move from occupied list to free list.
+ this->move_from_occupied_list_to_free_list (slot_index);
+
+#endif /* ACE_HAS_LAZY_MAP_MANAGER */
+
+ // Reset the slot_index. This will tell us that this entry is free.
+ this->search_structure_[slot_index].ext_id_.slot_index (this->free_list_id ());
+
+ // Update the current size.
+ --this->cur_size_;
+ }
+
+ return result;
+}
+
+template <class T> ACE_INLINE int
+ACE_Active_Map_Manager<T>::unbind (const ACE_Active_Map_Manager_Key &key,
+ T &value)
+{
+ T *internal_value;
+ int result = this->unbind (key,
+ internal_value);
+
+ if (result == 0)
+ {
+ // Copy old value.
+ value = *internal_value;
+ }
+
+ return result;
+}
+
+template <class T> ACE_INLINE int
+ACE_Active_Map_Manager<T>::unbind (const ACE_Active_Map_Manager_Key &key)
+{
+ T *internal_value;
+ return this->unbind (key,
+ internal_value);
+}
+
+template <class T> ACE_INLINE
+ACE_Active_Map_Manager<T>::ACE_Active_Map_Manager (ACE_Allocator *alloc)
+ : ACE_AMM_BASE (alloc)
+{
+}
+
+template <class T> ACE_INLINE
+ACE_Active_Map_Manager<T>::ACE_Active_Map_Manager (size_t size,
+ ACE_Allocator *alloc)
+ : ACE_AMM_BASE (size,
+ alloc)
+{
+}
+
+template <class T> ACE_INLINE
+ACE_Active_Map_Manager<T>::~ACE_Active_Map_Manager (void)
+{
+}
+
+template <class T> ACE_INLINE int
+ACE_Active_Map_Manager<T>::open (size_t length,
+ ACE_Allocator *alloc)
+{
+ return ACE_AMM_BASE::open (length, alloc);
+}
+
+template <class T> ACE_INLINE int
+ACE_Active_Map_Manager<T>::close (void)
+{
+ return ACE_AMM_BASE::close ();
+}
+
+template <class T> ACE_INLINE size_t
+ACE_Active_Map_Manager<T>::current_size (void) const
+{
+ return ACE_AMM_BASE::current_size ();
+}
+
+template <class T> ACE_INLINE size_t
+ACE_Active_Map_Manager<T>::total_size (void) const
+{
+ return ACE_AMM_BASE::total_size ();
+}
+
+/* static */
+template <class T> ACE_INLINE const ACE_Active_Map_Manager_Key
+ACE_Active_Map_Manager<T>::npos (void)
+{
+ return ACE_Active_Map_Manager_Key (~0, ~0);
+}
+
+template <class T> ACE_INLINE void
+ACE_Active_Map_Manager<T>::dump (void) const
+{
+ ACE_AMM_BASE::dump ();
+}
+
+template <class T> ACE_Map_Iterator<ACE_Active_Map_Manager_Key, T, ACE_Null_Mutex>
+ACE_Active_Map_Manager<T>::begin (void)
+{
+ return ACE_AMM_BASE::begin ();
+}
+
+template <class T> ACE_INLINE ACE_Map_Iterator<ACE_Active_Map_Manager_Key, T, ACE_Null_Mutex>
+ACE_Active_Map_Manager<T>::end (void)
+{
+ return ACE_AMM_BASE::end ();
+}
+
+template <class T> ACE_INLINE ACE_Map_Reverse_Iterator<ACE_Active_Map_Manager_Key, T, ACE_Null_Mutex>
+ACE_Active_Map_Manager<T>::rbegin (void)
+{
+ return ACE_AMM_BASE::rbegin ();
+}
+
+template <class T> ACE_INLINE ACE_Map_Reverse_Iterator<ACE_Active_Map_Manager_Key, T, ACE_Null_Mutex>
+ACE_Active_Map_Manager<T>::rend (void)
+{
+ return ACE_AMM_BASE::rend ();
+}
diff --git a/ace/Utils/Arg_Shifter.cpp b/ace/Utils/Arg_Shifter.cpp
new file mode 100644
index 00000000000..2fc8aca6a96
--- /dev/null
+++ b/ace/Utils/Arg_Shifter.cpp
@@ -0,0 +1,203 @@
+// $Id$
+
+// #include "ace/OS.h"
+#include "ace/Arg_Shifter.h"
+
+ACE_RCSID(ace, Arg_Shifter, "$Id$")
+
+ACE_Arg_Shifter::ACE_Arg_Shifter (int& argc,
+ const ACE_TCHAR** argv,
+ const ACE_TCHAR** temp)
+ : argc_ (argc),
+ total_size_ (argc),
+ temp_ (temp),
+ argv_ (argv),
+ current_index_ (0),
+ back_ (argc - 1),
+ front_ (0)
+{
+ this->init ();
+}
+
+ACE_Arg_Shifter::ACE_Arg_Shifter (int& argc,
+ ACE_TCHAR** argv,
+ ACE_TCHAR** temp)
+ : argc_ (argc),
+ total_size_ (argc),
+ temp_ ((const ACE_TCHAR **) temp),
+ argv_ ((const ACE_TCHAR **) argv),
+ current_index_ (0),
+ back_ (argc - 1),
+ front_ (0)
+{
+ this->init ();
+}
+
+void
+ACE_Arg_Shifter::init (void)
+{
+ // If not provided with one, allocate a temporary array.
+ if (this->temp_ == 0)
+ ACE_NEW (this->temp_,
+ const ACE_TCHAR *[this->total_size_]);
+
+ if (this->temp_ != 0)
+ {
+ // Fill the temporary array.
+ this->argc_ = 0;
+ for (int i = 0; i < this->total_size_; i++)
+ {
+ this->temp_[i] = this->argv_[i];
+ this->argv_[i] = 0;
+ }
+ }
+ else
+ {
+ // Allocation failed, prohibit iteration.
+ this->current_index_ = this->argc_;
+ this->front_ = this->argc_;
+ }
+}
+
+ACE_Arg_Shifter::~ACE_Arg_Shifter (void)
+{
+ // Delete the temporary vector.
+ delete [] temp_;
+}
+
+const ACE_TCHAR *
+ACE_Arg_Shifter::get_current (void) const
+{
+ const ACE_TCHAR * retval = 0;
+
+ if (this->is_anything_left ())
+ retval = this->temp_[current_index_];
+
+ return retval;
+}
+
+const ACE_TCHAR *
+ACE_Arg_Shifter::get_the_parameter (const ACE_TCHAR *flag)
+{
+ // the return 0's abound because this method
+ // would otherwise be a deep if { } else { }
+
+ // check to see if any arguments still exist
+ if (!this->is_anything_left())
+ return 0;
+
+ // check to see if the flag is the argument
+ int offset = this->cur_arg_strncasecmp (flag);
+ if (offset == -1)
+ return 0;
+
+ if (offset == 0)
+ {
+ this->consume_arg ();
+
+ if (!this->is_parameter_next())
+ {
+ return 0;
+ }
+ }
+ // the paramter is in the middle somewhere...
+ return this->temp_[current_index_] + offset;
+}
+
+int
+ACE_Arg_Shifter::cur_arg_strncasecmp (const ACE_TCHAR *flag)
+{
+ // Check for a current argument
+ if (this->is_anything_left())
+ {
+ unsigned int flag_length = ACE_OS::strlen(flag);
+
+ // Check for presence of the flag
+ if (ACE_OS::strncasecmp(this->temp_[current_index_],
+ flag,
+ flag_length) == 0)
+ {
+ if (ACE_OS::strlen(temp_[current_index_]) ==
+ flag_length)
+ {
+ // match and lengths are equal
+ return 0;
+ }
+ else
+ {
+ // matches, with more info to boot!
+ return ACE_OS::strspn
+ (this->temp_[current_index_] + flag_length,
+ ACE_LIB_TEXT (" ")) + flag_length;
+ }
+ }
+ }
+ // failure
+ return -1;
+}
+
+int
+ACE_Arg_Shifter::consume_arg (int number)
+{
+ int retval = 0;
+
+ // Stick knowns at the end of the vector (consumed).
+ if (this->is_anything_left() >= number)
+ {
+ for (int i = 0, j = this->back_ - (number - 1);
+ i < number;
+ ++i, ++j, ++this->current_index_)
+ this->argv_[j] = this->temp_[this->current_index_];
+
+ this->back_ -= number;
+ retval = 1;
+ }
+
+ return retval;
+}
+
+int
+ACE_Arg_Shifter::ignore_arg (int number)
+{
+ int retval = 0;
+
+ // Keep unknowns at the head of the vector.
+ if (this->is_anything_left () >= number)
+ {
+ for (int i = 0;
+ i < number;
+ i++, this->current_index_++, this->front_++)
+ this->argv_[this->front_] = this->temp_[this->current_index_];
+
+ retval = 1;
+ this->argc_ += number;
+ }
+
+ return retval;
+}
+
+int
+ACE_Arg_Shifter::is_anything_left (void) const
+{
+ return this->total_size_ - this->current_index_;
+}
+
+int
+ACE_Arg_Shifter::is_option_next (void) const
+{
+ return this->is_anything_left () &&
+ this->temp_[this->current_index_][0] == '-';
+}
+
+int
+ACE_Arg_Shifter::is_parameter_next (void) const
+{
+ return this->is_anything_left ()
+ && this->temp_[this->current_index_][0] != '-';
+}
+
+int
+ACE_Arg_Shifter::num_ignored_args (void) const
+{
+ return this->front_;
+}
diff --git a/ace/Utils/Arg_Shifter.h b/ace/Utils/Arg_Shifter.h
new file mode 100644
index 00000000000..8a6ab8222fc
--- /dev/null
+++ b/ace/Utils/Arg_Shifter.h
@@ -0,0 +1,192 @@
+// This may look like C, but it's really -*- C++ -*-
+
+//=============================================================================
+/**
+ * @file Arg_Shifter.h
+ *
+ * $Id$
+ *
+ * @author Seth Widoff
+ */
+//=============================================================================
+
+#ifndef ACE_ARG_SHIFTER_H
+#define ACE_ARG_SHIFTER_H
+#include "ace/pre.h"
+
+#include "ace/OS.h"
+
+/**
+ * @class ACE_Arg_Shifter
+ *
+ * @brief This ADT operates on a specified set of arguments (@a argv).
+ * As known arguments are scanned, they are shifted to the back of the
+ * @a argv vector, so deeper levels of argument parsing can locate the yet
+ * unprocessed arguments at the beginning of the vector.
+ *
+ * The @c ACE_Arg_Shifter copies the pointers of the @a argv vector
+ * into a temporary array. As the @c ACE_Arg_Shifter iterates over
+ * the copied vector, it places known arguments in the rear of the
+ * vector, leaving the unknown ones in the beginning. So, after having
+ * visited all the arguments in the temporary vector, @c ACE_Arg_Shifter
+ * has placed all the unknown arguments in their original order at
+ * the front of original @a argv.
+ */
+class ACE_Export ACE_Arg_Shifter
+{
+public:
+ // = Initialization and termination methods.
+ /**
+ * Initialize the ACE_Arg_Shifter to the vector over which to
+ * iterate. Optionally, also provide the temporary array for
+ * use in shifting the arguments. If ACE_Arg_Shifter must allocate
+ * the temporary vector internally and dynamic allocation fails, the
+ * ACE_Arg_Shifter will set all indicators to end of the vector,
+ * forbidding iteration. Following iteration over @a argv, the
+ * @a argc value will be updated to contain the number of
+ * unconsumed arguments.
+ * @arg argc The number of strings in @a argv. @a argc will be
+ * updated to reflect the number of unconsumed arguments.
+ * @arg argv The argument vector to shift. The string pointers in
+ * the vector will be reordered to place the @a argc unconsumed
+ * arguments at the front of the vector.
+ * @arg temp A vector of @c ACE_TCHAR pointers at least @a argc
+ * elements long. The vector will be used for argument shifting as
+ * the specified @a argv vector is consumed. The vector must not
+ * be modified while this object exists. If this argument is 0
+ * (the default) the object will allocate and free the temporary
+ * vector transparently.
+ */
+ ACE_Arg_Shifter (int& argc,
+ const ACE_TCHAR **argv,
+ const ACE_TCHAR **temp = 0);
+
+ /// Same behavior as the preceding constructor, but without the
+ /// "const" qualifier.
+ ACE_Arg_Shifter (int& argc,
+ ACE_TCHAR **argv,
+ ACE_TCHAR **temp = 0);
+
+ /// Destructor.
+ ~ACE_Arg_Shifter (void);
+
+ /// Get the current head of the vector.
+ const ACE_TCHAR *get_current (void) const;
+
+ /**
+ * If the <flag> matches the current_arg of arg shifter
+ * this method will attempt to return the associated
+ * parameter value
+ *
+ * Safe to call without checking that a current arg exists
+ *
+ * In the following examples, a pointer to the char* "value" is ret
+ *
+ * eg: main -foobar value, main -FooBar value
+ * main -FOOBARvalue
+ *
+ * all of the above will all match the <flag> == -FooBar
+ * and will return a char* to "value"
+ *
+ * main -foobar 4 would succeed and return a char* to "4"
+ * main -foobar -4 does not succeed (-4 is not a parameter)
+ * but instead, would return 0
+ *
+ * 0 is returned:
+ * If the current argument does not match flag
+ * If there is no parameter found after a 'matched' flag
+ *
+ * If the flag is matched and the flag and paramter DO NOT RUN
+ * together, the flag is consumed, the parameter is returned,
+ * and the new current argument is the parameter value.
+ * ie '-foobarflag VALUE' leaves the new cur arg == "VALUE"
+ *
+ * If the flag is matched and the flag and parameter RUN
+ * together '-foobarflagVALUE', the flag is NOT consumed
+ * and the cur arg is left pointing to the entire flag/value pair
+ */
+ const ACE_TCHAR *get_the_parameter (const ACE_TCHAR* flag);
+
+ /**
+ * Check if the current argument matches (case insensitive) <flag>
+ *
+ * ------------------------------------------------------------
+ *
+ * Case A: Perfect Match (case insensitive)
+ * 0 is returned.
+ *
+ * ie: when current_arg = "-foobar" or "-FOOBAR" or "-fooBAR"
+ * this->cur_arg_strncasecmp ("-FooBar);
+ * will return 0
+ *
+ * ------------------------------------------------------------
+ *
+ * Case B: Perfect Match (case insensitive) but the current_arg
+ * is longer than the flag. Returns a number equal to the index
+ * in the char* indicating the start of the extra characters
+ *
+ * ie: when current_arg = "-foobar98023"
+ * this->cur_arg_strncasecmp ("-FooBar);
+ * will return 7
+ *
+ * Notice: this number will always be > 0
+ *
+ * ------------------------------------------------------------
+ *
+ * Case C: If neither of Case A or B is met (no match)
+ * then -1 is returned
+ */
+ int cur_arg_strncasecmp (const ACE_TCHAR *flag);
+
+ /// Consume <number> argument(s) by sticking them/it on the end of
+ /// the vector.
+ int consume_arg (int number = 1);
+
+ /// Place <number> arguments in the same relative order ahead of the
+ /// known arguemnts in the vector.
+ int ignore_arg (int number = 1);
+
+ /// Returns the number of args left to see in the vector.
+ int is_anything_left (void) const;
+
+ /// Returns 1 if there's a next item in the vector and it begins with
+ /// '-'.
+ int is_option_next (void) const;
+
+ /// Returns 1 if there's a next item in the vector and it doesn't
+ /// begin with '-'.
+ int is_parameter_next (void) const;
+
+ /// Returns the number of irrelevant args seen.
+ int num_ignored_args (void) const;
+
+private:
+ /// Refactor the constructor logic.
+ void init (void);
+
+ /// The size of the argument vector.
+ int& argc_;
+
+ /// The size of argv_.
+ int total_size_;
+
+ /// The temporary array over which we traverse.
+ const ACE_TCHAR **temp_;
+
+ /// The array in which the arguments are reordered.
+ const ACE_TCHAR **argv_;
+
+ /// The element in <temp_> we're currently examining.
+ int current_index_;
+
+ /// The index of <argv_> in which we'll stick the next unknown
+ /// argument.
+ int back_;
+
+ /// The index of <argv_> in which we'll stick the next known
+ /// argument.
+ int front_;
+};
+
+#include "ace/post.h"
+#endif /* ACE_ARG_SHIFTER_H */
diff --git a/ace/Utils/Capabilities.cpp b/ace/Utils/Capabilities.cpp
new file mode 100644
index 00000000000..9257178d486
--- /dev/null
+++ b/ace/Utils/Capabilities.cpp
@@ -0,0 +1,368 @@
+// $Id$
+
+#include "ace/Map_Manager.h"
+#include "ace/Capabilities.h"
+#include "ace/Log_Msg.h"
+
+#if !defined (__ACE_INLINE__)
+#include "ace/Capabilities.i"
+#endif /* !__ACE_INLINE__ */
+
+#define ACE_ESC ((ACE_TCHAR)0x1b)
+
+ACE_CapEntry::~ACE_CapEntry (void)
+{
+}
+
+ACE_Capabilities::ACE_Capabilities (void)
+{
+}
+
+ACE_Capabilities::~ACE_Capabilities (void)
+{
+ this->resetcaps ();
+}
+
+const ACE_TCHAR *
+ACE_Capabilities::parse (const ACE_TCHAR *buf, ACE_TString &cap)
+{
+ while (*buf != ACE_LIB_TEXT ('\0') && *buf != ACE_LIB_TEXT (','))
+ {
+ if (*buf == ACE_LIB_TEXT ('\\'))
+ {
+ buf++;
+ if (*buf == ACE_LIB_TEXT ('E') || *buf == ACE_LIB_TEXT ('e'))
+ {
+ cap += ACE_ESC;
+ buf++;
+ continue;
+ }
+ else if (*buf == ACE_LIB_TEXT ('r'))
+ {
+ cap += ACE_LIB_TEXT ('\r');
+ buf++;
+ continue;
+ }
+ else if (*buf == ACE_LIB_TEXT ('n'))
+ {
+ cap += ACE_LIB_TEXT ('\n');
+ buf++;
+ continue;
+ }
+ else if (*buf == ACE_LIB_TEXT ('t'))
+ {
+ cap += ACE_LIB_TEXT ('\t');
+ buf++;
+ continue;
+ }
+ else if (*buf == ACE_LIB_TEXT ('\\'))
+ {
+ cap += *buf++;
+ continue;
+ }
+ if (isdigit(*buf))
+ {
+ // @@ UNICODE Does this work with unicode?
+ int oc = 0;
+ for (int i = 0;
+ i < 3 && *buf && isdigit (*buf);
+ i++)
+ oc = oc * 8 + (*buf++ - ACE_LIB_TEXT ('0'));
+
+ cap += (ACE_TCHAR) oc;
+ continue;
+ }
+ }
+ cap += *buf++;
+ }
+ return buf;
+}
+
+const ACE_TCHAR *
+ACE_Capabilities::parse (const ACE_TCHAR *buf, int &cap)
+{
+ int n = 0;
+
+ while (*buf && isdigit (*buf))
+ n = n * 10 + (*buf++ - ACE_LIB_TEXT ('0'));
+
+ cap = n;
+
+ return buf;
+}
+
+void
+ACE_Capabilities::resetcaps (void)
+{
+ for (ACE_Hash_Map_Iterator<ACE_TString, ACE_CapEntry *, ACE_Null_Mutex> iter (caps_);
+ !iter.done ();
+ iter.advance ())
+ {
+ ACE_Hash_Map_Entry<ACE_TString,ACE_CapEntry*> *entry;
+ iter.next (entry);
+ delete entry->int_id_;
+ }
+
+ caps_.close ();
+ caps_.open ();
+}
+
+int
+ACE_Capabilities::fillent (const ACE_TCHAR *buf)
+{
+ this->resetcaps ();
+ while (*buf)
+ {
+ ACE_TString s;
+ int n;
+ ACE_TString name;
+ ACE_CapEntry *ce;
+
+ // Skip blanks
+ while (*buf && isspace(*buf)) buf++;
+ // If we get end of line return
+
+ if (*buf == ACE_LIB_TEXT ('\0'))
+ break;
+
+ if (*buf == ACE_LIB_TEXT ('#'))
+ {
+ while (*buf && *buf != ACE_LIB_TEXT ('\n'))
+ buf++;
+ if (*buf == ACE_LIB_TEXT ('\n'))
+ buf++;
+ continue;
+ }
+ while(*buf && *buf != ACE_LIB_TEXT ('=')
+ && *buf!= ACE_LIB_TEXT ('#')
+ && *buf != ACE_LIB_TEXT (','))
+ name += *buf++;
+
+ // If name is null.
+ switch (*buf)
+ {
+ case ACE_LIB_TEXT ('='):
+ // String property
+ buf = this->parse (buf + 1, s);
+ ACE_NEW_RETURN (ce,
+ ACE_StringCapEntry (s),
+ -1);
+ if (caps_.bind (name, ce) == -1)
+ {
+ delete ce;
+ return -1;
+ }
+ break;
+ case ACE_LIB_TEXT ('#'):
+ // Integer property
+ buf = this->parse (buf + 1, n);
+ ACE_NEW_RETURN (ce,
+ ACE_IntCapEntry (n),
+ -1);
+ if (caps_.bind (name, ce) == -1)
+ {
+ delete ce;
+ return -1;
+ }
+ break;
+ case ACE_LIB_TEXT (','):
+ // Boolean
+ ACE_NEW_RETURN (ce,
+ ACE_BoolCapEntry (1),
+ -1);
+ if (caps_.bind (name, ce) == -1)
+ {
+ delete ce;
+ return -1;
+ }
+ break;
+ default:
+ return 0;
+ }
+
+ if (*buf++ != ACE_LIB_TEXT (','))
+ return -1;
+ }
+
+ return 0;
+}
+
+int
+ACE_Capabilities::is_entry (const ACE_TCHAR *name, const ACE_TCHAR *line)
+{
+ for (;;)
+ {
+ // Skip blanks or irrelevant characters
+ while (*line && isspace(*line))
+ line++;
+
+ // End of line reached
+ if (*line == ACE_LIB_TEXT ('\0'))
+ break;
+
+ // Build the entry name
+ ACE_TString nextname;
+ while (*line && *line != ACE_LIB_TEXT ('|') && *line != ACE_LIB_TEXT (','))
+ nextname += *line++;
+
+ // We have found the required entry?
+ if (ACE_OS::strcmp (nextname.c_str (), name) == 0)
+ return 1;
+
+ // Skip puntuaction char if neccesary.
+ if (*line == ACE_LIB_TEXT ('|') || *line == ACE_LIB_TEXT (','))
+ line++;
+ else
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_LIB_TEXT ("Invalid entry\n")));
+ break;
+ }
+ }
+ return 0;
+}
+
+int
+ACE_Capabilities::getline (FILE *fp, ACE_TString &line)
+{
+ int ch;
+
+ line.set (0, 0);
+
+ while ((ch = fgetc (fp)) != EOF && ch != ACE_LIB_TEXT ('\n'))
+ line += (ACE_TCHAR) ch;
+
+ if (ch == EOF && line.length () == 0)
+ return -1;
+ else
+ return 0;
+}
+
+int
+ACE_Capabilities::getval (const ACE_TCHAR *keyname, ACE_TString &val)
+{
+ ACE_CapEntry* cap;
+ if (caps_.find (keyname, cap) == -1)
+ return -1;
+
+ ACE_StringCapEntry *scap =
+ ACE_dynamic_cast (ACE_StringCapEntry *, cap);
+ if (scap == 0)
+ return -1;
+
+ val = scap->getval ();
+ return 0;
+}
+
+int
+ACE_Capabilities::getval (const ACE_TCHAR *keyname, int &val)
+{
+ ACE_CapEntry *cap;
+ if (caps_.find (keyname, cap) == -1)
+ return -1;
+
+ ACE_IntCapEntry *icap =
+ ACE_dynamic_cast (ACE_IntCapEntry *, cap);
+ if (icap != 0)
+ {
+ val = icap->getval ();
+ return 0;
+ }
+
+ ACE_BoolCapEntry *bcap =
+ ACE_dynamic_cast (ACE_BoolCapEntry *, cap);
+
+ if (bcap == 0)
+ return -1;
+
+ val = bcap->getval ();
+ return 0;
+}
+
+#if !defined (ACE_IS_SPLITTING)
+static int
+is_empty (const ACE_TCHAR *line)
+{
+ while (*line && isspace (*line))
+ line++;
+
+ return *line == ACE_LIB_TEXT ('\0') || *line == ACE_LIB_TEXT ('#');
+}
+
+static int
+is_line (const ACE_TCHAR *line)
+{
+ while (*line && isspace (*line))
+ line++;
+
+ return *line != ACE_LIB_TEXT ('\0');
+}
+#endif /* !ACE_IS_SPLITTING */
+
+int
+ACE_Capabilities::getent (const ACE_TCHAR *fname, const ACE_TCHAR *name)
+{
+ FILE *fp = ACE_OS::fopen (fname, ACE_LIB_TEXT ("r"));
+
+ if (fp == 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_LIB_TEXT ("Can't open %s file\n"),
+ fname),
+ -1);
+
+ int done;
+ ACE_TString line;
+
+ while (!(done = (this->getline (fp, line) == -1))
+ && is_empty (line.c_str ()))
+ continue;
+
+ while (!done)
+ {
+ ACE_TString newline;
+ ACE_TString description;
+
+ while (!(done = (this->getline (fp, newline) == -1)))
+ if (is_line (newline.c_str ()))
+ description += newline;
+ else
+ break;
+
+ if (this->is_entry (name, line.c_str()))
+ {
+ ACE_OS::fclose (fp);
+ return this->fillent (description.c_str ());
+ }
+
+ line = newline;
+ while (!done && is_empty (line.c_str ()))
+ done = this->getline (fp, line) == -1;
+ }
+
+ ACE_OS::fclose (fp);
+ return -1;
+}
+
+#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION)
+template class ACE_Hash_Map_Manager<ACE_TString,ACE_CapEntry*,ACE_Null_Mutex>;
+template class ACE_Hash_Map_Iterator<ACE_TString,ACE_CapEntry*,ACE_Null_Mutex>;
+template class ACE_Hash_Map_Reverse_Iterator<ACE_TString,ACE_CapEntry*,ACE_Null_Mutex>;
+template class ACE_Hash_Map_Entry<ACE_TString,ACE_CapEntry*>;
+template class ACE_Hash_Map_Manager_Ex<ACE_TString,ACE_CapEntry*,ACE_Hash<ACE_TString>,ACE_Equal_To<ACE_TString>,ACE_Null_Mutex>;
+template class ACE_Hash_Map_Iterator_Base_Ex<ACE_TString,ACE_CapEntry*,ACE_Hash<ACE_TString>,ACE_Equal_To<ACE_TString>,ACE_Null_Mutex>;
+template class ACE_Hash_Map_Iterator_Ex<ACE_TString,ACE_CapEntry*,ACE_Hash<ACE_TString>,ACE_Equal_To<ACE_TString>,ACE_Null_Mutex>;
+template class ACE_Hash_Map_Reverse_Iterator_Ex<ACE_TString,ACE_CapEntry*,ACE_Hash<ACE_TString>,ACE_Equal_To<ACE_TString>,ACE_Null_Mutex>;
+template class ACE_Hash<ACE_TString>;
+template class ACE_Equal_To<ACE_TString>;
+#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA)
+#pragma instantiate ACE_Hash_Map_Manager<ACE_TString,ACE_CapEntry*,ACE_Null_Mutex>
+#pragma instantiate ACE_Hash_Map_Iterator<ACE_TString,ACE_CapEntry*,ACE_Null_Mutex>
+#pragma instantiate ACE_Hash_Map_Reverse_Iterator<ACE_TString,ACE_CapEntry*,ACE_Null_Mutex>
+#pragma instantiate ACE_Hash_Map_Entry<ACE_TString,ACE_CapEntry*>
+#pragma instantiate ACE_Hash_Map_Manager_Ex<ACE_TString,ACE_CapEntry*,ACE_Hash<ACE_TString>,ACE_Equal_To<ACE_TString>,ACE_Null_Mutex>
+#pragma instantiate ACE_Hash_Map_Iterator_Base_Ex<ACE_TString,ACE_CapEntry*,ACE_Hash<ACE_TString>,ACE_Equal_To<ACE_TString>,ACE_Null_Mutex>
+#pragma instantiate ACE_Hash_Map_Iterator_Ex<ACE_TString,ACE_CapEntry*,ACE_Hash<ACE_TString>,ACE_Equal_To<ACE_TString>,ACE_Null_Mutex>
+#pragma instantiate ACE_Hash_Map_Reverse_Iterator_Ex<ACE_TString,ACE_CapEntry*,ACE_Hash<ACE_TString>,ACE_Equal_To<ACE_TString>,ACE_Null_Mutex>
+#pragma instantiate ACE_Hash<ACE_TString>
+#pragma instantiate ACE_Equal_To<ACE_TString>
+#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */
diff --git a/ace/Utils/Capabilities.h b/ace/Utils/Capabilities.h
new file mode 100644
index 00000000000..03fc25242e6
--- /dev/null
+++ b/ace/Utils/Capabilities.h
@@ -0,0 +1,199 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Capabilities.h
+ *
+ * $Id$
+ *
+ * @author Arturo Montes <mitosys@colomsat.net.co>
+ */
+//=============================================================================
+
+
+#ifndef ACE_CAPABILITIES_H
+#define ACE_CAPABILITIES_H
+#include "ace/pre.h"
+
+#include "ace/OS.h"
+#include "ace/Synch.h"
+#include "ace/Hash_Map_Manager.h"
+#include "ace/Containers.h"
+#include "ace/SString.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+/**
+ * @class ACE_CapEntry
+ *
+ * @brief This class is the base class for all ACE Capabilities entry
+ * subclasses.
+ *
+ * This class is not instantiable and does not provide accessors
+ * or methods. If you want to add a new kind of attribute you
+ * subclasses of this class and dynamic cast to proper subclass.
+ */
+class ACE_Export ACE_CapEntry
+{
+public:
+ virtual ~ACE_CapEntry (void);
+
+protected:
+ enum
+ {
+ ACE_INTCAP = 0,
+ ACE_STRINGCAP = 1,
+ ACE_BOOLCAP = 2
+ };
+
+ ACE_CapEntry (int captype);
+
+ int captype_;
+};
+
+/**
+ * @class ACE_IntCapEntry
+ *
+ * @brief This class implement the ACE Integer Capability subclass.
+ *
+ * This is a container class for ACE Capabilities integer container
+ * values.
+ */
+class ACE_Export ACE_IntCapEntry : public ACE_CapEntry
+{
+public:
+ ACE_IntCapEntry (int val);
+ int getval (void) const;
+
+protected:
+ int val_;
+};
+
+/**
+ * @class ACE_StringCapEntry
+ *
+ * @brief This class implement the ACE String Capability subclass.
+ *
+ * This is a container class for ACE Capabilities String container
+ * values.
+ */
+class ACE_Export ACE_StringCapEntry : public ACE_CapEntry
+{
+public:
+ ACE_StringCapEntry (const ACE_TString &val);
+ ACE_TString getval (void) const;
+
+protected:
+ ACE_TString val_;
+};
+
+/**
+ * @class ACE_BoolCapEntry
+ *
+ * @brief This class implement the ACE Bool Capability subclass.
+ *
+ * This is a container class for ACE Capabilities bool container
+ * values.
+ */
+class ACE_Export ACE_BoolCapEntry : public ACE_CapEntry
+{
+public:
+ ACE_BoolCapEntry (int val);
+ int getval (void) const;
+
+protected:
+ int val_;
+};
+
+/**
+ * @class ACE_Capabilities
+ *
+ * @brief This class implement the ACE Capabilities.
+ *
+ * This is a container class for ACE Capabilities
+ * values. Currently exist three different capability values:
+ * <ACE_IntCapEntry> (integer), <ACE_BoolCapEntry> (bool) and
+ * <ACE_StringCapEntry> (String). An <ACE_Capabilities> is a
+ * unordered set of pair = (<String>, <ACE_CapEntry> *). Where
+ * the first component is the name of capability and the second
+ * component is a pointer to the capability value container. A
+ * <FILE> is a container for <ACE_Capabilities>, the
+ * <ACE_Capabilities> has a name in the file, as a termcap file.
+ */
+class ACE_Export ACE_Capabilities
+{
+public:
+ /// The Constructor
+ ACE_Capabilities (void);
+
+ /// The Destructor
+ ~ACE_Capabilities(void);
+
+public:
+ /// Get a string entry.
+ int getval (const ACE_TCHAR *ent, ACE_TString &val);
+
+ /// Get an integer entry.
+ int getval (const ACE_TCHAR *ent, int &val);
+
+ /// Get the ACE_Capabilities name from FILE fname and load the
+ /// associated capabitily entries in map.
+ int getent (const ACE_TCHAR *fname, const ACE_TCHAR *name);
+
+protected:
+ // Parse an integer property
+ /// Parse a string property
+ const ACE_TCHAR *parse (const ACE_TCHAR *buf, int &cap);
+
+ /// Fill the ACE_Capabilities with description in ent.
+ const ACE_TCHAR *parse (const ACE_TCHAR *buf, ACE_TString &cap);
+
+ /// Parse a cap entry
+ int fillent(const ACE_TCHAR *ent);
+
+ /// Get a line from FILE input stream
+ int parseent (const ACE_TCHAR *name, ACE_TCHAR *line);
+
+ /// Is a valid entry
+ int getline (FILE* fp,
+ ACE_TString &line);
+
+ /// Reset the set of capabilities
+ int is_entry (const ACE_TCHAR *name, const ACE_TCHAR *line);
+
+ /// Atributes.
+ void resetcaps (void);
+
+private:
+ /// This is the set of ACE_CapEntry.
+ ACE_Hash_Map_Manager<ACE_TString, ACE_CapEntry *, ACE_Null_Mutex> caps_;
+};
+
+#if defined (ACE_IS_SPLITTING)
+int
+is_empty (const ACE_TCHAR *line)
+{
+ while (*line && isspace (*line))
+ line++;
+
+ return *line == ACE_LIB_TEXT ('\0') || *line == ACE_LIB_TEXT ('#');
+}
+
+int
+is_line (const ACE_TCHAR *line)
+{
+ while (*line && isspace (*line))
+ line++;
+
+ return *line != ACE_LIB_TEXT ('\0');
+}
+#endif /* ACE_IS_SPLITTING */
+
+#if defined (__ACE_INLINE__)
+#include "ace/Capabilities.i"
+#endif /* __ACE_INLINE__ */
+
+#include "ace/post.h"
+#endif /* __ACE_CAPABILITIES_H__ */
diff --git a/ace/Utils/Capabilities.i b/ace/Utils/Capabilities.i
new file mode 100644
index 00000000000..d34d0e08862
--- /dev/null
+++ b/ace/Utils/Capabilities.i
@@ -0,0 +1,47 @@
+/* -*- C++ -*- */
+// $Id$
+
+ACE_INLINE
+ACE_CapEntry::ACE_CapEntry (int captype)
+ : captype_ (captype)
+{
+}
+
+ACE_INLINE
+ACE_IntCapEntry::ACE_IntCapEntry (int val)
+ : ACE_CapEntry (ACE_INTCAP),
+ val_ (val)
+{
+}
+
+ACE_INLINE int
+ACE_IntCapEntry::getval (void) const
+{
+ return val_;
+}
+
+ACE_INLINE
+ACE_StringCapEntry::ACE_StringCapEntry (const ACE_TString &val)
+ : ACE_CapEntry (ACE_STRINGCAP),
+ val_(val)
+{
+}
+
+ACE_INLINE ACE_TString
+ACE_StringCapEntry::getval (void) const
+{
+ return val_;
+}
+
+ACE_INLINE
+ACE_BoolCapEntry::ACE_BoolCapEntry (int val)
+ : ACE_CapEntry (ACE_BOOLCAP),
+ val_(val)
+{
+}
+
+ACE_INLINE int
+ACE_BoolCapEntry::getval (void) const
+{
+ return val_;
+}
diff --git a/ace/Utils/Configuration.cpp b/ace/Utils/Configuration.cpp
new file mode 100644
index 00000000000..80f14b2a154
--- /dev/null
+++ b/ace/Utils/Configuration.cpp
@@ -0,0 +1,2055 @@
+// $Id$
+#include "ace/Configuration.h"
+#include "ace/Auto_Ptr.h"
+
+// Can remove this when import_config and export_config are removed from
+// ACE_Configuration. They're deprecated at ACE 5.2.
+#include "ace/Configuration_Import_Export.h"
+
+#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION)
+
+#if defined (ACE_HAS_THREADS)
+// ACE_SYNCH_MUTEX should not be used in the template instantiations
+// because the resulting template instantiation for the
+// single-threaded case already exists in ACE.
+template class ACE_Allocator_Adapter<ACE_Malloc<ACE_MMAP_MEMORY_POOL, ACE_Thread_Mutex> >;
+template class ACE_Malloc<ACE_MMAP_MEMORY_POOL, ACE_Thread_Mutex>;
+template class ACE_Malloc_T<ACE_MMAP_MEMORY_POOL, ACE_Thread_Mutex, ACE_Control_Block>;
+#endif /* ACE_HAS_THREADS */
+template class ACE_Hash_Map_Entry<ACE_Configuration_ExtId, ACE_Configuration_Section_IntId>;
+template class ACE_Hash_Map_Entry<ACE_Configuration_ExtId, ACE_Configuration_Value_IntId>;
+template class ACE_Hash_Map_Entry<ACE_Configuration_ExtId, int>;
+template class ACE_Hash_Map_Iterator_Base_Ex<ACE_Configuration_ExtId, ACE_Configuration_Section_IntId, ACE_Hash<ACE_Configuration_ExtId>, ACE_Equal_To<ACE_Configuration_ExtId>, ACE_Null_Mutex>;
+template class ACE_Hash_Map_Iterator_Base_Ex<ACE_Configuration_ExtId, ACE_Configuration_Value_IntId, ACE_Hash<ACE_Configuration_ExtId>, ACE_Equal_To<ACE_Configuration_ExtId>, ACE_Null_Mutex>;
+template class ACE_Hash_Map_Iterator_Base_Ex<ACE_Configuration_ExtId, int, ACE_Hash<ACE_Configuration_ExtId>, ACE_Equal_To<ACE_Configuration_ExtId>, ACE_Null_Mutex>;
+
+
+// Added to fix problems in SunOS CC5.0
+template class ACE_Hash_Map_Reverse_Iterator_Ex<ACE_Configuration_ExtId,ACE_Configuration_Value_IntId,ACE_Hash<ACE_Configuration_ExtId>,ACE_Equal_To<ACE_Configuration_ExtId>,ACE_Null_Mutex>;
+template class ACE_Hash_Map_Iterator_Ex<ACE_Configuration_ExtId,ACE_Configuration_Value_IntId,ACE_Hash<ACE_Configuration_ExtId>,ACE_Equal_To<ACE_Configuration_ExtId>,ACE_Null_Mutex>;
+template class ACE_Hash_Map_Iterator_Ex<ACE_Configuration_ExtId,int,ACE_Hash<ACE_Configuration_ExtId>,ACE_Equal_To<ACE_Configuration_ExtId>,ACE_Null_Mutex>;
+template class ACE_Hash_Map_Iterator_Ex<ACE_Configuration_ExtId,ACE_Configuration_Section_IntId,ACE_Hash<ACE_Configuration_ExtId>,ACE_Equal_To<ACE_Configuration_ExtId>,ACE_Null_Mutex>;
+template class ACE_Equal_To<ACE_Configuration_ExtId>;
+template class ACE_Hash_Map_Reverse_Iterator_Ex<ACE_Configuration_ExtId,ACE_Configuration_Section_IntId,ACE_Hash<ACE_Configuration_ExtId>,ACE_Equal_To<ACE_Configuration_ExtId>,ACE_Null_Mutex>;
+template class ACE_Hash_Map_Reverse_Iterator_Ex<ACE_Configuration_ExtId,int,ACE_Hash<ACE_Configuration_ExtId>,ACE_Equal_To<ACE_Configuration_ExtId>,ACE_Null_Mutex>;
+template class ACE_Hash<ACE_Configuration_ExtId>;
+
+template class ACE_Hash_Map_Manager_Ex<ACE_Configuration_ExtId, ACE_Configuration_Section_IntId, ACE_Hash<ACE_Configuration_ExtId>, ACE_Equal_To<ACE_Configuration_ExtId>, ACE_Null_Mutex>;
+template class ACE_Hash_Map_Manager_Ex<ACE_Configuration_ExtId, ACE_Configuration_Value_IntId, ACE_Hash<ACE_Configuration_ExtId>, ACE_Equal_To<ACE_Configuration_ExtId>, ACE_Null_Mutex>;
+template class ACE_Hash_Map_Manager_Ex<ACE_Configuration_ExtId, int, ACE_Hash<ACE_Configuration_ExtId>, ACE_Equal_To<ACE_Configuration_ExtId>, ACE_Null_Mutex>;
+template class ACE_Hash_Map_Manager<ACE_Configuration_ExtId, ACE_Configuration_Section_IntId, ACE_Null_Mutex>;
+template class ACE_Hash_Map_Manager<ACE_Configuration_ExtId, ACE_Configuration_Value_IntId, ACE_Null_Mutex>;
+template class ACE_Hash_Map_Manager<ACE_Configuration_ExtId, int, ACE_Null_Mutex>;
+template class ACE_Hash_Map_With_Allocator<ACE_Configuration_ExtId, ACE_Configuration_Section_IntId>;
+template class ACE_Hash_Map_With_Allocator<ACE_Configuration_ExtId, ACE_Configuration_Value_IntId>;
+template class ACE_Hash_Map_With_Allocator<ACE_Configuration_ExtId, int>;
+
+#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA)
+
+#if defined (ACE_HAS_THREADS)
+// ACE_SYNCH_MUTEX should not be used in the template instantiations
+// because the resulting template instantiation for the
+// single-threaded case already exists in ACE.
+#pragma instantiate ACE_Allocator_Adapter<ACE_Malloc<ACE_MMAP_MEMORY_POOL, ACE_Thread_Mutex> >
+#pragma instantiate ACE_Malloc<ACE_MMAP_MEMORY_POOL, ACE_Thread_Mutex>
+#pragma instantiate ACE_Malloc_T<ACE_MMAP_MEMORY_POOL, ACE_Thread_Mutex, ACE_Control_Block>
+#endif /* ACE_HAS_THREADS */
+#pragma instantiate ACE_Hash_Map_Entry<ACE_Configuration_ExtId, ACE_Configuration_Section_IntId>
+#pragma instantiate ACE_Hash_Map_Entry<ACE_Configuration_ExtId, ACE_Configuration_Value_IntId>
+#pragma instantiate ACE_Hash_Map_Entry<ACE_Configuration_ExtId, int>
+#pragma instantiate ACE_Hash_Map_Iterator_Base_Ex<ACE_Configuration_ExtId, ACE_Configuration_Section_IntId, ACE_Hash<ACE_Configuration_ExtId>, ACE_Equal_To<ACE_Configuration_ExtId>, ACE_Null_Mutex>
+#pragma instantiate ACE_Hash_Map_Iterator_Base_Ex<ACE_Configuration_ExtId, ACE_Configuration_Value_IntId, ACE_Hash<ACE_Configuration_ExtId>, ACE_Equal_To<ACE_Configuration_ExtId>, ACE_Null_Mutex>
+#pragma instantiate ACE_Hash_Map_Iterator_Base_Ex<ACE_Configuration_ExtId, int, ACE_Hash<ACE_Configuration_ExtId>, ACE_Equal_To<ACE_Configuration_ExtId>, ACE_Null_Mutex>
+
+#pragma instantiate ACE_Hash_Map_Reverse_Iterator_Ex<ACE_Configuration_ExtId,ACE_Configuration_Value_IntId,ACE_Hash<ACE_Configuration_ExtId>,ACE_Equal_To<ACE_Configuration_ExtId>,ACE_Null_Mutex>
+#pragma instantiate ACE_Hash_Map_Iterator_Ex<ACE_Configuration_ExtId,ACE_Configuration_Value_IntId,ACE_Hash<ACE_Configuration_ExtId>,ACE_Equal_To<ACE_Configuration_ExtId>,ACE_Null_Mutex>
+#pragma instantiate ACE_Hash_Map_Iterator_Ex<ACE_Configuration_ExtId,int,ACE_Hash<ACE_Configuration_ExtId>,ACE_Equal_To<ACE_Configuration_ExtId>,ACE_Null_Mutex>
+#pragma instantiate ACE_Hash_Map_Iterator_Ex<ACE_Configuration_ExtId,ACE_Configuration_Section_IntId,ACE_Hash<ACE_Configuration_ExtId>,ACE_Equal_To<ACE_Configuration_ExtId>,ACE_Null_Mutex>
+#pragma instantiate ACE_Equal_To<ACE_Configuration_ExtId>
+#pragma instantiate ACE_Hash_Map_Reverse_Iterator_Ex<ACE_Configuration_ExtId,ACE_Configuration_Section_IntId,ACE_Hash<ACE_Configuration_ExtId>,ACE_Equal_To<ACE_Configuration_ExtId>,ACE_Null_Mutex>
+#pragma instantiate ACE_Hash_Map_Reverse_Iterator_Ex<ACE_Configuration_ExtId,int,ACE_Hash<ACE_Configuration_ExtId>,ACE_Equal_To<ACE_Configuration_ExtId>,ACE_Null_Mutex>
+#pragma instantiate ACE_Hash<ACE_Configuration_ExtId>
+
+#pragma instantiate ACE_Hash_Map_Manager_Ex<ACE_Configuration_ExtId, ACE_Configuration_Section_IntId, ACE_Hash<ACE_Configuration_ExtId>, ACE_Equal_To<ACE_Configuration_ExtId>, ACE_Null_Mutex>
+#pragma instantiate ACE_Hash_Map_Manager_Ex<ACE_Configuration_ExtId, ACE_Configuration_Value_IntId, ACE_Hash<ACE_Configuration_ExtId>, ACE_Equal_To<ACE_Configuration_ExtId>, ACE_Null_Mutex>
+#pragma instantiate ACE_Hash_Map_Manager_Ex<ACE_Configuration_ExtId, int, ACE_Hash<ACE_Configuration_ExtId>, ACE_Equal_To<ACE_Configuration_ExtId>, ACE_Null_Mutex>
+#pragma instantiate ACE_Hash_Map_Manager<ACE_Configuration_ExtId, ACE_Configuration_Section_IntId, ACE_Null_Mutex>
+#pragma instantiate ACE_Hash_Map_Manager<ACE_Configuration_ExtId, ACE_Configuration_Value_IntId, ACE_Null_Mutex>
+#pragma instantiate ACE_Hash_Map_Manager<ACE_Configuration_ExtId, int, ACE_Null_Mutex>
+#pragma instantiate ACE_Hash_Map_With_Allocator<ACE_Configuration_ExtId, ACE_Configuration_Section_IntId>
+#pragma instantiate ACE_Hash_Map_With_Allocator<ACE_Configuration_ExtId, ACE_Configuration_Value_IntId>
+#pragma instantiate ACE_Hash_Map_With_Allocator<ACE_Configuration_ExtId, int>
+
+#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */
+
+ACE_Section_Key_Internal::ACE_Section_Key_Internal (void)
+ : ref_count_ (0)
+{
+}
+
+ACE_Section_Key_Internal::~ACE_Section_Key_Internal (void)
+{
+}
+
+int
+ACE_Section_Key_Internal::add_ref (void)
+{
+ ++ref_count_;
+ return 0;
+}
+
+int
+ACE_Section_Key_Internal::dec_ref (void)
+{
+ if (!--ref_count_)
+ delete this;
+ return 0;
+}
+
+ACE_Configuration_Section_Key::ACE_Configuration_Section_Key (void)
+ : key_ (0)
+{
+}
+
+ACE_Configuration_Section_Key::~ACE_Configuration_Section_Key (void)
+{
+ if (key_)
+ key_->dec_ref ();
+}
+
+ACE_Configuration_Section_Key::ACE_Configuration_Section_Key (ACE_Section_Key_Internal* key)
+ : key_ (key)
+{
+ if (key_)
+ key_->add_ref ();
+}
+
+ACE_Configuration_Section_Key::ACE_Configuration_Section_Key (const ACE_Configuration_Section_Key& rhs)
+ : key_ (rhs.key_)
+{
+ if (key_)
+ key_->add_ref ();
+}
+
+ACE_Configuration_Section_Key&
+ACE_Configuration_Section_Key::operator= (const ACE_Configuration_Section_Key& rhs)
+{
+ if (this != &rhs)
+ {
+ if (key_)
+ key_->dec_ref ();
+
+ key_ = rhs.key_;
+
+ if (key_)
+ key_->add_ref ();
+ }
+ return *this;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+ACE_Configuration::ACE_Configuration (void)
+ : root_ ()
+{
+}
+
+ACE_Configuration::~ACE_Configuration (void)
+{
+}
+
+ACE_Section_Key_Internal*
+ACE_Configuration::get_internal_key (const ACE_Configuration_Section_Key& key)
+{
+ return key.key_;
+}
+
+int
+ACE_Configuration::expand_path (const ACE_Configuration_Section_Key& key,
+ const ACE_TString& path_in,
+ ACE_Configuration_Section_Key& key_out,
+ int create)
+{
+ // Make a copy of key
+ ACE_Configuration_Section_Key current_section = key;
+ ACE_Auto_Basic_Array_Ptr<ACE_TCHAR> pData (path_in.rep ());
+ ACE_Tokenizer parser (pData.get ());
+ parser.delimiter_replace ('\\', '\0');
+ parser.delimiter_replace ('/', '\0');
+
+ for (ACE_TCHAR *temp = parser.next ();
+ temp != 0;
+ temp = parser.next ())
+ {
+ // Open the section
+ if (open_section (current_section,
+ temp,
+ create,
+ key_out))
+ return -1;
+
+ current_section = key_out;
+ }
+
+ return 0;
+
+}
+
+// import_config and export_config are here for backward compatibility,
+// and have been deprecated.
+int
+ACE_Configuration::export_config (const ACE_TCHAR* filename)
+{
+ ACE_Registry_ImpExp exporter (*this);
+ return exporter.export_config (filename);
+}
+
+int
+ACE_Configuration::import_config (const ACE_TCHAR* filename)
+{
+ ACE_Registry_ImpExp importer (*this);
+ return importer.import_config (filename);
+}
+
+int
+ACE_Configuration::validate_name (const ACE_TCHAR* name)
+{
+ const ACE_TCHAR *pos;
+
+ for (pos = name;
+ // Make sure it doesn't contain any invalid characters
+ *pos != '\0';
+ pos++)
+ if (ACE_OS::strchr (ACE_LIB_TEXT ("\\]["), *pos))
+ return -1;
+
+ // Make sure its not too long.
+ if (pos - name > 255)
+ return -2;
+
+ return 0;
+}
+
+
+const ACE_Configuration_Section_Key&
+ACE_Configuration::root_section (void) const
+{
+ return root_;
+}
+
+/**
+ * Determine if the contents of this object is the same as the
+ * contents of the object on the right hand side.
+ * Returns 1 (True) if they are equal and 0 (False) if they are not equal
+ */
+int ACE_Configuration::operator== (const ACE_Configuration& rhs) const
+{
+ int rc = 1;
+ int sectionIndex = 0;
+ ACE_TString sectionName;
+ ACE_Configuration *nonconst_this = ACE_const_cast (ACE_Configuration*, this);
+ ACE_Configuration &nonconst_rhs = ACE_const_cast (ACE_Configuration&, rhs);
+
+ const ACE_Configuration_Section_Key& rhsRoot = rhs.root_section ();
+ ACE_Configuration_Section_Key rhsSection;
+ ACE_Configuration_Section_Key thisSection;
+
+ // loop through each section in this object
+ while ((rc) && (!nonconst_this->enumerate_sections (this->root_,
+ sectionIndex,
+ sectionName)))
+ {
+ // find that section in the rhs object
+ if (nonconst_rhs.open_section (rhsRoot,
+ sectionName.c_str (),
+ 0,
+ rhsSection) != 0)
+ {
+ // If the rhs object does not contain the section then we are
+ // not equal.
+ rc = 0;
+ }
+ else if (nonconst_this->open_section (this->root_,
+ sectionName.c_str (),
+ 0,
+ thisSection) != 0)
+ {
+ // if there is some error opening the section in this object
+ rc = 0;
+ }
+ else
+ {
+ // Well the sections match
+ int valueIndex = 0;
+ ACE_TString valueName;
+ VALUETYPE valueType;
+ VALUETYPE rhsType;
+
+ // Enumerate each value in this section
+ while ((rc) && nonconst_this->enumerate_values (thisSection,
+ valueIndex,
+ valueName,
+ valueType))
+ {
+ // look for the same value in the rhs section
+ if (nonconst_rhs.find_value (rhsSection,
+ valueName.c_str (),
+ rhsType) != 0)
+ {
+ // We're not equal if the same value cannot
+ // be found in the rhs object.
+ rc = 0;
+ }
+ else if (valueType != rhsType)
+ {
+ // we're not equal if the types do not match.
+ rc = 0;
+ }
+ else
+ {
+ // finally compare values.
+ if (valueType == STRING)
+ {
+ ACE_TString thisString, rhsString;
+ if (nonconst_this->get_string_value (thisSection,
+ valueName.c_str (),
+ thisString) != 0)
+ {
+ // we're not equal if we cannot get this string
+ rc = 0;
+ }
+ else if (nonconst_rhs.get_string_value (rhsSection,
+ valueName.c_str (),
+ rhsString) != 0)
+ {
+ // we're not equal if we cannot get rhs string
+ rc = 0;
+ }
+ rc = thisString == rhsString;
+ }
+ else if (valueType == INTEGER)
+ {
+ u_int thisInt, rhsInt;
+ if (nonconst_this->get_integer_value (thisSection,
+ valueName.c_str (),
+ thisInt) != 0)
+ {
+ // we're not equal if we cannot get this int
+ rc = 0;
+ }
+ else if (nonconst_rhs.get_integer_value (rhsSection,
+ valueName.c_str (),
+ rhsInt) != 0)
+ {
+ // we're not equal if we cannot get rhs int
+ rc = 0;
+ }
+ rc = thisInt == rhsInt;
+ }
+ else if (valueType == BINARY)
+ {
+ void* thisData;
+ void* rhsData;
+ u_int thisLength, rhsLength;
+ if (nonconst_this->get_binary_value (thisSection,
+ valueName.c_str (),
+ thisData,
+ thisLength) != 0)
+ {
+ // we're not equal if we cannot get this data
+ rc = 0;
+ }
+ else if (nonconst_rhs.get_binary_value (rhsSection,
+ valueName.c_str (),
+ rhsData,
+ rhsLength) != 0)
+ {
+ // we're not equal if we cannot get this data
+ rc = 0;
+ }
+
+ rc = thisLength == rhsLength;
+ // are the length's the same?
+
+ if (rc)
+ {
+ unsigned char* thisCharData = (unsigned char*)thisData;
+ unsigned char* rhsCharData = (unsigned char*)rhsData;
+ // yes, then check each element
+ for (u_int count = 0;
+ (rc) && (count < thisLength);
+ count++)
+ {
+ rc = (* (thisCharData + count) == * (rhsCharData + count));
+ }
+ }// end if the length's match
+ }
+ // We should never have valueTypes of INVALID, therefore
+ // we're not comparing them. How would we since we have
+ // no get operation for invalid types.
+ // So, if we have them, we guess they are equal.
+
+ }// end else if values match.
+
+ valueIndex++;
+
+ }// end value while loop
+
+ // look in the rhs for values not in this
+ valueIndex = 0;
+ while ((rc) &&
+ (!nonconst_rhs.enumerate_values (rhsSection,
+ valueIndex,
+ valueName,
+ rhsType)))
+ {
+ // look for the same value in this section
+ if (nonconst_this->find_value (thisSection,
+ valueName.c_str (),
+ valueType) != 0)
+ {
+ // We're not equal if the same value cannot
+ // be found in the rhs object.
+ rc = 0;
+ }
+ valueIndex++;
+ }// end while for rhs values not in this.
+
+ }// end else if sections match.
+
+ sectionIndex++;
+
+ }// end section while loop
+
+ // Finally, make sure that there are no sections in rhs that do not
+ // exist in this
+ sectionIndex = 0;
+ while ((rc)
+ && (!nonconst_rhs.enumerate_sections (rhsRoot,
+ sectionIndex,
+ sectionName)))
+ {
+ // find the section in this
+ if (nonconst_this->open_section (this->root_,
+ sectionName.c_str (),
+ 0,
+ thisSection) != 0)
+ {
+ // if there is some error opening the section in this object
+ rc = 0;
+ }
+ else if (nonconst_rhs.open_section (rhsRoot,
+ sectionName.c_str (),
+ 0,
+ rhsSection) != 0)
+ {
+ // If the rhs object does not contain the section then we
+ // are not equal.
+ rc = 0;
+ }
+ sectionIndex++;
+ }
+ return rc;
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+
+#if defined (WIN32)
+
+static const int ACE_DEFAULT_BUFSIZE = 256;
+
+ACE_Section_Key_Win32::ACE_Section_Key_Win32 (HKEY hKey)
+ : hKey_ (hKey)
+{
+}
+
+ACE_Section_Key_Win32::~ACE_Section_Key_Win32 (void)
+{
+ ::RegCloseKey (hKey_);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+int
+ACE_Configuration_Win32Registry::operator== (const ACE_Configuration_Win32Registry &rhs) const
+{
+ ACE_UNUSED_ARG (rhs);
+ return 1;
+}
+
+int
+ACE_Configuration_Win32Registry::operator!=(const ACE_Configuration_Win32Registry &rhs) const
+{
+ ACE_UNUSED_ARG (rhs);
+ return 1;
+}
+
+ACE_Configuration_Win32Registry::ACE_Configuration_Win32Registry (HKEY hKey)
+{
+ ACE_Section_Key_Win32 *temp;
+
+ ACE_NEW (temp, ACE_Section_Key_Win32 (hKey));
+
+ root_ = ACE_Configuration_Section_Key (temp);
+}
+
+
+ACE_Configuration_Win32Registry::~ACE_Configuration_Win32Registry (void)
+{
+}
+
+int
+ACE_Configuration_Win32Registry::open_section (const ACE_Configuration_Section_Key& base,
+ const ACE_TCHAR* sub_section,
+ int create,
+ ACE_Configuration_Section_Key& result)
+{
+ if (validate_name (sub_section))
+ return -1;
+
+ HKEY base_key;
+ if (load_key (base, base_key))
+ return -1;
+
+ HKEY result_key;
+ if (ACE_TEXT_RegOpenKeyEx (base_key,
+ sub_section,
+ 0,
+ KEY_ALL_ACCESS,
+ &result_key) != ERROR_SUCCESS)
+ {
+ if (!create)
+ return -2;
+
+ if (ACE_TEXT_RegCreateKeyEx (base_key,
+ sub_section,
+ 0,
+ NULL,
+ REG_OPTION_NON_VOLATILE,
+ KEY_ALL_ACCESS,
+ NULL,
+ &result_key,
+#if defined (__MINGW32__)
+ (PDWORD) 0
+#else
+ NULL
+#endif /* __MINGW32__ */
+ ) != ERROR_SUCCESS)
+ return -3;
+ }
+
+ ACE_Section_Key_Win32 *temp;
+
+ ACE_NEW_RETURN (temp, ACE_Section_Key_Win32 (result_key), -4);
+ result = ACE_Configuration_Section_Key (temp);
+ return 0;
+}
+
+int
+ACE_Configuration_Win32Registry::remove_section (const ACE_Configuration_Section_Key& key,
+ const ACE_TCHAR* sub_section,
+ int recursive)
+{
+ if (validate_name (sub_section))
+ return -1;
+
+ HKEY base_key;
+ if (load_key (key, base_key))
+ return -1;
+
+ if (recursive)
+ {
+ ACE_Configuration_Section_Key section;
+ if (open_section (key, sub_section, 0, section))
+ return -2;
+
+ HKEY sub_key;
+ if (load_key (section, sub_key))
+ return -3;
+
+ ACE_TCHAR name_buffer[ACE_DEFAULT_BUFSIZE];
+ DWORD buffer_size = ACE_DEFAULT_BUFSIZE;
+ // Note we don't increment the index because the
+ // enumeration becomes invalid if we change the
+ // subkey, which we do when we delete it. By leaving
+ // it 0, we always delete the top entry
+ while (ACE_TEXT_RegEnumKeyEx (sub_key,
+ 0,
+ name_buffer,
+ &buffer_size,
+ NULL,
+ NULL,
+ NULL,
+ NULL) == ERROR_SUCCESS)
+ {
+ remove_section (section, name_buffer, 1);
+ buffer_size = ACE_DEFAULT_BUFSIZE;
+ }
+ }
+
+ if (ACE_TEXT_RegDeleteKey (base_key, sub_section) != ERROR_SUCCESS)
+ return -2;
+
+ return 0;
+}
+
+int
+ACE_Configuration_Win32Registry::enumerate_values (const ACE_Configuration_Section_Key& key,
+ int Index,
+ ACE_TString& name,
+ VALUETYPE& type)
+{
+ HKEY base_key;
+ if (load_key (key, base_key))
+ return -1;
+
+ ACE_TCHAR name_buffer[ACE_DEFAULT_BUFSIZE];
+ DWORD buffer_size = ACE_DEFAULT_BUFSIZE;
+ DWORD value_type;
+
+ int rc = ACE_TEXT_RegEnumValue (base_key,
+ Index,
+ name_buffer,
+ &buffer_size,
+ NULL,
+ &value_type,
+ NULL,
+ NULL);
+ if (rc == ERROR_NO_MORE_ITEMS)
+ return 1;
+ else if (rc != ERROR_SUCCESS)
+ return -2;
+
+ name = name_buffer;
+
+ switch (value_type)
+ {
+ case REG_BINARY:
+ type = BINARY;
+ break;
+ case REG_SZ:
+ type = STRING;
+ break;
+ case REG_DWORD:
+ type = INTEGER;
+ break;
+ default:
+ type = INVALID;
+ }
+
+ return 0;
+}
+
+int
+ACE_Configuration_Win32Registry::enumerate_sections (const ACE_Configuration_Section_Key& key,
+ int Index,
+ ACE_TString& name)
+{
+ HKEY base_key;
+ if (load_key (key, base_key))
+ return -1;
+
+ ACE_TCHAR name_buffer[ACE_DEFAULT_BUFSIZE];
+ DWORD buffer_size = ACE_DEFAULT_BUFSIZE;
+ int rc = ACE_TEXT_RegEnumKeyEx (base_key,
+ Index,
+ name_buffer,
+ &buffer_size,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+ if (rc == ERROR_NO_MORE_ITEMS)
+ return 1;
+ else if (rc != ERROR_MORE_DATA && rc != ERROR_SUCCESS)
+ return -2;
+
+ name = name_buffer;
+
+ return 0;
+}
+
+int
+ACE_Configuration_Win32Registry::set_string_value (const ACE_Configuration_Section_Key& key,
+ const ACE_TCHAR* name,
+ const ACE_TString& value)
+{
+ if (validate_name (name))
+ return -1;
+
+ HKEY base_key;
+ if (load_key (key, base_key))
+ return -1;
+
+ if (ACE_TEXT_RegSetValueEx (base_key,
+ name,
+ 0,
+ REG_SZ,
+ (BYTE *) value.fast_rep (),
+ (value.length () + 1) * sizeof (ACE_TCHAR)) != ERROR_SUCCESS)
+ return -2;
+
+ return 0;
+}
+
+int
+ACE_Configuration_Win32Registry::set_integer_value (const ACE_Configuration_Section_Key& key,
+ const ACE_TCHAR* name,
+ u_int value)
+{
+ if (validate_name (name))
+ return -1;
+
+ HKEY base_key;
+ if (load_key (key, base_key))
+ return -1;
+
+ if (ACE_TEXT_RegSetValueEx (base_key,
+ name,
+ 0,
+ REG_DWORD,
+ (BYTE *) &value,
+ sizeof (value)) != ERROR_SUCCESS)
+ return -2;
+
+ return 0;
+}
+
+int
+ACE_Configuration_Win32Registry::set_binary_value (const ACE_Configuration_Section_Key& key,
+ const ACE_TCHAR* name,
+ const void* data,
+ u_int length)
+{
+ if (validate_name (name))
+ return -1;
+
+ HKEY base_key;
+ if (load_key (key, base_key))
+ return -1;
+
+ if (ACE_TEXT_RegSetValueEx (base_key,
+ name,
+ 0,
+ REG_BINARY,
+ (BYTE *) data,
+ length) != ERROR_SUCCESS)
+ return -2;
+
+ return 0;
+}
+
+int
+ACE_Configuration_Win32Registry::get_string_value (const ACE_Configuration_Section_Key& key,
+ const ACE_TCHAR* name,
+ ACE_TString& value)
+{
+ if (validate_name (name))
+ return -1;
+
+ HKEY base_key;
+ if (load_key (key, base_key))
+ return -1;
+
+ // Get the size of the binary data from windows
+ DWORD buffer_length = 0;
+ DWORD type;
+ if (ACE_TEXT_RegQueryValueEx (base_key,
+ name,
+ NULL,
+ &type,
+ (BYTE *) 0,
+ &buffer_length) != ERROR_SUCCESS)
+ return -2;
+
+ if (type != REG_SZ)
+ return -3;
+
+ ACE_TCHAR *temp = 0;
+ ACE_NEW_RETURN (temp,
+ ACE_TCHAR[buffer_length],
+ 0);
+
+ ACE_Auto_Basic_Array_Ptr<ACE_TCHAR> buffer (temp);
+
+ if (ACE_TEXT_RegQueryValueEx (base_key,
+ name,
+ NULL,
+ &type,
+ (BYTE *) buffer.get (),
+ &buffer_length) != ERROR_SUCCESS)
+ {
+ return -5;
+ }
+
+ value = buffer.get ();
+ return 0;
+}
+
+int
+ACE_Configuration_Win32Registry::get_integer_value (const ACE_Configuration_Section_Key& key,
+ const ACE_TCHAR* name,
+ u_int& value)
+{
+ if (validate_name (name))
+ return -1;
+
+ HKEY base_key;
+ if (load_key (key, base_key))
+ return -1;
+
+ DWORD length = sizeof (value);
+ DWORD type;
+ if (ACE_TEXT_RegQueryValueEx (base_key,
+ name,
+ NULL,
+ &type,
+ (BYTE *) &value,
+ &length) != ERROR_SUCCESS)
+ return -2;
+
+ if (type != REG_DWORD)
+ return -3;
+
+ return 0;
+}
+
+int
+ACE_Configuration_Win32Registry::get_binary_value (const ACE_Configuration_Section_Key &key,
+ const ACE_TCHAR *name,
+ void *&data,
+ u_int &length)
+{
+ if (validate_name (name))
+ return -1;
+
+ HKEY base_key;
+ if (load_key (key, base_key))
+ return -1;
+
+ // Get the size of the binary data from windows
+ DWORD buffer_length = 0;
+ DWORD type;
+ if (ACE_TEXT_RegQueryValueEx (base_key,
+ name,
+ NULL,
+ &type,
+ (BYTE *) 0,
+ &buffer_length) != ERROR_SUCCESS)
+ return -2;
+
+ if (type != REG_BINARY)
+ return -3;
+
+ length = buffer_length;
+
+ ACE_NEW_RETURN (data, BYTE[length], -4);
+
+ if (ACE_TEXT_RegQueryValueEx (base_key,
+ name,
+ NULL,
+ &type,
+ (BYTE *) data,
+ &buffer_length) != ERROR_SUCCESS)
+ {
+ delete [] (BYTE *) data;
+ data = 0;
+ return -5;
+ }
+
+ return 0;
+}
+
+int
+ACE_Configuration_Win32Registry::find_value (const ACE_Configuration_Section_Key& key,
+ const ACE_TCHAR* name,
+ VALUETYPE& type_out)
+{
+ if (validate_name (name))
+ return -1;
+
+ HKEY base_key;
+ if (load_key (key, base_key))
+ return -1;
+
+ DWORD buffer_length=0;
+ DWORD type;
+ int result=ACE_TEXT_RegQueryValueEx (base_key,
+ name,
+ NULL,
+ &type,
+ NULL,
+ &buffer_length);
+ if (result != ERROR_SUCCESS)
+ return -1;
+
+ switch (type)
+ {
+ case REG_SZ:
+ type_out = STRING;
+ break;
+ case REG_DWORD:
+ type_out = INTEGER;
+ break;
+ case REG_BINARY:
+ type_out = BINARY;
+ break;
+ default:
+ return -1; // unknown type
+ }
+
+ return 0;
+}
+
+int
+ACE_Configuration_Win32Registry::remove_value (const ACE_Configuration_Section_Key& key,
+ const ACE_TCHAR* name)
+{
+ if (validate_name (name))
+ return -1;
+
+ HKEY base_key;
+ if (load_key (key, base_key))
+ return -1;
+
+ if (ACE_TEXT_RegDeleteValue (base_key, name) != ERROR_SUCCESS)
+ return -2;
+
+ return 0;
+}
+
+
+int
+ACE_Configuration_Win32Registry::load_key (const ACE_Configuration_Section_Key& key,
+ HKEY& hKey)
+{
+ ACE_Section_Key_Win32* pKey = ACE_dynamic_cast (ACE_Section_Key_Win32*,
+ get_internal_key (key));
+ if (!pKey)
+ return -1;
+
+ hKey = pKey->hKey_;
+ return 0;
+}
+
+HKEY
+ACE_Configuration_Win32Registry::resolve_key (HKEY hKey,
+ const ACE_TCHAR* path,
+ int create)
+{
+ HKEY result = 0;
+ // Make a copy of hKey
+ if (::RegOpenKey (hKey, NULL, &result) != ERROR_SUCCESS)
+ return 0;
+
+ // recurse through the path
+ ACE_TCHAR *temp_path = 0;
+ ACE_NEW_RETURN (temp_path,
+ ACE_TCHAR[ACE_OS::strlen (path) + 1],
+ 0);
+ ACE_Auto_Basic_Array_Ptr<ACE_TCHAR> pData (temp_path);
+ ACE_OS::strcpy (pData.get (), path);
+ ACE_Tokenizer parser (pData.get ());
+ parser.delimiter_replace ('\\', '\0');
+ parser.delimiter_replace ('/', '\0');
+
+ for (ACE_TCHAR *temp = parser.next ();
+ temp != 0;
+ temp = parser.next ())
+ {
+ // Open the key
+ HKEY subkey;
+ if (ACE_TEXT_RegOpenKey (result,
+ temp,
+ &subkey) != ERROR_SUCCESS)
+ {
+ // try creating it
+ if (!create || ACE_TEXT_RegCreateKeyEx (result,
+ temp,
+ 0,
+ NULL,
+ 0,
+ KEY_ALL_ACCESS,
+ NULL,
+ &subkey,
+#if defined (__MINGW32__)
+ (PDWORD) 0
+#else
+ NULL
+#endif /* __MINGW32__ */
+ ) != ERROR_SUCCESS)
+ {
+ // error
+ ::RegCloseKey (result);
+ return 0;
+ }
+ }
+ // release our open key handle
+ ::RegCloseKey (result);
+ result = subkey;
+ }
+
+ return result;
+}
+
+#endif /* WIN_32 */
+
+///////////////////////////////////////////////////////////////
+
+ACE_Configuration_Value_IntId::ACE_Configuration_Value_IntId (void)
+ : type_ (ACE_Configuration::INVALID),
+ data_ (0),
+ length_ (0)
+{
+}
+
+ACE_Configuration_Value_IntId::ACE_Configuration_Value_IntId (ACE_TCHAR* string)
+ : type_ (ACE_Configuration::STRING),
+ data_ (string),
+ length_ (0)
+{
+}
+
+ACE_Configuration_Value_IntId::ACE_Configuration_Value_IntId (u_int integer)
+ : type_ (ACE_Configuration::INTEGER),
+ data_ (ACE_reinterpret_cast (void*, integer)),
+ length_ (0)
+{
+}
+
+ACE_Configuration_Value_IntId::ACE_Configuration_Value_IntId (void* data, u_int length)
+ : type_ (ACE_Configuration::BINARY),
+ data_ (data),
+ length_ (length)
+{
+}
+
+ACE_Configuration_Value_IntId::ACE_Configuration_Value_IntId (const ACE_Configuration_Value_IntId& rhs)
+ : type_ (rhs.type_),
+ data_ (rhs.data_),
+ length_ (rhs.length_)
+{
+}
+
+ACE_Configuration_Value_IntId::~ACE_Configuration_Value_IntId (void)
+{
+}
+
+ACE_Configuration_Value_IntId& ACE_Configuration_Value_IntId::operator= (const ACE_Configuration_Value_IntId& rhs)
+{
+ if (this != &rhs)
+ {
+ type_ = rhs.type_;
+ data_ = rhs.data_;
+ length_ = rhs.length_;
+ }
+ return *this;
+}
+
+void
+ACE_Configuration_Value_IntId::free (ACE_Allocator *alloc)
+{
+ if (this->type_ == ACE_Configuration::STRING
+ || this->type_ == ACE_Configuration::BINARY)
+ alloc->free ((void *) (data_));
+ // Do nothing in other cases...
+}
+
+ACE_Configuration_ExtId::ACE_Configuration_ExtId (void)
+ : name_ (0)
+{
+}
+
+ACE_Configuration_ExtId::ACE_Configuration_ExtId (const ACE_TCHAR* name)
+ : name_ (name)
+{
+}
+
+ACE_Configuration_ExtId::ACE_Configuration_ExtId (const ACE_Configuration_ExtId& rhs)
+ : name_ (rhs.name_)
+{
+}
+
+ACE_Configuration_ExtId::~ACE_Configuration_ExtId (void)
+{
+}
+
+ACE_Configuration_ExtId& ACE_Configuration_ExtId::operator= (const ACE_Configuration_ExtId& rhs)
+{
+ if (this != &rhs)
+ name_ = rhs.name_;
+
+ return *this;
+}
+
+int
+ACE_Configuration_ExtId::operator == (const ACE_Configuration_ExtId& rhs) const
+{
+ return (ACE_OS::strcmp (name_, rhs.name_) == 0);
+}
+
+int
+ACE_Configuration_ExtId::operator != (const ACE_Configuration_ExtId& rhs) const
+{
+ return (ACE_OS::strcmp (name_, rhs.name_) != 0);
+}
+
+u_long
+ACE_Configuration_ExtId::hash (void) const
+{
+ ACE_TString temp (name_);
+ return temp.hash ();
+}
+
+const ACE_TCHAR*
+ACE_Configuration_ExtId::name (void)
+{
+ return name_;
+}
+
+void
+ACE_Configuration_ExtId::free (ACE_Allocator *alloc)
+{
+ alloc->free ((void *) (name_));
+}
+
+///////////////////////////////////////////////////////////////////////
+
+ACE_Configuration_Section_IntId::ACE_Configuration_Section_IntId (void)
+ : value_hash_map_ (0),
+ section_hash_map_ (0)
+{
+}
+
+ACE_Configuration_Section_IntId::ACE_Configuration_Section_IntId (VALUE_MAP* value_hash_map, SUBSECTION_MAP* section_hash_map)
+ : value_hash_map_ (value_hash_map),
+ section_hash_map_ (section_hash_map)
+{
+}
+
+ACE_Configuration_Section_IntId::ACE_Configuration_Section_IntId (const ACE_Configuration_Section_IntId& rhs)
+ : value_hash_map_ (rhs.value_hash_map_),
+ section_hash_map_ (rhs.section_hash_map_)
+{
+
+}
+
+ACE_Configuration_Section_IntId::~ACE_Configuration_Section_IntId ()
+{
+}
+
+ACE_Configuration_Section_IntId&
+ACE_Configuration_Section_IntId::operator= (const ACE_Configuration_Section_IntId& rhs)
+{
+ if (this != &rhs)
+ {
+ value_hash_map_ = rhs.value_hash_map_;
+ section_hash_map_ = rhs.section_hash_map_;
+ }
+ return *this;
+}
+
+void
+ACE_Configuration_Section_IntId::free (ACE_Allocator *alloc)
+{
+ alloc->free ((void *) (value_hash_map_));
+ alloc->free ((void *) (section_hash_map_));
+}
+
+ACE_Configuration_Section_Key_Heap::ACE_Configuration_Section_Key_Heap (const ACE_TCHAR* path)
+ : path_ (0),
+ value_iter_ (0),
+ section_iter_ (0)
+{
+ path_ = ACE_OS::strdup (path);
+}
+
+ACE_Configuration_Section_Key_Heap::~ACE_Configuration_Section_Key_Heap ()
+{
+ delete value_iter_;
+ delete section_iter_;
+ ACE_OS::free (path_);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+ACE_Configuration_Heap::ACE_Configuration_Heap (void)
+ : allocator_ (0),
+ index_ (0),
+ default_map_size_ (0)
+{
+ ACE_Configuration_Section_Key_Heap *temp = 0;
+
+ ACE_NEW (temp, ACE_Configuration_Section_Key_Heap (ACE_LIB_TEXT ("")));
+ root_ = ACE_Configuration_Section_Key (temp);
+}
+
+ACE_Configuration_Heap::~ACE_Configuration_Heap (void)
+{
+ if (allocator_)
+ allocator_->sync ();
+
+ delete allocator_;
+}
+
+int
+ACE_Configuration_Heap::open (int default_map_size)
+{
+ default_map_size_ = default_map_size;
+ // Create the allocator with the appropriate options.
+ // The name used for the lock is the same as one used
+ // for the file.
+ ACE_NEW_RETURN (this->allocator_,
+ HEAP_ALLOCATOR (),
+ -1);
+ return create_index ();
+}
+
+
+int
+ACE_Configuration_Heap::open (const ACE_TCHAR* file_name,
+ void* base_address,
+ int default_map_size)
+{
+ default_map_size_ = default_map_size;
+
+ // Make sure that the file name is of the legal length.
+ if (ACE_OS::strlen (file_name) >= MAXNAMELEN + MAXPATHLEN)
+ {
+ errno = ENAMETOOLONG;
+ return -1;
+ }
+
+#if !defined (CHORUS)
+ ACE_MMAP_Memory_Pool::OPTIONS options (base_address);
+#else
+ // Use base address == 0, don't use a fixed address.
+ ACE_MMAP_Memory_Pool::OPTIONS options (0,
+ 0,
+ 0,
+ ACE_CHORUS_LOCAL_NAME_SPACE_T_SIZE);
+#endif /* CHORUS */
+
+ // Create the allocator with the appropriate options. The name used
+ // for the lock is the same as one used for the file.
+ ACE_NEW_RETURN (this->allocator_,
+ PERSISTENT_ALLOCATOR (file_name,
+ file_name,
+ &options),
+ -1);
+
+#if !defined (ACE_LACKS_ACCESS)
+ // Now check if the backing store has been created successfully.
+ if (ACE_OS::access (file_name, F_OK) != 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_LIB_TEXT ("create_index\n")),
+ -1);
+#endif /* ACE_LACKS_ACCESS */
+
+ return create_index ();
+}
+
+int
+ACE_Configuration_Heap::create_index (void)
+{
+ void *section_index = 0;
+
+ // This is the easy case since if we find hash table in the
+ // memory-mapped file we know it's already initialized.
+ if (this->allocator_->find (ACE_CONFIG_SECTION_INDEX, section_index) == 0)
+ this->index_ = (SECTION_MAP *) section_index;
+
+ // Create a new <index_> (because we've just created a new
+ // memory-mapped file).
+ else
+ {
+ size_t index_size = sizeof (SECTION_MAP);
+ section_index = this->allocator_->malloc (index_size);
+
+ if (section_index == 0
+ || create_index_helper (section_index) == -1
+ || this->allocator_->bind (ACE_CONFIG_SECTION_INDEX,
+ section_index) == -1)
+ {
+ // Attempt to clean up.
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("create_index\n")));
+ this->allocator_->remove ();
+ return -1;
+ }
+ // Add the root section
+ return new_section (ACE_LIB_TEXT (""), root_);
+ }
+ return 0;
+}
+
+int
+ACE_Configuration_Heap::create_index_helper (void *buffer)
+{
+ ACE_ASSERT (this->allocator_);
+ this->index_ = new (buffer) SECTION_MAP (this->allocator_);
+ return 0;
+}
+
+int
+ACE_Configuration_Heap::load_key (const ACE_Configuration_Section_Key& key,
+ ACE_TString& name)
+{
+ ACE_ASSERT (this->allocator_);
+ ACE_Configuration_Section_Key_Heap* pKey =
+ ACE_dynamic_cast (ACE_Configuration_Section_Key_Heap*,
+ get_internal_key (key));
+ if (!pKey)
+ return -1;
+
+ name = pKey->path_;
+ return 0;
+}
+
+
+int
+ACE_Configuration_Heap::add_section (const ACE_Configuration_Section_Key& base,
+ const ACE_TCHAR* sub_section,
+ ACE_Configuration_Section_Key& result)
+{
+ ACE_ASSERT (this->allocator_);
+ ACE_TString section;
+ if (load_key (base, section))
+ return -1;
+
+ // Find the base section
+ ACE_Configuration_ExtId ExtId (section.fast_rep ());
+ ACE_Configuration_Section_IntId IntId;
+ if (index_->find (ExtId, IntId, allocator_))
+ return -2;
+
+ // See if this section already exists
+ ACE_Configuration_ExtId SubSectionExtId (sub_section);
+ int ignored = 0;
+
+ if (!IntId.section_hash_map_->find (SubSectionExtId, ignored, allocator_))
+ // already exists!
+ return -3;
+
+ // Create the new section name
+ // only prepend a separater if were not at the root
+ if (section.length ())
+ section += ACE_LIB_TEXT ("\\");
+
+ section += sub_section;
+
+ // Add it to the base section
+ ACE_TCHAR* pers_name = (ACE_TCHAR *) allocator_->malloc ((ACE_OS::strlen (sub_section) + 1) * sizeof (ACE_TCHAR));
+ ACE_OS::strcpy (pers_name, sub_section);
+ ACE_Configuration_ExtId SSExtId (pers_name);
+ if (IntId.section_hash_map_->bind (SSExtId, ignored, allocator_))
+ {
+ allocator_->free (pers_name);
+ return -4;
+ }
+ return (new_section (section, result));
+}
+
+int
+ACE_Configuration_Heap::new_section (const ACE_TString& section,
+ ACE_Configuration_Section_Key& result)
+{
+ ACE_ASSERT (this->allocator_);
+ // Create a new section and add it to the global list
+
+ // Allocate memory for items to be stored in the table.
+ size_t section_len = section.length () + 1;
+ ACE_TCHAR *ptr = (ACE_TCHAR*) this->allocator_->malloc (section_len * sizeof (ACE_TCHAR));
+
+ int return_value = -1;
+
+ if (ptr == 0)
+ return -1;
+ else
+ {
+ // Populate memory with data.
+ ACE_OS::strcpy (ptr, section.fast_rep ());
+
+ void *value_hash_map = 0;
+ size_t map_size = sizeof (VALUE_MAP);
+ value_hash_map = this->allocator_->malloc (map_size);
+
+ // If allocation failed ...
+ if (value_hash_map == 0)
+ return -1;
+
+ // Initialize allocated hash map through placement new.
+ if (value_open_helper (default_map_size_, value_hash_map ) == -1)
+ {
+ this->allocator_->free (value_hash_map );
+ return -2;
+ }
+
+ // create the section map
+ void* section_hash_map = 0;
+ map_size = sizeof (SUBSECTION_MAP);
+ section_hash_map = this->allocator_->malloc (map_size);
+
+ // If allocation failed
+ if (section_hash_map == 0)
+ return -1;
+
+ // initialize allocated hash map through placement new
+ if (section_open_helper (default_map_size_, section_hash_map) == -1)
+ {
+ this->allocator_->free (value_hash_map );
+ this->allocator_->free (section_hash_map);
+ return -2;
+ }
+
+ ACE_Configuration_ExtId name (ptr);
+ ACE_Configuration_Section_IntId entry ((VALUE_MAP*) value_hash_map ,
+ (SUBSECTION_MAP*) section_hash_map);
+
+ // Do a normal bind. This will fail if there's already an
+ // entry with the same name.
+ return_value = this->index_->bind (name, entry, this->allocator_);
+
+ if (return_value == 1)
+ {
+ // Entry already existed so bind failed. Free our dynamically
+ // allocated memory.
+ this->allocator_->free ((void *) ptr);
+ return return_value;
+ }
+
+ if (return_value == -1)
+ // Free our dynamically allocated memory.
+ this->allocator_->free ((void *) ptr);
+ else
+ // If bind () succeed, it will automatically sync
+ // up the map manager entry. However, we must sync up our
+ // name/value memory.
+ this->allocator_->sync (ptr, section_len);
+
+ }
+
+ // set the result
+ ACE_Configuration_Section_Key_Heap *temp;
+ ACE_NEW_RETURN (temp, ACE_Configuration_Section_Key_Heap (section.fast_rep ()), -2);
+ result = ACE_Configuration_Section_Key (temp);
+ return return_value;
+}
+
+int
+ACE_Configuration_Heap::value_open_helper (size_t hash_table_size,
+ void *buffer)
+{
+ ACE_ASSERT (this->allocator_);
+ new (buffer) VALUE_MAP (hash_table_size, this->allocator_);
+ return 0;
+}
+
+int
+ACE_Configuration_Heap::section_open_helper (size_t hash_table_size,
+ void *buffer)
+{
+ ACE_ASSERT (this->allocator_);
+ new (buffer) SUBSECTION_MAP (hash_table_size, this->allocator_);
+ return 0;
+}
+
+int
+ACE_Configuration_Heap::open_section (const ACE_Configuration_Section_Key& base,
+ const ACE_TCHAR* sub_section,
+ int create,
+ ACE_Configuration_Section_Key& result)
+{
+ ACE_ASSERT (this->allocator_);
+ if (validate_name (sub_section))
+ return -1;
+
+ ACE_TString section;
+ if (load_key (base, section))
+ return -1;
+
+ // Only add the \\ if were not at the root
+ if (section.length ())
+ section += ACE_LIB_TEXT ("\\");
+
+ section += sub_section;
+
+ // resolve the section
+ ACE_Configuration_ExtId ExtId (section.fast_rep ());
+ ACE_Configuration_Section_IntId IntId;
+ if (index_->find (ExtId, IntId, allocator_))
+ {
+ if (!create)
+ return -2;
+
+ return add_section (base, sub_section, result);
+ }
+
+ ACE_Configuration_Section_Key_Heap *temp;
+
+ ACE_NEW_RETURN (temp, ACE_Configuration_Section_Key_Heap (section.fast_rep ()), -3);
+ result = ACE_Configuration_Section_Key (temp);
+
+ return 0;
+}
+
+int
+ACE_Configuration_Heap::remove_section (const ACE_Configuration_Section_Key& key,
+ const ACE_TCHAR* sub_section,
+ int recursive)
+{
+ ACE_ASSERT (this->allocator_);
+ if (validate_name (sub_section))
+ return -1;
+
+ ACE_TString section;
+ if (load_key (key, section))
+ return -1;
+
+ // Find this key
+ ACE_Configuration_ExtId ParentExtId (section.fast_rep ());
+ ACE_Configuration_Section_IntId ParentIntId;
+ if (index_->find (ParentExtId, ParentIntId, allocator_))
+ return -2;// no parent key
+
+ // Find this subkey
+ if (section.length ())
+ section += ACE_LIB_TEXT ("\\");
+
+ section += sub_section;
+ ACE_Configuration_ExtId SectionExtId (section.fast_rep ());
+ SECTION_ENTRY* section_entry;
+ SECTION_HASH* hashmap = index_;
+ if (hashmap->find (SectionExtId, section_entry))
+ return -2;
+
+ if (recursive)
+ {
+ ACE_Configuration_Section_Key section;
+ if (open_section (key, sub_section, 0, section))
+ return -3;
+
+ int index = 0;
+ ACE_TString name;
+ while (!enumerate_sections (section, index, name))
+ {
+ if (remove_section (section, name.fast_rep (), 1))
+ return -4;
+
+ index++;
+ }
+ }
+
+ // Now make sure we dont have any subkeys
+ if (section_entry->int_id_.section_hash_map_->current_size ())
+ return -3;
+
+ // Now remove subkey from parent key
+ ACE_Configuration_ExtId SubSExtId (sub_section);
+ SUBSECTION_ENTRY* subsection_entry;
+ if (((SUBSECTION_HASH*)ParentIntId.section_hash_map_)->
+ find (SubSExtId, subsection_entry))
+ return -4;
+
+ if (ParentIntId.section_hash_map_->unbind (SubSExtId, allocator_))
+ return -5;
+
+ subsection_entry->ext_id_.free (allocator_);
+
+ // Remember the pointers so we can free them after we unbind
+ ACE_Configuration_ExtId ExtIdToFree (section_entry->ext_id_);
+ ACE_Configuration_Section_IntId IntIdToFree (section_entry->int_id_);
+
+ // iterate over all values and free memory
+ VALUE_HASH* value_hash_map = section_entry->int_id_.value_hash_map_;
+ VALUE_HASH::ITERATOR value_iter = value_hash_map->begin ();
+ while (!value_iter.done ())
+ {
+ VALUE_ENTRY* value_entry;
+ if (!value_iter.next (value_entry))
+ return 1;
+
+ value_entry->ext_id_.free (allocator_);
+ value_entry->int_id_.free (allocator_);
+
+ value_iter.advance ();
+ }
+
+ // remove it
+ if (index_->unbind (SectionExtId, allocator_))
+ return -5;
+
+ // Free the memory
+ ExtIdToFree.free (allocator_);
+ IntIdToFree.free (allocator_);
+
+ return 0;
+}
+
+int
+ACE_Configuration_Heap::enumerate_values (const ACE_Configuration_Section_Key& key,
+ int index,
+ ACE_TString& name,
+ VALUETYPE& type)
+{
+ ACE_ASSERT (this->allocator_);
+ ACE_Configuration_Section_Key_Heap* pKey =
+ ACE_dynamic_cast (ACE_Configuration_Section_Key_Heap*,
+ get_internal_key (key));
+ if (!pKey)
+ return -1;
+
+ name = pKey->path_;
+
+ // resolve the section
+ ACE_Configuration_ExtId ExtId (pKey->path_);
+ ACE_Configuration_Section_IntId IntId;
+ if (index_->find (ExtId, IntId, allocator_))
+ return -2;
+
+ // Handle iterator resets
+ if (index == 0)
+ {
+ ACE_Hash_Map_Manager_Ex<ACE_Configuration_ExtId ,
+ ACE_Configuration_Value_IntId,
+ ACE_Hash<ACE_Configuration_ExtId>,
+ ACE_Equal_To<ACE_Configuration_ExtId>,
+ ACE_Null_Mutex>* hash_map = IntId.value_hash_map_;
+ delete pKey->value_iter_;
+
+ ACE_NEW_RETURN (pKey->value_iter_,
+ VALUE_HASH::ITERATOR (hash_map->begin ()),
+ -3);
+ }
+
+ // Get the next entry
+ ACE_Hash_Map_Entry<ACE_Configuration_ExtId, ACE_Configuration_Value_IntId>* entry;
+
+ if (!pKey->value_iter_->next (entry))
+ return 1;
+
+ // Return the value of the iterator and advance it
+ name = entry->ext_id_.name_;
+ type = entry->int_id_.type_;
+ pKey->value_iter_->advance ();
+
+ return 0;
+}
+
+int
+ACE_Configuration_Heap::enumerate_sections (const ACE_Configuration_Section_Key& key,
+ int index,
+ ACE_TString& name)
+{
+ ACE_ASSERT (this->allocator_);
+ // cast to a heap section key
+ ACE_Configuration_Section_Key_Heap* pKey =
+ ACE_dynamic_cast (ACE_Configuration_Section_Key_Heap*,
+ get_internal_key (key));
+ if (!pKey)
+ return -1; // not a heap key!
+
+ // resolve the section
+ ACE_Configuration_ExtId ExtId (pKey->path_);
+ ACE_Configuration_Section_IntId IntId;
+ if (index_->find (ExtId, IntId, allocator_))
+ return -2; // unknown section
+
+ // Handle iterator resets
+ if (index == 0)
+ {
+ if (pKey->section_iter_)
+ delete pKey->section_iter_;
+
+ ACE_NEW_RETURN (pKey->section_iter_,
+ SUBSECTION_HASH::ITERATOR (IntId.section_hash_map_->begin ()),
+ -3);
+ }
+
+ // Get the next entry
+ ACE_Hash_Map_Entry<ACE_Configuration_ExtId, int>* entry;
+ if (!pKey->section_iter_->next (entry))
+ return 1;
+
+ // Return the value of the iterator and advance it
+ pKey->section_iter_->advance ();
+ name = entry->ext_id_.name_;
+
+ return 0;
+}
+
+int
+ACE_Configuration_Heap::set_string_value (const ACE_Configuration_Section_Key& key,
+ const ACE_TCHAR* name,
+ const ACE_TString& value)
+{
+ ACE_ASSERT (this->allocator_);
+ if (validate_name (name))
+ return -1;
+
+ ACE_TString section;
+ if (load_key (key, section))
+ return -1;
+
+ ACE_Configuration_ExtId section_ext (section.fast_rep ());
+ ACE_Configuration_Section_IntId section_int;
+ if (index_->find (section_ext, section_int, allocator_))
+ return -2;
+
+ // Get the entry for this item (if it exists)
+ VALUE_ENTRY* entry;
+ ACE_Configuration_ExtId item_name (name);
+ if (section_int.value_hash_map_->VALUE_HASH::find (item_name, entry) == 0)
+ {
+ // found item, replace it
+ // Free the old value
+ entry->int_id_.free (allocator_);
+ // Allocate the new value in this heap
+ ACE_TCHAR* pers_value =
+ (ACE_TCHAR *) allocator_->malloc ((value.length () + 1) * sizeof (ACE_TCHAR));
+ ACE_OS::strcpy (pers_value, value.fast_rep ());
+ ACE_Configuration_Value_IntId new_value_int (pers_value);
+ entry->int_id_ = new_value_int;
+ }
+ else
+ {
+ // it doesn't exist, bind it
+ ACE_TCHAR* pers_name =
+ (ACE_TCHAR *) allocator_->malloc ((ACE_OS::strlen (name) + 1) * sizeof (ACE_TCHAR));
+ ACE_OS::strcpy (pers_name, name);
+ ACE_TCHAR* pers_value =
+ (ACE_TCHAR *) allocator_->malloc ((value.length () + 1) * sizeof (ACE_TCHAR));
+ ACE_OS::strcpy (pers_value, value.fast_rep ());
+ ACE_Configuration_ExtId item_name (pers_name);
+ ACE_Configuration_Value_IntId item_value (pers_value);
+ if (section_int.value_hash_map_->bind (item_name, item_value, allocator_))
+ {
+ allocator_->free (pers_value);
+ allocator_->free (pers_name);
+ return -3;
+ }
+ return 0;
+ }
+
+ return 0;
+}
+
+int
+ACE_Configuration_Heap::set_integer_value (const ACE_Configuration_Section_Key& key,
+ const ACE_TCHAR* name,
+ u_int value)
+{
+ ACE_ASSERT (this->allocator_);
+ if (validate_name (name))
+ return -1;
+
+ // Get the section name from the key
+ ACE_TString section;
+ if (load_key (key, section))
+ return -1;
+
+ // Find this section
+ ACE_Configuration_ExtId section_ext (section.fast_rep ());
+ ACE_Configuration_Section_IntId section_int;
+ if (index_->find (section_ext, section_int, allocator_))
+ return -2; // section does not exist
+
+ // Get the entry for this item (if it exists)
+ VALUE_ENTRY* entry;
+ ACE_Configuration_ExtId item_name (name);
+ if (section_int.value_hash_map_->VALUE_HASH::find (item_name, entry) == 0)
+ {
+ // found item, replace it
+ ACE_Configuration_Value_IntId new_value_int (value);
+ entry->int_id_ = new_value_int;
+ }
+ else
+ {
+ // it doesn't exist, bind it
+ ACE_TCHAR* pers_name =
+ (ACE_TCHAR *) allocator_->malloc ((ACE_OS::strlen (name) + 1) * sizeof (ACE_TCHAR));
+ ACE_OS::strcpy (pers_name, name);
+ ACE_Configuration_ExtId item_name (pers_name);
+ ACE_Configuration_Value_IntId item_value (value);
+ if (section_int.value_hash_map_->bind (item_name, item_value, allocator_))
+ {
+ allocator_->free (pers_name);
+ return -3;
+ }
+ return 0;
+ }
+
+ return 0;
+}
+
+int
+ACE_Configuration_Heap::set_binary_value (const ACE_Configuration_Section_Key& key,
+ const ACE_TCHAR* name,
+ const void* data,
+ u_int length)
+{
+ ACE_ASSERT (this->allocator_);
+ if (validate_name (name))
+ return -1;
+
+ // Get the section name from the key
+ ACE_TString section;
+ if (load_key (key, section))
+ return -1;
+
+ // Find this section
+ ACE_Configuration_ExtId section_ext (section.fast_rep ());
+ ACE_Configuration_Section_IntId section_int;
+ if (index_->find (section_ext, section_int, allocator_))
+ return -2; // section does not exist
+
+ // Get the entry for this item (if it exists)
+ VALUE_ENTRY* entry;
+ ACE_Configuration_ExtId item_name (name);
+ if (section_int.value_hash_map_->VALUE_HASH::find (item_name, entry) == 0)
+ {
+ // found item, replace it
+ // Free the old value
+ entry->int_id_.free (allocator_);
+ // Allocate the new value in this heap
+ ACE_TCHAR* pers_value = (ACE_TCHAR *) allocator_->malloc (length);
+ ACE_OS::memcpy (pers_value, data, length);
+ ACE_Configuration_Value_IntId new_value_int (pers_value, length);
+ entry->int_id_ = new_value_int;
+ }
+ else
+ {
+ // it doesn't exist, bind it
+ ACE_TCHAR* pers_name =
+ (ACE_TCHAR *) allocator_->malloc ((ACE_OS::strlen (name) + 1) * sizeof (ACE_TCHAR));
+ ACE_OS::strcpy (pers_name, name);
+ ACE_TCHAR* pers_value = (ACE_TCHAR *) allocator_->malloc (length);
+ ACE_OS::memcpy (pers_value, data, length);
+ ACE_Configuration_ExtId item_name (pers_name);
+ ACE_Configuration_Value_IntId item_value (pers_value, length);
+ if (section_int.value_hash_map_->bind (item_name, item_value, allocator_))
+ {
+ allocator_->free (pers_value);
+ allocator_->free (pers_name);
+ return -3;
+ }
+ return 0;
+ }
+
+/*
+ // Find this section
+ ACE_Configuration_ExtId ExtId (section.fast_rep ());
+ ACE_Configuration_Section_IntId IntId;
+ if (index_->find (ExtId, IntId, allocator_))
+ return -2; // section does not exist
+
+ // See if the value exists first
+ ACE_Configuration_ExtId VExtIdFind (name);
+ ACE_Configuration_Value_IntId VIntIdFind;
+ if (IntId.value_hash_map_->find (VExtIdFind, VIntIdFind, allocator_))
+ {
+ // it doesn't exist, bind it
+ ACE_TCHAR* pers_name =
+ (ACE_TCHAR *) allocator_->malloc ((ACE_OS::strlen (name) + 1) * sizeof (ACE_TCHAR));
+ ACE_OS::strcpy (pers_name, name);
+ ACE_TCHAR* pers_value =
+ (ACE_TCHAR *) allocator_->malloc (length);
+ ACE_OS::memcpy (pers_value, data, length);
+ ACE_Configuration_ExtId VExtId (pers_name);
+ ACE_Configuration_Value_IntId VIntId (pers_value, length);
+ if (IntId.value_hash_map_->bind (VExtId, VIntId, allocator_))
+ {
+ allocator_->free (pers_value);
+ allocator_->free (pers_name);
+ return -3;
+ }
+ return 0;
+ }
+ else
+ {
+ // it does exist, free the old value memory
+ VIntIdFind.free (allocator_);
+ // Assign a new value
+ ACE_TCHAR* pers_value = (ACE_TCHAR *) allocator_->malloc (length);
+ ACE_OS::memcpy (pers_value, data, length);
+ VIntIdFind = ACE_Configuration_Value_IntId (pers_value, length);
+ }
+*/
+ return 0;
+}
+
+int
+ACE_Configuration_Heap::get_string_value (const ACE_Configuration_Section_Key& key,
+ const ACE_TCHAR* name,
+ ACE_TString& value)
+{
+ ACE_ASSERT (this->allocator_);
+ if (validate_name (name))
+ return -1;
+
+ // Get the section name from the key
+ ACE_TString section;
+ if (load_key (key, section))
+ return -1;
+
+ // Find this section
+ ACE_Configuration_ExtId ExtId (section.fast_rep ());
+ ACE_Configuration_Section_IntId IntId;
+ if (index_->find (ExtId, IntId, allocator_))
+ return -2; // section does not exist
+
+ // See if it exists first
+ ACE_Configuration_ExtId VExtId (name);
+ ACE_Configuration_Value_IntId VIntId;
+ if (IntId.value_hash_map_->find (VExtId, VIntId, allocator_))
+ return -3; // unknown value
+
+ // Check type
+ if (VIntId.type_ != ACE_Configuration::STRING)
+ return -4;
+
+ // everythings ok, return the data
+ value = (ACE_TCHAR*)VIntId.data_;
+ return 0;
+}
+
+int
+ACE_Configuration_Heap::get_integer_value (const ACE_Configuration_Section_Key& key,
+ const ACE_TCHAR* name,
+ u_int& value)
+{
+ ACE_ASSERT (this->allocator_);
+ if (validate_name (name))
+ return -1;
+
+ // Get the section name from the key
+ ACE_TString section;
+ if (load_key (key, section))
+ return -1;
+
+ // Find this section
+ ACE_Configuration_ExtId ExtId (section.fast_rep ());
+ ACE_Configuration_Section_IntId IntId;
+ if (index_->find (ExtId, IntId, allocator_))
+ return -2; // section does not exist
+
+
+ // See if it exists first
+ ACE_Configuration_ExtId VExtId (name);
+ ACE_Configuration_Value_IntId VIntId;
+ if (IntId.value_hash_map_->find (VExtId, VIntId, allocator_))
+ return -3; // unknown value
+
+ // Check type
+ if (VIntId.type_ != ACE_Configuration::INTEGER)
+ return -4;
+
+ // Everythings ok, return the data
+ value = (u_int) ((long)VIntId.data_);
+ return 0;
+}
+
+int
+ACE_Configuration_Heap::get_binary_value (const ACE_Configuration_Section_Key& key,
+ const ACE_TCHAR* name,
+ void*& data,
+ u_int& length)
+{
+ ACE_ASSERT (this->allocator_);
+ if (validate_name (name))
+ return -1;
+
+ // Get the section name from the key
+ ACE_TString section;
+ if (load_key (key, section))
+ return -1;
+
+ // Find this section
+ ACE_Configuration_ExtId ExtId (section.fast_rep ());
+ ACE_Configuration_Section_IntId IntId;
+ if (index_->find (ExtId, IntId, allocator_))
+ return -2; // section does not exist
+
+ ACE_Configuration_ExtId VExtId (name);
+ ACE_Configuration_Value_IntId VIntId;
+ // See if it exists first
+ if (IntId.value_hash_map_->find (VExtId, VIntId, allocator_))
+ return -3; // unknown value
+
+ // Check type
+ if (VIntId.type_ != ACE_Configuration::BINARY)
+ return -4;
+
+ // Make a copy
+ ACE_NEW_RETURN (data, char[VIntId.length_], -5);
+ ACE_OS::memcpy (data, VIntId.data_, VIntId.length_);
+ length = VIntId.length_;
+ return 0;
+}
+
+int
+ACE_Configuration_Heap::find_value (const ACE_Configuration_Section_Key& key,
+ const ACE_TCHAR* name,
+ VALUETYPE& type_out)
+{
+ ACE_ASSERT (this->allocator_);
+ if (validate_name (name))
+ return -1;
+
+ // Get the section name from the key
+ ACE_TString section;
+ if (load_key (key, section))
+ return -1;
+
+ // Find this section
+ ACE_Configuration_ExtId ExtId (section.fast_rep ());
+ ACE_Configuration_Section_IntId IntId;
+ if (index_->find (ExtId, IntId, allocator_))
+ return -1; // section does not exist
+
+ // Find it
+ ACE_Configuration_ExtId ValueExtId (name);
+ VALUE_ENTRY* value_entry;
+ if (((VALUE_HASH *) IntId.value_hash_map_)->find (ValueExtId, value_entry))
+ return -1; // value does not exist
+
+ type_out = value_entry->int_id_.type_;
+ return 0;
+}
+
+int
+ACE_Configuration_Heap::remove_value (const ACE_Configuration_Section_Key& key,
+ const ACE_TCHAR* name)
+{
+ ACE_ASSERT (this->allocator_);
+ if (validate_name (name))
+ return -1;
+
+ // Get the section name from the key
+ ACE_TString section;
+ if (load_key (key, section))
+ return -1;
+
+ // Find this section
+ ACE_Configuration_ExtId ExtId (section.fast_rep ());
+ ACE_Configuration_Section_IntId IntId;
+ if (index_->find (ExtId, IntId, allocator_))
+ return -2; // section does not exist
+
+ // Find it
+ ACE_Configuration_ExtId ValueExtId (name);
+ VALUE_ENTRY* value_entry;
+ if (((VALUE_HASH *) IntId.value_hash_map_)->find (ValueExtId, value_entry))
+ return -4;
+
+ // free it
+ value_entry->ext_id_.free (allocator_);
+ value_entry->int_id_.free (allocator_);
+
+ // Unbind it
+ if (IntId.value_hash_map_->unbind (ValueExtId, allocator_))
+ return -3;
+
+ return 0;
+}
diff --git a/ace/Utils/Configuration.h b/ace/Utils/Configuration.h
new file mode 100644
index 00000000000..a4e30d1b43c
--- /dev/null
+++ b/ace/Utils/Configuration.h
@@ -0,0 +1,759 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Configuration.h
+ *
+ * $Id$
+ *
+ * @author Chris Hafey <chafey@stentor.com>
+ *
+ * The ACE configuration API provides a portable abstraction for
+ * program configuration similar to the Microsoft Windows registry.
+ * The API supports a tree based hierarchy of configuration sections. Each
+ * section contains other sections or values. Values may contain string,
+ * unsigned integer and binary data.
+ *
+ * Note: these classes are not thread safe, if multiple threads use these
+ * classes, you are responsible for serializing access.
+ *
+ * For examples of using this class, see:
+ * 1) The test code in ACE_Wrappers/test
+ * 2) wxConfigViewer, a Windows like Registry Editor for ACE_Configuration
+ * 3) TAO's IFR, it makes extensive use of ACE_Configuration
+ *
+ * @todo Templatize this class with an ACE_LOCK to provide thread safety
+ *
+ */
+//=============================================================================
+
+#ifndef ACE_CONFIGURATION_H
+#define ACE_CONFIGURATION_H
+#include "ace/pre.h"
+
+#include "ace/ACE.h"
+#include "ace/SString.h"
+#include "ace/Hash_Map_With_Allocator_T.h"
+#include "ace/Malloc.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+// configurable parameters
+
+#if !defined (ACE_CONFIG_SECTION_INDEX)
+# define ACE_CONFIG_SECTION_INDEX "Config_Section_Index"
+#endif /* ! ACE_CONFIG_SECTION_INDEX */
+
+#if !defined (ACE_DEFAULT_CONFIG_SECTION_SIZE)
+#define ACE_DEFAULT_CONFIG_SECTION_SIZE 16
+#endif /* ACE_DEFAULT_CONFIG_SECTION_SIZE */
+
+/**
+ * @class ACE_Section_Key_Internal
+ *
+ * @brief A base class for internal handles to section keys for
+ * configuration implementations
+ *
+ * Implementations subclass this base class to represent a
+ * section key.
+ *
+ */
+class ACE_Export ACE_Section_Key_Internal
+{
+public:
+ /// Virtual destructor, make sure descendants are virtual!
+ virtual ~ACE_Section_Key_Internal (void);
+
+ /// Increment reference count
+ virtual int add_ref (void);
+
+ /// Decrement reference count. Will delete this if count gets to 0
+ virtual int dec_ref (void);
+protected:
+ ACE_Section_Key_Internal (void);
+ ACE_Section_Key_Internal (const ACE_Section_Key_Internal& rhs);
+ ACE_Section_Key_Internal& operator= (ACE_Section_Key_Internal& rhs);
+
+ u_int ref_count_;
+};
+
+/**
+ * @class ACE_Configuration_Section_Key
+ *
+ * @brief Referenced counted wrapper for <ACE_Section_Key_Internal>.
+ *
+ * Reference counted wrapper class for the abstract internal
+ * section key. A user gets one of these to represent a section
+ * in the configuration database.
+ */
+class ACE_Export ACE_Configuration_Section_Key
+{
+ friend class ACE_Configuration;
+public:
+ /// Default ctor
+ ACE_Configuration_Section_Key (void);
+
+ /// ctor based on a pointer to a concrete internal key, does an
+ /// add_ref on <key>.
+ ACE_EXPLICIT ACE_Configuration_Section_Key (ACE_Section_Key_Internal *key);
+
+ /// Copy ctor, does an add_ref on rhs.key_.
+ ACE_Configuration_Section_Key (const ACE_Configuration_Section_Key &rhs);
+
+ /// destructor, does a <dec_ref> on <key_>.
+ ~ACE_Configuration_Section_Key (void);
+
+ /// assignment operator, does a <dec_ref> on <key_> and <add_ref> to
+ /// <rhs.key_>
+ ACE_Configuration_Section_Key &
+ operator= (const ACE_Configuration_Section_Key &rhs);
+private:
+ ACE_Section_Key_Internal *key_;
+};
+
+/**
+ * @class ACE_Configuration
+ *
+ * @brief Base class for configuration databases
+ *
+ * This class provides an interface for configuration databases.
+ */
+class ACE_Export ACE_Configuration
+{
+public:
+ /// Enumeration for the various types of values we can store.
+ enum VALUETYPE
+ {
+ STRING,
+ INTEGER,
+ BINARY,
+ INVALID
+ };
+
+ /// destructor
+ virtual ~ACE_Configuration (void);
+
+ /// Returns the root section of this configuration.
+ virtual const ACE_Configuration_Section_Key& root_section (void) const;
+
+ /**
+ * Finds a <sub_section> in <base> and places the resulting key in
+ * <result>. If create is non zero, the sub_section will be created
+ * if it doesn't exist
+ */
+ virtual int open_section (const ACE_Configuration_Section_Key &base,
+ const ACE_TCHAR *sub_section,
+ int create,
+ ACE_Configuration_Section_Key& result) = 0;
+
+ /// Removes the <sub_section> from <key>. If recursive is non zero,
+ /// any subkeys below <sub_section> are remove as well.
+ virtual int remove_section (const ACE_Configuration_Section_Key &key,
+ const ACE_TCHAR *sub_section,
+ int recursive) = 0;
+
+ /**
+ * method to enumerate through the <name> and <type> of values in a
+ * <key>. To begin iteration, <index> must be zero. to continue
+ * iteration, invoke enumerate_values again while incrementing
+ * index. Each iteration will return the <name> of the value and
+ * its <type>. This method returns 0 on success, <0 on error and 1
+ * when there are no more values to iterate through. Note - you may
+ * not delete or add values while enumerating. If you need to do
+ * this, you start the enumeration over again.
+ */
+ virtual int enumerate_values (const ACE_Configuration_Section_Key& key,
+ int index,
+ ACE_TString& name,
+ VALUETYPE& type) = 0;
+
+ /**
+ * method to enumerate through the <name> subsections in <key>. To
+ * begin iteration, <index> must zero. to continue iteration, invoke
+ * enumerate_sections again while incrementing index. Each
+ * iteration will return the <name> of the sub section. This method
+ * returns 0 on success, <0 on error and 1 when there are no more
+ * subsections to iterate through. Note - you may not delete or add
+ * values while enumerating. If you need to do this, you start the
+ * enumeration over again.
+ */
+ virtual int enumerate_sections (const ACE_Configuration_Section_Key& key,
+ int index, ACE_TString& name) = 0;
+
+ /// sets the value in <key> with <name> to a string of <value>
+ virtual int set_string_value (const ACE_Configuration_Section_Key& key,
+ const ACE_TCHAR* name,
+ const ACE_TString& value) = 0;
+
+ /// sets the value in <key> with <name> to an integer of <value>
+ virtual int set_integer_value (const ACE_Configuration_Section_Key& key,
+ const ACE_TCHAR* name,
+ u_int value) = 0;
+
+ /// sets the value in <key> with <name> to binary data of <data> with
+ /// <length>.
+ virtual int set_binary_value (const ACE_Configuration_Section_Key& key,
+ const ACE_TCHAR* name,
+ const void* data,
+ u_int length) = 0;
+
+ /// gets the string value of <name> from <key> and places it in
+ /// <value>. Returns non zero on error (if value is not a string).
+ virtual int get_string_value (const ACE_Configuration_Section_Key& key,
+ const ACE_TCHAR* name,
+ ACE_TString& value) = 0;
+
+ /// gets the integer value of <name> from <key> and places it in
+ /// <value>. Returns non zero on error (if value is not an integer).
+ virtual int get_integer_value (const ACE_Configuration_Section_Key& key,
+ const ACE_TCHAR* name,
+ u_int& value) = 0;
+
+ /**
+ * gets the binary value of <name> from <key> and places a copy in
+ * <data> and sets <length> to the length of the data. caller is
+ * responsible for deleting <data>. Returns non zero on error (if
+ * value is not binary).
+ */
+ virtual int get_binary_value (const ACE_Configuration_Section_Key& key,
+ const ACE_TCHAR* name,
+ void*& data,
+ u_int& length) = 0;
+
+ /**
+ * checks to see if an entry of <name> is in <key> and places the
+ * data type in <type>. Returns 0 on success (entry is found),
+ * -1 on error
+ */
+ virtual int find_value(const ACE_Configuration_Section_Key& key,
+ const ACE_TCHAR* name,
+ VALUETYPE& type) = 0;
+
+
+ /// Removes the the value <name> from <key>. returns non zero on
+ /// error.
+ virtual int remove_value (const ACE_Configuration_Section_Key& key,
+ const ACE_TCHAR* name) = 0;
+
+ /**
+ * Expands <path_in> to <key_out> from <key>. If create is true,
+ * the subsections are created. Returns 0 on success, non zero on
+ * error The path consists of sections separated by the backslash
+ * '\' or forward slash '/'.
+ * Returns 0 on success, -1 if <create) is 0 and the path refers
+ * a nonexistant section
+ */
+ int expand_path (const ACE_Configuration_Section_Key& key,
+ const ACE_TString& path_in,
+ ACE_Configuration_Section_Key& key_out,
+ int create = 1);
+
+ /**
+ * Exports the configuration database to filename. If <filename> is
+ * already present, it is overwritten. This function is deprecated and
+ * will be removed in a future version of ACE. Please use either
+ * ACE_Registry_ImpExp or ACE_Ini_ImpExp instead.
+ */
+ int export_config (const ACE_TCHAR* filename);
+
+ /**
+ * Imports the configuration database from filename. Any existing
+ * data is not removed. This function is deprecated and will be
+ * removed in a future version of ACE. Please use ACE_Registry_ImpExp
+ * or ACE_Ini_ImpExp instead.
+ */
+ int import_config (const ACE_TCHAR* filename);
+
+ /**
+ * Determine if the contents of this object is the same as the
+ * contents of the object on the right hand side.
+ * Returns 1 (True) if they are equal and 0 (False) if they are not equal
+ */
+ int operator==(const ACE_Configuration& rhs) const;
+
+ /**
+ * Determine if the contents of this object are different from the
+ * contents of the object on the right hand side.
+ * Returns 0 (False) if they are equal and 1 (True) if they are not equal
+ */
+ int operator!=(const ACE_Configuration& rhs) const {return !(*this == rhs);}
+
+protected:
+ /// Default ctor
+ ACE_Configuration (void);
+
+ /// resolves the internal key from a section key
+ ACE_Section_Key_Internal* get_internal_key
+ (const ACE_Configuration_Section_Key& key);
+
+ /**
+ * tests to see if <name> is valid. <name> must be < 255 characters
+ * and not contain the path separator '\', brackets [] or = (maybe
+ * just restrict to alphanumeric?) returns non zero if name is not
+ * valid
+ */
+ int validate_name (const ACE_TCHAR* name);
+
+ // Not used
+ ACE_Configuration (const ACE_Configuration& rhs);
+ ACE_Configuration& operator= (const ACE_Configuration& rhs);
+
+
+ ACE_Configuration_Section_Key root_;
+};
+
+#if defined (ACE_WIN32)
+
+/**
+ * @class ACE_Section_Key_Win32
+ *
+ * @brief The Win32 registry implementation of an internal section key.
+ *
+ * Holds the HKEY for a section (registry key).
+ */
+class ACE_Export ACE_Section_Key_Win32 : public ACE_Section_Key_Internal
+{
+public:
+ /// constructor based on an HKEY
+ ACE_Section_Key_Win32 (HKEY hKey);
+
+ HKEY hKey_;
+
+protected:
+ /// destructor - invokes <RegCloseKey>
+ virtual ~ACE_Section_Key_Win32 (void);
+
+ // Not used
+ ACE_Section_Key_Win32 (const ACE_Section_Key_Win32& rhs);
+ ACE_Section_Key_Win32& operator= (const ACE_Section_Key_Win32& rhs);
+};
+
+/**
+ * @class ACE_Configuration_Win32Registry
+ *
+ * @brief The win32 registry implementation of a configuration database
+ *
+ * The win32 implementation basically makes calls through to the
+ * registry functions. The API is very similar so very little
+ * work must be done
+ */
+class ACE_Export ACE_Configuration_Win32Registry : public ACE_Configuration
+{
+public:
+
+ /**
+ * constructor for registry configuration database. hKey is the
+ * base registry key to attach to. This class takes ownership of
+ * hKey, it will invoke <RegCloseKey> on it upon destruction.
+ */
+ ACE_EXPLICIT ACE_Configuration_Win32Registry (HKEY hKey);
+
+ /// destructor
+ virtual ~ACE_Configuration_Win32Registry (void);
+
+ virtual int open_section (const ACE_Configuration_Section_Key& base,
+ const ACE_TCHAR* sub_section,
+ int create,
+ ACE_Configuration_Section_Key& result);
+
+ virtual int remove_section (const ACE_Configuration_Section_Key& key,
+ const ACE_TCHAR* sub_section,
+ int recursive);
+
+ virtual int enumerate_values (const ACE_Configuration_Section_Key& key,
+ int Index,
+ ACE_TString& name,
+ VALUETYPE& type);
+
+ virtual int enumerate_sections (const ACE_Configuration_Section_Key& key,
+ int Index,
+ ACE_TString& name);
+
+ virtual int set_string_value (const ACE_Configuration_Section_Key& key,
+ const ACE_TCHAR* name,
+ const ACE_TString& value);
+
+ virtual int set_integer_value (const ACE_Configuration_Section_Key& key,
+ const ACE_TCHAR* name,
+ u_int value);
+
+ virtual int set_binary_value (const ACE_Configuration_Section_Key& key,
+ const ACE_TCHAR* name,
+ const void* data,
+ u_int length);
+
+ virtual int get_string_value (const ACE_Configuration_Section_Key& key,
+ const ACE_TCHAR* name,
+ ACE_TString& value);
+
+ virtual int get_integer_value (const ACE_Configuration_Section_Key& key,
+ const ACE_TCHAR* name,
+ u_int& value);
+
+ virtual int get_binary_value (const ACE_Configuration_Section_Key& key,
+ const ACE_TCHAR* name,
+ void*& data,
+ u_int& length);
+
+ virtual int find_value(const ACE_Configuration_Section_Key& key,
+ const ACE_TCHAR* name,
+ VALUETYPE& type);
+
+ /// Removes the the value <name> from <key>. returns non zero on error
+ virtual int remove_value (const ACE_Configuration_Section_Key& key,
+ const ACE_TCHAR* name);
+
+ /**
+ * This method traverses <path> through <hKey>. It is useful when
+ * you want the HKEY for a specific registry key, especially when
+ * initializing this implementation. Caller is responsible for
+ * closeing this key when it is no longer used. If create is 1
+ * (default) the keys are create if they don't already exist.
+ * Returns 0 on error
+ */
+ static HKEY resolve_key (HKEY hKey,
+ const ACE_TCHAR* path,
+ int create = 1);
+ virtual int operator== (const ACE_Configuration_Win32Registry &rhs) const;
+ virtual int operator!= (const ACE_Configuration_Win32Registry &rhs) const;
+
+protected:
+
+ /// Gets the HKEY for a configuration section
+ int load_key (const ACE_Configuration_Section_Key& key, HKEY& hKey);
+
+ // Not used
+ ACE_Configuration_Win32Registry (void);
+ ACE_Configuration_Win32Registry (const ACE_Configuration_Win32Registry& rhs);
+ ACE_Configuration_Win32Registry& operator= (const ACE_Configuration_Win32Registry& rhs);
+};
+#endif /* ACE_WIN32 */
+
+// ACE_Allocator version
+
+typedef ACE_Allocator_Adapter <ACE_Malloc <ACE_MMAP_MEMORY_POOL,
+ ACE_SYNCH_MUTEX> >
+ PERSISTENT_ALLOCATOR;
+typedef ACE_Allocator_Adapter <ACE_Malloc <ACE_LOCAL_MEMORY_POOL,
+ ACE_SYNCH_MUTEX> >
+ HEAP_ALLOCATOR;
+
+/**
+ * @class ACE_Configuration_ExtId
+ *
+ * @brief External ID for the section and value hash
+ *
+ * Contains a pointer to the section or value name.
+ */
+class ACE_Export ACE_Configuration_ExtId
+{
+public:
+ /// defeault ctor
+ ACE_Configuration_ExtId (void);
+
+ /// named constructor
+ ACE_EXPLICIT ACE_Configuration_ExtId (const ACE_TCHAR* name);
+
+ /// copy ctor
+ ACE_Configuration_ExtId (const ACE_Configuration_ExtId& rhs);
+
+ /// destructor
+ ~ACE_Configuration_ExtId (void);
+
+ /// assignment operator
+ ACE_Configuration_ExtId& operator= (const ACE_Configuration_ExtId& rhs);
+
+ /// Equality comparison operator (must match name_).
+ int operator== (const ACE_Configuration_ExtId &rhs) const;
+
+ /// Inequality comparison operator.
+ int operator!= (const ACE_Configuration_ExtId &rhs) const;
+
+ /// Frees the name of the value. needed since we don't know the
+ /// allocator name_ was created in
+ void free (ACE_Allocator *alloc);
+
+ /// <hash> function is required in order for this class to be usable by
+ /// ACE_Hash_Map_Manager.
+ u_long hash (void) const;
+
+ // = Data members.
+
+ const ACE_TCHAR * name_;
+
+ // Accessors
+ const ACE_TCHAR *name (void);
+};
+
+typedef ACE_Hash_Map_With_Allocator<ACE_Configuration_ExtId, int>
+ SUBSECTION_MAP;
+typedef ACE_Hash_Map_Manager_Ex<ACE_Configuration_ExtId,
+ int,
+ ACE_Hash<ACE_Configuration_ExtId>,
+ ACE_Equal_To<ACE_Configuration_ExtId>,
+ ACE_Null_Mutex>
+ SUBSECTION_HASH;
+typedef ACE_Hash_Map_Entry<ACE_Configuration_ExtId, int>
+ SUBSECTION_ENTRY;
+
+/**
+ * @class ACE_Configuration_Value_IntId
+ *
+ * @brief The section hash table internal value class
+ *
+ * This class is present as the internal portion of a section's
+ * value hash table It may store string, integer or binary data.
+ */
+class ACE_Export ACE_Configuration_Value_IntId
+{
+public:
+ /// default constructor
+ ACE_Configuration_Value_IntId (void);
+
+ /// string constructor, takes ownership of string
+ ACE_EXPLICIT ACE_Configuration_Value_IntId (ACE_TCHAR* string);
+
+ /// integer constructor
+ ACE_EXPLICIT ACE_Configuration_Value_IntId (u_int integer);
+
+ /// binary constructor, takes ownership of data
+ ACE_Configuration_Value_IntId (void* data, u_int length);
+
+ /// copy ctor
+ ACE_Configuration_Value_IntId (const ACE_Configuration_Value_IntId& rhs);
+
+ /// destructor
+ ~ACE_Configuration_Value_IntId (void);
+
+ /// Assignment operator
+ ACE_Configuration_Value_IntId& operator= (
+ const ACE_Configuration_Value_IntId& rhs);
+
+ void free (ACE_Allocator *alloc);
+
+ // = Data members.
+
+ /**
+ * points to the string value or binary data or IS the integer
+ * (XXX need to change this since sizeof (u_int) is
+ * not the same accross different platforms)
+ * Length is only used when type_ == BINARY
+ */
+ ACE_Configuration::VALUETYPE type_;
+ void* data_;
+ u_int length_;
+};
+
+typedef ACE_Hash_Map_With_Allocator<ACE_Configuration_ExtId,
+ ACE_Configuration_Value_IntId>
+ VALUE_MAP;
+typedef ACE_Hash_Map_Manager_Ex<ACE_Configuration_ExtId,
+ ACE_Configuration_Value_IntId,
+ ACE_Hash<ACE_Configuration_ExtId>,
+ ACE_Equal_To<ACE_Configuration_ExtId>,
+ ACE_Null_Mutex>
+ VALUE_HASH;
+typedef ACE_Hash_Map_Entry<ACE_Configuration_ExtId,
+ ACE_Configuration_Value_IntId>
+ VALUE_ENTRY;
+
+/**
+ * @class ACE_Configuration_Section_IntId
+ *
+ * @brief The internal ID for a section hash table
+ *
+ * Contains a hash table containing value name/values
+ */
+class ACE_Export ACE_Configuration_Section_IntId
+{
+public:
+ /// default ctor
+ ACE_Configuration_Section_IntId (void);
+
+ /// named ctor
+ ACE_EXPLICIT ACE_Configuration_Section_IntId (VALUE_MAP* value_hash_map,
+ SUBSECTION_MAP* section_hash_map);
+
+ /// copy ctor
+ ACE_Configuration_Section_IntId (const ACE_Configuration_Section_IntId& rhs);
+
+ /// destructor
+ ~ACE_Configuration_Section_IntId (void);
+
+ /// asignment operator
+ ACE_Configuration_Section_IntId& operator= (
+ const ACE_Configuration_Section_IntId& rhs);
+
+ /// frees the hash table and all its values
+ void free (ACE_Allocator *alloc);
+
+ // = Data Members.
+ VALUE_MAP* value_hash_map_;
+
+ SUBSECTION_MAP* section_hash_map_;
+};
+
+typedef ACE_Hash_Map_With_Allocator<ACE_Configuration_ExtId,
+ ACE_Configuration_Section_IntId>
+ SECTION_MAP;
+typedef ACE_Hash_Map_Manager_Ex<ACE_Configuration_ExtId,
+ ACE_Configuration_Section_IntId,
+ ACE_Hash<ACE_Configuration_ExtId>,
+ ACE_Equal_To<ACE_Configuration_ExtId>,
+ ACE_Null_Mutex>
+ SECTION_HASH;
+typedef ACE_Hash_Map_Entry<ACE_Configuration_ExtId,
+ ACE_Configuration_Section_IntId>
+ SECTION_ENTRY;
+
+/**
+ * @class ACE_Configuration_Section_Key_Heap
+ *
+ * @brief Internal section key class for heap based configuration
+ * database.
+ *
+ * Contains a value iterator and full path name of section.
+ */
+class ACE_Export ACE_Configuration_Section_Key_Heap
+ : public ACE_Section_Key_Internal
+{
+public:
+ /// constructor based on the full path of the section
+ ACE_Configuration_Section_Key_Heap (const ACE_TCHAR* path);
+
+ ///the path itself
+ ACE_TCHAR* path_;
+
+ /// The value iterator
+ VALUE_HASH::ITERATOR* value_iter_;
+
+ /// The sub section iterator
+ SUBSECTION_HASH::ITERATOR* section_iter_;
+protected:
+ /// destructor - will delete the iterators
+ virtual ~ACE_Configuration_Section_Key_Heap (void);
+
+ // Not used
+ ACE_Configuration_Section_Key_Heap (const ACE_Configuration_Section_Key_Heap& rhs);
+ ACE_Configuration_Section_Key_Heap& operator= (const ACE_Configuration_Section_Key_Heap& rhs);
+};
+
+/**
+ * @class ACE_Configuration_Heap
+ *
+ * @brief The concrete implementation of a allocator based
+ * configuration database
+ *
+ * This class uses ACE's Allocators to manage a memory
+ * representation of a configuraiton database. A persistent heap
+ * may be used to store configurations persistently
+ *
+ * Note: Before using this class you must call one of the open methods.
+ *
+ * @todo
+ * - Need to investigate what happens if memory mapped file gets mapped to
+ * a location different than it was created with.
+ */
+class ACE_Export ACE_Configuration_Heap : public ACE_Configuration
+{
+public:
+
+ /// Default ctor
+ ACE_Configuration_Heap (void);
+
+ /// destructor
+ virtual ~ACE_Configuration_Heap (void);
+
+ /// opens a configuration based on a file name
+ int open (const ACE_TCHAR* file_name,
+ void* base_address = ACE_DEFAULT_BASE_ADDR,
+ int default_map_size = ACE_DEFAULT_CONFIG_SECTION_SIZE);
+
+ /// opens a heap based configuration
+ int open (int default_map_size = ACE_DEFAULT_CONFIG_SECTION_SIZE);
+
+ virtual int open_section (const ACE_Configuration_Section_Key& base,
+ const ACE_TCHAR* sub_section,
+ int create, ACE_Configuration_Section_Key& result);
+
+ virtual int remove_section (const ACE_Configuration_Section_Key& key,
+ const ACE_TCHAR* sub_section,
+ int recursive);
+
+ virtual int enumerate_values (const ACE_Configuration_Section_Key& key,
+ int Index,
+ ACE_TString& name,
+ VALUETYPE& type);
+
+ virtual int enumerate_sections (const ACE_Configuration_Section_Key& key,
+ int Index,
+ ACE_TString& name);
+
+ virtual int set_string_value (const ACE_Configuration_Section_Key& key,
+ const ACE_TCHAR* name,
+ const ACE_TString& value);
+
+ virtual int set_integer_value (const ACE_Configuration_Section_Key& key,
+ const ACE_TCHAR* name,
+ u_int value);
+
+ virtual int set_binary_value (const ACE_Configuration_Section_Key& key,
+ const ACE_TCHAR* name,
+ const void* data,
+ u_int length);
+
+ virtual int get_string_value (const ACE_Configuration_Section_Key& key,
+ const ACE_TCHAR* name,
+ ACE_TString& value);
+
+ virtual int get_integer_value (const ACE_Configuration_Section_Key& key,
+ const ACE_TCHAR* name,
+ u_int& value);
+
+ virtual int get_binary_value (const ACE_Configuration_Section_Key& key,
+ const ACE_TCHAR* name,
+ void* &data,
+ u_int &length);
+
+ virtual int find_value(const ACE_Configuration_Section_Key& key,
+ const ACE_TCHAR* name,
+ VALUETYPE& type);
+
+ /// Removes the the value <name> from <key>. returns non zero on error
+ virtual int remove_value (const ACE_Configuration_Section_Key& key,
+ const ACE_TCHAR* name);
+
+private:
+ /// adds a new section
+ int add_section (const ACE_Configuration_Section_Key& base,
+ const ACE_TCHAR* sub_section,
+ ACE_Configuration_Section_Key& result);
+
+ /// Helper for the <open> method.
+ int create_index (void);
+
+ /// Helper for <create_index> method: places hash table into an
+ /// allocated space.
+ int create_index_helper (void *buffer);
+
+ int value_open_helper (size_t hash_table_size, void *buffer);
+
+ int section_open_helper (size_t hash_table_size, void *buffer);
+
+ int load_key (const ACE_Configuration_Section_Key& key, ACE_TString& name);
+
+ int new_section (const ACE_TString& section,
+ ACE_Configuration_Section_Key& result);
+
+ ACE_Configuration_Heap (const ACE_Configuration_Heap& rhs);
+ ACE_Configuration_Heap& operator= (const ACE_Configuration_Heap& rhs);
+
+ ACE_Allocator *allocator_;
+ SECTION_MAP *index_;
+ int default_map_size_;
+};
+
+#include "ace/post.h"
+#endif /* ACE_CONFIGURATION_H */
diff --git a/ace/Utils/Configuration_Import_Export.cpp b/ace/Utils/Configuration_Import_Export.cpp
new file mode 100644
index 00000000000..ec4648731c8
--- /dev/null
+++ b/ace/Utils/Configuration_Import_Export.cpp
@@ -0,0 +1,610 @@
+// $Id$
+
+#include "ace/Configuration_Import_Export.h"
+
+ACE_Config_ImpExp_Base::ACE_Config_ImpExp_Base (ACE_Configuration& config)
+ : config_ (config)
+{
+}
+
+ACE_Config_ImpExp_Base::~ACE_Config_ImpExp_Base (void)
+{
+}
+
+ACE_Registry_ImpExp::ACE_Registry_ImpExp (ACE_Configuration& config)
+ : ACE_Config_ImpExp_Base (config)
+{
+}
+
+ACE_Registry_ImpExp::~ACE_Registry_ImpExp (void)
+{
+}
+
+// Imports the configuration database from filename.
+// No existing data is removed.
+int
+ACE_Registry_ImpExp::import_config (const ACE_TCHAR* filename)
+{
+ ACE_ASSERT (filename != NULL); // Cannot have a NULL filename
+ FILE* in = ACE_OS::fopen (filename, ACE_LIB_TEXT ("r"));
+ if (!in)
+ return -1;
+
+ // @@ XXX - change this to a dynamic buffer
+ ACE_TCHAR buffer[4096];
+ ACE_Configuration_Section_Key section;
+ while (ACE_OS::fgets (buffer, 4096, in))
+ {
+ // Check for a comment
+ if (buffer[0] == ACE_LIB_TEXT (';') || buffer[0] == ACE_LIB_TEXT ('#'))
+ continue;
+
+ if (buffer[0] == ACE_LIB_TEXT ('['))
+ {
+ // We have a new section here, strip out the section name
+ ACE_TCHAR* end = ACE_OS::strrchr (buffer, ACE_LIB_TEXT (']'));
+ if (!end)
+ {
+ ACE_OS::fclose (in);
+ return -3;
+ }
+ *end = 0;
+
+ if (config_.expand_path (config_.root_section (), buffer + 1, section, 1))
+ {
+ ACE_OS::fclose (in);
+ return -3;
+ }
+ continue;
+ } // end if firs char is a [
+
+ if (buffer[0] == ACE_LIB_TEXT ('"'))
+ {
+ // we have a value
+ ACE_TCHAR* end = ACE_OS::strchr (buffer+1, '"');
+ if (!end) // no closing quote, not a value so just skip it
+ continue;
+
+ // null terminate the name
+ *end = 0;
+ ACE_TCHAR* name = buffer + 1;
+ end+=2;
+ // determine the type
+ if (*end == '\"')
+ {
+ // string type
+ // truncate trailing "
+ ++end;
+ ACE_TCHAR* trailing = ACE_OS::strrchr (end, '"');
+ if (trailing)
+ *trailing = 0;
+ if (config_.set_string_value (section, name, end))
+ {
+ ACE_OS::fclose (in);
+ return -4;
+ }
+ }
+ else if (ACE_OS::strncmp (end, ACE_LIB_TEXT ("dword:"), 6) == 0)
+ {
+ // number type
+ ACE_TCHAR* endptr = 0;
+ u_int value = ACE_OS::strtoul (end + 6, &endptr, 16);
+ if (config_.set_integer_value (section, name, value))
+ {
+ ACE_OS::fclose (in);
+ return -4;
+ }
+ }
+ else if (ACE_OS::strncmp (end, ACE_LIB_TEXT ("hex:"), 4) == 0)
+ {
+ // binary type
+ u_int string_length = ACE_OS::strlen (end + 4);
+ // divide by 3 to get the actual buffer length
+ u_int length = string_length / 3;
+ u_int remaining = length;
+ u_char* data = 0;
+ ACE_NEW_RETURN (data,
+ u_char[length],
+ -1);
+ u_char* out = data;
+ ACE_TCHAR* inb = end + 4;
+ ACE_TCHAR* endptr = 0;
+ while (remaining)
+ {
+ u_char charin = (u_char) ACE_OS::strtoul (inb, &endptr, 16);
+ *out = charin;
+ ++out;
+ --remaining;
+ inb += 3;
+ }
+ if (config_.set_binary_value (section, name, data, length))
+ {
+ ACE_OS::fclose (in);
+ return -4;
+ }
+ }
+ else
+ {
+ // invalid type, ignore
+ continue;
+ }
+ }// end if first char is a "
+ else
+ {
+ // if the first character is not a ", [, ;, or # we may be
+ // processing a file in the old format.
+ // Try and process the line as such and if it fails,
+ // return an error
+ int rc;
+ if ((rc = process_previous_line_format (buffer, section)) != 0)
+ {
+ ACE_OS::fclose (in);
+ return rc;
+ }
+ } // end if maybe old format
+ } // end while fgets
+
+ if (ferror (in))
+ {
+ ACE_OS::fclose (in);
+ return -1;
+ }
+
+ ACE_OS::fclose (in);
+ return 0;
+}
+
+// This method exports the entire configuration database to <filename>.
+// Once the file is opened this method calls 'export_section' passing
+// the root section.
+int
+ACE_Registry_ImpExp::export_config (const ACE_TCHAR* filename)
+{
+ ACE_ASSERT (filename != NULL); // Cannot have a NULL filename
+ int result = -1;
+
+ FILE* out = ACE_OS::fopen (filename, ACE_LIB_TEXT ("w"));
+ if (out)
+ {
+ result = this->export_section (config_.root_section (),
+ ACE_LIB_TEXT (""),
+ out);
+ ACE_OS::fclose (out);
+ }
+ return result;
+}
+
+// Method provided by derived classes in order to write one section
+// to the file specified. Called by export_config when exporting
+// the entire configuration object.
+
+int
+ACE_Registry_ImpExp::export_section (const ACE_Configuration_Section_Key& section,
+ const ACE_TString& path,
+ FILE* out)
+{
+ // don't export the root
+ if (path.length ())
+ {
+ // Write out the section header
+ ACE_TString header = ACE_LIB_TEXT ("[");
+ header += path;
+ header += ACE_LIB_TEXT ("]");
+ header += ACE_LIB_TEXT (" \n");
+ if (ACE_OS::fputs (header.fast_rep (), out) < 0)
+ return -1;
+ // Write out each value
+ int index = 0;
+ ACE_TString name;
+ ACE_Configuration::VALUETYPE type;
+ ACE_TString line;
+ ACE_TCHAR int_value[32];
+ ACE_TCHAR bin_value[3];
+ void* binary_data;
+ u_int binary_length;
+ ACE_TString string_value;
+ while (!config_.enumerate_values (section, index, name, type))
+ {
+ line = ACE_LIB_TEXT ("\"") + name + ACE_LIB_TEXT ("\"=");
+ switch (type)
+ {
+ case ACE_Configuration::INTEGER:
+ {
+ u_int value;
+ if (config_.get_integer_value (section, name.fast_rep (), value))
+ return -2;
+ ACE_OS::sprintf (int_value, ACE_LIB_TEXT ("%08x"), value);
+ line += ACE_LIB_TEXT ("dword:");
+ line += int_value;
+ break;
+ }
+ case ACE_Configuration::STRING:
+ {
+ if (config_.get_string_value (section,
+ name.fast_rep (),
+ string_value))
+ return -2;
+ line += ACE_LIB_TEXT ("\"");
+ line += string_value + ACE_LIB_TEXT ("\"");
+ break;
+ }
+#ifdef _WIN32
+ case ACE_Configuration::INVALID:
+ break; // JDO added break. Otherwise INVALID is processed
+ // like BINARY. If that's correct, please remove the
+ // break and these comments
+#endif
+ case ACE_Configuration::BINARY:
+ {
+ // not supported yet - maybe use BASE64 codeing?
+ if (config_.get_binary_value (section,
+ name.fast_rep (),
+ binary_data,
+ binary_length))
+ return -2;
+ line += ACE_LIB_TEXT ("hex:");
+ unsigned char* ptr = (unsigned char*)binary_data;
+ while (binary_length)
+ {
+ if (ptr != binary_data)
+ {
+ line += ACE_LIB_TEXT (",");
+ }
+ ACE_OS::sprintf (bin_value, ACE_LIB_TEXT ("%02x"), *ptr);
+ line += bin_value;
+ --binary_length;
+ ++ptr;
+ }
+ delete [] (char*) binary_data;
+ break;
+ }
+ default:
+ return -3;
+ }
+ line += ACE_LIB_TEXT ("\n");
+ if (ACE_OS::fputs (line.fast_rep (), out) < 0)
+ return -4;
+ index++;
+ }
+ }
+ // Export all sub sections
+ int index = 0;
+ ACE_TString name;
+ ACE_Configuration_Section_Key sub_key;
+ ACE_TString sub_section;
+ while (!config_.enumerate_sections (section, index, name))
+ {
+ ACE_TString sub_section (path);
+ if (path.length ())
+ sub_section += ACE_LIB_TEXT ("\\");
+ sub_section += name;
+ if (config_.open_section (section, name.fast_rep (), 0, sub_key))
+ return -5;
+ if (export_section (sub_key, sub_section.fast_rep (), out))
+ return -6;
+ index++;
+ }
+ return 0;
+}
+
+//
+// This method read the line format origionally used in ACE 5.1
+//
+int
+ACE_Registry_ImpExp::process_previous_line_format (ACE_TCHAR* buffer,
+ ACE_Configuration_Section_Key& section)
+{
+ // Chop any cr/lf at the end of the line.
+ ACE_TCHAR *endp = ACE_OS_String::strpbrk (buffer, ACE_LIB_TEXT ("\r\n"));
+ if (endp != 0)
+ *endp = '\0';
+
+ // assume this is a value, read in the value name
+ ACE_TCHAR* end = ACE_OS::strchr (buffer, '=');
+ if (end) // no =, not a value so just skip it
+ {
+ // null terminate the name
+ *end = 0;
+ end++;
+ // determine the type
+ if (*end == '\"')
+ {
+ // string type
+ if(config_.set_string_value (section, buffer, end + 1))
+ return -4;
+ }
+ else if (*end == '#')
+ {
+ // number type
+ u_int value = ACE_OS::atoi (end + 1);
+ if (config_.set_integer_value (section, buffer, value))
+ return -4;
+ }
+ }
+ return 0;
+} // end read_previous_line_format
+
+
+ACE_Ini_ImpExp::ACE_Ini_ImpExp (ACE_Configuration& config)
+ : ACE_Config_ImpExp_Base (config)
+{
+}
+
+ACE_Ini_ImpExp::~ACE_Ini_ImpExp (void)
+{
+}
+
+// Method to read file and populate object.
+int
+ACE_Ini_ImpExp::import_config (const ACE_TCHAR* fileName)
+{
+ ACE_ASSERT (fileName != NULL); // Cannot have a NULL filename
+ FILE* in = ACE_OS::fopen (fileName, ACE_LIB_TEXT ("r"));
+ if (!in)
+ return -1;
+
+ // @@ Make this a dynamic size!
+ ACE_TCHAR buffer[4096];
+ ACE_Configuration_Section_Key section;
+ while (ACE_OS::fgets (buffer, sizeof buffer, in))
+ {
+ // Check for a comment and blank line
+ if (buffer[0] == ACE_LIB_TEXT (';') ||
+ buffer[0] == ACE_LIB_TEXT ('#') ||
+ buffer[0] == ACE_LIB_TEXT ('\r') ||
+ buffer[0] == ACE_LIB_TEXT ('\n'))
+ continue;
+
+ if (buffer[0] == ACE_LIB_TEXT ('['))
+ {
+ // We have a new section here, strip out the section name
+ ACE_TCHAR* end = ACE_OS::strrchr (buffer, ACE_LIB_TEXT (']'));
+ if (!end)
+ {
+ ACE_OS::fclose (in);
+ return -3;
+ }
+ *end = 0;
+
+ if (config_.expand_path (config_.root_section (), buffer + 1, section, 1))
+ {
+ ACE_OS::fclose (in);
+ return -3;
+ }
+
+ continue;
+ }
+
+ // we have a line
+ const ACE_TCHAR *name = this->skip_whitespace (buffer);
+ if (*name != '\0')
+ {
+ ACE_TCHAR *end = (ACE_TCHAR *) ACE_OS::strpbrk (name, ACE_LIB_TEXT ("= \t\n\r"));
+
+ // locate equal sign after name and retrieve value
+ //
+ // This used to be strrchr. I don't know if there was a reason that a
+ // reverse search was done but it was not acting as expected. If there
+ // was an equals sign in the value it would cut off the first part of
+ // the value. This happened even if the value was quoted.
+ // -Glen Coakley
+ //
+ const ACE_TCHAR *value = ACE_OS::strchr (name, ACE_LIB_TEXT ('='));
+ if (value)
+ {
+ value++; // jump over equal sign
+ value = this->skip_whitespace (value);
+ ACE_TCHAR *value_end;
+ if (value[0] != ACE_LIB_TEXT ('"'))
+ value_end = (ACE_TCHAR *) ACE_OS::strpbrk (value, ACE_LIB_TEXT (" \t\n\r"));
+ else
+ {
+ // double quote delimited allows spaces and tabs in string
+ value++;
+ value_end = (ACE_TCHAR *) ACE_OS::strpbrk (value, ACE_LIB_TEXT ("\"\n\r"));
+ }
+ if (value_end)
+ *value_end = '\0'; // terminate value
+ }
+ else
+ value = ACE_LIB_TEXT ("");
+
+ if (end)
+ *end = '\0'; // terminate name now
+
+ if (config_.set_string_value (section, name, value))
+ {
+ ACE_OS::fclose (in);
+ return -4;
+ }
+ } // end if (name)
+ } // end while fgets
+
+ if (ferror (in))
+ {
+ ACE_OS::fclose (in);
+ return -1;
+ }
+
+ ACE_OS::fclose (in);
+ return 0;
+}
+
+// This method exports the entire configuration database to <filename>.
+// Once the file is opened this method calls 'export_section' passing
+// the root section.
+int
+ACE_Ini_ImpExp::export_config (const ACE_TCHAR* filename)
+{
+ ACE_ASSERT (filename != NULL); // Cannot have a NULL filename
+ int result = -1;
+
+ FILE* out = ACE_OS::fopen (filename, ACE_LIB_TEXT ("w"));
+ if (out)
+ {
+ result = this->export_section (config_.root_section (), ACE_LIB_TEXT (""), out);
+ ACE_OS::fclose (out);
+ }
+ return result;
+}
+
+// Method provided by derived classes in order to write one section to the
+// file specified. Called by export_config when exporting the entire
+// configuration objet
+
+int
+ACE_Ini_ImpExp::export_section (const ACE_Configuration_Section_Key& section,
+ const ACE_TString& path,
+ FILE* out)
+{
+ // don't export the root
+ if (path.length ())
+ {
+ // Write out the section header
+ ACE_TString header = ACE_LIB_TEXT ("[");
+ header += path;
+ header += ACE_LIB_TEXT ("]");
+ header += ACE_LIB_TEXT (" \n");
+ if (ACE_OS::fputs (header.fast_rep (), out) < 0)
+ return -1;
+ // Write out each value
+ int index = 0;
+ ACE_TString name;
+ ACE_Configuration::VALUETYPE type;
+ ACE_TString line;
+ ACE_TCHAR int_value[32];
+ ACE_TCHAR bin_value[3];
+ void* binary_data;
+ u_int binary_length;
+ ACE_TString string_value;
+ while (!config_.enumerate_values (section, index, name, type))
+ {
+ line = name + ACE_LIB_TEXT ("=");
+ switch (type)
+ {
+ case ACE_Configuration::INTEGER:
+ {
+ u_int value;
+ if (config_.get_integer_value (section, name.fast_rep (), value))
+ return -2;
+ ACE_OS::sprintf (int_value, ACE_LIB_TEXT ("%08x"), value);
+ line += int_value;
+ break;
+ }
+ case ACE_Configuration::STRING:
+ {
+ if (config_.get_string_value (section,
+ name.fast_rep (),
+ string_value))
+ return -2;
+ if (string_has_white_space (string_value.c_str ()))
+ {
+ line += ACE_LIB_TEXT ("\"");
+ line += string_value + ACE_LIB_TEXT ("\"");
+ }
+ else
+ {
+ line += string_value;
+ }
+ break;
+ }
+#ifdef _WIN32
+ case ACE_Configuration::INVALID:
+ break; // JDO added break. Otherwise INVALID is processed
+ // like BINARY. If that's correct, please remove the
+ // break and these comments
+#endif
+ case ACE_Configuration::BINARY:
+ {
+ // not supported yet - maybe use BASE64 codeing?
+ if (config_.get_binary_value (section,
+ name.fast_rep (),
+ binary_data,
+ binary_length))
+ return -2;
+ line += ACE_LIB_TEXT ("\"");
+ unsigned char* ptr = (unsigned char*)binary_data;
+ while (binary_length)
+ {
+ if (ptr != binary_data)
+ {
+ line += ACE_LIB_TEXT (",");
+ }
+ ACE_OS::sprintf (bin_value, ACE_LIB_TEXT ("%02x"), *ptr);
+ line += bin_value;
+ --binary_length;
+ ++ptr;
+ }
+ line += ACE_LIB_TEXT ("\"");
+ delete [] (char *) binary_data;
+ break;
+ }
+ default:
+ return -3;
+
+ }// end switch on type
+
+ line += ACE_LIB_TEXT ("\n");
+ if (ACE_OS::fputs (line.fast_rep (), out) < 0)
+ return -4;
+ index++;
+ }// end while enumerating values
+ }
+ // Export all sub sections
+ int index = 0;
+ ACE_TString name;
+ ACE_Configuration_Section_Key sub_key;
+ ACE_TString sub_section;
+ while (!config_.enumerate_sections (section, index, name))
+ {
+ ACE_TString sub_section (path);
+ if (path.length ())
+ sub_section += ACE_LIB_TEXT ("\\");
+ sub_section += name;
+ if (config_.open_section (section, name.fast_rep (), 0, sub_key))
+ return -5;
+ if (export_section (sub_key, sub_section.fast_rep (), out))
+ return -6;
+ index++;
+ }
+ return 0;
+
+}
+
+// Method to skip whitespaces in a string. Whitespace is defined as:
+// spaces (' ') and tabs ('\t'). Returns a pointer to the first
+// non-whitespace character in the buffer provided. It does return
+// null ('\0') if it is reached
+
+const ACE_TCHAR *
+ACE_Ini_ImpExp::skip_whitespace (const ACE_TCHAR *src)
+{
+ const ACE_TCHAR *cp;
+
+ for (cp = src;
+ (*cp != '\0') && ((*cp == ' ') || (*cp == '\t'));
+ cp++)
+ continue;
+
+ return cp;
+}
+
+// Looks in provided string for whitespace. Whitespace is defined as
+// spaces (' ') and tabs ('\t'). Returns true if found and false if
+// not found
+
+int
+ACE_Ini_ImpExp::string_has_white_space (const ACE_TCHAR *string_value)
+{
+ int rc = 0;
+
+ while ((!rc) && (*string_value != '\0'))
+ {
+ if ((*string_value == ' ') || (*string_value == '\t'))
+ rc = 1;
+
+ string_value++;
+ }
+
+ return rc;
+}
diff --git a/ace/Utils/Configuration_Import_Export.h b/ace/Utils/Configuration_Import_Export.h
new file mode 100644
index 00000000000..fdb90ae6373
--- /dev/null
+++ b/ace/Utils/Configuration_Import_Export.h
@@ -0,0 +1,216 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Configuration_Import_Export.h
+ *
+ * $Id$
+ *
+ * @author Jerry D. Odenwelder Jr. <jerry.o@mindspring.com>
+ * Chris Hafey <chris@stentorsoft.com>
+ *
+ * Classes defined in this file provide the ability to import and export
+ * ACE Configuration objects to/from disk files. The base class
+ * ACE_Config_ImpExp_Base provides the common functionality and the derived
+ * classes implement the import/export functionality for the specific format.
+ *
+ * @todo
+ * - Add locking for thread safety.
+ * - Provide ability to read file in one format and write in another.
+ * - See todo's in each class
+ */
+//=============================================================================
+
+#ifndef ACE_CONFIGURATION_IMPORT_EXPORT_H
+#define ACE_CONFIGURATION_IMPORT_EXPORT_H
+#include "ace/pre.h"
+
+#include "ace/Configuration.h"
+#include "ace/SString.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+/**
+ * @class ACE_Config_ImpExp_Base
+ *
+ * @brief Base class for file import/export configuration.
+ *
+ * This class provides base functionality for configuration objects
+ * that are persisted in files. It takes an ACE_Configuration
+ * object that it populates with the data read.
+ *
+ */
+class ACE_Export ACE_Config_ImpExp_Base
+{
+public:
+ /// ctor taking the ACE_Configuration to import/export to
+ ACE_Config_ImpExp_Base (ACE_Configuration& config);
+
+ /**
+ * Destructor
+ */
+ virtual ~ACE_Config_ImpExp_Base (void);
+
+ /**
+ * Imports the configuration database from filename.
+ * No existing data is removed.
+ */
+ virtual int import_config (const ACE_TCHAR* filename) = 0;
+
+ /**
+ * This method exports the entire configuration database to <filename>.
+ * Once the file is opened this method calls 'export_section' passing
+ * the root section.
+ */
+ virtual int export_config (const ACE_TCHAR* filename) = 0;
+
+protected:
+ ACE_Configuration &config_;
+
+private:
+ ACE_Config_ImpExp_Base (const ACE_Config_ImpExp_Base&);
+ ACE_Config_ImpExp_Base& operator= (const ACE_Config_ImpExp_Base&);
+};
+
+/**
+ * @class ACE_Registry_ImpExp
+ *
+ * @brief Configuration object that imports/exports data to a file formatted
+ * using the Win32 Registry file export format. This format looks like
+ * [Section]
+ * "key"="String Data"
+ * "key"=dword: numeric data
+ * "key"=hex: binary data
+ *
+ * @todo
+ * - Add dynamic buffer when importing. currently it will not allow
+ * importing of values greater than a fixed ammount (4096 bytes)
+ *
+ */
+class ACE_Export ACE_Registry_ImpExp : public ACE_Config_ImpExp_Base
+{
+public:
+ /// Construction
+ ACE_Registry_ImpExp (ACE_Configuration&);
+
+ /// Destruction.
+ virtual ~ACE_Registry_ImpExp (void);
+
+ /**
+ * Imports the configuration database from filename.
+ * No existing data is removed.
+ */
+ virtual int import_config (const ACE_TCHAR* filename);
+
+ /**
+ * This method exports the entire configuration database to <filename>.
+ * Once the file is opened this method calls 'export_section' passing
+ * the root section.
+ */
+ virtual int export_config (const ACE_TCHAR* filename);
+
+private:
+ int export_section (const ACE_Configuration_Section_Key& section,
+ const ACE_TString& path,
+ FILE* out);
+
+ int process_previous_line_format (ACE_TCHAR* buffer,
+ ACE_Configuration_Section_Key& section);
+
+ ACE_Registry_ImpExp ( const ACE_Registry_ImpExp&);
+ ACE_Registry_ImpExp& operator= ( const ACE_Registry_ImpExp&);
+};
+
+/**
+ * @class ACE_Ini_ImpExp
+ *
+ * @brief Imports the configuration database from filename as strings.
+ * Allows non-typed values. (no #, dword: hex:, etc. prefixes) and
+ * skips whitespace (tabs and spaces) as in standard .ini and .conf
+ * files. Values (to right of equal sign) can be double quote
+ * delimited to embed tabs and spaces in the string.
+ * Caller must convert string to type.
+ *
+ * This method allows for lines in the .ini or .conf file like this:
+ *
+ * TimeToLive = 100
+ * Delay = FALSE
+ * Flags = FF34
+ * Heading = "ACE - Adaptive Communication Environment"
+ *
+ * (note leading whitespace (tabs) in examples below)
+ *
+ * SeekIndex = 14
+ * TraceLevel = 6 # Can comment lines like this
+ * Justification = left_justified
+ *
+ * The caller can then retrieve the string with the regular
+ * <get_string_value> function and convert the string to the
+ * desired data type.
+ *
+ * @todo
+ * - Strings with embedded newlines cause the import to fail
+ * - Strings with embedded quotes " cause the import to fail
+ * - Importing/exporting for values in the root section does not work
+ * - Add dynamic buffer when importing. currently it will not allow
+ * importing of values greater than a fixed ammount (4096 bytes)
+*/
+class ACE_Export ACE_Ini_ImpExp : public ACE_Config_ImpExp_Base
+{
+public:
+ /**
+ * Construction
+ */
+ ACE_Ini_ImpExp (ACE_Configuration&);
+
+ /**
+ * Destructor
+ */
+ virtual ~ACE_Ini_ImpExp (void);
+
+ /**
+ * Imports the configuration database from filename.
+ * No existing data is removed.
+ */
+ virtual int import_config (const ACE_TCHAR* filename);
+
+ /**
+ * This method exports the entire configuration database to <filename>.
+ * Once the file is opened this method calls 'export_section' passing
+ * the root section.
+ */
+ virtual int export_config (const ACE_TCHAR* filename);
+
+private:
+ /**
+ * Method provided by derived classes in order to write one section
+ * to the file specified. Called by export_config when exporting
+ * the entire configuration object.
+ */
+ int export_section (const ACE_Configuration_Section_Key& section,
+ const ACE_TString& path,
+ FILE* out);
+
+ /**
+ * Method to skip whitespaces in a string. Whitespace is defined as:
+ * spaces (' ') and tabs ('\t').
+ * Returns a pointer to the first non-whitespace character in the
+ * buffer provided. It does return null ('\0') if it is reached
+ */
+ const ACE_TCHAR *skip_whitespace (const ACE_TCHAR *src);
+
+ /**
+ * Looks in provided string for whitespace. Whitespace is defined as
+ * spaces (' ') and tabs ('\t').
+ * Returns true if found and false if not found
+ */
+ int string_has_white_space (const ACE_TCHAR *string_value);
+
+ ACE_Ini_ImpExp (const ACE_Ini_ImpExp&);
+ ACE_Ini_ImpExp& operator= (const ACE_Ini_ImpExp&);
+};
+
+#include "ace/post.h"
+#endif /* ACE_CONFIGURATION_IMPORT_EXPORT_H */
diff --git a/ace/Utils/Connection_Recycling_Strategy.cpp b/ace/Utils/Connection_Recycling_Strategy.cpp
new file mode 100644
index 00000000000..351dde2ea52
--- /dev/null
+++ b/ace/Utils/Connection_Recycling_Strategy.cpp
@@ -0,0 +1,13 @@
+#include "ace/Connection_Recycling_Strategy.h"
+
+
+ACE_RCSID(ace, Connection_Recycling_Strategy, "$Id$")
+
+
+ACE_Connection_Recycling_Strategy::ACE_Connection_Recycling_Strategy (void)
+{
+}
+
+ACE_Connection_Recycling_Strategy::~ACE_Connection_Recycling_Strategy (void)
+{
+}
diff --git a/ace/Utils/Connection_Recycling_Strategy.h b/ace/Utils/Connection_Recycling_Strategy.h
new file mode 100644
index 00000000000..71a328e7d10
--- /dev/null
+++ b/ace/Utils/Connection_Recycling_Strategy.h
@@ -0,0 +1,67 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Connection_Recycling_Strategy.h
+ *
+ * $Id$
+ *
+ * @author Doug Schmidt
+ */
+//=============================================================================
+#ifndef ACE_CONNECTION_RECYCLING_STRATEGY_H
+#define ACE_CONNECTION_RECYCLING_STRATEGY_H
+#include "ace/pre.h"
+
+#include "ace/Recyclable.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+
+
+
+/**
+ * @class ACE_Connection_Recycling_Strategy
+ *
+ * @brief Defines the interface for a connection recycler.
+ */
+
+class ACE_Export ACE_Connection_Recycling_Strategy
+{
+public:
+ /// Virtual Destructor
+ virtual ~ACE_Connection_Recycling_Strategy (void);
+
+ /// Remove from cache.
+ virtual int purge (const void *recycling_act) = 0;
+
+ /// Add to cache.
+ virtual int cache (const void *recycling_act) = 0;
+
+ virtual int recycle_state (const void *recycling_act,
+ ACE_Recyclable_State new_state) = 0;
+
+ /// Get/Set <recycle_state>.
+ virtual ACE_Recyclable_State recycle_state (const void *recycling_act) const = 0;
+
+ /// Mark as closed.
+ virtual int mark_as_closed (const void *recycling_act) = 0;
+
+ /// Mark as closed.(non-locking version)
+ virtual int mark_as_closed_i (const void *recycling_act) = 0;
+
+ /// Cleanup hint and reset <*act_holder> to zero if <act_holder != 0>.
+ virtual int cleanup_hint (const void *recycling_act,
+ void **act_holder = 0) = 0;
+
+protected:
+ /// Default ctor.
+ ACE_Connection_Recycling_Strategy (void);
+};
+
+
+
+#include "ace/post.h"
+#endif /*ACE_CONNECTION_RECYCLING_STRATEGY*/
diff --git a/ace/Utils/Containers.cpp b/ace/Utils/Containers.cpp
new file mode 100644
index 00000000000..9fb16735ea4
--- /dev/null
+++ b/ace/Utils/Containers.cpp
@@ -0,0 +1,23 @@
+// $Id$
+
+#include "ace/OS.h"
+#include "ace/Containers.h"
+
+ACE_RCSID(ace, Containers, "$Id$")
+
+#if !defined (__ACE_INLINE__)
+#include "ace/Containers.i"
+#endif /* __ACE_INLINE__ */
+
+#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION)
+template class ACE_Double_Linked_List<ACE_DLList_Node>;
+template class ACE_Double_Linked_List_Iterator_Base<ACE_DLList_Node>;
+template class ACE_Double_Linked_List_Iterator<ACE_DLList_Node>;
+template class ACE_Double_Linked_List_Reverse_Iterator<ACE_DLList_Node>;
+#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA)
+#pragma instantiate ACE_Double_Linked_List<ACE_DLList_Node>
+#pragma instantiate ACE_Double_Linked_List_Iterator_Base<ACE_DLList_Node>
+#pragma instantiate ACE_Double_Linked_List_Iterator<ACE_DLList_Node>
+#pragma instantiate ACE_Double_Linked_List_Reverse_Iterator<ACE_DLList_Node>
+#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */
+
diff --git a/ace/Utils/Containers.h b/ace/Utils/Containers.h
new file mode 100644
index 00000000000..5e28cc43c8e
--- /dev/null
+++ b/ace/Utils/Containers.h
@@ -0,0 +1,72 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Containers.h
+ *
+ * $Id$
+ *
+ * @author Douglas C. Schmidt <schmidt@cs.wustl.edu>
+ */
+//=============================================================================
+
+#ifndef ACE_CONTAINERS_H
+#define ACE_CONTAINERS_H
+#include "ace/pre.h"
+
+#include "ace/OS.h"
+#include "ace/Malloc_Base.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+template <class T>
+class ACE_Double_Linked_List;
+
+template <class T>
+class ACE_Double_Linked_List_Iterator_Base;
+template <class T>
+class ACE_Double_Linked_List_Iterator;
+template <class T>
+class ACE_Double_Linked_List_Reverse_Iterator;
+
+/**
+ * @class ACE_DLList_Node
+ *
+ * @brief Base implementation of element in a DL list. Needed for
+ * ACE_Double_Linked_List.
+ */
+class ACE_Export ACE_DLList_Node
+{
+public:
+ friend class ACE_Double_Linked_List<ACE_DLList_Node>;
+ friend class ACE_Double_Linked_List_Iterator_Base<ACE_DLList_Node>;
+ friend class ACE_Double_Linked_List_Iterator<ACE_DLList_Node>;
+ friend class ACE_Double_Linked_List_Reverse_Iterator<ACE_DLList_Node>;
+
+ ACE_DLList_Node (void *&i,
+ ACE_DLList_Node *n = 0,
+ ACE_DLList_Node *p = 0);
+ ~ACE_DLList_Node (void);
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+ void *item_;
+
+ ACE_DLList_Node *next_;
+ ACE_DLList_Node *prev_;
+
+protected:
+ ACE_DLList_Node (void);
+};
+
+#if defined (__ACE_INLINE__)
+#include "ace/Containers.i"
+#endif /* __ACE_INLINE__ */
+
+#include "ace/Containers_T.h"
+
+#include "ace/post.h"
+#endif /* ACE_CONTAINERS_H */
diff --git a/ace/Utils/Containers.i b/ace/Utils/Containers.i
new file mode 100644
index 00000000000..1312f2a47a6
--- /dev/null
+++ b/ace/Utils/Containers.i
@@ -0,0 +1,25 @@
+/* -*- C++ -*- */
+// $Id$
+
+ACE_INLINE
+ACE_DLList_Node::ACE_DLList_Node (void)
+ : item_ (0),
+ next_ (0),
+ prev_ (0)
+{
+}
+
+ACE_INLINE
+ACE_DLList_Node::ACE_DLList_Node (void *&i,
+ ACE_DLList_Node *n,
+ ACE_DLList_Node *p)
+ : item_ (i),
+ next_ (n),
+ prev_ (p)
+{
+}
+
+ACE_INLINE
+ACE_DLList_Node::~ACE_DLList_Node (void)
+{
+}
diff --git a/ace/Utils/Dirent.cpp b/ace/Utils/Dirent.cpp
new file mode 100644
index 00000000000..d8a283a7368
--- /dev/null
+++ b/ace/Utils/Dirent.cpp
@@ -0,0 +1,11 @@
+// $Id$
+
+#include "ace/Dirent.h"
+
+#if !defined (__ACE_INLINE__)
+#include "ace/Dirent.i"
+#else
+#if defined (__hpux) && !defined (__GNUG__)
+static int shut_up_aCC = 0;
+#endif /* HPUX && !g++ */
+#endif /* __ACE_INLINE__ */
diff --git a/ace/Utils/Dirent.h b/ace/Utils/Dirent.h
new file mode 100644
index 00000000000..0764011cd4d
--- /dev/null
+++ b/ace/Utils/Dirent.h
@@ -0,0 +1,115 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Dirent.h
+ *
+ * $Id$
+ *
+ * Define a portable C++ interface to <ACE_OS_Dirent> directory-entry manipulation.
+ *
+ * @author Douglas C. Schmidt <schmidt@cs.wustl.edu>
+ */
+//=============================================================================
+
+#ifndef ACE_DIRENT_H
+#define ACE_DIRENT_H
+#include "ace/pre.h"
+
+#include "ace/OS_Dirent.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+/**
+ * @class ACE_Dirent
+ *
+ * @brief Define a portable C++ directory-entry iterator based on the POSIX API.
+ */
+class ACE_Export ACE_Dirent
+{
+public:
+ // = Initialization and termination methods.
+ /// Default constructor.
+ ACE_Dirent (void);
+
+ /// Constructor calls <opendir>
+ ACE_EXPLICIT ACE_Dirent (const ACE_TCHAR *dirname);
+
+ /// Opens the directory named by filename and associates a directory
+ /// stream with it.
+ int open (const ACE_TCHAR *filename);
+
+ /// Destructor calls <closedir>.
+ ~ACE_Dirent (void);
+
+ /// Closes the directory stream and frees the <ACE_DIR> structure.
+ void close (void);
+
+ // = Iterator methods.
+ /**
+ * Returns a pointer to a structure representing the directory entry
+ * at the current position in the directory stream to which dirp
+ * refers, and positions the directory stream at the next entry,
+ * except on read-only filesystems. It returns a NULL pointer upon
+ * reaching the end of the directory stream, or upon detecting an
+ * invalid location in the directory. <readdir> shall not return
+ * directory entries containing empty names. It is unspecified
+ * whether entries are returned for dot or dot-dot. The pointer
+ * returned by <readdir> points to data that may be overwritten by
+ * another call to <readdir> on the same directory stream. This
+ * data shall not be overwritten by another call to <readdir> on a
+ * different directory stream. <readdir> may buffer several
+ * directory entries per actual read operation; <readdir> marks for
+ * update the st_atime field of the directory each time the
+ * directory is actually read.
+ */
+ dirent *read (void);
+
+ /**
+ * Has the equivalent functionality as <readdir> except that an
+ * <entry> and <result> buffer must be supplied by the caller to
+ * store the result.
+ */
+ int read (struct dirent *entry,
+ struct dirent **result);
+
+ // = Manipulators.
+ /// Returns the current location associated with the directory
+ /// stream.
+ long tell (void);
+
+ /**
+ * Sets the position of the next <readdir> operation on the
+ * directory stream. The new position reverts to the position
+ * associated with the directory stream at the time the <telldir>
+ * operation that provides loc was performed. Values returned by
+ * <telldir> are good only for the lifetime of the <ACE_DIR> pointer from
+ * which they are derived. If the directory is closed and then
+ * reopened, the <telldir> value may be invalidated due to
+ * undetected directory compaction. It is safe to use a previous
+ * <telldir> value immediately after a call to <opendir> and before
+ * any calls to readdir.
+ */
+ void seek (long loc);
+
+ /**
+ * Resets the position of the directory stream to the beginning of
+ * the directory. It also causes the directory stream to refer to
+ * the current state of the corresponding directory, as a call to
+ * <opendir> would.
+ */
+ void rewind (void);
+
+private:
+ /// Pointer to the directory stream.
+ ACE_DIR *dirp_;
+};
+
+#if defined (__ACE_INLINE__)
+#include "ace/Dirent.i"
+#endif /* __ACE_INLINE__ */
+
+#include "ace/post.h"
+#endif /* ACE_DIRENT_H */
diff --git a/ace/Utils/Dirent.i b/ace/Utils/Dirent.i
new file mode 100644
index 00000000000..4c731311c29
--- /dev/null
+++ b/ace/Utils/Dirent.i
@@ -0,0 +1,95 @@
+/* -*- C++ -*- */
+// $Id$
+
+#include "ace/Log_Msg.h"
+
+ACE_INLINE int
+ACE_Dirent::open (const ACE_TCHAR *dirname)
+{
+ // If the directory stream is already open, close it to prevent
+ // possible resource leaks.
+
+ if (this->dirp_ != 0)
+ {
+ ACE_OS_Dirent::closedir (this->dirp_);
+ this->dirp_ = 0;
+ }
+
+ this->dirp_ = ACE_OS_Dirent::opendir (dirname);
+
+ if (this->dirp_ == 0)
+ return -1;
+ else
+ return 0;
+}
+
+ACE_INLINE
+ACE_Dirent::ACE_Dirent (void)
+ : dirp_ (0)
+{
+}
+
+ACE_INLINE
+ACE_Dirent::ACE_Dirent (const ACE_TCHAR *dirname)
+ : dirp_ (0)
+{
+ if (this->open (dirname) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("%p\n"),
+ ACE_LIB_TEXT ("Dirent::Dirent")));
+}
+
+ACE_INLINE
+ACE_Dirent::~ACE_Dirent (void)
+{
+ if (this->dirp_ != 0)
+ ACE_OS_Dirent::closedir (this->dirp_);
+}
+
+ACE_INLINE dirent *
+ACE_Dirent::read (void)
+{
+ return this->dirp_ ? ACE_OS_Dirent::readdir (this->dirp_) : 0;
+}
+
+ACE_INLINE int
+ACE_Dirent::read (struct dirent *entry,
+ struct dirent **result)
+{
+ return this->dirp_
+ ? ACE_OS_Dirent::readdir_r (this->dirp_, entry, result)
+ : 0;
+}
+
+ACE_INLINE void
+ACE_Dirent::close (void)
+{
+ if (this->dirp_ != 0)
+ {
+ ACE_OS_Dirent::closedir (this->dirp_);
+
+ // Prevent double closure
+ this->dirp_ = 0;
+ }
+}
+
+ACE_INLINE void
+ACE_Dirent::rewind (void)
+{
+ if (this->dirp_)
+ ACE_OS_Dirent::rewinddir (this->dirp_);
+}
+
+ACE_INLINE void
+ACE_Dirent::seek (long loc)
+{
+ if (this->dirp_)
+ ACE_OS_Dirent::seekdir (this->dirp_, loc);
+}
+
+ACE_INLINE long
+ACE_Dirent::tell (void)
+{
+ return this->dirp_ ? ACE_OS_Dirent::telldir (this->dirp_) : 0;
+}
+
diff --git a/ace/Utils/Dirent_Selector.cpp b/ace/Utils/Dirent_Selector.cpp
new file mode 100644
index 00000000000..bef6c40a8d1
--- /dev/null
+++ b/ace/Utils/Dirent_Selector.cpp
@@ -0,0 +1,44 @@
+// $Id$
+
+#include "ace/OS.h"
+#include "ace/Dirent_Selector.h"
+
+#if !defined (__ACE_INLINE__)
+#include "ace/Dirent_Selector.inl"
+#endif /* __ACE_INLINE__ */
+
+ACE_RCSID (ace,
+ Dirent_Selector,
+ "$Id$")
+
+// Construction/Destruction
+
+ACE_Dirent_Selector::ACE_Dirent_Selector (void)
+ : namelist_ (0),
+ n_ (0)
+{
+}
+
+ACE_Dirent_Selector::~ACE_Dirent_Selector (void)
+{
+}
+
+int
+ACE_Dirent_Selector::open (const ACE_TCHAR *dir,
+ int (*sel)(const dirent *d),
+ int (*cmp) (const dirent **d1,
+ const dirent **d2))
+{
+ n_ = ACE_OS::scandir (dir, &this->namelist_, sel, cmp);
+ return n_;
+}
+
+int
+ACE_Dirent_Selector::close (void)
+{
+ for (--n_; n_>=0; --n_)
+ ACE_OS::free (this->namelist_[n_]);
+
+ ACE_OS::free (this->namelist_);
+ return 0;
+}
diff --git a/ace/Utils/Dirent_Selector.h b/ace/Utils/Dirent_Selector.h
new file mode 100644
index 00000000000..4dcfd945b5b
--- /dev/null
+++ b/ace/Utils/Dirent_Selector.h
@@ -0,0 +1,66 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Dirent_Selector.h
+ *
+ * $Id$
+ *
+ * Define a portable C++ interface to the <ACE_OS_Dirent::scandir> method.
+ *
+ * @author Rich Newman <RNewman@directv.com>
+ */
+//=============================================================================
+
+#ifndef ACE_DIRENT_SELECTOR_H
+#define ACE_DIRENT_SELECTOR_H
+#include "ace/pre.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+#pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+/**
+ * @class ACE_Dirent
+ *
+ * @brief Define a portable C++ directory-entry iterator based on the
+ * POSIX @param scandir API.
+ */
+class ACE_Export ACE_Dirent_Selector
+{
+public:
+ /// Constructor
+ ACE_Dirent_Selector (void);
+
+ /// Destructor.
+ virtual ~ACE_Dirent_Selector (void);
+
+ /// Return the length of the list of matching directory entries.
+ int length (void) const;
+
+ /// Return the entry at <index>.
+ dirent *operator[] (const int index) const;
+
+ /// Free up resources.
+ int close (void);
+
+ /// Open the director <dir> and populate the <namelist_> array with
+ /// directory entries that match the <selector> and <comparator>.
+ int open (const ACE_TCHAR *dir,
+ int (*selector)(const dirent *d) = 0,
+ int (*comparator)(const dirent **d1, const dirent **d2) = 0);
+
+protected:
+ /// Ptr to the namelist array.
+ dirent **namelist_;
+
+ /// # of entries in the array.
+ int n_;
+};
+
+#if defined (__ACE_INLINE__)
+#include "ace/Dirent_Selector.inl"
+#endif /* __ACE_INLINE__ */
+
+#include "ace/post.h"
+#endif /* ACE_DIRENT_SELECTOR_H */
diff --git a/ace/Utils/Dirent_Selector.inl b/ace/Utils/Dirent_Selector.inl
new file mode 100644
index 00000000000..577c4db4584
--- /dev/null
+++ b/ace/Utils/Dirent_Selector.inl
@@ -0,0 +1,15 @@
+// -*- C++ -*-
+//
+// $Id$
+
+ACE_INLINE int
+ACE_Dirent_Selector::length (void) const
+{
+ return n_;
+}
+
+ACE_INLINE dirent *
+ACE_Dirent_Selector::operator[] (const int n) const
+{
+ return this->namelist_[n];
+}
diff --git a/ace/Utils/Dynamic.cpp b/ace/Utils/Dynamic.cpp
new file mode 100644
index 00000000000..7dce958461d
--- /dev/null
+++ b/ace/Utils/Dynamic.cpp
@@ -0,0 +1,39 @@
+// Dynamic.cpp
+// $Id$
+
+#include "ace/Dynamic.h"
+#include "ace/Singleton.h"
+#include "ace/Synch_T.h"
+
+#if !defined (__ACE_INLINE__)
+#include "ace/Dynamic.i"
+#endif /* __ACE_INLINE__ */
+
+ACE_RCSID(ace, Dynamic, "$Id$")
+
+ACE_Dynamic::ACE_Dynamic (void)
+ : is_dynamic_ (0)
+{
+ ACE_TRACE ("ACE_Dynamic::ACE_Dynamic");
+}
+
+/* static */ ACE_Dynamic *
+ACE_Dynamic::instance (void)
+{
+ return ACE_TSS_Singleton<ACE_Dynamic, ACE_SYNCH_NULL_MUTEX>::instance ();
+}
+
+#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION)
+ template class ACE_TSS_Singleton<ACE_Dynamic, ACE_Null_Mutex>;
+# if (defined (ACE_HAS_THREADS) && (defined (ACE_HAS_THREAD_SPECIFIC_STORAGE) || defined (ACE_HAS_TSS_EMULATION)))
+ template class ACE_TSS<ACE_Dynamic>;
+# endif /* ACE_HAS_THREADS && (ACE_HAS_THREAD_SPECIFIC_STORAGE || ACE_HAS_TSS_EMULATION) */
+
+#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA)
+ #pragma instantiate ACE_TSS_Singleton<ACE_Dynamic, ACE_Null_Mutex>
+
+# if (defined (ACE_HAS_THREADS) && (defined (ACE_HAS_THREAD_SPECIFIC_STORAGE) || defined (ACE_HAS_TSS_EMULATION)))
+ #pragma instantiate ACE_TSS<ACE_Dynamic>
+# endif /* ACE_HAS_THREADS && (ACE_HAS_THREAD_SPECIFIC_STORAGE || ACE_HAS_TSS_EMULATION) */
+
+#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */
diff --git a/ace/Utils/Dynamic.h b/ace/Utils/Dynamic.h
new file mode 100644
index 00000000000..ad8db6f7615
--- /dev/null
+++ b/ace/Utils/Dynamic.h
@@ -0,0 +1,74 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Dynamic.h
+ *
+ * $Id$
+ *
+ * @author Doug Schmidt
+ * @author Irfan Pyarali.
+ */
+//=============================================================================
+
+#ifndef ACE_DYNAMIC_H
+#define ACE_DYNAMIC_H
+#include "ace/pre.h"
+
+#include "ace/ACE.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "ace/Synch_T.h"
+#include "ace/Singleton.h"
+
+/**
+ * @class ACE_Dynamic
+ *
+ * @brief Checks to see if an object was dynamically allocated.
+ *
+ * This class holds the pointer in a thread-safe manner between
+ * the call to operator new and the call to the constructor.
+ */
+class ACE_Export ACE_Dynamic
+{
+public:
+ // = Initialization and termination method.
+ /// Constructor.
+ ACE_Dynamic (void);
+
+ /// Destructor.
+ ~ACE_Dynamic (void);
+
+ /**
+ * Sets a flag that indicates that the object was dynamically
+ * created. This method is usually called in operator new and then
+ * checked and reset in the constructor.
+ */
+ void set (void);
+
+ /// 1 if we were allocated dynamically, else 0.
+ int is_dynamic (void);
+
+ /// Resets state flag.
+ void reset (void);
+
+ static ACE_Dynamic *instance (void);
+
+private:
+ /**
+ * Flag that indicates that the object was dynamically created. This
+ * method is usually called in operator new and then checked and
+ * reset in the constructor.
+ */
+ int is_dynamic_;
+};
+
+#if defined (__ACE_INLINE__)
+#include "ace/Dynamic.i"
+#endif /* __ACE_INLINE__ */
+
+#include "ace/post.h"
+#endif /* ACE_DYNAMIC_H */
diff --git a/ace/Utils/Dynamic.i b/ace/Utils/Dynamic.i
new file mode 100644
index 00000000000..5b25ac54f55
--- /dev/null
+++ b/ace/Utils/Dynamic.i
@@ -0,0 +1,32 @@
+/* -*- C++ -*- */
+// $Id$
+
+// Dynamic.i
+
+ACE_INLINE
+ACE_Dynamic::~ACE_Dynamic (void)
+{
+ ACE_TRACE ("ACE_Dynamic::~ACE_Dynamic");
+}
+
+ACE_INLINE void
+ACE_Dynamic::set (void)
+{
+ ACE_TRACE ("ACE_Dynamic::set");
+ this->is_dynamic_ = 1;
+}
+
+ACE_INLINE int
+ACE_Dynamic::is_dynamic ()
+{
+ ACE_TRACE ("ACE_Dynamic::is_dynamic");
+ return this->is_dynamic_;
+}
+
+ACE_INLINE void
+ACE_Dynamic::reset (void)
+{
+ ACE_TRACE ("ACE_Dynamic::reset");
+ this->is_dynamic_ = 0;
+}
+
diff --git a/ace/Utils/Filecache.cpp b/ace/Utils/Filecache.cpp
new file mode 100644
index 00000000000..b37a9ca20da
--- /dev/null
+++ b/ace/Utils/Filecache.cpp
@@ -0,0 +1,774 @@
+// $Id$
+
+#include "ace/Filecache.h"
+#include "ace/Object_Manager.h"
+#include "ace/Log_Msg.h"
+
+ACE_RCSID(ace, Filecache, "$Id$")
+
+#if defined (ACE_WIN32)
+// Specifies no sharing flags.
+#define R_MASK 0
+#define W_MASK 0
+#else
+#define R_MASK S_IRUSR|S_IRGRP|S_IROTH
+#define W_MASK S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR|S_IWGRP|S_IWOTH
+#endif /* __BORLANDC__ */
+
+#if defined (ACE_WIN32)
+// See if you can get rid of some of these.
+#define READ_FLAGS (FILE_FLAG_SEQUENTIAL_SCAN | \
+ FILE_FLAG_OVERLAPPED | \
+ O_RDONLY)
+// static const int RCOPY_FLAGS = (FILE_FLAG_SEQUENTIAL_SCAN |
+// O_RDONLY);
+#define WRITE_FLAGS (FILE_FLAG_SEQUENTIAL_SCAN | \
+ FILE_FLAG_OVERLAPPED | \
+ O_RDWR | O_CREAT | O_TRUNC)
+// static const int WCOPY_FLAGS = (FILE_FLAG_SEQUENTIAL_SCAN |
+// O_RDWR | O_CREAT | O_TRUNC);
+#else
+#define READ_FLAGS O_RDONLY
+// static const int RCOPY_FLAGS = O_RDONLY;
+#define WRITE_FLAGS (O_RDWR | O_CREAT | O_TRUNC)
+// static const int WCOPY_FLAGS = O_RDWR | O_CREAT | O_TRUNC;
+#endif /* ACE_WIN32 */
+
+// static data members
+ACE_Filecache *ACE_Filecache::cvf_ = 0;
+
+void
+ACE_Filecache_Handle::init (void)
+{
+ this->file_ = 0;
+ this->handle_ = ACE_INVALID_HANDLE;
+}
+
+ACE_Filecache_Handle::ACE_Filecache_Handle (void)
+ : file_ (0), handle_ (0), mapit_ (0)
+{
+ this->init ();
+}
+
+ACE_Filecache_Handle::ACE_Filecache_Handle (const ACE_TCHAR *filename,
+ ACE_Filecache_Flag mapit)
+ : file_ (0), handle_ (0), mapit_ (mapit)
+{
+ this->init ();
+ // Fetch the file from the Virtual_Filesystem let the
+ // Virtual_Filesystem do the work of cache coherency.
+
+ // Filecache will also do the acquire, since it holds the lock at
+ // that time.
+ this->file_ = ACE_Filecache::instance ()->fetch (filename, mapit);
+}
+
+ACE_Filecache_Handle::ACE_Filecache_Handle (const ACE_TCHAR *filename,
+ int size,
+ ACE_Filecache_Flag mapit)
+ : file_ (0), handle_ (0), mapit_ (mapit)
+{
+ this->init ();
+
+ if (size == 0)
+ ACE_Filecache::instance ()->remove (filename);
+ else
+ {
+ // Since this is being opened for a write, simply create a new
+ // ACE_Filecache_Object now, and let the destructor add it into CVF
+ // later
+
+ // Filecache will also do the acquire, since it holds the lock at
+ // that time.
+ this->file_ = ACE_Filecache::instance ()->create (filename, size);
+ }
+}
+
+ACE_Filecache_Handle::~ACE_Filecache_Handle (void)
+{
+ if (this->handle_ != ACE_INVALID_HANDLE)
+ // this was dup ()'d
+ ACE_OS::close (this->handle_);
+
+ ACE_Filecache::instance ()->finish (this->file_);
+}
+
+void *
+ACE_Filecache_Handle::address (void) const
+{
+ return this->file_ == 0 ? 0 : this->file_->address ();
+}
+
+ACE_HANDLE
+ACE_Filecache_Handle::handle (void) const
+{
+ if (this->handle_ == ACE_INVALID_HANDLE && this->file_ != 0)
+ {
+ ACE_Filecache_Handle *mutable_this =
+ (ACE_Filecache_Handle *) this;
+ mutable_this->handle_ = ACE_OS::dup (this->file_->handle ());
+ }
+ return this->handle_;
+}
+
+int
+ACE_Filecache_Handle::error (void) const
+{
+ if (this->file_ == 0)
+ return -1;
+ else
+ return this->file_->error ();
+}
+
+size_t
+ACE_Filecache_Handle::size (void) const
+{
+ if (this->file_ == 0)
+ return (size_t) -1;
+ else
+ return this->file_->size ();
+}
+
+// ------------------
+// ACE_Filecache_Hash
+// ------------------
+
+#if defined (ACE_HAS_TEMPLATE_SPECIALIZATION)
+
+#define ACE_Filecache_Hash \
+ ACE_Hash_Map_Manager<const ACE_TCHAR *, ACE_Filecache_Object *, ACE_Null_Mutex>
+#define ACE_Filecache_Hash_Entry \
+ ACE_Hash_Map_Entry<const ACE_TCHAR *, ACE_Filecache_Object *>
+
+ACE_TEMPLATE_SPECIALIZATION
+ACE_Filecache_Hash_Entry::ACE_Hash_Map_Entry (const ACE_TCHAR *const &ext_id,
+ ACE_Filecache_Object *const &int_id,
+ ACE_Filecache_Hash_Entry *next,
+ ACE_Filecache_Hash_Entry *prev)
+ : ext_id_ (ext_id ? ACE_OS::strdup (ext_id) : ACE_OS::strdup (ACE_LIB_TEXT (""))),
+ int_id_ (int_id),
+ next_ (next),
+ prev_ (prev)
+{
+}
+
+ACE_TEMPLATE_SPECIALIZATION
+ACE_Filecache_Hash_Entry::ACE_Hash_Map_Entry (ACE_Filecache_Hash_Entry *next,
+ ACE_Filecache_Hash_Entry *prev)
+ : ext_id_ (0),
+ next_ (next),
+ prev_ (prev)
+{
+}
+
+ACE_TEMPLATE_SPECIALIZATION
+ACE_Filecache_Hash_Entry::~ACE_Hash_Map_Entry (void)
+{
+ ACE_OS::free ((void *) ext_id_);
+}
+
+// We need these template specializations since KEY is defined as a
+// ACE_TCHAR*, which doesn't have a hash() or equal() method defined on it.
+
+ACE_TEMPLATE_SPECIALIZATION
+unsigned long
+ACE_Filecache_Hash::hash (const ACE_TCHAR *const &ext_id)
+{
+ return ACE::hash_pjw (ext_id);
+}
+
+ACE_TEMPLATE_SPECIALIZATION
+int
+ACE_Filecache_Hash::equal (const ACE_TCHAR *const &id1, const ACE_TCHAR *const &id2)
+{
+ return ACE_OS::strcmp (id1, id2) == 0;
+}
+
+#undef ACE_Filecache_Hash
+#undef ACE_Filecache_Hash_Entry
+
+#endif /* ACE_HAS_TEMPLATE_SPECIALIZATION */
+
+
+// -------------
+// ACE_Filecache
+// -------------
+
+ACE_Filecache *
+ACE_Filecache::instance (void)
+{
+ // Double check locking pattern.
+ if (ACE_Filecache::cvf_ == 0)
+ {
+ ACE_SYNCH_RW_MUTEX &lock =
+ *ACE_Managed_Object<ACE_SYNCH_RW_MUTEX>::get_preallocated_object
+ (ACE_Object_Manager::ACE_FILECACHE_LOCK);
+ ACE_GUARD_RETURN (ACE_SYNCH_RW_MUTEX, ace_mon, lock, 0);
+
+ // @@ James, please check each of the ACE_NEW_RETURN calls to
+ // make sure that it is safe to return if allocation fails.
+ if (ACE_Filecache::cvf_ == 0)
+ ACE_NEW_RETURN (ACE_Filecache::cvf_,
+ ACE_Filecache,
+ 0);
+ }
+
+ return ACE_Filecache::cvf_;
+}
+
+ACE_Filecache::ACE_Filecache (void)
+ : size_ (ACE_DEFAULT_VIRTUAL_FILESYSTEM_TABLE_SIZE),
+ hash_ (this->size_)
+{
+}
+
+ACE_Filecache::~ACE_Filecache (void)
+{
+}
+
+ACE_Filecache_Object *
+ACE_Filecache::insert_i (const ACE_TCHAR *filename,
+ ACE_SYNCH_RW_MUTEX &filelock,
+ int mapit)
+{
+ ACE_Filecache_Object *handle = 0;
+
+ if (this->hash_.find (filename, handle) == -1)
+ {
+ ACE_NEW_RETURN (handle,
+ ACE_Filecache_Object (filename, filelock, 0, mapit),
+ 0);
+
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT (" (%t) CVF: creating %s\n"), filename));
+
+ if (this->hash_.bind (filename, handle) == -1)
+ {
+ delete handle;
+ handle = 0;
+ }
+ }
+ else
+ handle = 0;
+
+ return handle;
+}
+
+ACE_Filecache_Object *
+ACE_Filecache::remove_i (const ACE_TCHAR *filename)
+{
+ ACE_Filecache_Object *handle = 0;
+
+ // Disassociate file from the cache.
+ if (this->hash_.unbind (filename, handle) == 0)
+ {
+ handle->stale_ = 1;
+
+ // Try a lock. If it succeds, we can delete it now.
+ // Otherwise, it will clean itself up later.
+ if (handle->lock_.tryacquire_write () == 0)
+ {
+ delete handle;
+ handle = 0;
+ }
+ }
+ else
+ handle = 0;
+
+ return handle;
+}
+
+ACE_Filecache_Object *
+ACE_Filecache::update_i (const ACE_TCHAR *filename,
+ ACE_SYNCH_RW_MUTEX &filelock,
+ int mapit)
+{
+ ACE_Filecache_Object *handle = 0;
+
+ handle = this->remove_i (filename);
+ handle = this->insert_i (filename, filelock, mapit);
+
+ return handle;
+}
+
+int
+ACE_Filecache::find (const ACE_TCHAR *filename)
+{
+ return this->hash_.find (filename);
+}
+
+
+ACE_Filecache_Object *
+ACE_Filecache::remove (const ACE_TCHAR *filename)
+{
+ ACE_Filecache_Object *handle = 0;
+
+ u_long loc = ACE::hash_pjw (filename) % this->size_;
+ ACE_SYNCH_RW_MUTEX &hashlock = this->hash_lock_[loc];
+ // ACE_SYNCH_RW_MUTEX &filelock = this->file_lock_[loc];
+
+ if (this->hash_.find (filename, handle) != -1)
+ {
+ ACE_WRITE_GUARD_RETURN (ACE_SYNCH_RW_MUTEX,
+ ace_mon,
+ hashlock,
+ 0);
+
+ return this->remove_i (filename);
+ }
+
+ return 0;
+}
+
+
+ACE_Filecache_Object *
+ACE_Filecache::fetch (const ACE_TCHAR *filename, int mapit)
+{
+ ACE_Filecache_Object *handle = 0;
+
+ u_long loc = ACE::hash_pjw (filename) % this->size_;
+ ACE_SYNCH_RW_MUTEX &hashlock = this->hash_lock_[loc];
+ ACE_SYNCH_RW_MUTEX &filelock = this->file_lock_[loc];
+
+ filelock.acquire_read ();
+
+ if (this->hash_.find (filename, handle) == -1)
+ {
+ ACE_WRITE_GUARD_RETURN (ACE_SYNCH_RW_MUTEX,
+ ace_mon,
+ hashlock,
+ 0);
+
+ // Second check in the method call
+ handle = this->insert_i (filename, filelock, mapit);
+
+ if (handle == 0)
+ filelock.release ();
+ }
+ else
+ {
+ if (handle->update ())
+ {
+ {
+ // Double check locking pattern
+ ACE_WRITE_GUARD_RETURN (ACE_SYNCH_RW_MUTEX,
+ ace_mon,
+ hashlock,
+ 0);
+
+ // Second check in the method call
+ handle = this->update_i (filename, filelock, mapit);
+
+ if (handle == 0)
+ filelock.release ();
+ }
+ }
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT (" (%t) CVF: found %s\n"), filename));
+ }
+
+ return handle;
+}
+
+ACE_Filecache_Object *
+ACE_Filecache::create (const ACE_TCHAR *filename, int size)
+{
+ ACE_Filecache_Object *handle = 0;
+
+ u_long loc = ACE::hash_pjw (filename) % this->size_;
+ ACE_SYNCH_RW_MUTEX &filelock = this->file_lock_[loc];
+
+ ACE_NEW_RETURN (handle,
+ ACE_Filecache_Object (filename, size, filelock),
+ 0);
+ handle->acquire ();
+
+ return handle;
+}
+
+ACE_Filecache_Object *
+ACE_Filecache::finish (ACE_Filecache_Object *&file)
+{
+ if (file == 0)
+ return file;
+
+ u_long loc = ACE::hash_pjw (file->filename_) % this->size_;
+ ACE_SYNCH_RW_MUTEX &hashlock = this->hash_lock_[loc];
+
+ if (file != 0)
+ switch (file->action_)
+ {
+ case ACE_Filecache_Object::ACE_WRITING:
+ {
+ ACE_WRITE_GUARD_RETURN (ACE_SYNCH_RW_MUTEX,
+ ace_mon,
+ hashlock,
+ 0);
+
+ file->release ();
+
+ this->remove_i (file->filename_);
+#if 0
+ int result = this->hash_.bind (file->filename (), file);
+
+ if (result == 0)
+ file->acquire ();
+#else
+ // Last one using a stale file is resposible for deleting it.
+ if (file->stale_)
+ {
+ // Try a lock. If it succeds, we can delete it now.
+ // Otherwise, it will clean itself up later.
+ if (file->lock_.tryacquire_write () == 0)
+ {
+ delete file;
+ file = 0;
+ }
+ }
+#endif
+ }
+
+ break;
+ default:
+ file->release ();
+
+ // Last one using a stale file is resposible for deleting it.
+ if (file->stale_)
+ {
+ // Try a lock. If it succeds, we can delete it now.
+ // Otherwise, it will clean itself up later.
+ if (file->lock_.tryacquire_write () == 0)
+ {
+ delete file;
+ file = 0;
+ }
+ }
+
+ break;
+ }
+
+ return file;
+}
+
+void
+ACE_Filecache_Object::init (void)
+{
+ this->filename_[0] = '\0';
+ this->handle_ = ACE_INVALID_HANDLE;
+ this->error_ = ACE_SUCCESS;
+ this->tempname_ = 0;
+ this->size_ = 0;
+
+ ACE_OS::memset (&(this->stat_), 0, sizeof (this->stat_));
+}
+
+ACE_Filecache_Object::ACE_Filecache_Object (void)
+ : tempname_ (0),
+ mmap_ (),
+ handle_ (0),
+ // stat_ (),
+ size_ (0),
+ action_ (0),
+ error_ (0),
+ stale_ (0),
+ // sa_ (),
+ junklock_ (),
+ lock_ (junklock_)
+{
+ this->init ();
+}
+
+ACE_Filecache_Object::ACE_Filecache_Object (const ACE_TCHAR *filename,
+ ACE_SYNCH_RW_MUTEX &lock,
+ LPSECURITY_ATTRIBUTES sa,
+ int mapit)
+ : tempname_ (0),
+ mmap_ (),
+ handle_ (0),
+ // stat_ (),
+ size_ (0),
+ action_ (0),
+ error_ (0),
+ stale_ (0),
+ sa_ (sa),
+ junklock_ (),
+ lock_ (lock)
+{
+ this->init ();
+
+ // ASSERT strlen(filename) < sizeof (this->filename_)
+ ACE_OS::strcpy (this->filename_, filename);
+ this->action_ = ACE_Filecache_Object::ACE_READING;
+ // place ourselves into the READING state
+
+ // Can we access the file?
+ if (ACE_OS::access (this->filename_, R_OK) == -1)
+ {
+ this->error_i (ACE_Filecache_Object::ACE_ACCESS_FAILED);
+ return;
+ }
+
+ // Can we stat the file?
+ if (ACE_OS::stat (this->filename_, &this->stat_) == -1)
+ {
+ this->error_i (ACE_Filecache_Object::ACE_STAT_FAILED);
+ return;
+ }
+
+ this->size_ = this->stat_.st_size;
+ this->tempname_ = this->filename_;
+
+ // Can we open the file?
+ this->handle_ = ACE_OS::open (this->tempname_,
+ READ_FLAGS, R_MASK, this->sa_);
+ if (this->handle_ == ACE_INVALID_HANDLE)
+ {
+ this->error_i (ACE_Filecache_Object::ACE_OPEN_FAILED,
+ ACE_LIB_TEXT ("ACE_Filecache_Object::ctor: open"));
+ return;
+ }
+
+ if (mapit)
+ {
+ // Can we map the file?
+ if (this->mmap_.map (this->handle_, -1,
+ PROT_READ, ACE_MAP_PRIVATE, 0, 0, this->sa_) != 0)
+ {
+ this->error_i (ACE_Filecache_Object::ACE_MEMMAP_FAILED,
+ ACE_LIB_TEXT ("ACE_Filecache_Object::ctor: map"));
+ ACE_OS::close (this->handle_);
+ this->handle_ = ACE_INVALID_HANDLE;
+ return;
+ }
+ }
+
+ // Ok, finished!
+ this->action_ = ACE_Filecache_Object::ACE_READING;
+}
+
+ACE_Filecache_Object::ACE_Filecache_Object (const ACE_TCHAR *filename,
+ int size,
+ ACE_SYNCH_RW_MUTEX &lock,
+ LPSECURITY_ATTRIBUTES sa)
+ : stale_ (0),
+ sa_ (sa),
+ lock_ (lock)
+{
+ this->init ();
+
+ this->size_ = size;
+ ACE_OS::strcpy (this->filename_, filename);
+ this->action_ = ACE_Filecache_Object::ACE_WRITING;
+
+ // Can we access the file?
+ if (ACE_OS::access (this->filename_, R_OK|W_OK) == -1
+ // Does it exist?
+ && ACE_OS::access (this->filename_, F_OK) != -1)
+ {
+ // File exists, but we cannot access it.
+ this->error_i (ACE_Filecache_Object::ACE_ACCESS_FAILED);
+ return;
+ }
+
+ this->tempname_ = this->filename_;
+
+ // Can we open the file?
+ this->handle_ = ACE_OS::open (this->tempname_, WRITE_FLAGS, W_MASK, this->sa_);
+ if (this->handle_ == ACE_INVALID_HANDLE)
+ {
+ this->error_i (ACE_Filecache_Object::ACE_OPEN_FAILED,
+ ACE_LIB_TEXT ("ACE_Filecache_Object::acquire: open"));
+ return;
+ }
+
+ // Can we write?
+ if (ACE_OS::pwrite (this->handle_, "", 1, this->size_ - 1) != 1)
+ {
+ this->error_i (ACE_Filecache_Object::ACE_WRITE_FAILED,
+ ACE_LIB_TEXT ("ACE_Filecache_Object::acquire: write"));
+ ACE_OS::close (this->handle_);
+ return;
+ }
+
+ // Can we map?
+ if (this->mmap_.map (this->handle_, this->size_, PROT_RDWR, MAP_SHARED,
+ 0, 0, this->sa_) != 0)
+ {
+ this->error_i (ACE_Filecache_Object::ACE_MEMMAP_FAILED,
+ ACE_LIB_TEXT ("ACE_Filecache_Object::acquire: map"));
+ ACE_OS::close (this->handle_);
+ }
+
+ // Ok, done!
+}
+
+ACE_Filecache_Object::~ACE_Filecache_Object (void)
+{
+ if (this->error_ == ACE_SUCCESS)
+ {
+ this->mmap_.unmap ();
+ ACE_OS::close (this->handle_);
+ this->handle_ = ACE_INVALID_HANDLE;
+ }
+}
+
+int
+ACE_Filecache_Object::acquire (void)
+{
+ return this->lock_.tryacquire_read ();
+}
+
+int
+ACE_Filecache_Object::release (void)
+{
+ if (this->action_ == ACE_WRITING)
+ {
+ // We are safe since only one thread has a writable Filecache_Object
+
+#if 0
+ ACE_HANDLE original = ACE_OS::open (this->filename_, WRITE_FLAGS, W_MASK,
+ this->sa_);
+ if (original == ACE_INVALID_HANDLE)
+ this->error_ = ACE_Filecache_Object::ACE_OPEN_FAILED;
+ else if (ACE_OS::write (original, this->mmap_.addr (),
+ this->size_) == -1)
+ {
+ this->error_ = ACE_Filecache_Object::ACE_WRITE_FAILED;
+ ACE_OS::close (original);
+ ACE_OS::unlink (this->filename_);
+ }
+ else if (ACE_OS::stat (this->filename_, &this->stat_) == -1)
+ this->error_ = ACE_Filecache_Object::ACE_STAT_FAILED;
+#endif
+
+ this->mmap_.unmap ();
+ ACE_OS::close (this->handle_);
+ this->handle_ = ACE_INVALID_HANDLE;
+
+#if 0
+ // Leave the file in an acquirable state.
+ this->handle_ = ACE_OS::open (this->tempname_, READ_FLAGS, R_MASK);
+ if (this->handle_ == ACE_INVALID_HANDLE)
+ {
+ this->error_i (ACE_Filecache_Object::ACE_OPEN_FAILED,
+ "ACE_Filecache_Object::acquire: open");
+ }
+ else if (this->mmap_.map (this->handle_, -1,
+ PROT_READ,
+ ACE_MAP_PRIVATE,
+ 0,
+ 0,
+ this->sa_) != 0)
+ {
+ this->error_i (ACE_Filecache_Object::ACE_MEMMAP_FAILED,
+ "ACE_Filecache_Object::acquire: map");
+ ACE_OS::close (this->handle_);
+ this->handle_ = ACE_INVALID_HANDLE;
+ }
+
+ this->action_ = ACE_Filecache_Object::ACE_READING;
+#endif
+ }
+
+ return this->lock_.release ();
+}
+
+int
+ACE_Filecache_Object::error (void) const
+{
+ // The existence of the object means a read lock is being held.
+ return this->error_;
+}
+
+int
+ACE_Filecache_Object::error_i (int error_value, const ACE_TCHAR *s)
+{
+ s = s;
+ ACE_ERROR ((LM_ERROR, ACE_LIB_TEXT ("%p.\n"), s));
+ this->error_ = error_value;
+ return error_value;
+}
+
+const ACE_TCHAR *
+ACE_Filecache_Object::filename (void) const
+{
+ // The existence of the object means a read lock is being held.
+ return this->filename_;
+}
+
+size_t
+ACE_Filecache_Object::size (void) const
+{
+ // The existence of the object means a read lock is being held.
+ return this->size_;
+}
+
+ACE_HANDLE
+ACE_Filecache_Object::handle (void) const
+{
+ // The existence of the object means a read lock is being held.
+ return this->handle_;
+}
+
+void *
+ACE_Filecache_Object::address (void) const
+{
+ // The existence of the object means a read lock is being held.
+ return this->mmap_.addr ();
+}
+
+int
+ACE_Filecache_Object::update (void) const
+{
+ // The existence of the object means a read lock is being held.
+ int result;
+ ACE_stat statbuf;
+
+ if (ACE_OS::stat (this->filename_, &statbuf) == -1)
+ result = 1;
+ else
+ // non-portable code may follow
+ result = ACE_OS::difftime (this->stat_.st_mtime, statbuf.st_mtime) < 0;
+
+ return result;
+}
+
+#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION)
+#if defined (ACE_HAS_TEMPLATE_SPECIALIZATION)
+template class ACE_Hash_Map_Entry<const ACE_TCHAR *, ACE_Filecache_Object *>;
+template class ACE_Hash_Map_Manager<const ACE_TCHAR *, ACE_Filecache_Object *, ACE_Null_Mutex>;
+template class ACE_Hash_Map_Iterator<const ACE_TCHAR *, ACE_Filecache_Object *, ACE_Null_Mutex>;
+template class ACE_Hash_Map_Reverse_Iterator<const ACE_TCHAR *, ACE_Filecache_Object *, ACE_Null_Mutex>;
+template class ACE_Hash_Map_Manager_Ex<const ACE_TCHAR *, ACE_Filecache_Object *, ACE_Hash<const ACE_TCHAR *>, ACE_Equal_To<const ACE_TCHAR *>, ACE_Null_Mutex>;
+template class ACE_Hash_Map_Iterator_Base_Ex<const ACE_TCHAR *, ACE_Filecache_Object *, ACE_Hash<const ACE_TCHAR *>, ACE_Equal_To<const ACE_TCHAR *>, ACE_Null_Mutex>;
+template class ACE_Hash_Map_Iterator_Ex<const ACE_TCHAR *, ACE_Filecache_Object *, ACE_Hash<const ACE_TCHAR *>, ACE_Equal_To<const ACE_TCHAR *>, ACE_Null_Mutex>;
+template class ACE_Hash_Map_Reverse_Iterator_Ex<const ACE_TCHAR *, ACE_Filecache_Object *, ACE_Hash<const ACE_TCHAR *>, ACE_Equal_To<const ACE_TCHAR *>, ACE_Null_Mutex>;
+#else
+template class ACE_Hash_Map_Entry<ACE_TString, ACE_Filecache_Object *>;
+template class ACE_Hash_Map_Manager<ACE_TString, ACE_Filecache_Object *, ACE_Null_Mutex>;
+template class ACE_Hash_Map_Iterator<ACE_TString, ACE_Filecache_Object *, ACE_Null_Mutex>;
+template class ACE_Hash_Map_Reverse_Iterator<ACE_TString, ACE_Filecache_Object *, ACE_Null_Mutex>;
+template class ACE_Hash_Map_Manager_Ex<ACE_TString, ACE_Filecache_Object *, ACE_Hash<ACE_TString>, ACE_Equal_To<ACE_TString>, ACE_Null_Mutex>;
+template class ACE_Hash_Map_Iterator_Base_Ex<ACE_TString, ACE_Filecache_Object *, ACE_Hash<ACE_TString>, ACE_Equal_To<ACE_TString>, ACE_Null_Mutex>;
+template class ACE_Hash_Map_Iterator_Ex<ACE_TString, ACE_Filecache_Object *, ACE_Hash<ACE_TString>, ACE_Equal_To<ACE_TString>, ACE_Null_Mutex>;
+template class ACE_Hash_Map_Reverse_Iterator_Ex<ACE_TString, ACE_Filecache_Object *, ACE_Hash<ACE_TString>, ACE_Equal_To<ACE_TString>, ACE_Null_Mutex>;
+#endif /* ACE_HAS_TEMPLATE_SPECIALIZATION */
+#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA)
+#if defined (ACE_HAS_TEMPLATE_SPECIALIZATION)
+#pragma instantiate ACE_Hash_Map_Entry<const ACE_TCHAR *, ACE_Filecache_Object *>
+#pragma instantiate ACE_Hash_Map_Manager<const ACE_TCHAR *, ACE_Filecache_Object *, ACE_Null_Mutex>
+#pragma instantiate ACE_Hash_Map_Iterator<const ACE_TCHAR *, ACE_Filecache_Object *, ACE_Null_Mutex>
+#pragma instantiate ACE_Hash_Map_Reverse_Iterator<const ACE_TCHAR *, ACE_Filecache_Object *, ACE_Null_Mutex>
+#pragma instantiate ACE_Hash_Map_Manager_Ex<const ACE_TCHAR *, ACE_Filecache_Object *, ACE_Hash<const ACE_TCHAR *>, ACE_Equal_To<const ACE_TCHAR *>, ACE_Null_Mutex>
+#pragma instantiate ACE_Hash_Map_Iterator_Base_Ex<const ACE_TCHAR *, ACE_Filecache_Object *, ACE_Hash<const ACE_TCHAR *>, ACE_Equal_To<const ACE_TCHAR *>, ACE_Null_Mutex>
+#pragma instantiate ACE_Hash_Map_Iterator_Ex<const ACE_TCHAR *, ACE_Filecache_Object *, ACE_Hash<const ACE_TCHAR *>, ACE_Equal_To<const ACE_TCHAR *>, ACE_Null_Mutex>
+#pragma instantiate ACE_Hash_Map_Reverse_Iterator_Ex<const ACE_TCHAR *, ACE_Filecache_Object *, ACE_Hash<const ACE_TCHAR *>, ACE_Equal_To<const ACE_TCHAR *>, ACE_Null_Mutex>
+#else
+#pragma instantiate ACE_Hash_Map_Entry<ACE_TString, ACE_Filecache_Object *>
+#pragma instantiate ACE_Hash_Map_Manager<ACE_TString, ACE_Filecache_Object *, ACE_Null_Mutex>
+#pragma instantiate ACE_Hash_Map_Iterator<ACE_TString, ACE_Filecache_Object *, ACE_Null_Mutex>
+#pragma instantiate ACE_Hash_Map_Reverse_Iterator<ACE_TString, ACE_Filecache_Object *, ACE_Null_Mutex>
+#pragma instantiate ACE_Hash_Map_Manager_Ex<ACE_TString, ACE_Filecache_Object *, ACE_Hash<ACE_TString>, ACE_Equal_To<ACE_TString>, ACE_Null_Mutex>
+#pragma instantiate ACE_Hash_Map_Iterator_Base_Ex<ACE_TString, ACE_Filecache_Object *, ACE_Hash<ACE_TString>, ACE_Equal_To<ACE_TString>, ACE_Null_Mutex>
+#pragma instantiate ACE_Hash_Map_Iterator_Ex<ACE_TString, ACE_Filecache_Object *, ACE_Hash<ACE_TString>, ACE_Equal_To<ACE_TString>, ACE_Null_Mutex>
+#pragma instantiate ACE_Hash_Map_Reverse_Iterator_Ex<ACE_TString, ACE_Filecache_Object *, ACE_Hash<ACE_TString>, ACE_Equal_To<ACE_TString>, ACE_Null_Mutex>
+#endif /* ACE_HAS_TEMPLATE_SPECIALIZATION */
+#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */
diff --git a/ace/Utils/Filecache.h b/ace/Utils/Filecache.h
new file mode 100644
index 00000000000..7e8df017878
--- /dev/null
+++ b/ace/Utils/Filecache.h
@@ -0,0 +1,353 @@
+/* -*- c++ -*- */
+
+//=============================================================================
+/**
+ * @file Filecache.h
+ *
+ * $Id$
+ *
+ * @author James Hu
+ */
+//=============================================================================
+
+
+#ifndef ACE_FILECACHE_H
+#define ACE_FILECACHE_H
+#include "ace/pre.h"
+
+#include "ace/Mem_Map.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "ace/Synch_T.h"
+#include "ace/Hash_Map_Manager.h"
+#include "ace/SString.h"
+
+enum ACE_Filecache_Flag
+{
+ ACE_NOMAP = 0,
+ ACE_MAPIT = 1
+};
+
+class ACE_Filecache_Object;
+
+/**
+ * @class ACE_Filecache_Handle
+ *
+ * @brief Abstraction over a real file. This is meant to be the entry
+ * point into the Cached Virtual Filesystem.
+ *
+ * This is a cached filesystem implementation based loosely on the
+ * implementation of JAWS_File. The interfaces will be nearly the
+ * same. The under-the-hood implementation should hopefully be a
+ * much faster thing.
+ * These will be given their own implementations later. For now, we
+ * borrow the implementation provided by JAWS.
+ * On creation, the cache is checked, and reference count is
+ * incremented. On destruction, reference count is decremented. If
+ * the reference count is 0, the file is removed from the cache.
+ * E.g. 1,
+ * {
+ * ACE_Filecache_Handle foo("foo.html");
+ * this->peer ().send (foo.address (), foo.size ());
+ * }
+ * E.g. 2,
+ * {
+ * ACE_Filecache_Handle foo("foo.html");
+ * io->transmitfile (foo.handle (), this->peer ().handle ());
+ * }
+ * E.g. 3,
+ * {
+ * ACE_Filecache_Handle foo("foo.html", content_length);
+ * this->peer ().recv (foo.address (), content_length);
+ * }
+ * TODO:
+ */
+class ACE_Export ACE_Filecache_Handle
+{
+
+ // (1) Get rid of the useless copying of files when reading. Although
+ // it does make sure the file you send isn't being changed, it doesn't
+ // make sure the file is in a sensible state before sending it.
+
+ // Alternative: if the file get's trashed while it is being shipped, let
+ // the client request the file again. The cache should have an updated
+ // copy by that point.
+
+ // (2) Use hashing for locating files. This means I need a hastable
+ // implementation with buckets.
+
+ // (3) Only lock when absolutely necessary. JAWS_Virtual_Filesystem was
+ // rather conservative, but for some reason it still ran into problems.
+ // Since this design should be simpler, problems should be easier to spot.
+ //
+public:
+
+ /// Query cache for file, and acquire it. Assumes the file is being
+ /// opened for reading.
+ ACE_Filecache_Handle (const ACE_TCHAR *filename,
+ ACE_Filecache_Flag mapit = ACE_MAPIT);
+
+ /**
+ * Create new entry, and acquire it. Presence of SIZE assumes the
+ * file is being opened for writing. If SIZE is zero, assumes the
+ * file is to be removed from the cache.
+ */
+ ACE_Filecache_Handle (const ACE_TCHAR *filename,
+ int size,
+ ACE_Filecache_Flag mapit = ACE_MAPIT);
+
+ /// Closes any open handles, release acquired file.
+ ~ACE_Filecache_Handle (void);
+
+ /// Base address of memory mapped file.
+ void *address (void) const;
+
+ /// A handle (e.g., UNIX file descriptor, or NT file handle).
+ ACE_HANDLE handle (void) const;
+
+ /// Any associated error in handle creation and acquisition.
+ int error (void) const;
+
+ /// The size of the file.
+ size_t size (void) const;
+
+protected:
+ /// Default do nothing constructor. Prevent it from being called.
+ ACE_Filecache_Handle (void);
+
+ /// Common initializations for constructors.
+ void init (void);
+
+public:
+ /// These come from ACE_Filecache_Object, which is an internal class.
+ enum
+ {
+ ACE_SUCCESS = 0,
+ ACE_ACCESS_FAILED,
+ ACE_OPEN_FAILED,
+ ACE_COPY_FAILED,
+ ACE_STAT_FAILED,
+ ACE_MEMMAP_FAILED,
+ ACE_WRITE_FAILED
+ };
+
+private:
+ /// A reference to the low level instance.
+ ACE_Filecache_Object *file_;
+
+ /// A <dup>'d version of the one from <file_>.
+ ACE_HANDLE handle_;
+
+ int mapit_;
+};
+
+#if defined (ACE_HAS_TEMPLATE_SPECIALIZATION)
+typedef ACE_Hash_Map_Entry<const ACE_TCHAR *, ACE_Filecache_Object *>
+ ACE_Filecache_Hash_Entry;
+
+typedef ACE_Hash_Map_Manager<const ACE_TCHAR *, ACE_Filecache_Object *, ACE_Null_Mutex>
+ ACE_Filecache_Hash;
+#else
+typedef ACE_Hash_Map_Entry<ACE_TString, ACE_Filecache_Object *>
+ ACE_Filecache_Hash_Entry;
+
+typedef ACE_Hash_Map_Manager<ACE_TString, ACE_Filecache_Object *, ACE_Null_Mutex>
+ ACE_Filecache_Hash;
+#endif /* ACE_HAS_TEMPLATE_SPECIALIZATION */
+
+/**
+ * @class ACE_Filecache
+ *
+ * @brief A hash table holding the information about entry point into
+ * the Cached Virtual Filesystem. On insertion, the reference
+ * count is incremented. On destruction, reference count is
+ * decremented.
+ */
+class ACE_Export ACE_Filecache
+{
+public:
+ /// Singleton pattern.
+ static ACE_Filecache *instance (void);
+
+ ~ACE_Filecache (void);
+
+ /// Returns 0 if the file associated with ``filename'' is in the cache,
+ /// or -1 if not.
+ int find (const ACE_TCHAR *filename);
+
+ /// Return the file associated with ``filename'' if it is in the cache,
+ /// or create if not.
+ ACE_Filecache_Object *fetch (const ACE_TCHAR *filename, int mapit = 1);
+
+ /// Remove the file associated with ``filename'' from the cache.
+ ACE_Filecache_Object *remove (const ACE_TCHAR *filename);
+
+ /// Create a new Filecache_Object, returns it.
+ ACE_Filecache_Object *create (const ACE_TCHAR *filename, int size);
+
+ /// Release an acquired Filecache_Object, returns it again or NULL if it
+ /// was deleted.
+ ACE_Filecache_Object *finish (ACE_Filecache_Object *&new_file);
+
+protected:
+ ACE_Filecache_Object *insert_i (const ACE_TCHAR *filename,
+ ACE_SYNCH_RW_MUTEX &filelock,
+ int mapit);
+ ACE_Filecache_Object *remove_i (const ACE_TCHAR *filename);
+ ACE_Filecache_Object *update_i (const ACE_TCHAR *filename,
+ ACE_SYNCH_RW_MUTEX &filelock,
+ int mapit);
+
+public:
+
+ enum
+ {
+ /// For this stupid implementation, use an array. Someday, use a
+ /// balanced search tree, or real hash table.
+ ACE_DEFAULT_VIRTUAL_FILESYSTEM_TABLE_SIZE = 512,
+
+ /// This determines the highwater mark in megabytes for the cache.
+ /// This will be ignored for now.
+ ACE_DEFAULT_VIRTUAL_FILESYSTEM_CACHE_SIZE = 20
+ };
+
+protected:
+ /// Prevent it from being called.
+ ACE_Filecache (void);
+
+private:
+ int size_;
+
+ /// The hash table
+ ACE_Filecache_Hash hash_;
+
+ /// The reference to the instance
+ static ACE_Filecache *cvf_;
+
+ // = Synchronization variables.
+ ACE_SYNCH_RW_MUTEX hash_lock_[ACE_DEFAULT_VIRTUAL_FILESYSTEM_TABLE_SIZE];
+ ACE_SYNCH_RW_MUTEX file_lock_[ACE_DEFAULT_VIRTUAL_FILESYSTEM_TABLE_SIZE];
+};
+
+/**
+ * @class ACE_Filecache_Object
+ *
+ * @brief Abstraction over a real file. This is what the Virtual
+ * Filesystem contains. This class is not intended for general
+ * consumption. Please consult a physician before attempting to
+ * use this class.
+ */
+class ACE_Export ACE_Filecache_Object
+{
+public:
+ friend class ACE_Filecache;
+
+ /// Creates a file for reading.
+ ACE_Filecache_Object (const ACE_TCHAR *filename,
+ ACE_SYNCH_RW_MUTEX &lock,
+ LPSECURITY_ATTRIBUTES sa = 0,
+ int mapit = 1);
+
+ /// Creates a file for writing.
+ ACE_Filecache_Object (const ACE_TCHAR *filename,
+ int size,
+ ACE_SYNCH_RW_MUTEX &lock,
+ LPSECURITY_ATTRIBUTES sa = 0);
+
+ /// Only if reference count is zero should this be called.
+ ~ACE_Filecache_Object (void);
+
+ /// Increment the reference_count_.
+ int acquire (void);
+
+ /// Decrement the reference_count_.
+ int release (void);
+
+ // = error_ accessors
+ int error (void) const;
+ int error (int error_value,
+ const ACE_TCHAR *s = ACE_LIB_TEXT ("ACE_Filecache_Object"));
+
+ /// filename_ accessor
+ const ACE_TCHAR *filename (void) const;
+
+ /// handle_ accessor.
+ ACE_HANDLE handle (void) const;
+
+ /// Base memory address for memory mapped file.
+ void *address (void) const;
+
+ /// size_ accessor.
+ size_t size (void) const;
+
+ /// True if file on disk is newer than cached file.
+ int update (void) const;
+
+protected:
+ /// Prevent from being called.
+ ACE_Filecache_Object (void);
+
+ /// Common initialization code,
+ void init (void);
+
+private:
+ /// Internal error logging method, no locking.
+ int error_i (int error_value,
+ const ACE_TCHAR *s = ACE_LIB_TEXT ("ACE_Filecache_Object"));
+
+public:
+
+ enum Creation_States
+ {
+ ACE_READING = 1,
+ ACE_WRITING = 2
+ };
+
+ enum Error_Conditions
+ {
+ ACE_SUCCESS = 0,
+ ACE_ACCESS_FAILED,
+ ACE_OPEN_FAILED,
+ ACE_COPY_FAILED,
+ ACE_STAT_FAILED,
+ ACE_MEMMAP_FAILED,
+ ACE_WRITE_FAILED
+ };
+
+private:
+ /// The temporary file name and the real file name. The real file is
+ /// copied into the temporary file for safety reasons.
+ ACE_TCHAR *tempname_;
+ ACE_TCHAR filename_[MAXPATHLEN + 1];
+
+ /// mmap_ holds the memory mapped version of the temporary file.
+ /// handle_ is the descriptor to the temporary file.
+ ACE_Mem_Map mmap_;
+ ACE_HANDLE handle_;
+
+ /// Used to compare against the real file to test if an update is needed.
+ ACE_stat stat_;
+ size_t size_;
+
+ /// Status indicators.
+ int action_;
+ int error_;
+
+ /// If set to 1, means the object is flagged for removal.
+ int stale_;
+
+ /// Security attribute object.
+ LPSECURITY_ATTRIBUTES sa_;
+
+ /// lock_ provides a bookkeeping mechanism for users of this object.
+ /// junklock_ is the default initializer
+ ACE_SYNCH_RW_MUTEX junklock_;
+ ACE_SYNCH_RW_MUTEX &lock_;
+};
+
+
+#include "ace/post.h"
+#endif /* ACE_FILECACHE_H */
diff --git a/ace/Utils/Flag_Manip.cpp b/ace/Utils/Flag_Manip.cpp
new file mode 100644
index 00000000000..0b644d88f9d
--- /dev/null
+++ b/ace/Utils/Flag_Manip.cpp
@@ -0,0 +1,80 @@
+// $Id$
+
+#include "Flag_Manip.h"
+
+#if defined (ACE_LACKS_INLINE_FUNCTIONS)
+#include "ace/Flag_Manip.i"
+#endif /* ACE_LACKS_INLINE_FUNCTIONS */
+
+ACE_RCSID(ace, Flag_Manip, "$Id$")
+
+// Flags are file status flags to turn on.
+
+int
+ACE_Flag_Manip::set_flags (ACE_HANDLE handle, int flags)
+{
+ ACE_TRACE ("ACE_Flag_Manip::set_flags");
+#if defined (ACE_WIN32) || defined (VXWORKS) || defined (ACE_LACKS_FCNTL)
+ switch (flags)
+ {
+ case ACE_NONBLOCK:
+ // nonblocking argument (1)
+ // blocking: (0)
+ {
+ u_long nonblock = 1;
+ return ACE_OS::ioctl (handle, FIONBIO, &nonblock);
+ }
+ default:
+ ACE_NOTSUP_RETURN (-1);
+ }
+#else
+ int val = ACE_OS::fcntl (handle, F_GETFL, 0);
+
+ if (val == -1)
+ return -1;
+
+ // Turn on flags.
+ ACE_SET_BITS (val, flags);
+
+ if (ACE_OS::fcntl (handle, F_SETFL, val) == -1)
+ return -1;
+ else
+ return 0;
+#endif /* ACE_WIN32 || ACE_LACKS_FCNTL */
+}
+
+// Flags are the file status flags to turn off.
+
+int
+ACE_Flag_Manip::clr_flags (ACE_HANDLE handle, int flags)
+{
+ ACE_TRACE ("ACE_Flag_Manip::clr_flags");
+
+#if defined (ACE_WIN32) || defined (VXWORKS) || defined (ACE_LACKS_FCNTL)
+ switch (flags)
+ {
+ case ACE_NONBLOCK:
+ // nonblocking argument (1)
+ // blocking: (0)
+ {
+ u_long nonblock = 0;
+ return ACE_OS::ioctl (handle, FIONBIO, &nonblock);
+ }
+ default:
+ ACE_NOTSUP_RETURN (-1);
+ }
+#else
+ int val = ACE_OS::fcntl (handle, F_GETFL, 0);
+
+ if (val == -1)
+ return -1;
+
+ // Turn flags off.
+ ACE_CLR_BITS (val, flags);
+
+ if (ACE_OS::fcntl (handle, F_SETFL, val) == -1)
+ return -1;
+ else
+ return 0;
+#endif /* ACE_WIN32 || ACE_LACKS_FCNTL */
+}
diff --git a/ace/Utils/Flag_Manip.h b/ace/Utils/Flag_Manip.h
new file mode 100644
index 00000000000..1359966b9ba
--- /dev/null
+++ b/ace/Utils/Flag_Manip.h
@@ -0,0 +1,47 @@
+//=============================================================================
+/**
+ * @file Flag_Manip.h
+ *
+ * $Id$
+ *
+ * This class includes the functions used for the Flag Manipulation.
+ *
+ * @author Priyanka Gontla <pgontla@ece.uci.edu>
+ */
+//=============================================================================
+
+#ifndef ACE_FLAG_MANIP_H
+#define ACE_FLAG_MANIP_H
+#include "ace/pre.h"
+
+#include "ace/OS/OS.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+class ACE_Export ACE_Flag_Manip
+{
+ public:
+
+ // = Set/get/clear various flags related to I/O HANDLE.
+ /// Set flags associated with <handle>.
+ static int set_flags (ACE_HANDLE handle,
+ int flags);
+
+ /// Clear flags associated with <handle>.
+ static int clr_flags (ACE_HANDLE handle,
+ int flags);
+
+ /// Return the current setting of flags associated with <handle>.
+ static int get_flags (ACE_HANDLE handle);
+
+
+};
+
+#if !defined (ACE_LACKS_INLINE_FUNCTIONS)
+#include "Flag_Manip.i"
+#endif /* ACE_LACKS_INLINE_FUNCTIONS */
+
+#include "ace/post.h"
+#endif /* ACE_FLAG_MANIP_H */
diff --git a/ace/Utils/Flag_Manip.i b/ace/Utils/Flag_Manip.i
new file mode 100644
index 00000000000..b041e1f19d8
--- /dev/null
+++ b/ace/Utils/Flag_Manip.i
@@ -0,0 +1,20 @@
+/* -*- C++ -*- */
+// $Id$
+
+// Return flags currently associated with handle.
+
+ASYS_INLINE int
+ACE_Flag_Manip::get_flags (ACE_HANDLE handle)
+{
+ ACE_TRACE ("ACE_Flag_Manip::get_flags");
+
+#if defined (ACE_LACKS_FCNTL)
+ // ACE_OS::fcntl is not supported, e.g., on VxWorks. It
+ // would be better to store ACE's notion of the flags
+ // associated with the handle, but this works for now.
+ ACE_UNUSED_ARG (handle);
+ return 0;
+#else
+ return ACE_OS::fcntl (handle, F_GETFL, 0);
+#endif /* ACE_LACKS_FCNTL */
+}
diff --git a/ace/Utils/Functor.cpp b/ace/Utils/Functor.cpp
new file mode 100644
index 00000000000..d83ef473c6f
--- /dev/null
+++ b/ace/Utils/Functor.cpp
@@ -0,0 +1,48 @@
+/* -*- C++ -*- */
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// ace
+//
+// = FILENAME
+// Functor.cpp
+//
+// = DESCRIPTION
+// Non-inlinable method definitions for non-templatized classes
+// and template specializations implementing the GOF Command Pattern,
+// and STL-style functors.
+//
+// = AUTHOR
+// Chris Gill <cdgill@cs.wustl.edu>
+//
+// Based on Command Pattern implementations originally done by
+//
+// Carlos O'Ryan <coryan@cs.wustl.edu> and
+// Douglas C. Schmidt <schmidt@cs.wustl.edu> and
+// Sergio Flores-Gaitan <sergio@cs.wustl.edu>
+//
+// and on STL-style functor implementations originally done by
+//
+// Irfan Pyarali <irfan@cs.wustl.edu>
+//
+// ============================================================================
+
+#if !defined (ACE_FUNCTOR_C)
+#define ACE_FUNCTOR_C
+
+#include "ace/Functor_T.h"
+#include "ace/Functor.h"
+
+#if !defined (__ACE_INLINE__)
+#include "ace/Functor.i"
+#endif /* __ACE_INLINE__ */
+
+ACE_RCSID(ace, Functor, "$Id$")
+
+#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION)
+#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA)
+#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */
+
+#endif /* ACE_FUNCTOR_C */
diff --git a/ace/Utils/Functor.h b/ace/Utils/Functor.h
new file mode 100644
index 00000000000..5e96d5cbad5
--- /dev/null
+++ b/ace/Utils/Functor.h
@@ -0,0 +1,363 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Functor.h
+ *
+ * $Id$
+ *
+ * Non-templatized classes and class template specializations for
+ * implementing function objects that are used in various places
+ * in ACE. There are currently two major categories of function
+ * objects in ACE: GoF Command Pattern objects, and STL-style
+ * functors for comparison of container elements. The command objects
+ * are invoked via an execute () method, while the STL-style functors are
+ * invoked via an operator() () method.
+ * Non-templatized classes for implementing the GoF Command Pattern,
+ * also known as functors or function objects.
+ *
+ *
+ * @author Chris Gill <cdgill@cs.wustl.edu>
+ * @author Based on Command Pattern implementations originally done by
+ * @author Carlos O'Ryan <coryan@cs.wustl.edu>
+ * @author Douglas C. Schmidt <schmidt@cs.wustl.edu>
+ * @author Sergio Flores-Gaitan <sergio@cs.wustl.edu>
+ * @author and on STL-style functor implementations originally done by
+ * @author Irfan Pyarali <irfan@cs.wustl.edu>
+ */
+//=============================================================================
+
+
+#ifndef ACE_FUNCTOR_H
+#define ACE_FUNCTOR_H
+#include "ace/pre.h"
+
+#include "ace/ACE.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+//////////////////////////////////////////////////////////////
+// GOF Command Pattern Classes and Template Specializations //
+//////////////////////////////////////////////////////////////
+
+/**
+ * @class ACE_Command_Base
+ *
+ * @brief Defines an abstract class that allows us to invoke commands
+ * without knowing anything about the implementation.
+ *
+ * This class declares an interface to execute a command
+ * independent of the effect of the command, or the objects used
+ * to implement it.
+ */
+class ACE_Export ACE_Command_Base
+{
+public:
+ // = Initialization and termination methods.
+ /// Default constructor.
+ ACE_Command_Base (void);
+
+ /// Virtaul destructor.
+ virtual ~ACE_Command_Base (void);
+
+ /**
+ * Invokes the method encapsulated by the command, passing along the
+ * passed argument (if any). Users of classes derived from this
+ * class must ensure that the resulting invocation can tolerate a
+ * null void pointer being passed, or otherwise ensure that this
+ * will never occur.
+ */
+ virtual int execute (void *arg = 0) = 0;
+};
+
+////////////////////////////////////////////////////////////
+// STL-style Functor Classes and Template Specializations //
+////////////////////////////////////////////////////////////
+
+// Forward declaration since we are going to specialize that template
+// here. The template itself requires this file so every user of the
+// template should also see the specialization.
+template <class TYPE> class ACE_Hash;
+template <class TYPE> class ACE_Equal_To;
+template <class TYPE> class ACE_Less_Than;
+
+ACE_TEMPLATE_SPECIALIZATION
+/**
+ * @class ACE_Hash<char>
+ *
+ * @brief Function object for hashing a char
+ */
+class ACE_Export ACE_Hash<char>
+{
+public:
+ /// Simply returns t
+ u_long operator () (char t) const;
+};
+
+ACE_TEMPLATE_SPECIALIZATION
+/**
+ * @class ACE_Hash<signed
+ *
+ * @brief Function object for hashing a signed char
+ */
+class ACE_Export ACE_Hash<signed char>
+{
+public:
+ /// Simply returns t
+ u_long operator () (signed char t) const;
+};
+
+ACE_TEMPLATE_SPECIALIZATION
+/**
+ * @class ACE_Hash<unsigned
+ *
+ * @brief Function object for hashing an unsigned char
+ */
+class ACE_Export ACE_Hash<unsigned char>
+{
+public:
+ /// Simply returns t
+ u_long operator () (unsigned char t) const;
+};
+
+// @@ ADD HASHES FOR ACE TYPES
+
+ACE_TEMPLATE_SPECIALIZATION
+/**
+ * @class ACE_Hash<ACE_INT16>
+ *
+ * @brief Function object for hashing a 16-bit signed number
+ */
+class ACE_Export ACE_Hash<ACE_INT16>
+{
+public:
+ /// Simply returns t
+ u_long operator () (ACE_INT16 t) const;
+};
+
+ACE_TEMPLATE_SPECIALIZATION
+/**
+ * @class ACE_Hash<ACE_UINT16>
+ *
+ * @brief Function object for hashing a 16-bit unsigned number
+ */
+class ACE_Export ACE_Hash<ACE_UINT16>
+{
+public:
+ /// Simply returns t
+ u_long operator () (ACE_UINT16 t) const;
+};
+
+ACE_TEMPLATE_SPECIALIZATION
+/**
+ * @class ACE_Hash<ACE_INT32>
+ *
+ * @brief Function object for hashing a 32-bit signed number
+ */
+class ACE_Export ACE_Hash<ACE_INT32>
+{
+public:
+ /// Simply returns t
+ u_long operator () (ACE_INT32 t) const;
+};
+
+ACE_TEMPLATE_SPECIALIZATION
+/**
+ * @class ACE_Hash<ACE_UINT32>
+ *
+ * @brief Function object for hashing a 32-bit unsigned number
+ */
+class ACE_Export ACE_Hash<ACE_UINT32>
+{
+public:
+ /// Simply returns t
+ u_long operator () (ACE_UINT32 t) const;
+};
+
+ACE_TEMPLATE_SPECIALIZATION
+/**
+ * @class ACE_Hash<ACE_UINT64>
+ *
+ * @brief Function object for hashing a 64-bit unsigned number
+ */
+class ACE_Export ACE_Hash<ACE_UINT64>
+{
+public:
+ /// Simply returns t
+ u_long operator () (ACE_UINT64 t) const;
+};
+
+// @@ DONE ADDING HASHES FOR ACE TYPES
+
+ACE_TEMPLATE_SPECIALIZATION
+/**
+ * @class ACE_Hash<const
+ *
+ * @brief Function object for hashing a const string
+ */
+class ACE_Export ACE_Hash<const ACE_TCHAR *>
+{
+public:
+ /// Calls ACE::hash_pjw
+ u_long operator () (const ACE_TCHAR *t) const;
+};
+
+ACE_TEMPLATE_SPECIALIZATION
+/**
+ * @class ACE_Hash<ACE_TCHAR
+ *
+ * @brief Function object for hashing a string
+ */
+class ACE_Export ACE_Hash<ACE_TCHAR *>
+{
+public:
+ /// Calls ACE::hash_pjw
+ u_long operator () (const ACE_TCHAR *t) const;
+};
+
+ACE_TEMPLATE_SPECIALIZATION
+/**
+ * @class ACE_Equal_To<const
+ *
+ * @brief Function object for determining whether two const strings are equal.
+ */
+class ACE_Export ACE_Equal_To<const ACE_TCHAR *>
+{
+public:
+ /// Simply calls ACE_OS::strcmp
+ int operator () (const ACE_TCHAR *lhs,
+ const ACE_TCHAR *rhs) const;
+};
+
+ACE_TEMPLATE_SPECIALIZATION
+/**
+ * @class ACE_Equal_To<ACE_TCHAR
+ *
+ * @brief Function object for determining whether two non-const
+ * strings are equal.
+ */
+class ACE_Export ACE_Equal_To<ACE_TCHAR *>
+{
+public:
+ /// Simply calls ACE_OS::strcmp
+ int operator () (const ACE_TCHAR *lhs,
+ const ACE_TCHAR *rhs) const;
+};
+
+ ACE_TEMPLATE_SPECIALIZATION
+ /**
+ * @class ACE_Equal_To<ACE_UINT16>
+ *
+ * @brief Function object for determining whether two unsigned
+ * 16 bit ints are equal.
+ */
+class ACE_Export ACE_Equal_To<ACE_UINT16>
+{
+public:
+ /// Simply calls built-in operators
+ int operator () (const ACE_UINT16 lhs,
+ const ACE_UINT16 rhs) const;
+};
+
+ACE_TEMPLATE_SPECIALIZATION
+/**
+ * @class ACE_Equal_To<ACE_INT16>
+ *
+ * @brief Function object for determining whether two
+ * 16 bit ints are equal.
+ */
+class ACE_Export ACE_Equal_To<ACE_INT16>
+{
+public:
+ /// Simply calls built-in operators
+ int operator () (const ACE_INT16 lhs,
+ const ACE_INT16 rhs) const;
+};
+
+ACE_TEMPLATE_SPECIALIZATION
+/**
+ * @class ACE_Equal_To<ACE_UINT32>
+ *
+ * @brief Function object for determining whether two unsigned
+ * 32 bit ints are equal.
+ */
+class ACE_Export ACE_Equal_To<ACE_UINT32>
+{
+public:
+ /// Simply calls built-in operators
+ int operator () (const ACE_UINT32 lhs,
+ const ACE_UINT32 rhs) const;
+};
+
+ACE_TEMPLATE_SPECIALIZATION
+/**
+ * @class ACE_Equal_To<ACE_INT32>
+ *
+ * @brief Function object for determining whether two
+ * 32 bit ints are equal.
+ */
+class ACE_Export ACE_Equal_To<ACE_INT32>
+{
+public:
+ /// Simply calls built-in operators
+ int operator () (const ACE_INT32 lhs,
+ const ACE_INT32 rhs) const;
+};
+
+ACE_TEMPLATE_SPECIALIZATION
+/**
+ * @class ACE_Equal_To<ACE_UINT64>
+ *
+ * @brief Function object for determining whether two unsigned
+ * 64 bit ints are equal.
+ */
+class ACE_Export ACE_Equal_To<ACE_UINT64>
+{
+public:
+ /// Simply calls built-in operators
+ int operator () (const ACE_UINT64 lhs,
+ const ACE_UINT64 rhs) const;
+};
+
+
+ACE_TEMPLATE_SPECIALIZATION
+/**
+ * @class ACE_Less_Than<const
+ *
+ * @brief Function object for determining whether the first const string
+ * is less than the second const string.
+ */
+class ACE_Export ACE_Less_Than<const ACE_TCHAR *>
+{
+public:
+ /// Simply calls ACE_OS::strcmp
+ int operator () (const ACE_TCHAR *lhs,
+ const ACE_TCHAR *rhs) const;
+};
+
+ACE_TEMPLATE_SPECIALIZATION
+/**
+ * @class ACE_Less_Than<ACE_TCHAR
+ *
+ * @brief Function object for determining whether the first string
+ * is less than the second string.
+ */
+class ACE_Export ACE_Less_Than<ACE_TCHAR *>
+{
+public:
+ /// Simply calls ACE_OS::strcmp
+ int operator () (const ACE_TCHAR *lhs,
+ const ACE_TCHAR *rhs) const;
+};
+
+#if defined (__ACE_INLINE__)
+#include "ace/Functor.i"
+#endif /* __ACE_INLINE__ */
+
+// Include the templates here.
+#include "ace/Functor_T.h"
+
+#include "ace/post.h"
+#endif /* ACE_FUNCTOR_H */
diff --git a/ace/Utils/Functor.i b/ace/Utils/Functor.i
new file mode 100644
index 00000000000..5e46485304d
--- /dev/null
+++ b/ace/Utils/Functor.i
@@ -0,0 +1,188 @@
+/* -*- C++ -*- */
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// ace
+//
+// = FILENAME
+// Functor.i
+//
+// = DESCRIPTION
+// Inlinable method definitions for non-templatized classes
+// and template specializations implementing the GOF Command Pattern,
+// and STL-style functors.
+//
+// = AUTHOR
+// Chris Gill <cdgill@cs.wustl.edu>
+//
+// Based on Command Pattern implementations originally done by
+//
+// Carlos O'Ryan <coryan@cs.wustl.edu> and
+// Douglas C. Schmidt <schmidt@cs.wustl.edu> and
+// Sergio Flores-Gaitan <sergio@cs.wustl.edu>
+//
+// and on STL-style functor implementations originally done by
+//
+// Irfan Pyarali <irfan@cs.wustl.edu>
+//
+// ============================================================================
+
+//////////////////////////////////////////////////////////////
+// GOF Command Pattern Classes and Template Specializations //
+//////////////////////////////////////////////////////////////
+
+// Default constructor.
+
+ACE_INLINE
+ACE_Command_Base::ACE_Command_Base (void)
+{
+}
+
+// Virtaul destructor.
+
+ACE_INLINE
+ACE_Command_Base::~ACE_Command_Base (void)
+{
+}
+
+////////////////////////////////////////////////////////////
+// STL-style Functor Classes and Template Specializations //
+////////////////////////////////////////////////////////////
+
+ACE_TEMPLATE_METHOD_SPECIALIZATION
+ACE_INLINE
+u_long
+ACE_Hash<char>::operator () (char t) const
+{
+ return t;
+}
+
+ACE_TEMPLATE_METHOD_SPECIALIZATION
+ACE_INLINE u_long
+ACE_Hash<signed char>::operator () (signed char t) const
+{
+ return t;
+}
+
+ACE_TEMPLATE_METHOD_SPECIALIZATION
+ACE_INLINE u_long
+ACE_Hash<unsigned char>::operator () (unsigned char t) const
+{
+ return t;
+}
+
+ACE_TEMPLATE_METHOD_SPECIALIZATION
+ACE_INLINE u_long
+ACE_Hash<ACE_INT16>::operator () (ACE_INT16 t) const
+{
+ return t;
+}
+
+ACE_TEMPLATE_METHOD_SPECIALIZATION
+ACE_INLINE u_long
+ACE_Hash<ACE_UINT16>::operator () (ACE_UINT16 t) const
+{
+ return t;
+}
+
+ACE_TEMPLATE_METHOD_SPECIALIZATION
+ACE_INLINE u_long
+ACE_Hash<ACE_INT32>::operator () (ACE_INT32 t) const
+{
+ return t;
+}
+
+ACE_TEMPLATE_METHOD_SPECIALIZATION
+ACE_INLINE u_long
+ACE_Hash<ACE_UINT32>::operator () (ACE_UINT32 t) const
+{
+ return t;
+}
+
+ACE_TEMPLATE_METHOD_SPECIALIZATION
+ACE_INLINE u_long
+ACE_Hash<ACE_UINT64>::operator () (ACE_UINT64 t) const
+{
+ return ACE_U64_TO_U32 (t);
+}
+
+
+ACE_TEMPLATE_METHOD_SPECIALIZATION
+ACE_INLINE u_long
+ACE_Hash<const ACE_TCHAR *>::operator () (const ACE_TCHAR *t) const
+{
+ return ACE::hash_pjw (t);
+}
+
+ACE_TEMPLATE_METHOD_SPECIALIZATION
+ACE_INLINE u_long
+ACE_Hash<ACE_TCHAR *>::operator () (const ACE_TCHAR *t) const
+{
+ return ACE::hash_pjw (t);
+}
+
+/***********************************************************************/
+ACE_TEMPLATE_METHOD_SPECIALIZATION
+ACE_INLINE int
+ACE_Equal_To<const ACE_TCHAR *>::operator () (const ACE_TCHAR *lhs, const ACE_TCHAR *rhs) const
+{
+ return !ACE_OS::strcmp (lhs, rhs);
+}
+
+ACE_TEMPLATE_METHOD_SPECIALIZATION
+ACE_INLINE int
+ACE_Equal_To<ACE_TCHAR *>::operator () (const ACE_TCHAR *lhs, const ACE_TCHAR *rhs) const
+{
+ return !ACE_OS::strcmp (lhs, rhs);
+}
+
+ACE_INLINE int
+ACE_Equal_To<ACE_UINT16>::operator () (const ACE_UINT16 lhs, const ACE_UINT16 rhs) const
+{
+ return (lhs == rhs);
+}
+
+ACE_TEMPLATE_METHOD_SPECIALIZATION
+ACE_INLINE int
+ACE_Equal_To<ACE_INT16>::operator () (const ACE_INT16 lhs, const ACE_INT16 rhs) const
+{
+ return (lhs == rhs);
+}
+
+ACE_TEMPLATE_METHOD_SPECIALIZATION
+ACE_INLINE int
+ACE_Equal_To<ACE_UINT32>::operator () (const ACE_UINT32 lhs, const ACE_UINT32 rhs) const
+{
+ return (lhs == rhs);
+}
+
+ACE_TEMPLATE_METHOD_SPECIALIZATION
+ACE_INLINE int
+ACE_Equal_To<ACE_INT32>::operator () (const ACE_INT32 lhs, const ACE_INT32 rhs) const
+{
+ return (lhs == rhs);
+}
+
+ACE_TEMPLATE_METHOD_SPECIALIZATION
+ACE_INLINE int
+ACE_Equal_To<ACE_UINT64>::operator () (const ACE_UINT64 lhs, const ACE_UINT64 rhs) const
+{
+ return (lhs == rhs);
+}
+
+/****************************************************************************/
+ACE_TEMPLATE_METHOD_SPECIALIZATION
+ACE_INLINE int
+ACE_Less_Than<const ACE_TCHAR *>::operator () (const ACE_TCHAR *lhs, const ACE_TCHAR *rhs) const
+{
+ return (ACE_OS::strcmp (lhs, rhs) < 0) ? 1 : 0;
+}
+
+ACE_TEMPLATE_METHOD_SPECIALIZATION
+ACE_INLINE int
+ACE_Less_Than<ACE_TCHAR *>::operator () (const ACE_TCHAR *lhs, const ACE_TCHAR *rhs) const
+{
+ return (ACE_OS::strcmp (lhs, rhs) < 0) ? 1 : 0;
+}
diff --git a/ace/Utils/Functor_T.cpp b/ace/Utils/Functor_T.cpp
new file mode 100644
index 00000000000..73b183d0fd3
--- /dev/null
+++ b/ace/Utils/Functor_T.cpp
@@ -0,0 +1,49 @@
+/* -*- C++ -*- */
+// $Id$
+
+#ifndef ACE_FUNCTOR_T_C
+#define ACE_FUNCTOR_T_C
+
+#include "ace/Functor_T.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#if !defined (__ACE_INLINE__)
+#include "ace/Functor_T.i"
+#endif /* __ACE_INLINE__ */
+
+ACE_RCSID(ace, Functor_T, "$Id$")
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Command_Callback)
+
+///////////////////////////////////
+// GOF Command Pattern Templates //
+///////////////////////////////////
+
+// Constructor.
+
+template <class RECEIVER, class ACTION>
+ACE_Command_Callback<RECEIVER, ACTION>::ACE_Command_Callback (RECEIVER &recvr,
+ ACTION action)
+ : receiver_ (recvr),
+ action_ (action)
+{
+}
+
+template <class RECEIVER, class ACTION>
+ACE_Command_Callback<RECEIVER, ACTION>::~ACE_Command_Callback (void)
+{
+}
+
+// Invokes an operation.
+
+template <class RECEIVER, class ACTION> int
+ACE_Command_Callback<RECEIVER, ACTION>::execute (void *arg)
+{
+ return (receiver_.*action_) (arg);
+}
+
+
+#endif /* ACE_FUNCTOR_T_C */
diff --git a/ace/Utils/Functor_T.h b/ace/Utils/Functor_T.h
new file mode 100644
index 00000000000..32101c32abe
--- /dev/null
+++ b/ace/Utils/Functor_T.h
@@ -0,0 +1,152 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Functor_T.h
+ *
+ * $Id$
+ *
+ * Templatized classes for implementing function objects that are
+ * used in various places in ACE. There are currently two major
+ * categories of function objects in ACE: GOF Command Pattern
+ * objects, and STL-style functors for comparison of container
+ * elements. The command objects are invoked via an <execute>
+ * method, while the STL-style functors are invoked via an
+ * <operator()> method.
+ *
+ *
+ * @author Chris Gill <cdgill@cs.wustl.edu>
+ * @author Based on Command Pattern implementations originally done by
+ * @author Carlos O'Ryan <coryan@cs.wustl.edu>
+ * @author Douglas C. Schmidt <schmidt@cs.wustl.edu>
+ * @author Sergio Flores-Gaitan <sergio@cs.wustl.edu>
+ * @author and on STL-style functor implementations originally done by
+ * @author Irfan Pyarali <irfan@cs.wustl.edu>
+ */
+//=============================================================================
+
+
+#ifndef ACE_FUNCTOR_T_H
+#define ACE_FUNCTOR_T_H
+#include "ace/pre.h"
+
+#include "ace/Functor.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+///////////////////////////////////
+// GOF Command Pattern Templates //
+///////////////////////////////////
+
+/**
+ * @class ACE_Command_Callback
+ *
+ * @brief Defines a class template that allows us to invoke a GOF
+ * command style callback to an object without knowing anything
+ * about the object except its type.
+ *
+ * This class declares an interface to execute operations,
+ * binding a RECEIVER object with an ACTION. The RECEIVER knows
+ * how to implement the operation. A class can invoke operations
+ * without knowing anything about it, or how it was implemented.
+ */
+template <class RECEIVER, class ACTION>
+class ACE_Command_Callback : public ACE_Command_Base
+{
+public:
+ /// Constructor: sets the <receiver_> of the Command to recvr, and the
+ /// <action_> of the Command to <action>.
+ ACE_Command_Callback (RECEIVER &recvr, ACTION action);
+
+ /// Virtual destructor.
+ virtual ~ACE_Command_Callback (void);
+
+ /// Invokes the method <action_> from the object <receiver_>.
+ virtual int execute (void *arg = 0);
+
+private:
+ /// Object where the method resides.
+ RECEIVER &receiver_;
+
+ /// Method that is going to be invoked.
+ ACTION action_;
+};
+
+/////////////////////////////////
+// STL-style Functor Templates //
+/////////////////////////////////
+
+/**
+ * @class ACE_Hash
+ *
+ * @brief Function object for hashing
+ */
+template <class TYPE>
+class ACE_Hash
+{
+public:
+ /// Simply calls t.hash ()
+ u_long operator () (const TYPE &t) const;
+};
+
+/**
+ * @class ACE_Pointer_Hash
+ *
+ * @brief Function object for hashing pointers
+ */
+template <class TYPE>
+class ACE_Pointer_Hash
+{
+public:
+ /// Simply returns t.
+ u_long operator () (TYPE t) const;
+};
+
+/**
+ * @class ACE_Equal_To
+ *
+ * @brief Function object for comparing two objects of
+ * the given type for equality.
+ */
+template <class TYPE>
+class ACE_Equal_To
+{
+public:
+ /// Simply calls operator==
+ int operator () (const TYPE &lhs,
+ const TYPE &rhs) const;
+};
+
+/**
+ * @class ACE_Less_Than
+ *
+ * @brief Function object for determining whether the first object of
+ * the given type is less than the second object of the same
+ * type.
+ */
+template <class TYPE>
+class ACE_Less_Than
+{
+public:
+ /// Simply calls operator<
+ int operator () (const TYPE &lhs,
+ const TYPE &rhs) const;
+};
+
+#if defined (__ACE_INLINE__)
+#include "ace/Functor_T.i"
+#endif /* __ACE_INLINE__ */
+
+
+#if defined (ACE_TEMPLATES_REQUIRE_SOURCE)
+#include "ace/Functor_T.cpp"
+#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */
+
+#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA)
+#pragma implementation ("Functor_T.cpp")
+#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */
+
+#include "ace/post.h"
+#endif /* ACE_FUNCTOR_T_H */
diff --git a/ace/Utils/Functor_T.i b/ace/Utils/Functor_T.i
new file mode 100644
index 00000000000..d626f76ed15
--- /dev/null
+++ b/ace/Utils/Functor_T.i
@@ -0,0 +1,28 @@
+/* -*- C++ -*- */
+// $Id$
+
+template <class TYPE> ACE_INLINE u_long
+ACE_Hash<TYPE>::operator () (const TYPE &t) const
+{
+ return t.hash ();
+}
+
+template <class TYPE> ACE_INLINE u_long
+ACE_Pointer_Hash<TYPE>::operator () (TYPE t) const
+{
+ return u_long (t);
+}
+
+template <class TYPE> ACE_INLINE int
+ACE_Equal_To<TYPE>::operator () (const TYPE &lhs,
+ const TYPE &rhs) const
+{
+ return lhs == rhs;
+}
+
+template <class TYPE> ACE_INLINE int
+ACE_Less_Than<TYPE>::operator () (const TYPE &lhs,
+ const TYPE &rhs) const
+{
+ return lhs < rhs ? 1 : 0;
+}
diff --git a/ace/Utils/Future.cpp b/ace/Utils/Future.cpp
new file mode 100644
index 00000000000..d0c263ee473
--- /dev/null
+++ b/ace/Utils/Future.cpp
@@ -0,0 +1,448 @@
+// $Id$
+
+#ifndef ACE_FUTURE_CPP
+#define ACE_FUTURE_CPP
+
+#include "ace/Future.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+ACE_RCSID (ace, Future, "$Id$")
+
+#if defined (ACE_HAS_THREADS)
+
+template <class T>
+ACE_Future_Holder<T>::ACE_Future_Holder (void)
+{
+}
+
+template <class T>
+ACE_Future_Holder<T>::ACE_Future_Holder (const ACE_Future<T> &item)
+ : item_ (item)
+{
+}
+
+template <class T>
+ACE_Future_Holder<T>::~ACE_Future_Holder (void)
+{
+}
+
+template <class T>
+ACE_Future_Observer<T>::ACE_Future_Observer (void)
+{
+}
+
+template <class T>
+ACE_Future_Observer<T>::~ACE_Future_Observer (void)
+{
+}
+
+// Dump the state of an object.
+
+template <class T> void
+ACE_Future_Rep<T>::dump (void) const
+{
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+ ACE_DEBUG ((LM_DEBUG,
+ "ref_count_ = %d\n",
+ (int) this->ref_count_));
+ ACE_DEBUG ((LM_INFO,"value_: \n"));
+ if (this->value_)
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT (" (NON-NULL)\n")));
+ else
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT (" (NULL)\n")));
+
+ ACE_DEBUG ((LM_INFO,"value_ready_: \n"));
+ this->value_ready_.dump ();
+ ACE_DEBUG ((LM_INFO,"value_ready_mutex_: \n"));
+ this->value_ready_mutex_.dump ();
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+template <class T> ACE_Future_Rep<T> *
+ACE_Future_Rep<T>::internal_create (void)
+{
+ ACE_Future_Rep<T> *temp = 0;
+ ACE_NEW_RETURN (temp,
+ ACE_Future_Rep<T> (),
+ 0);
+ return temp;
+}
+
+template <class T> ACE_Future_Rep<T> *
+ACE_Future_Rep<T>::create (void)
+{
+ // Yes set ref count to zero.
+ ACE_Future_Rep<T> *temp = internal_create ();
+#if defined (ACE_NEW_THROWS_EXCEPTIONS)
+ if (temp == 0)
+ ACE_throw_bad_alloc;
+#else
+ ACE_ASSERT (temp != 0);
+#endif /* ACE_NEW_THROWS_EXCEPTIONS */
+ return temp;
+ }
+
+
+template <class T> ACE_Future_Rep<T> *
+ACE_Future_Rep<T>::attach (ACE_Future_Rep<T>*& rep)
+{
+ ACE_ASSERT (rep != 0);
+ // Use value_ready_mutex_ for both condition and ref count management
+ ACE_MT (ACE_Guard<ACE_Thread_Mutex> r_mon (rep->value_ready_mutex_));
+ ++rep->ref_count_;
+ return rep;
+}
+
+template <class T> void
+ACE_Future_Rep<T>::detach (ACE_Future_Rep<T>*& rep)
+{
+ ACE_ASSERT (rep != 0);
+ // Use value_ready_mutex_ for both condition and ref count management
+ ACE_MT (ACE_GUARD (ACE_Thread_Mutex, r_mon, rep->value_ready_mutex_));
+
+ if (rep->ref_count_-- == 0)
+ {
+ ACE_MT (r_mon.release ());
+ // We do not need the lock when deleting the representation.
+ // There should be no side effects from deleting rep and we don
+ // not want to release a deleted mutex.
+ delete rep;
+ }
+}
+
+template <class T> void
+ACE_Future_Rep<T>::assign (ACE_Future_Rep<T>*& rep, ACE_Future_Rep<T>* new_rep)
+{
+ ACE_ASSERT (rep != 0);
+ ACE_ASSERT (new_rep != 0);
+ // Use value_ready_mutex_ for both condition and ref count management
+ ACE_MT (ACE_GUARD (ACE_Thread_Mutex, r_mon, rep->value_ready_mutex_));
+
+ ACE_Future_Rep<T>* old = rep;
+ rep = new_rep;
+
+ // detached old last for exception safety
+ if (old->ref_count_-- == 0)
+ {
+ ACE_MT (r_mon.release ());
+ // We do not need the lock when deleting the representation.
+ // There should be no side effects from deleting rep and we don
+ // not want to release a deleted mutex.
+ delete old;
+ }
+}
+
+template <class T>
+ACE_Future_Rep<T>::ACE_Future_Rep (void)
+ : value_ (0),
+ ref_count_ (0),
+ value_ready_ (this->value_ready_mutex_)
+{
+}
+
+template <class T>
+ACE_Future_Rep<T>::~ACE_Future_Rep (void)
+{
+ delete this->value_;
+}
+
+template <class T> int
+ACE_Future_Rep<T>::ready (void) const
+{
+ return this->value_ != 0;
+}
+
+template <class T> int
+ACE_Future_Rep<T>::set (const T &r,
+ ACE_Future<T> &caller)
+{
+ // If the value is already produced, ignore it...
+ if (this->value_ == 0)
+ {
+ ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex,
+ ace_mon,
+ this->value_ready_mutex_,
+ -1));
+ // Otherwise, create a new result value. Note the use of the
+ // Double-checked locking pattern to avoid multiple allocations.
+
+ if (this->value_ == 0) // Still no value, so proceed
+ {
+ ACE_NEW_RETURN (this->value_,
+ T (r),
+ -1);
+
+ // Remove and notify all subscribed observers.
+ ACE_TYPENAME OBSERVER_COLLECTION::iterator iterator =
+ this->observer_collection_.begin ();
+
+ ACE_TYPENAME OBSERVER_COLLECTION::iterator end =
+ this->observer_collection_.end ();
+
+ for (;
+ iterator != end;
+ ++iterator)
+ {
+ OBSERVER *observer = *iterator;
+ observer->update (caller);
+ }
+
+ // Signal all the waiting threads.
+ return this->value_ready_.broadcast ();
+ }
+ // Destructor releases the lock.
+ }
+ return 0;
+}
+
+template <class T> int
+ACE_Future_Rep<T>::get (T &value,
+ ACE_Time_Value *tv) const
+{
+ // If the value is already produced, return it.
+ if (this->value_ == 0)
+ {
+ ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon,
+ ACE_const_cast (ACE_Thread_Mutex &, this->value_ready_mutex_),
+ -1));
+ // If the value is not yet defined we must block until the
+ // producer writes to it.
+
+ while (this->value_ == 0)
+ // Perform a timed wait.
+ if ((ACE_const_cast (ACE_Condition_Thread_Mutex &, this->value_ready_)).wait (tv) == -1)
+ return -1;
+
+ // Destructor releases the lock.
+ }
+
+ value = *this->value_;
+ return 0;
+}
+
+template <class T> int
+ACE_Future_Rep<T>::attach (ACE_Future_Observer<T> *observer,
+ ACE_Future<T> &caller)
+{
+ ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->value_ready_mutex_, -1));
+
+ // Otherwise, create a new result value. Note the use of the
+ // Double-checked locking pattern to avoid corrupting the list.
+
+ int result = 1;
+
+ // If the value is already produced, then notify observer
+ if (this->value_ == 0)
+ {
+ result = this->observer_collection_.insert (observer);
+ }
+ else
+ observer->update (caller);
+
+ return result;
+}
+
+template <class T> int
+ACE_Future_Rep<T>::detach (ACE_Future_Observer<T> *observer)
+{
+ ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->value_ready_mutex_, -1));
+
+ // Remove all occurrences of the specified observer from this
+ // objects hash map.
+ return this->observer_collection_.remove (observer);
+}
+
+template <class T>
+ACE_Future_Rep<T>::operator T ()
+{
+ // If the value is already produced, return it.
+ if (this->value_ == 0)
+ {
+ // Constructor of ace_mon acquires the mutex.
+ ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->value_ready_mutex_, 0));
+
+ // If the value is not yet defined we must block until the
+ // producer writes to it.
+
+ // Wait ``forever.''
+
+ while (this->value_ == 0)
+ if (this->value_ready_.wait () == -1)
+ // What to do in this case since we've got to indicate
+ // failure somehow? Exceptions would be nice, but they're
+ // not portable...
+ return 0;
+
+ // Destructor releases the mutex
+ }
+
+ return *this->value_;
+}
+
+template <class T>
+ACE_Future<T>::ACE_Future (void)
+ : future_rep_ (FUTURE_REP::create ())
+{
+}
+
+template <class T>
+ACE_Future<T>::ACE_Future (const ACE_Future<T> &r)
+ : future_rep_ (FUTURE_REP::attach (((ACE_Future<T> &) r).future_rep_))
+{
+}
+
+template <class T>
+ACE_Future<T>::ACE_Future (const T &r)
+ : future_rep_ (FUTURE_REP::create ())
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_LIB_TEXT (" (%t) funny constructor\n")));
+ this->future_rep_->set (r,
+ *this);
+}
+
+template <class T>
+ACE_Future<T>::~ACE_Future (void)
+{
+ FUTURE_REP::detach (future_rep_);
+}
+
+template <class T> int
+ACE_Future<T>::operator== (const ACE_Future<T> &r) const
+{
+ return r.future_rep_ == this->future_rep_;
+}
+
+template <class T> int
+ACE_Future<T>::operator!= (const ACE_Future<T> &r) const
+{
+ return r.future_rep_ != this->future_rep_;
+}
+
+template <class T> int
+ACE_Future<T>::cancel (const T &r)
+{
+ this->cancel ();
+ return this->future_rep_->set (r,
+ *this);
+}
+
+template <class T> int
+ACE_Future<T>::cancel (void)
+{
+ // If this ACE_Future is already attached to a ACE_Future_Rep,
+ // detach it (maybe delete the ACE_Future_Rep).
+ FUTURE_REP::assign (this->future_rep_,
+ FUTURE_REP::create ());
+ return 0;
+}
+
+template <class T> int
+ACE_Future<T>::set (const T &r)
+{
+ // Give the pointer to the result to the ACE_Future_Rep.
+ return this->future_rep_->set (r,
+ *this);
+}
+
+template <class T> int
+ACE_Future<T>::ready (void) const
+{
+ // We're ready if the ACE_Future_rep is ready...
+ return this->future_rep_->ready ();
+}
+
+template <class T> int
+ACE_Future<T>::get (T &value,
+ ACE_Time_Value *tv) const
+{
+ // We return the ACE_Future_rep.
+ return this->future_rep_->get (value, tv);
+}
+
+template <class T> int
+ACE_Future<T>::attach (ACE_Future_Observer<T> *observer)
+{
+ return this->future_rep_->attach (observer, *this);
+}
+
+template <class T> int
+ACE_Future<T>::detach (ACE_Future_Observer<T> *observer)
+{
+ return this->future_rep_->detach (observer);
+}
+
+template <class T>
+ACE_Future<T>::operator T ()
+{
+ // note that this will fail (and COREDUMP!)
+ // if future_rep_ == 0 !
+ //
+ // but...
+ // this is impossible unless somebody is so stupid to
+ // try something like this:
+ //
+ // Future<T> futT;
+ // T t;
+ // t = futT;
+
+ // perform type conversion on Future_Rep.
+ return *future_rep_;
+}
+
+template <class T> void
+ACE_Future<T>::operator = (const ACE_Future<T> &rhs)
+{
+ // assignment:
+ //
+ // bind <this> to the same <ACE_Future_Rep> as <r>.
+
+ // This will work if &r == this, by first increasing the ref count
+ ACE_Future<T> &r = (ACE_Future<T> &) rhs;
+ FUTURE_REP::assign (this->future_rep_,
+ FUTURE_REP::attach (r.future_rep_));
+}
+
+template <class T> void
+ACE_Future<T>::dump (void) const
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_BEGIN_DUMP, this));
+
+ if (this->future_rep_)
+ this->future_rep_->dump ();
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_END_DUMP));
+}
+
+template <class T> ACE_Future_Rep<T> *
+ACE_Future<T>::get_rep ()
+{
+ return this->future_rep_;
+}
+
+template <class T> void *
+ACE_Future<T>::operator new (size_t)
+{
+ ACE_throw_bad_alloc;
+#if defined (__HP_aCC)
+ return 0;
+#endif /* 0 */
+}
+
+template <class T> void
+ACE_Future<T>::operator delete (void *)
+{
+}
+
+template <class T> void
+ACE_Future<T>::operator & ()
+{
+}
+
+#endif /* ACE_HAS_THREADS */
+#endif /* ACE_FUTURE_CPP */
diff --git a/ace/Utils/Future.h b/ace/Utils/Future.h
new file mode 100644
index 00000000000..451f5908327
--- /dev/null
+++ b/ace/Utils/Future.h
@@ -0,0 +1,371 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Future.h
+ *
+ * $Id$
+ *
+ * @author Andres Kruse <Andres.Kruse@cern.ch>
+ * @author Douglas C. Schmidt <schmidt@cs.wustl.edu>
+ * @author Per Andersson <Per.Andersson@hfera.ericsson.se> and
+ * @author John Tucker <jtucker@infoglide.com>
+ */
+//=============================================================================
+
+#ifndef ACE_FUTURE_H
+#define ACE_FUTURE_H
+#include "ace/pre.h"
+
+#include "ace/Unbounded_Set.h"
+#include "ace/Synch.h"
+#include "ace/Strategies_T.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#if defined (ACE_HAS_THREADS)
+
+// Forward decl.
+template <class T> class ACE_Future_Holder;
+template <class T> class ACE_Future_Observer;
+template <class T> class ACE_Future_Rep;
+template <class T> class ACE_Future;
+
+/**
+ * @class ACE_Future_Holder
+ *
+ * @brief Implementation of object which has holds ACE_Future.
+ */
+template <class T>
+class ACE_Future_Holder
+{
+public:
+ ACE_Future_Holder (const ACE_Future<T> &future);
+ ~ACE_Future_Holder (void);
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+ ACE_Future<T> item_;
+
+protected:
+ ACE_Future_Holder (void);
+};
+
+/**
+ * @class ACE_Future_Observer
+ *
+ * @brief ACE_Future_Observer<T>
+ *
+ * An ACE_Future_Observer object implements an object that is
+ * subscribed with an ACE_Future object so that it may be
+ * notified when the value of the ACE_Future object is
+ * written to by a writer thread.
+ * It uses the Observer pattern
+ */
+template <class T>
+class ACE_Future_Observer
+{
+public:
+ // = Destructor
+ virtual ~ACE_Future_Observer (void);
+
+ /// Called by the ACE_Future in which we are subscribed to when
+ /// its value is written to.
+ virtual void update (const ACE_Future<T> &future) = 0;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+protected:
+
+ // = Constructor
+ ACE_Future_Observer (void);
+};
+
+/**
+ * @class ACE_Future_Rep
+ *
+ * @brief ACE_Future_Rep<T>
+ *
+ * An ACE_Future_Rep<T> object encapsules a pointer to an object
+ * of class T which is the result of an asynchronous method
+ * invocation. It is pointed to by ACE_Future<T> object[s] and
+ * only accessible through them.
+ */
+template <class T>
+class ACE_Future_Rep
+{
+private:
+ friend class ACE_Future<T>;
+
+ /**
+ * Set the result value. The specified <caller> represents the
+ * future that invoked this <set> method, which is used to notify
+ * the list of future observers. Returns 0 for success, -1 on error.
+ * This function only has an effect the first time it is called for
+ * the object. Subsequent calls return 0 (success) but have no effect.
+ */
+ int set (const T &r,
+ ACE_Future<T> &caller);
+
+ /// Wait up to <tv> time to get the <value>. Note that <tv> must be
+ /// specified in absolute time rather than relative time.
+ int get (T &value,
+ ACE_Time_Value *tv) const;
+
+ /**
+ * Attaches the specified observer to a subject (i.e. the
+ * <ACE_Future_Rep>). The update method of the specified subject will
+ * be invoked with a copy of the written-to <ACE_Future> as input when
+ * the result gets set.
+ *
+ * Returns 0 if the observer is successfully attached, 1 if the
+ * observer is already attached, and -1 if failures occur.
+ */
+ int attach (ACE_Future_Observer<T> *observer,
+ ACE_Future<T> &caller);
+
+ /**
+ * Detaches the specified observer from a subject (i.e. the
+ * <ACE_Future_Rep>). The update method of the specified subject will
+ * not be invoked when the <ACE_Future_Rep>s result gets set. Returns
+ * 1 if the specified observer was actually attached to the subject
+ * prior to this call and 0 if was not.
+ *
+ * Returns 0 if the observer was successfully detached, and -1 if the
+ * observer was not attached in the first place.
+ */
+ int detach (ACE_Future_Observer<T> *observer);
+
+ /**
+ * Type conversion. will block forever until the result is
+ * available. Note that this method is going away in a subsequent
+ * release since it doesn't distinguish between failure results and
+ * success results (exceptions should be used, but they aren't
+ * portable...). The <get> method should be used instead since it
+ * separates the error value from the result, and also permits
+ * timeouts.
+ */
+ operator T ();
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+ // = Encapsulate reference count and object lifetime of instances.
+
+ // These methods must go after the others to work around a bug with
+ // Borland's C++ Builder...
+
+ /// Allocate a new ACE_Future_Rep<T> instance, returning NULL if it
+ /// cannot be created.
+ static ACE_Future_Rep<T> *internal_create (void);
+
+ /// Create a ACE_Future_Rep<T> and initialize the reference count.
+ static ACE_Future_Rep<T> *create (void);
+
+ /**
+ * Increase the reference count and return argument. Uses the
+ * attribute "value_ready_mutex_" to synchronize reference count
+ * updating.
+ *
+ * Precondition (rep != 0).
+ */
+ static ACE_Future_Rep<T> *attach (ACE_Future_Rep<T> *&rep);
+
+ /**
+ * Decreases the reference count and and deletes rep if there are no
+ * more references to rep.
+ *
+ * Precondition (rep != 0)
+ */
+ static void detach (ACE_Future_Rep<T> *&rep);
+
+ /**
+ * Decreases the rep's reference count and and deletes rep if there
+ * are no more references to rep. Then assigns new_rep to rep.
+ *
+ * Precondition (rep != 0 && new_rep != 0)
+ */
+ static void assign (ACE_Future_Rep<T> *&rep,
+ ACE_Future_Rep<T> *new_rep);
+
+ /// Is result available?
+ int ready (void) const;
+
+ /// Pointer to the result.
+ T *value_;
+
+ /// Reference count.
+ int ref_count_;
+
+ typedef ACE_Future_Observer<T>
+ OBSERVER;
+
+ typedef ACE_Unbounded_Set<OBSERVER *>
+ OBSERVER_COLLECTION;
+
+ /// Keep a list of ACE_Future_Observers unread by client's reader thread.
+ OBSERVER_COLLECTION observer_collection_;
+
+ // = Condition variable and mutex that protect the <value_>.
+ ACE_Thread_Mutex value_ready_mutex_;
+ ACE_Condition_Thread_Mutex value_ready_;
+
+private:
+ // = Constructor and destructor private.
+ ACE_Future_Rep (void);
+ ~ACE_Future_Rep (void);
+};
+
+/**
+ * @class ACE_Future
+ *
+ * @brief This class implements a ``single write, multiple read''
+ * pattern that can be used to return results from asynchronous
+ * method invocations.
+ */
+template <class T>
+class ACE_Future
+{
+public:
+ // = Initialization and termination methods.
+ /// Constructor.
+ ACE_Future (void);
+
+ /// Copy constructor binds <this> and <r> to the same
+ /// <ACE_Future_Rep>. An <ACE_Future_Rep> is created if necessary.
+ ACE_Future (const ACE_Future<T> &r);
+
+ /// Constructor that initialises an <ACE_Future> to point to the
+ /// result <r> immediately.
+ ACE_Future (const T &r);
+
+ /// Destructor.
+ ~ACE_Future (void);
+
+ /// Assignment operator that binds <this> and <r> to the same
+ /// <ACE_Future_Rep>. An <ACE_Future_Rep> is created if necessary.
+ void operator = (const ACE_Future<T> &r);
+
+ /// Cancel an <ACE_Future> and assign the value <r>. It is used if a
+ /// client does not want to wait for <T> to be produced.
+ int cancel (const T &r);
+
+ /**
+ * Cancel an <ACE_Future>. Put the future into its initial
+ * state. Returns 0 on succes and -1 on failure. It is now possible
+ * to reuse the ACE_Future<T>. But remember, the ACE_Future<T>
+ * is now bound to a new ACE_Future_Rep<T>.
+ */
+ int cancel (void);
+
+ /**
+ * Equality operator that returns 1 if both ACE_Future<T> objects
+ * point to the same ACE_Future_Rep<T> object. Attention: It also
+ * returns 1 if both objects have just been instantiated and not
+ * used yet.
+ */
+ int operator == (const ACE_Future<T> &r) const;
+
+ /// Inequality operator, which is the opposite of equality.
+ int operator != (const ACE_Future<T> &r) const;
+
+ /**
+ * Make the result available. Is used by the server thread to give
+ * the result to all waiting clients. Returns 0 for success, -1 on failure.
+ * This function only has an effect the first time it is called for
+ * the object (actually, the first time the underlying ACE_Future_Rep has a
+ * value assigned to it). Subsequent calls return 0 (success) but have no
+ * effect.
+ */
+ int set (const T &r);
+
+ /// Wait up to <tv> time to get the <value>. Note that <tv> must be
+ /// specified in absolute time rather than relative time.
+ int get (T &value,
+ ACE_Time_Value *tv = 0) const;
+
+ /**
+ * Type conversion, which obtains the result of the asynchronous
+ * method invocation. Will block forever. Note that this method is
+ * going away in a subsequent release since it doesn't distinguish
+ * between failure results and success results (exceptions should be
+ * used, but they aren't portable...). The <get> method should be
+ * used instead since it separates the error value from the result,
+ * and also permits timeouts.
+ */
+ operator T ();
+
+ /// Check if the result is available.
+ int ready (void) const;
+
+ /**
+ * Attaches the specified observer to a subject (i.e. the
+ * <ACE_Future>). The update method of the specified subject will be
+ * invoked with a copy of the associated <ACE_Future> as input when
+ * the result gets set. If the result is already set when this
+ * method gets invoked, then the update method of the specified
+ * subject will be invoked immediately.
+ *
+ * Returns 0 if the observer is successfully attached, 1 if the
+ * observer is already attached, and -1 if failures occur.
+ */
+ int attach (ACE_Future_Observer<T> *observer);
+
+ /**
+ * Detaches the specified observer from a subject (i.e. the
+ * <ACE_Future_Rep>). The update method of the specified subject will
+ * not be invoked when the <ACE_Future_Reps> result gets set. Returns
+ * 1 if the specified observer was actually attached to the subject
+ * prior to this call and 0 if was not.
+ *
+ * Returns 0 if the observer was successfully detached, and -1 if the
+ * observer was not attached in the first place.
+ */
+ int detach (ACE_Future_Observer<T> *observer);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /**
+ * Get the underlying <ACE_Future_Rep>*. Note that this method should
+ * rarely, if ever, be used and that modifying the undlerlying <ACE_Future_Rep>*
+ * should be done with extreme caution.
+ */
+ ACE_Future_Rep<T> *get_rep (void);
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+private:
+ /// Do not allow new operator.
+ void *operator new (size_t nbytes);
+
+ /// Do not allow delete operator
+ void operator delete (void *);
+
+ /// Do not allow address-of operator.
+ void operator & ();
+
+ // the ACE_Future_Rep
+ /// Protect operations on the <Future>.
+ typedef ACE_Future_Rep<T> FUTURE_REP;
+ FUTURE_REP *future_rep_;
+};
+
+#if defined (ACE_TEMPLATES_REQUIRE_SOURCE)
+#include "ace/Future.cpp"
+#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */
+
+#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA)
+#pragma implementation ("Future.cpp")
+#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */
+
+#endif /* ACE_HAS_THREADS */
+#include "ace/post.h"
+#endif /* ACE_FUTURE_H */
diff --git a/ace/Utils/Future_Set.cpp b/ace/Utils/Future_Set.cpp
new file mode 100644
index 00000000000..5b0069fac4f
--- /dev/null
+++ b/ace/Utils/Future_Set.cpp
@@ -0,0 +1,137 @@
+// Future.cpp
+// $Id$
+
+#ifndef ACE_FUTURE_SET_CPP
+#define ACE_FUTURE_SET_CPP
+
+#include "ace/Future_Set.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+#pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+ACE_RCSID (ace, Future_Set, "$Id$")
+
+#if defined (ACE_HAS_THREADS)
+
+template <class T>
+ACE_Future_Set<T>::ACE_Future_Set (ACE_Message_Queue<ACE_SYNCH> *new_queue)
+ : delete_queue_ (0)
+{
+ if (new_queue)
+ this->future_notification_queue_ = new_queue;
+ else
+ {
+ ACE_NEW (this->future_notification_queue_,
+ ACE_Message_Queue<ACE_SYNCH>);
+ this->delete_queue_ = 1;
+ }
+}
+
+template <class T>
+ACE_Future_Set<T>::~ACE_Future_Set (void)
+{
+ // Detach ourselves from all remaining futures, if any, in our map.
+ ACE_TYPENAME FUTURE_HASH_MAP::iterator iterator =
+ this->future_map_.begin ();
+
+ ACE_TYPENAME FUTURE_HASH_MAP::iterator end =
+ this->future_map_.end ();
+
+ for (;
+ iterator != end;
+ ++iterator)
+ {
+ FUTURE_HOLDER *future_holder = (*iterator).int_id_;
+ future_holder->item_.detach (this);
+ delete future_holder;
+ }
+
+ if (this->delete_queue_ != 0)
+ delete this->future_notification_queue_;
+}
+
+template <class T> int
+ACE_Future_Set<T>::is_empty () const
+{
+ return (((ACE_Future_Set<T>*)this)->future_map_.current_size () == 0 );
+}
+
+template <class T> int
+ACE_Future_Set<T>::insert (ACE_Future<T> &future)
+{
+ FUTURE_HOLDER *future_holder;
+ ACE_NEW_RETURN (future_holder,
+ FUTURE_HOLDER (future),
+ -1);
+
+ FUTURE_REP *future_rep = future.get_rep ();
+ int result = this->future_map_.bind (future_rep,
+ future_holder);
+
+ // If a new map entry was created, then attach to the future,
+ // otherwise we were already attached to the future or some error
+ // occurred so just delete the future holder.
+ if ( result == 0 )
+ // Attach ourself to the ACE_Futures list of observer
+ future.attach (this);
+ else
+ delete future_holder;
+
+ return result;
+}
+
+template <class T> void
+ACE_Future_Set<T>::update (const ACE_Future<T> &future)
+{
+ ACE_Message_Block *mb;
+ FUTURE &local_future = ACE_const_cast (ACE_Future<T> &, future);
+
+ ACE_NEW (mb,
+ ACE_Message_Block ((char *) local_future.get_rep (), 0));
+
+ // Enqueue in priority order.
+ this->future_notification_queue_->enqueue (mb, 0);
+}
+
+template <class T> int
+ACE_Future_Set<T>::next_readable (ACE_Future<T> &future,
+ ACE_Time_Value *tv)
+{
+ if (this->is_empty ())
+ return 0;
+
+ ACE_Message_Block *mb = 0;
+ FUTURE_REP *future_rep = 0;
+
+ // Wait for a "readable future" signal from the message queue.
+ if (this->future_notification_queue_->dequeue_head (mb,
+ tv) != -1)
+ {
+ // Extract future rep from the message block.
+ future_rep =
+ ACE_reinterpret_cast (FUTURE_REP *,
+ mb->base ());
+
+ // Delete the message block.
+ mb->release ();
+ }
+ else
+ return 0;
+
+ // Remove the hash map entry with the specified future rep from our map.
+ FUTURE_HOLDER *future_holder;
+ if ( this->future_map_.find (future_rep,
+ future_holder) != -1 )
+ {
+ future = future_holder->item_;
+ this->future_map_.unbind (future_rep);
+ delete future_holder;
+ return 1;
+ }
+
+ return 0;
+}
+
+#endif /* ACE_HAS_THREADS */
+#endif /* ACE_FUTURE_SET_CPP */
diff --git a/ace/Utils/Future_Set.h b/ace/Utils/Future_Set.h
new file mode 100644
index 00000000000..b79241dfa14
--- /dev/null
+++ b/ace/Utils/Future_Set.h
@@ -0,0 +1,123 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Future_Set.h
+ *
+ * $Id$
+ *
+ * @author John Tucker <jtucker@infoglide.com>
+ */
+//=============================================================================
+
+#ifndef ACE_FUTURE_SET_H
+#define ACE_FUTURE_SET_H
+#include "ace/pre.h"
+
+#include "ace/Thread.h"
+#include "ace/Message_Queue.h"
+#include "ace/Future.h"
+#include "ace/Hash_Map_Manager.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+#pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#if defined (ACE_HAS_THREADS)
+
+/**
+ * @class ACE_Future_Set
+ *
+ * @brief This class implements a mechanism which allows the values of
+ * a collections of <ACE_Future> objects to be accessed by
+ * reader threads as they become available.
+ */
+template <class T>
+class ACE_Future_Set : public ACE_Future_Observer<T>
+{
+public:
+ // = Initialization and termination methods.
+
+ /// Constructor.
+ ACE_Future_Set (ACE_Message_Queue<ACE_SYNCH> *future_notification_queue_ = 0);
+
+ /// Destructor.
+ ~ACE_Future_Set (void);
+
+ /// Return 1 if their are no <ACE_Future> objects left on its queue and
+ /// 0 otherwise
+ int is_empty (void) const;
+
+ /**
+ * Enqueus the given <ACE_Future> into this objects queue when it is
+ * readable.
+ *
+ * Returns 0 if the future is successfully inserted, 1 if the
+ * future is already inserted, and -1 if failures occur.
+ */
+ int insert (ACE_Future<T> &future);
+
+ /**
+ * Wait up to <tv> time to get the <value>. Note that <tv> must be
+ * specified in absolute time rather than relative time.); get the
+ * next <ACE_Future> that is readable. If <tv> = 0, the will block
+ * forever.
+ *
+ * If a readable future becomes available, then the input result
+ * will be assigned with it and 1 will will be returned. If the set
+ * is empty, then 0 is returned.
+ */
+ int next_readable (ACE_Future<T> &result,
+ ACE_Time_Value *tv = 0);
+
+ /// Called by the <ACE_Future> subject in which we are subscribed to
+ /// when its value is written to.
+ virtual void update (const ACE_Future<T> &future);
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+private:
+ // = Disallow these operations.
+ ACE_UNIMPLEMENTED_FUNC (void operator= (const ACE_Future_Set<T> &))
+ ACE_UNIMPLEMENTED_FUNC (ACE_Future_Set (const ACE_Future_Set<T> &))
+
+ typedef ACE_Future<T> FUTURE;
+
+ typedef ACE_Future_Rep<T> FUTURE_REP;
+
+ typedef ACE_Future_Holder<T> FUTURE_HOLDER;
+
+ typedef ACE_Pointer_Hash<FUTURE_REP *> FUTURE_REP_HASH;
+
+ typedef ACE_Equal_To<FUTURE_REP *> FUTURE_REP_COMPARE;
+
+ typedef ACE_Hash_Map_Manager_Ex<FUTURE_REP *,
+ FUTURE_HOLDER *,
+ FUTURE_REP_HASH,
+ FUTURE_REP_COMPARE,
+ ACE_Null_Mutex> FUTURE_HASH_MAP;
+
+ /// Map of <ACE_Futures>, subjects, which have not been written to by
+ /// client's writer thread.
+ FUTURE_HASH_MAP future_map_;
+
+ /// Message queue for notifying the reader thread of <ACE_Futures> which
+ /// have been written to by client's writer thread.
+ ACE_Message_Queue<ACE_SYNCH> *future_notification_queue_;
+
+ /// Keeps track of whether we need to delete the message queue.
+ int delete_queue_;
+};
+
+#if defined (ACE_TEMPLATES_REQUIRE_SOURCE)
+#include "ace/Future_Set.cpp"
+#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */
+
+#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA)
+#pragma implementation ("Future_Set.cpp")
+#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */
+
+#endif /* ACE_HAS_THREADS */
+#include "ace/post.h"
+#endif /* ACE_FUTURE_SET_H */
diff --git a/ace/Utils/Get_Opt.cpp b/ace/Utils/Get_Opt.cpp
new file mode 100644
index 00000000000..d198ef01cf8
--- /dev/null
+++ b/ace/Utils/Get_Opt.cpp
@@ -0,0 +1,608 @@
+// Get_Opt.cpp
+// $Id$
+
+#include "ace/Get_Opt.h"
+#include "ace/Log_Msg.h"
+
+#if !defined (__ACE_INLINE__)
+#include "ace/Get_Opt.i"
+#endif /* __ACE_INLINE__ */
+
+ACE_RCSID(ace, Get_Opt, "$Id$")
+
+/*
+ * Copyright (c) 1987, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*-
+ * Copyright (c) 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Dieter Baron and Thomas Klausner.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Get_Opt)
+
+ACE_Get_Opt::ACE_Get_Opt (int argc,
+ ACE_TCHAR **argv,
+ const ACE_TCHAR *optstring,
+ int skip,
+ int report_errors,
+ int ordering,
+ int long_only)
+ : argc_ (argc),
+ argv_ (argv),
+ optind (skip),
+ opterr (report_errors),
+ optarg (0),
+ optstring_ (optstring),
+ long_only_ (long_only),
+ has_colon_ (0),
+ nextchar_ (0),
+ ordering_ (ordering),
+ nonopt_start_ (optind),
+ nonopt_end_ (optind),
+ long_option_ (0)
+{
+ ACE_TRACE ("ACE_Get_Opt::ACE_Get_Opt");
+
+ // First check to see if POSIXLY_CORRECT was set.
+ if (ACE_OS::getenv (ACE_LIB_TEXT ("POSIXLY_CORRECT")) != 0)
+ this->ordering_ = REQUIRE_ORDER;
+
+ // Now, check to see if any or the following were passed at
+ // the begining of optstring: '+' same as POSIXLY_CORRECT;
+ // '-' turns off POSIXLY_CORRECT; or ':' which signifies we
+ // should return ':' if a parameter is missing for an option.
+ // We use a loop here, since a combination of "{+|-}:" in any
+ // order should be legal.
+ int done = 0;
+ int offset = 0;
+ while (!done)
+ {
+ switch (optstring[offset++])
+ {
+ case '+':
+ this->ordering_ = REQUIRE_ORDER;
+ break;
+ case '-':
+ this->ordering_ = RETURN_IN_ORDER;
+ break;
+ case ':':
+ this->has_colon_ = 1;
+ break;
+ default:
+ // Quit as soon as we see something else...
+ done = 1;
+ break;
+ }
+ }
+}
+
+ACE_Get_Opt::~ACE_Get_Opt (void)
+{
+ ACE_TRACE ("ACE_Get_Opt::~ACE_Get_Opt");
+
+ size_t i = 0;
+ size_t size = this->long_opts_.size ();
+ ACE_Get_Opt_Long_Option *option = 0;
+ for (i = 0; i < size; ++i)
+ {
+ int retval = this->long_opts_.get (option, i);
+ if (retval != 0)
+ {
+ // Should never happen.
+ retval = 0;
+ continue;
+ }
+ if (option)
+ {
+ delete option;
+ option = 0;
+ }
+ }
+}
+
+int
+ACE_Get_Opt::nextchar_i (void)
+{
+ ACE_TRACE ("ACE_Get_Opt::nextchar_i");
+
+ if (this->ordering_ == PERMUTE_ARGS)
+ if (this->permute () == EOF)
+ return EOF;
+
+ // Update scanning pointer.
+ if (this->optind >= this->argc_)
+ {
+ // We're done...
+ this->nextchar_ = 0;
+ return EOF;
+ }
+ else if (*(this->nextchar_ = this->argv_[this->optind]) != '-'
+ || this->nextchar_[1] == '\0')
+ {
+ // We didn't get an option.
+
+ if (this->ordering_ == REQUIRE_ORDER
+ || this->ordering_ == PERMUTE_ARGS)
+ // If we permuted or require the options to be in order, we're done.
+ return EOF;
+
+ // It must be RETURN_IN_ORDER...
+ this->optarg = this->argv_[this->optind++];
+ this->nextchar_ = 0;
+ return 1;
+ }
+ else if (this->nextchar_[1] != 0
+ && *++this->nextchar_ == '-'
+ && this->nextchar_[1] == 0)
+ {
+ // Found "--" so we're done...
+ ++this->optind;
+ this->nextchar_ = 0;
+ return EOF;
+ }
+
+ // If it's a long option, and we allow long options advance nextchar_.
+ if (*this->nextchar_ == '-' && this->long_opts_.size () != 0)
+ this->nextchar_++;
+
+ return 0;
+}
+
+int
+ACE_Get_Opt::long_option_i (void)
+{
+ ACE_TRACE ("ACE_Get_Opt::long_option_i");
+
+ ACE_Get_Opt_Long_Option *p;
+ ACE_TCHAR *s = this->nextchar_;
+ int hits = 0;
+ int exact = 0;
+ ACE_Get_Opt_Long_Option *pfound = 0;
+ int indfound = 0;
+
+ // Advance to the end of the long option name so we can use
+ // it to get the length for a string compare.
+ while (*s && *s != '=')
+ s++;
+
+ size_t len = s - this->nextchar_;
+ size_t size = this->long_opts_.size ();
+ u_int option_index = 0;
+ for (option_index = 0; option_index < size ; option_index++)
+ {
+ p = this->long_opts_[option_index];
+ ACE_ASSERT (p);
+
+ if (!ACE_OS::strncmp (p->name_.c_str (), this->nextchar_, len))
+ {
+ // Got at least a partial match.
+ pfound = p;
+ indfound = option_index;
+ hits += 1;
+ if (len == p->name_.length ())
+ {
+ // And in fact, it an exact match, so let's use it.
+ exact = 1;
+ break;
+ }
+ }
+ }
+
+ if ((hits > 1) && !exact)
+ {
+ // Great, we found a match, but unfortunately we found more than
+ // one and it wasn't exact.
+ if (this->opterr)
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("%s: option `%s' is ambiguous\n"),
+ this->argv_[0], this->argv_[this->optind]));
+ this->nextchar_ = 0;
+ this->optind++;
+ return '?';
+ }
+
+ if (pfound != 0)
+ {
+ // Okay, we found a good one (either a single hit or an exact match).
+ option_index = indfound;
+ this->optind++;
+ if (*s)
+ {
+ // s must point to '=' which means there's an argument (well close enougth).
+ if (pfound->has_arg_ != NO_ARG)
+ // Good, we want an argument and here it is.
+ this->optarg = ++s;
+ else
+ {
+ // Whoops, we've got what looks like an argument, but we don't want one.
+ if (this->opterr)
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("%s: long option `--%s' doesn't allow an argument\n"),
+ this->argv_[0], pfound->name_.c_str ()));
+ // The spec doesn't cover this, so we keep going and the program
+ // doesn't know we ignored an argument if opt_err is off!!!
+ }
+ }
+ else if (pfound->has_arg_ == ARG_REQUIRED)
+ {
+ // s didn't help us, but we need an argument. Note that optional arguments
+ // for long options must use the "=" syntax, so we won't get here
+ // in that case.
+ if (this->optind < this->argc_)
+ // We still have some elements left, so use the next one.
+ this->optarg = this->argv_[this->optind++];
+ else
+ {
+ // All out of elements, so we have to punt...
+ if (this->opterr)
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("%s: long option '--%s' requires an argument\n"),
+ this->argv_[0], pfound->name_.c_str ()));
+ this->nextchar_ = 0;
+ return this->has_colon_ ? ':' : '?';
+ }
+ }
+ this->nextchar_ = 0;
+ this->long_option_ = pfound;
+ // Since val_ has to be either a valid short option or 0, this works
+ // great. If the user really wants to know if a long option was passed.
+ return pfound->val_;
+ }
+ if (!this->long_only_ || this->argv_[this->optind][1] == '-'
+ || this->optstring_.find (*this->nextchar_) == ACE_TString::npos)
+ {
+ // Okay, we couldn't find a long option. If it isn't long_only (which
+ // means try the long first, and if not found try the short) or a long
+ // signature was passed, e.g. "--", or it's not a short (not sure when
+ // this could happen) it's an error.
+ if (this->opterr)
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("%s: illegal long option '--%s'\n"),
+ this->argv_[0], this->nextchar_));
+ this->nextchar_ = 0;
+ this->optind++;
+ return '?';
+ }
+ return this->short_option_i ();
+}
+
+int
+ACE_Get_Opt::short_option_i (void)
+{
+ ACE_TRACE ("ACE_Get_Opt::short_option_i");
+
+ /* Look at and handle the next option-character. */
+ ACE_TCHAR opt = *this->nextchar_++;
+ ACE_TCHAR *oli = 0;
+ oli = ACE_const_cast (ACE_TCHAR*, ACE_OS::strchr (this->optstring_.c_str (), opt));
+
+ /* Increment `optind' when we start to process its last character. */
+ if (*this->nextchar_ == '\0')
+ ++this->optind;
+
+ if (oli == 0 || opt == ':')
+ {
+ if (this->opterr)
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("%s: illegal short option -- %c\n"),
+ this->argv_[0], opt));
+ return '?';
+ }
+ if (opt == 'W' && oli[1] == ';')
+ {
+ if (this->nextchar_[0] == 0)
+ this->nextchar_ = this->argv_[this->optind];
+ return long_option_i ();
+ }
+ if (oli[1] == ':')
+ {
+ if (oli[2] == ':')
+ {
+ // Takes an optional argument, and since short option args must
+ // must follow directly in the same argument, a NULL nextchar_
+ // means we didn't get one.
+ if (*this->nextchar_ != '\0')
+ {
+ this->optarg = this->nextchar_;
+ this->optind++;
+ }
+ else
+ this->optarg = 0;
+ this->nextchar_ = 0;
+ }
+ else
+ {
+ // Takes a required argument.
+ if (*this->nextchar_ != '\0')
+ {
+ // Found argument in same argv-element.
+ this->optarg = this->nextchar_;
+ this->optind++;
+ }
+ else if (this->optind == this->argc_)
+ {
+ // Ran out of arguments before finding required argument.
+ if (this->opterr)
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("%s: short option requires an argument -- %c\n"),
+ this->argv_[0], opt));
+ opt = this->has_colon_ ? ':' : '?';
+ }
+ else
+ // Use the next argv-element as the argument.
+ this->optarg = this->argv_[this->optind++];
+ this->nextchar_ = 0;
+ }
+ }
+ return opt;
+}
+
+int
+ACE_Get_Opt::operator () (void)
+{
+ ACE_TRACE ("ACE_Get_Opt_Long::operator");
+
+ // First of all, make sure we reinitialize any pointers..
+ this->optarg = 0;
+ this->long_option_ = 0;
+
+ this->optarg = 0;
+ if (this->argv_ == 0)
+ {
+ // It can happen, e.g., on VxWorks.
+ this->optind = 0;
+ return -1;
+ }
+
+ // We check this because we can string short options together if the preceding one doesn't take
+ // an argument.
+ if (this->nextchar_ == 0 || *this->nextchar_ == '\0')
+ {
+ int retval = this->nextchar_i ();
+ if (retval != 0)
+ return retval;
+ }
+
+ if (((this->argv_[this->optind][0] == '-')
+ && (this->argv_[this->optind][1] == '-')) || this->long_only_)
+ return this->long_option_i ();
+
+ return this->short_option_i ();
+}
+
+int
+ACE_Get_Opt::long_option (const ACE_TCHAR *name,
+ OPTION_ARG_MODE has_arg)
+{
+ ACE_TRACE ("ACE_Get_Opt::long_option (const ACE_TCHAR *name, OPTION_ARG_MODE has_arg)");
+ return this->long_option (name, 0, has_arg);
+}
+
+int
+ACE_Get_Opt::long_option (const ACE_TCHAR *name,
+ int short_option,
+ OPTION_ARG_MODE has_arg)
+{
+ ACE_TRACE ("ACE_Get_Opt::long_option (const ACE_TCHAR *name, int short_option, OPTION_ARG_MODE has_arg)");
+
+ // We only allow valid alpha-numeric characters as short options. If short_options
+ // is not a valid alpha-numeric, we can still return it when the long option
+ // is found, but won't allow the caller to pass it on the command line (how could
+ // they?). The special case is 0, but since we always return it, we let the caller
+ // worry about that.
+ if (isalnum (short_option) != 0)
+ {
+ // If the short_option already exists, make sure it matches, otherwise
+ // add it.
+ ACE_TCHAR *s = 0;
+ if ((s = ACE_const_cast (ACE_TCHAR*,
+ ACE_OS::strchr (this->optstring_.c_str (), short_option))) != 0)
+ {
+ // Short option exists, so verify the argument options
+ if (s[1] == ':')
+ {
+ if (s[2] == ':')
+ {
+ if (has_arg != ARG_OPTIONAL)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "Argument type for existing short option '%c' "
+ "does not match '%s'-- != 'ARG_OPTIONAL'\n",
+ short_option, s), -1);
+ }
+ else
+ if (has_arg != ARG_REQUIRED)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "Argument type for existing short option '%c' "
+ "does not match '%s' -- != 'ARG_REQUIRED'\n",
+ short_option, s), -1);
+ }
+ else if (has_arg != NO_ARG)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "Argument type for existing short option '%c' "
+ "does not match '%s' -- != 'NO_ARG'\n",
+ short_option, s), -1);
+ }
+ else
+ {
+ // Didn't find short option, so add it...
+ this->optstring_ += (ACE_TCHAR) short_option;
+ if (has_arg == ARG_REQUIRED)
+ this->optstring_ += ACE_LIB_TEXT (":");
+ else if (has_arg == ARG_OPTIONAL)
+ this->optstring_ += ACE_LIB_TEXT ("::");
+ }
+ }
+
+ ACE_Get_Opt_Long_Option *option =
+ new ACE_Get_Opt_Long_Option (name, has_arg, short_option);
+
+ if (!option)
+ return -1;
+
+ // Add to array
+ size_t size = this->long_opts_.size ();
+ if (this->long_opts_.size (size + 1) != 0
+ || this->long_opts_.set (option, size) != 0)
+ {
+ delete option;
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "Could not add long option to array.\n"), -1);
+ }
+ return 0;
+}
+
+const ACE_TCHAR*
+ACE_Get_Opt::long_option (void) const
+{
+ ACE_TRACE ("ACE_Get_Opt::long_option (void)");
+ if (this->long_option_)
+ return this->long_option_->name_.c_str ();
+ return 0;
+}
+
+void
+ACE_Get_Opt::dump (void) const
+{
+ ACE_TRACE ("ACE_Get_Opt::dump");
+
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\n")));
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+void
+ACE_Get_Opt::permute_args (void)
+{
+ ACE_TRACE ("ACE_Get_Opt::permute_args");
+
+ int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
+ ACE_TCHAR *swap;
+ int opt_end = this->optind;
+
+ nnonopts = this->nonopt_end_ - this->nonopt_start_;
+ nopts = opt_end - this->nonopt_end_;
+ ncycle = ACE::gcd (nnonopts, nopts);
+ cyclelen = (opt_end - this->nonopt_start_) / ncycle;
+
+ this->optind = this->optind - nnonopts;
+
+ for (i = 0; i < ncycle; i++)
+ {
+ cstart = this->nonopt_end_ + i;
+ pos = cstart;
+ for (j = 0; j < cyclelen; j++)
+ {
+ if (pos >= this->nonopt_end_)
+ pos -= nnonopts;
+ else
+ pos += nopts;
+ swap = this->argv_[pos];
+
+ ((ACE_TCHAR **)this->argv_)[pos] = argv_[cstart];
+
+ ((ACE_TCHAR **)this->argv_)[cstart] = swap;
+ }
+ }
+}
+
+int
+ACE_Get_Opt::permute (void)
+{
+ ACE_TRACE ("ACE_Get_Opt::permute");
+
+ if (this->nonopt_start_ != this->nonopt_end_
+ && this->nonopt_start_ != this->optind)
+ this->permute_args ();
+
+ this->nonopt_start_ = this->optind;
+
+ // Skip over args untill we find the next option.
+ while (this->optind < this->argc_
+ && (this->argv_[this->optind][0] != '-'
+ || this->argv_[this->optind][1] == '\0'))
+ this->optind++;
+
+ // Got an option, so mark this as the end of the non options.
+ this->nonopt_end_ = this->optind;
+
+ if (this->optind != this->argc_
+ && ACE_OS::strcmp (this->argv_[this->optind],
+ ACE_LIB_TEXT ("--")) == 0)
+ {
+ // We found the marker for the end of the options.
+ this->optind++;
+
+ if (this->nonopt_start_ != this->nonopt_end_
+ && this->nonopt_end_ != this->optind)
+ this->permute_args ();
+ }
+
+ if (this->optind == this->argc_)
+ {
+ if (this->nonopt_start_ != this->nonopt_end_)
+ this->optind = this->nonopt_start_;
+ return EOF;
+ }
+ return 0;
+}
diff --git a/ace/Utils/Get_Opt.h b/ace/Utils/Get_Opt.h
new file mode 100644
index 00000000000..793056a1e36
--- /dev/null
+++ b/ace/Utils/Get_Opt.h
@@ -0,0 +1,357 @@
+/* -*- C++ -*- */
+//=============================================================================
+/**
+ * @file Get_Opt.h
+ *
+ * $Id$
+ *
+ * @author Douglas C. Schmidt <schmidt@cs.wustl.edu>
+ *
+ * Long option support added by Don Hinton <dhinton@gmx.net>.
+ */
+//=============================================================================
+
+#ifndef ACE_GET_OPT_H
+#define ACE_GET_OPT_H
+#include "ace/pre.h"
+
+#include "ace/ACE.h"
+#include "ace/SString.h"
+#include "ace/Containers.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#undef optind
+#undef optarg
+#undef opterr
+
+/*
+ * These definitions are for backward compatibility with previous versions.
+ * of ACE_Get_Opt.
+ */
+
+/**
+ * @class ACE_Get_Opt
+ *
+ * @brief Iterator for parsing command-line arguments.
+ *
+ * This is a C++ wrapper for getopt(3c) and getopt_long(3c).
+ */
+
+class ACE_Export ACE_Get_Opt
+{
+public:
+ /// Mutually exclusive ordering values.
+ enum
+ {
+ /// The options must come first, return <EOF> as soon as a
+ /// non-option argument is encountered.
+ REQUIRE_ORDER = 1,
+
+ /// Reorder the arguments so that all the options come first (the
+ /// order of the options and the following arguments are
+ /// maintained).
+ PERMUTE_ARGS = 2,
+
+ /// Continue processing the command line for each argument. The
+ /// return value '1' signifies a non-option argument.
+ RETURN_IN_ORDER = 3
+ };
+
+ /// Mutually exclusive option argument mode used by long options.
+ enum OPTION_ARG_MODE
+ {
+ /// Doesn't take an argument.
+ NO_ARG = 0,
+
+ /// Requires an argument, same as passing ":" after a short option
+ /// character in <optstring>.
+ ARG_REQUIRED = 1,
+
+ /// Argument is optional, same as passing "::" after a short
+ /// option character in <optstring>.
+ ARG_OPTIONAL = 2
+ };
+
+ /**
+ * Initialize the internal data when the first call is made. Start
+ * processing options with <argv>-element 0 + <skip_argv0>; the
+ * sequence of previously skipped non-option <argv>-elements is
+ * empty.
+ *
+ * <optstring> is a string containing the legitimate short option
+ * characters. A single colon ":" in <optstring> means that the
+ * previous character is an option that wants, requires, an argument,
+ * whereas a double colon "::" signifies the argument is optional.
+ * The argument is taken from the rest of the current <argv>-element,
+ * or from the following <argv>-element (only valid for required
+ * arguments, optional arguments must always reside in the same
+ * <argv>-element), and returned in by <opt_arg ()>.
+ *
+ * Multiple short options can be combined as long as only the last
+ * one can takes an argument, e.g., if <optstring> is defined as
+ * "abc:" or "abc::" then the command line "program -abcxxx" short
+ * options a, b, and c are found with "xxx" as the argument for c.
+ * However, if the command line is specified as "program -acb" only
+ * options a and c are found with "b" as the argument for c. Also,
+ * for options with optional arguments, e.g., those followed by "::"
+ * the argument must be in the same <argv>-element, so "program -abc
+ * xxx" will only find "xxx" as the argument for c if <optstring> is
+ * specified as "abc:" not "abc::".
+ *
+ * If a missing required option argument is detected, return the
+ * colon character ':' if the first character of <optstring> was a
+ * colon, or a '?' otherwise. (Note that the standards are unclear in
+ * this respect, so we scan the initial *characters* of <optstring>
+ * up unto the first short option character for '+', '-', and ':' in
+ * order to determine ordering and missing argument behavior.)
+ *
+ * If an short option character is seen that is not listed in
+ * <optstring>, return '?' after printing an error message. If you
+ * set <report_errors> to zero, the error message is suppressed but
+ * we still return '?'.
+ *
+ * <optstring> can be extended by adding long options,
+ * <long_option()>, that have corresponding short options. If the
+ * short option already appears in <optstring> they argument
+ * characteristics must match, otherwise it is added -- see
+ * <long_option()> for more information.
+ *
+ * If 'W', followed by a semi-colon ';' appears in <optstring>, then
+ * any time a 'W' appears on the command line, the following argument
+ * is treated as a long option, e.g., if the command line contains
+ * "program -W foo" "foo" is treated as a long option, i.e., as if
+ * "program --foo" had been passed.
+ *
+ * <ordering> refers to how the <argv>-elements are processed.
+ * <REQUIRE_ORDER> means that we stop processing and return <EOF> as
+ * soon as a non-option argument is found, and <opt_ind ()>
+ * holds the index of the next <argv>-element so the program can
+ * continue processing the rest of the <argv>-elements. If
+ * <PERMUTE_ARGS> (default) is passed, the <argv>-elements are
+ * reordered dynamically, permuted, so that all options appear first.
+ * When the last option has been process, <EOF> is returned and
+ * <opt_ind()> holds the index into the next non-option
+ * element. If <RETURN_IN_ORDER> is passed, then each <argv>-element
+ * is processed in the order is it seen. If the element is not
+ * recognized as an option, '1' is returned and <opt_arg()>
+ * contains the <argv>-element found.
+ *
+ * If <long_only> is non-zero, then all options are treated as long
+ * options. If a long option is not recognized, we try to find a
+ * matching short option. */
+ ACE_Get_Opt (int argc,
+ ACE_TCHAR **argv,
+ const ACE_TCHAR *optstring,
+ int skip_argv0 = 1,
+ int report_errors = 0,
+ int ordering = PERMUTE_ARGS,
+ int long_only = 0);
+
+ /// Default dtor.
+ ~ACE_Get_Opt (void);
+
+ /**
+ * Scan elements of <argv> (whose length is <argc>) for short option
+ * characters given in <optstring> or long options (with no short
+ * option equivilents).
+ *
+ * If an element of <argv> starts with '-', and is not exactly "-"
+ * or "--", then it is a short option element. The characters of this
+ * element (aside from the initial '-') are option characters. If
+ * it starts with "--" followed by other characters it is treated as
+ * a long option. If <operator()> is called repeatedly, it returns
+ * successively each of the option characters from each of the option
+ * elements.
+ *
+ * If <operator()> finds another option character, it returns that
+ * character, updating <optind> and <nextchar> so that the next call
+ * to <operator()> can resume the scan with the following option
+ * character or <argv>-element.
+ *
+ * If <operator()> returns 0, it found a long option, '?' indicates
+ * an unknown option character, and '1' means that <RETURN_IN_ORDER>
+ * was specified and we found an non-option argument.
+ *
+ * If there are no more option characters, <operator()> returns
+ * <EOF>. Then <opt_ind()> is the index in <argv> of the first
+ * <argv>-element that is not an option. (If <PERMUTE_ARGS> was
+ * specified, the <argv>-elements have been permuted so that those
+ * that are not options now come last.)
+ */
+ int operator () (void);
+
+ /**
+ * For communication from <operator()> to the caller. When
+ * <operator()> finds an option that takes an argument, the argument
+ * value is returned here, otherwise it returns 0.
+ */
+ ACE_TCHAR *opt_arg (void) const;
+
+ /**
+ * Index in <argv> of the next element to be scanned. This is used
+ * for communication to and from the caller and for communication
+ * between successive calls to <operator()>. On entry to
+ * <operator()>, zero means this is the first call; initialize.
+ *
+ * When <operator()> returns <EOF>, this is the index of the first of
+ * the non-option elements that the caller should itself scan.
+ *
+ * Otherwise, <opt_ind()> communicates from one call to the next how
+ * much of <argv> has been scanned so far.
+ */
+ int &opt_ind (void);
+
+ // Adds a long option with no corresponding short option.
+ int long_option (const ACE_TCHAR *name,
+ OPTION_ARG_MODE has_arg = NO_ARG);
+
+ /// Adds a long option with a corresponding short option. If the
+ /// short option has already been supplied in the <optstring>,
+ /// has_arg match match or an error is returned, otherwise the new
+ /// short option it is added to the <optstring>.
+ /// Returns 0 on success and -1 if the long option can not be added.
+ int long_option (const ACE_TCHAR *name,
+ int short_option,
+ OPTION_ARG_MODE has_arg = NO_ARG);
+
+ /// Returns the name of the long option found on the last call to
+ /// <operator()> or 0 if none was found.
+ const ACE_TCHAR *long_option (void) const;
+
+ /// Accessor for the <argv_> pointer.
+ ACE_TCHAR **argv (void) const;
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Return the <optstring>. This is handy to verify that calls to
+ /// long_option added short options as expected.
+ const ACE_TCHAR *optstring (void) const;
+
+public:
+ /**
+ * The following five data members should be private, but that
+ * would break backwards compatibility. However, we recommend not
+ * writing code that uses these fields directly.
+ */
+
+ /// Holds the <argc> count.
+ int argc_;
+
+ /// Holds the <argv> pointer.
+ ACE_TCHAR **argv_;
+
+ /// Index in argv_ of the next element to be scanned.
+ int optind;
+
+ /// Callers store zero here to inhibit the error message for
+ /// unrecognized options.
+ int opterr;
+
+ /// Points to the option argument when one is found on last call to
+ /// <operator()>.
+ ACE_TCHAR *optarg;
+
+private:
+ class ACE_Get_Opt_Long_Option
+ {
+ public:
+ /// ctor
+ ACE_Get_Opt_Long_Option (const ACE_TString name,
+ int has_arg,
+ int val = 0)
+ : name_ (name),
+ has_arg_ (has_arg),
+ val_ (val) {};
+
+ /// Default dtor.
+ ~ACE_Get_Opt_Long_Option (void) {};
+
+ int operator < (const ACE_Get_Opt_Long_Option &rhs);
+
+ /// Long option name.
+ const ACE_TString name_;
+
+ /// Contains value for <OPTION_ARG_MODE>.
+ int has_arg_;
+
+ /// Contains a valid short option character or zero if it doesn't
+ /// have a corresponding short option. It can also contain a
+ /// non-printable value that cannot be passed to <optstring> but
+ /// will be returned by <operator()>. This is handy for
+ /// simplifying long option handling, see tests/Get_Opt_Test.cpp
+ /// for an example of this technique.
+ int val_;
+ };
+
+ /// Updates nextchar_.
+ int nextchar_i (void);
+
+ /// Handles long options.
+ int long_option_i (void);
+
+ /// Handles short options.
+ int short_option_i (void);
+
+ /// If permuting args, this functions manages the nonopt_start_ and
+ /// nonopt_end_ indexes and makes calls to permute to actually
+ /// reorder the <argv>-elements.
+ void permute_args (void);
+
+ /// Handles reordering <argv>-elements.
+ int permute (void);
+
+ /// Holds the option string.
+ ACE_TString optstring_;
+
+ /// Treat all options as long options.
+ int long_only_;
+
+ /// Keeps track of whether or not a colon was passed in <optstring>.
+ /// This is used to determine the return value when required
+ /// arguments are missing.
+ int has_colon_;
+
+ /**
+ * The next char to be scanned in the option-element in which the
+ * last option character we returned was found. This allows us to
+ * pick up the scan where we left off.
+ *
+ * If this is zero, or a null string, it means resume the scan
+ * by advancing to the next <argv>-element.
+ */
+ ACE_TCHAR *nextchar_;
+
+ /// Keeps track of ordering mode (default <PERMUTE_ARGS>).
+ int ordering_;
+
+ /// Index of the first non-option <argv>-element found (only valid
+ /// when permuting).
+ int nonopt_start_;
+
+ /// Index of the <argv>-element following the last non-option element
+ /// (only valid when permuting).
+ int nonopt_end_;
+
+ /// Points to the long_option found on last call to <operator()>.
+ ACE_Get_Opt_Long_Option *long_option_;
+
+ /// Array of long options.
+ ACE_Array<ACE_Get_Opt_Long_Option*> long_opts_;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+ ACE_UNIMPLEMENTED_FUNC (ACE_Get_Opt (const ACE_Get_Opt &))
+ ACE_UNIMPLEMENTED_FUNC (ACE_Get_Opt &operator= (const ACE_Get_Opt &))
+};
+
+#if defined (__ACE_INLINE__)
+#include "ace/Get_Opt.i"
+#endif /* __ACE_INLINE__ */
+
+#include "ace/post.h"
+#endif /* ACE_GET_OPT_H */
diff --git a/ace/Utils/Get_Opt.i b/ace/Utils/Get_Opt.i
new file mode 100644
index 00000000000..f89190a954e
--- /dev/null
+++ b/ace/Utils/Get_Opt.i
@@ -0,0 +1,34 @@
+/* -*- C++ -*- */
+// $Id$
+
+// Get_Opt.i
+
+ACE_INLINE int
+ACE_Get_Opt::ACE_Get_Opt_Long_Option::operator < (const ACE_Get_Opt_Long_Option &rhs)
+{
+ return this->name_ < rhs.name_;
+}
+
+ACE_INLINE ACE_TCHAR **
+ACE_Get_Opt::argv (void) const
+{
+ return this->argv_;
+}
+
+ACE_INLINE ACE_TCHAR*
+ACE_Get_Opt::opt_arg (void) const
+{
+ return this->optarg;
+}
+
+ACE_INLINE int &
+ACE_Get_Opt::opt_ind (void)
+{
+ return this->optind;
+}
+
+ACE_INLINE const ACE_TCHAR *
+ACE_Get_Opt::optstring (void) const
+{
+ return this->optstring_.c_str ();
+}
diff --git a/ace/Utils/Hash_Map_Manager.cpp b/ace/Utils/Hash_Map_Manager.cpp
new file mode 100644
index 00000000000..4378551c7f8
--- /dev/null
+++ b/ace/Utils/Hash_Map_Manager.cpp
@@ -0,0 +1,19 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// ace
+//
+// = FILENAME
+// Hash_Map_Manager.cpp
+//
+// = AUTHOR
+// Douglas C. Schmidt <schmidt@cs.wustl.edu>
+//
+// ============================================================================
+
+#include "ace/Hash_Map_Manager.h"
+
+ACE_RCSID(ace, Hash_Map_Manager, "$Id$")
+
diff --git a/ace/Utils/Hash_Map_Manager.h b/ace/Utils/Hash_Map_Manager.h
new file mode 100644
index 00000000000..dc2b7fce755
--- /dev/null
+++ b/ace/Utils/Hash_Map_Manager.h
@@ -0,0 +1,28 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Hash_Map_Manager.h
+ *
+ * $Id$
+ *
+ * @author Douglas C. Schmidt <schmidt@cs.wustl.edu>
+ */
+//=============================================================================
+
+#ifndef ACE_HASH_MAP_MANAGER_H
+#define ACE_HASH_MAP_MANAGER_H
+#include "ace/pre.h"
+
+#include "ace/OS.h"
+#include "ace/Functor.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+// Include the templates here.
+#include "ace/Hash_Map_Manager_T.h"
+
+#include "ace/post.h"
+#endif /* ACE_HASH_MAP_MANAGER_H */
diff --git a/ace/Utils/Hashable.cpp b/ace/Utils/Hashable.cpp
new file mode 100644
index 00000000000..c07ec6d0d65
--- /dev/null
+++ b/ace/Utils/Hashable.cpp
@@ -0,0 +1,8 @@
+//$Id$
+#include "ace/Hashable.h"
+
+#if !defined (__ACE_INLINE__)
+#include "ace/Hashable.inl"
+#endif /* __ACE_INLINE __ */
+
+ACE_RCSID(ace, Hashable, "$Id$")
diff --git a/ace/Utils/Hashable.h b/ace/Utils/Hashable.h
new file mode 100644
index 00000000000..ff12aed4ec6
--- /dev/null
+++ b/ace/Utils/Hashable.h
@@ -0,0 +1,64 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Hashable.h
+ *
+ * $Id$
+ *
+ * @author Doug Schmidt
+ */
+//=============================================================================
+#ifndef ACE_HASHABLE_H
+#define ACE_HASHABLE_H
+#include "ace/pre.h"
+
+// @@todo: Hate to do this. Looks like we have less luck here as
+// compilers complain for type u_long unknowns
+#include "ace/OS.h"
+
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+
+
+/**
+ * @class ACE_Recyclable
+ *
+ * @brief
+ *
+ *
+ */
+
+class ACE_Export ACE_Hashable
+{
+public:
+
+ /// Destructor.
+ virtual ~ACE_Hashable (void);
+
+ /// Computes and returns hash value. This "caches" the hash value to
+ /// improve performance.
+ virtual u_long hash (void) const;
+
+protected:
+ /// Protected constructor.
+ ACE_Hashable (void);
+
+ /// This is the method that actually performs the non-cached hash
+ /// computation.
+ virtual u_long hash_i (void) const = 0;
+
+ /// Pre-computed hash-value.
+ u_long hash_value_;
+};
+
+
+#if defined (__ACE_INLINE__)
+#include "ace/Hashable.inl"
+#endif /* __ACE_INLINE __ */
+
+#include "ace/post.h"
+#endif /*ACE_HASHABLE_H*/
diff --git a/ace/Utils/Hashable.inl b/ace/Utils/Hashable.inl
new file mode 100644
index 00000000000..efe4f9a8d75
--- /dev/null
+++ b/ace/Utils/Hashable.inl
@@ -0,0 +1,27 @@
+/* -*- C++ -*- */
+// $Id$
+ACE_INLINE
+ACE_Hashable::ACE_Hashable (void)
+ : hash_value_ (0)
+{
+}
+
+ACE_INLINE
+ACE_Hashable::~ACE_Hashable (void)
+{
+}
+
+ACE_INLINE u_long
+ACE_Hashable::hash (void) const
+{
+ // In doing the check below, we take chance of paying a performance
+ // price when the hash value is zero. But, that will (hopefully)
+ // happen far less often than a non-zero value, so this caching
+ // strategy should pay off, esp. if hash computation is expensive
+ // relative to the simple comparison.
+
+ if (this->hash_value_ == 0)
+ ((ACE_Hashable *) this)->hash_value_ = this->hash_i ();
+
+ return this->hash_value_;
+}
diff --git a/ace/Utils/IO_Cntl_Msg.cpp b/ace/Utils/IO_Cntl_Msg.cpp
new file mode 100644
index 00000000000..aa8281f63d4
--- /dev/null
+++ b/ace/Utils/IO_Cntl_Msg.cpp
@@ -0,0 +1,38 @@
+// IO_Cntl_Msg.cpp
+// $Id$
+
+#if 0
+// This is not meant to be used, it's just a place holder...
+
+ACE_RCSID(ace, IO_Cntl_Msg, "$Id$")
+
+// Forward decl
+template <class SYNCH> class ACE_Module;
+
+
+class ACE_Module_Link
+{
+ // = TITLE
+ // Data structure used to link two modules together
+ //
+ // = DESCRIPTION
+ //
+public:
+ ACE_Module_Link (ACE_Module *m1, ACE_Module *m2): mod_upper_ (m1), mod_lower_ (m2), count_ (0) {}
+
+ ACE_Module *upper (void) { return this->mod_upper_; }
+ void upper (ACE_Module *u) { this->mod_upper_ = u; }
+
+ ACE_Module *lower (void) { return this->mod_lower_; }
+ void lower (ACE_Module *l) { this->mod_lower_ = l; }
+
+ int count (void) { return this->count_; }
+ void count (int c) { this->count_ = c; }
+
+private:
+ ACE_Module *mod_upper_;
+ ACE_Module *mod_lower_;
+ int count_;
+};
+#endif
+
diff --git a/ace/Utils/IO_Cntl_Msg.h b/ace/Utils/IO_Cntl_Msg.h
new file mode 100644
index 00000000000..549becfa70d
--- /dev/null
+++ b/ace/Utils/IO_Cntl_Msg.h
@@ -0,0 +1,95 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file IO_Cntl_Msg.h
+ *
+ * $Id$
+ *
+ * @author Doug Schmidt
+ */
+//=============================================================================
+
+
+#ifndef ACE_IO_CNTL_MSG_H
+#define ACE_IO_CNTL_MSG_H
+#include "ace/pre.h"
+
+/**
+ * @class ACE_IO_Cntl_Msg
+ *
+ * @brief Data format for IOCTL messages
+ */
+class ACE_Export ACE_IO_Cntl_Msg
+{
+public:
+ enum
+ {
+ /// Set the low water mark.
+ SET_LWM = 1,
+ /// Get the low water mark.
+ GET_LWM = 2,
+ /// Set the high water mark.
+ SET_HWM = 3,
+ /// Get the high water mark.
+ GET_HWM = 4,
+ /// Link modules
+ MOD_LINK = 5,
+ /// Unlink modules
+ MOD_UNLINK = 6
+ };
+
+ typedef u_short ACE_IO_Cntl_Cmds;
+
+ // = Initialization method.
+ /// Initialize the control message.
+ ACE_IO_Cntl_Msg (ACE_IO_Cntl_Cmds c) { this->cmd_ = c; }
+
+ // = Get/set methods
+
+ /// Get command.
+ ACE_IO_Cntl_Cmds cmd (void) { return this->cmd_; }
+
+ /// Set command.
+ void cmd (ACE_IO_Cntl_Cmds c) { this->cmd_ = c; }
+
+ /// Get count.
+ size_t count (void) { return this->count_; }
+
+ /// Set count.
+ void count (size_t c) { this->count_ = c; }
+
+ /// Get error.
+ int error (void) { return this->error_; }
+
+ /// Set error.
+ void error (int e) { this->error_ = e; }
+
+ /// Get return value.
+ int rval (void) { return this->rval_; }
+
+ /// Set return value.
+ void rval (int r) { this->rval_ = r; }
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+private:
+ /// Command.
+ ACE_IO_Cntl_Cmds cmd_;
+
+ /// Count.
+ size_t count_;
+
+ /// Error.
+ int error_;
+
+ /// Return value
+ int rval_;
+};
+
+#include "ace/post.h"
+#endif /* ACE_IO_CNTL_MSG_H */
diff --git a/ace/Utils/Init_ACE.cpp b/ace/Utils/Init_ACE.cpp
new file mode 100644
index 00000000000..d40ba6fbfb9
--- /dev/null
+++ b/ace/Utils/Init_ACE.cpp
@@ -0,0 +1,44 @@
+// $Id$
+
+#include "Init_ACE.h"
+
+#include "ace/Utils/Object_Manager.h"
+
+#if defined (ACE_LACKS_INLINE_FUNCTIONS)
+#include "Init_ACE.i"
+#endif /* ACE_LACKS_INLINE_FUNCTIONS */
+
+ACE_RCSID(ace, Init_ACE, "$Id$")
+
+ // Static data members.
+ u_int ACE_Init_ACE::init_fini_count_ = 0;
+int
+ACE_Init_ACE::init (void)
+{
+ // Don't use ACE_TRACE, because Object_Manager might not have been
+ // instantiated yet.
+ // ACE_TRACE ("ACE_Init_ACE::init");
+
+ ++init_fini_count_;
+
+ return ACE_Object_Manager::instance ()->init ();
+}
+
+int
+ACE_Init_ACE::fini (void)
+{
+ ACE_TRACE ("ACE_Init_ACE::fini");
+
+ if (init_fini_count_ > 0)
+ {
+ if (--init_fini_count_ == 0)
+ return ACE_Object_Manager::instance ()->fini ();
+ else
+ // Wait for remaining fini () calls.
+ return 1;
+ }
+ else
+ // More ACE_Init_ACE::fini () calls than ACE_Init_ACE::init () calls. Bad
+ // application!
+ return -1;
+}
diff --git a/ace/Utils/Init_ACE.h b/ace/Utils/Init_ACE.h
new file mode 100644
index 00000000000..9c5f0bb97c9
--- /dev/null
+++ b/ace/Utils/Init_ACE.h
@@ -0,0 +1,65 @@
+
+//=============================================================================
+/**
+ * @file Init_ACE.h
+ *
+ * $Id$
+ *
+ * This class consolidates the operations on the Handles.
+ *
+ *
+ * @author Priyanka Gontla <pgontla@ece.uci.edu>
+ */
+//=============================================================================
+
+
+#ifndef ACE_INIT_ACE_H
+#define ACE_INIT_ACE_H
+#include "ace/pre.h"
+
+#include "ace/OS/OS.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+/**
+ * @class ACE_Init_ACE
+ *
+ * @brief Initialize ACE library services. Can be called only once
+ * per program invocation.
+ *
+ */
+class ACE_Export ACE_Init_ACE
+{
+public:
+ /// Returns 0 on success, -1 on failure, and 1 if it had already been called.
+ /**
+ * This class implements the fucntions for the initialization and
+ * shutting down ACE. These functions are called only once per ACE
+ * invokation.
+ */
+ static int init (void);
+
+ /// Returns 0 on success, -1 on failure, and 1 if it had already been called.
+ /**
+ * Shut down ACE library services. Can be called only once per
+ * program invocation.
+ */
+ static int fini (void);
+
+private:
+ /**
+ * Counter to match <init>/<fini> calls. <init> must increment it;
+ * <fini> must decrement it. <fini> then does nothing until it
+ * reaches 0.
+ */
+ static u_int init_fini_count_;
+};
+
+#if !defined (ACE_LACKS_INLINE_FUNCTIONS)
+#include "Init_ACE.i"
+#endif /* ACE_LACKS_INLINE_FUNCTIONS */
+
+#include "ace/post.h"
+#endif /* ACE_INIT_ACE_H */
diff --git a/ace/Utils/Init_ACE.i b/ace/Utils/Init_ACE.i
new file mode 100644
index 00000000000..cfa1da318d3
--- /dev/null
+++ b/ace/Utils/Init_ACE.i
@@ -0,0 +1 @@
+// $Id$
diff --git a/ace/Utils/Lib_Find.cpp b/ace/Utils/Lib_Find.cpp
new file mode 100644
index 00000000000..4d63eb430c5
--- /dev/null
+++ b/ace/Utils/Lib_Find.cpp
@@ -0,0 +1,562 @@
+// $Id$
+
+#include "ace/Lib_Find.h"
+#include "ace/Log_Msg.h"
+
+ACE_RCSID(ace, Lib_Find, "$Id$")
+
+
+#if ! defined (ACE_PSOS_DIAB_MIPS)
+int
+ACE_Lib_Find::ldfind (const ACE_TCHAR filename[],
+ ACE_TCHAR pathname[],
+ size_t maxpathnamelen)
+{
+ ACE_TRACE ("ACE_Lib_Find::ldfind");
+
+#if defined (ACE_WIN32) && !defined (ACE_HAS_WINCE) && \
+ !defined (ACE_HAS_PHARLAP)
+ ACE_TCHAR expanded_filename[MAXPATHLEN];
+ if (ACE_TEXT_ExpandEnvironmentStrings (filename,
+ expanded_filename,
+ sizeof expanded_filename
+ / sizeof (ACE_TCHAR)))
+ filename = expanded_filename;
+#endif /* ACE_WIN32 && !ACE_HAS_WINCE && !ACE_HAS_PHARLAP */
+
+ ACE_TCHAR tempcopy[MAXPATHLEN + 1];
+ ACE_TCHAR searchpathname[MAXPATHLEN + 1];
+#if defined (ACE_WIN32) && defined (ACE_LD_DECORATOR_STR) && !defined (ACE_DISABLE_DEBUG_DLL_CHECK)
+ ACE_TCHAR decorator[] = ACE_LD_DECORATOR_STR;
+ ACE_TCHAR searchfilename[MAXPATHLEN + sizeof(decorator) / sizeof (ACE_TCHAR)];
+#else
+ ACE_TCHAR searchfilename[MAXPATHLEN + 1];
+#endif /* ACE_WIN32 && ACE_LD_DECORATOR_STR && !ACE_DISABLE_DEBUG_DLL_CHECK */
+
+ // Create a copy of filename to work with.
+ if (ACE_OS::strlen (filename) + 1
+ > (sizeof tempcopy / sizeof (ACE_TCHAR)))
+ {
+ errno = ENOMEM;
+ return -1;
+ }
+ else
+ ACE_OS::strcpy (tempcopy, filename);
+
+ // Insert canonical directory separators.
+ ACE_TCHAR *separator_ptr;
+
+#if (ACE_DIRECTORY_SEPARATOR_CHAR != '/')
+ // Make all the directory separators "canonical" to simplify
+ // subsequent code.
+ ACE_Lib_Find::strrepl (tempcopy, ACE_DIRECTORY_SEPARATOR_CHAR, '/');
+#endif /* ACE_DIRECTORY_SEPARATOR_CHAR */
+
+ // Separate filename from pathname.
+ separator_ptr = ACE_OS::strrchr (tempcopy, '/');
+
+ // This is a relative path.
+ if (separator_ptr == 0)
+ {
+ searchpathname[0] = '\0';
+ ACE_OS::strcpy (searchfilename, tempcopy);
+ }
+ else // This is an absolute path.
+ {
+ ACE_OS::strcpy (searchfilename, separator_ptr + 1);
+ separator_ptr[1] = '\0';
+ ACE_OS::strcpy (searchpathname, tempcopy);
+ }
+
+ int got_suffix = 0;
+
+ // Check to see if this has an appropriate DLL suffix for the OS
+ // platform.
+ ACE_TCHAR *s = ACE_OS::strrchr (searchfilename, '.');
+
+ const ACE_TCHAR *dll_suffix = ACE_DLL_SUFFIX;
+
+ if (s != 0)
+ {
+ // If we have a dot, we have a suffix
+ got_suffix = 1;
+
+ // Check whether this matches the appropriate platform-specific
+ // suffix.
+#if defined (ACE_WIN32)
+ // Use <ACE_OS::strcasecmp> on any platform with
+ // case-insensitive filenames.
+ if (ACE_OS::strcasecmp (s, dll_suffix) != 0)
+#else
+ if (ACE_OS::strcmp (s, dll_suffix) != 0)
+#endif /* ACE_WIN32 */
+ {
+ ACE_ERROR ((LM_WARNING,
+ ACE_LIB_TEXT ("Warning: improper suffix for a ")
+ ACE_LIB_TEXT ("shared library on this platform: %s\n"),
+ s));
+ }
+ }
+
+ // Make sure we've got enough space in searchfilename.
+ if (ACE_OS::strlen (searchfilename)
+ + ACE_OS::strlen (ACE_DLL_PREFIX)
+ + got_suffix ? 0 : ACE_OS::strlen (dll_suffix) >= (sizeof searchfilename /
+ sizeof (ACE_TCHAR)))
+ {
+ errno = ENOMEM;
+ return -1;
+ }
+
+#if defined (ACE_WIN32) && defined (ACE_LD_DECORATOR_STR) && !defined (ACE_DISABLE_DEBUG_DLL_CHECK)
+ size_t len_searchfilename = ACE_OS::strlen (searchfilename);
+ if (! got_suffix)
+ ACE_OS_String::strcpy (searchfilename + len_searchfilename,
+ decorator);
+
+ for (int tag = 1; tag >= 0; tag --)
+ {
+ if (tag == 0)
+ searchfilename [len_searchfilename] = 0;
+
+#endif /* ACE_WIN32 && ACE_LD_DECORATOR_STR && !ACE_DISABLE_DEBUG_DLL_CHECK */
+ // Use absolute pathname if there is one.
+ if (ACE_OS::strlen (searchpathname) > 0)
+ {
+ if (ACE_OS::strlen (searchfilename)
+ + ACE_OS::strlen (searchpathname) >= maxpathnamelen)
+ {
+ errno = ENOMEM;
+ return -1;
+ }
+ else
+ {
+#if (ACE_DIRECTORY_SEPARATOR_CHAR != '/')
+ // Revert to native path name separators.
+ ACE_Lib_Find::strrepl (searchpathname,
+ '/',
+ ACE_DIRECTORY_SEPARATOR_CHAR);
+#endif /* ACE_DIRECTORY_SEPARATOR_CHAR */
+ // First, try matching the filename *without* adding a
+ // prefix.
+#if defined (ACE_HAS_BROKEN_CONDITIONAL_STRING_CASTS)
+ ACE_OS::sprintf (pathname,
+ ACE_LIB_TEXT ("%s%s%s"),
+ searchpathname,
+ searchfilename,
+ got_suffix ? ACE_static_cast (ACE_TCHAR *,
+ ACE_LIB_TEXT (""))
+ : ACE_static_cast (ACE_TCHAR *,
+ dll_suffix));
+#else /* ! defined (ACE_HAS_BROKEN_CONDITIONAL_STRING_CASTS) */
+ ACE_OS::sprintf (pathname,
+ ACE_LIB_TEXT ("%s%s%s"),
+ searchpathname,
+ searchfilename,
+ got_suffix ? ACE_LIB_TEXT ("") : dll_suffix);
+#endif /* ! defined (ACE_HAS_BROKEN_CONDITIONAL_STRING_CASTS) */
+ if (ACE_OS::access (pathname, F_OK) == 0)
+ return 0;
+
+ // Second, try matching the filename *with* adding a prefix.
+#if defined (ACE_HAS_BROKEN_CONDITIONAL_STRING_CASTS)
+ ACE_OS::sprintf (pathname,
+ ACE_LIB_TEXT ("%s%s%s%s"),
+ searchpathname,
+ ACE_DLL_PREFIX,
+ searchfilename,
+ got_suffix ? ACE_static_cast (ACE_TCHAR *,
+ ACE_LIB_TEXT (""))
+ : ACE_static_cast (ACE_TCHAR *,
+ dll_suffix));
+#else /* ! defined (ACE_HAS_BROKEN_CONDITIONAL_STRING_CASTS) */
+ ACE_OS::sprintf (pathname,
+ ACE_LIB_TEXT ("%s%s%s%s"),
+ searchpathname,
+ ACE_DLL_PREFIX,
+ searchfilename,
+ got_suffix ? ACE_LIB_TEXT ("") : dll_suffix);
+#endif /* ! defined (ACE_HAS_BROKEN_CONDITIONAL_STRING_CASTS) */
+ if (ACE_OS::access (pathname, F_OK) == 0)
+ return 0;
+ }
+ }
+
+ // Use relative filenames via LD_LIBRARY_PATH or PATH (depending on
+ // OS platform).
+ else
+ {
+ ACE_TCHAR *ld_path =
+#if defined ACE_DEFAULT_LD_SEARCH_PATH
+ ACE_DEFAULT_LD_SEARCH_PATH;
+#else
+ ACE_OS::getenv (ACE_LD_SEARCH_PATH);
+#endif /* ACE_DEFAULT_LD_SEARCH_PATH */
+
+#if defined (ACE_WIN32)
+ ACE_TCHAR *ld_path_temp = 0;
+ if (ld_path != 0)
+ {
+ ld_path_temp = (ACE_TCHAR *) ACE_OS::malloc ((ACE_OS::strlen (ld_path) + 2)
+ * sizeof (ACE_TCHAR));
+ if (ld_path_temp != 0)
+ {
+ ACE_OS::strcpy (ld_path_temp, ACE_LD_SEARCH_PATH_SEPARATOR_STR);
+ ACE_OS::strcat (ld_path_temp, ld_path);
+ ld_path = ld_path_temp;
+ }
+ else
+ {
+ ACE_OS::free ((void *) ld_path_temp);
+ ld_path = ld_path_temp = 0;
+ }
+ }
+#endif /* ACE_WIN32 */
+
+ if (ld_path != 0
+ && (ld_path = ACE_OS::strdup (ld_path)) != 0)
+ {
+ // strtok has the strange behavior of not separating the
+ // string ":/foo:/bar" into THREE tokens. One would expect
+ // that the first iteration the token would be an empty
+ // string, the second iteration would be "/foo", and the
+ // third iteration would be "/bar". However, this is not
+ // the case; one only gets two iterations: "/foo" followed
+ // by "/bar".
+
+ // This is especially a problem in parsing Unix paths
+ // because it is permissible to specify 'the current
+ // directory' as an empty entry. So, we introduce the
+ // following special code to cope with this:
+
+ // Look at each dynamic lib directory in the search path.
+
+ ACE_TCHAR *nextholder = 0;
+ const ACE_TCHAR *path_entry =
+ ACE_Lib_Find::strsplit_r (ld_path,
+ ACE_LD_SEARCH_PATH_SEPARATOR_STR,
+ nextholder);
+ int result = 0;
+
+ for (;;)
+ {
+ // Check if at end of search path.
+ if (path_entry == 0)
+ {
+ errno = ENOENT;
+ result = -1;
+ break;
+ }
+ else if (ACE_OS::strlen (path_entry)
+ + 1
+ + ACE_OS::strlen (searchfilename)
+ >= maxpathnamelen)
+ {
+ errno = ENOMEM;
+ result = -1;
+ break;
+ }
+ // This works around the issue where a path might have
+ // an empty component indicating 'current directory'.
+ // We need to do it here rather than anywhere else so
+ // that the loop condition will still work.
+ else if (path_entry[0] == '\0')
+ path_entry = ACE_LIB_TEXT (".");
+
+ // First, try matching the filename *without* adding a
+ // prefix.
+#if defined (ACE_HAS_BROKEN_CONDITIONAL_STRING_CASTS)
+ ACE_OS::sprintf (pathname,
+ ACE_LIB_TEXT ("%s%c%s%s"),
+ path_entry,
+ ACE_DIRECTORY_SEPARATOR_CHAR,
+ searchfilename,
+ got_suffix ? ACE_static_cast (ACE_TCHAR *,
+ ACE_LIB_TEXT (""))
+ : ACE_static_cast (ACE_TCHAR *,
+ dll_suffix));
+#else /* ! defined (ACE_HAS_BROKEN_CONDITIONAL_STRING_CASTS) */
+ ACE_OS::sprintf (pathname,
+ ACE_LIB_TEXT ("%s%c%s%s"),
+ path_entry,
+ ACE_DIRECTORY_SEPARATOR_CHAR,
+ searchfilename,
+ got_suffix ? ACE_LIB_TEXT ("") : dll_suffix);
+#endif /* ! defined (ACE_HAS_BROKEN_CONDITIONAL_STRING_CASTS) */
+ if (ACE_OS::access (pathname, F_OK) == 0)
+ break;
+
+ // Second, try matching the filename *with* adding a
+ // prefix.
+#if defined (ACE_HAS_BROKEN_CONDITIONAL_STRING_CASTS)
+ ACE_OS::sprintf (pathname,
+ ACE_LIB_TEXT ("%s%c%s%s%s"),
+ path_entry,
+ ACE_DIRECTORY_SEPARATOR_CHAR,
+ ACE_DLL_PREFIX,
+ searchfilename,
+ got_suffix ? ACE_static_cast (ACE_TCHAR *,
+ ACE_LIB_TEXT (""))
+ : ACE_static_cast (ACE_TCHAR *,
+ dll_suffix));
+#else /* ! defined (ACE_HAS_BROKEN_CONDITIONAL_STRING_CASTS) */
+ ACE_OS::sprintf (pathname,
+ ACE_LIB_TEXT ("%s%c%s%s%s"),
+ path_entry,
+ ACE_DIRECTORY_SEPARATOR_CHAR,
+ ACE_DLL_PREFIX,
+ searchfilename,
+ got_suffix ? ACE_LIB_TEXT ("") : dll_suffix);
+#endif /* ! defined (ACE_HAS_BROKEN_CONDITIONAL_STRING_CASTS) */
+ if (ACE_OS::access (pathname, F_OK) == 0)
+ break;
+
+ // Fetch the next item in the path
+ path_entry = ACE_Lib_Find::strsplit_r (0,
+ ACE_LD_SEARCH_PATH_SEPARATOR_STR,
+ nextholder);
+ }
+
+#if defined (ACE_WIN32)
+ if (ld_path_temp != 0)
+ ACE_OS::free (ld_path_temp);
+#endif /* ACE_WIN32 */
+ ACE_OS::free ((void *) ld_path);
+#if defined (ACE_WIN32) && defined (ACE_LD_DECORATOR_STR) && !defined (ACE_DISABLE_DEBUG_DLL_CHECK)
+ if (result == 0 || tag == 0)
+#endif /* ACE_WIN32 && ACE_LD_DECORATOR_STR && !ACE_DISABLE_DEBUG_DLL_CHECK */
+ return result;
+ }
+ }
+#if defined (ACE_WIN32) && defined (ACE_LD_DECORATOR_STR) && !defined (ACE_DISABLE_DEBUG_DLL_CHECK)
+ }
+#endif /* ACE_WIN32 && ACE_LD_DECORATOR_STR && !ACE_DISABLE_DEBUG_DLL_CHECK */
+
+ errno = ENOENT;
+ return -1;
+}
+
+FILE *
+ACE_Lib_Find::ldopen (const ACE_TCHAR *filename,
+ const ACE_TCHAR *type)
+{
+ ACE_TRACE ("ACE_Lib_Find::ldopen");
+
+ ACE_TCHAR buf[MAXPATHLEN + 1];
+ if (ACE_Lib_Find::ldfind (filename,
+ buf,
+ sizeof (buf) /sizeof (ACE_TCHAR)) == -1)
+ return 0;
+ else
+ return ACE_OS::fopen (buf, type);
+}
+
+ACE_TCHAR *
+ACE_Lib_Find::ldname (const ACE_TCHAR *entry_point)
+{
+ ACE_TRACE ("ACE_Lib_Find::ldname");
+
+#if defined (__BORLANDC__)
+ size_t size =
+ 1 // leading '_'
+ + ACE_OS::strlen (entry_point)
+ + 1;
+
+ ACE_TCHAR *new_name;
+ ACE_NEW_RETURN (new_name,
+ ACE_TCHAR[size],
+ 0);
+
+ ACE_OS::strcpy (new_name, ACE_LIB_TEXT ("_"));
+ ACE_OS::strcat (new_name, entry_point);
+
+ return new_name;
+#else /* __BORLANDC__ */
+ size_t size =
+ ACE_OS::strlen (entry_point)
+ + 1;
+
+ ACE_TCHAR *new_name;
+ ACE_NEW_RETURN (new_name,
+ ACE_TCHAR[size],
+ 0);
+
+ ACE_OS::strcpy (new_name, entry_point);
+
+ return new_name;
+#endif /* __BORLANDC__ */
+}
+
+int
+ACE_Lib_Find::get_temp_dir (ACE_TCHAR *buffer, size_t buffer_len)
+{
+ int result;
+#if defined (ACE_WIN32)
+ result = ACE_TEXT_GetTempPath (buffer_len, buffer);
+
+ // Make sure to return -1 if there is an error
+ if (result == 0 && ::GetLastError () != ERROR_SUCCESS
+ || result > ACE_static_cast (int, buffer_len))
+ result = -1;
+
+#else /* ACE_WIN32 */
+
+ // On non-win32 platforms, check to see what the TMPDIR environment
+ // variable is defined to be. If it doesn't exist, just use /tmp
+ const ACE_TCHAR *tmpdir = ACE_OS::getenv (ACE_LIB_TEXT ("TMPDIR"));
+
+ if (tmpdir == NULL)
+ tmpdir = ACE_LIB_TEXT ("/tmp");
+
+ size_t len = ACE_OS::strlen (tmpdir);
+
+ // Check to see if the buffer is large enough for the string,
+ // another /, and its null character (hence the + 2)
+ if ((len + 2) > buffer_len)
+ {
+ result = -1;
+ }
+ else
+ {
+ ACE_OS::strcpy (buffer, tmpdir);
+
+ // Add a trailing slash because we cannot assume there is already one
+ // at the end. And having an extra one should not cause problems.
+ buffer[len] = '/';
+ buffer[len + 1] = 0;
+ result = 0;
+ }
+#endif /* ACE_WIN32 */
+ return result;
+}
+
+ACE_HANDLE
+ACE_Lib_Find::open_temp_file (const ACE_TCHAR *name, int mode, int perm)
+{
+#if defined (ACE_WIN32)
+ ACE_UNUSED_ARG(perm);
+ return ACE_OS::open (name,
+ mode | _O_TEMPORARY);
+#else
+ // Open it.
+ ACE_HANDLE handle = ACE_OS::open (name, mode, perm);
+
+ if (handle == ACE_INVALID_HANDLE)
+ return ACE_INVALID_HANDLE;
+
+ // Unlink it so that the file will be removed automatically when the
+ // process goes away.
+ if (ACE_OS::unlink (name) == -1)
+ return -1;
+ else
+ // Return the handle.
+ return handle;
+#endif /* ACE_WIN32 */
+}
+#endif /* ! ACE_PSOS_DIAB_MIPS */
+
+size_t
+ACE_Lib_Find::strrepl (char *s, char search, char replace)
+{
+ ACE_TRACE ("ACE_Lib_Find::strrepl");
+
+ size_t replaced = 0;
+
+ for (size_t i = 0; s[i] != '\0'; i++)
+ if (s[i] == search)
+ {
+ s[i] = replace;
+ replaced++;
+ }
+
+ return replaced;
+}
+
+
+// Split a string up into 'token'-delimited pieces, ala Perl's
+// "split".
+
+char *
+ACE_Lib_Find::strsplit_r (char *str,
+ const char *token,
+ char *&next_start)
+{
+ char *result = 0;
+
+ if (str != 0)
+ next_start = str;
+
+ if (next_start != 0)
+ {
+ char *tok_loc = ACE_OS::strstr (next_start, token);
+
+ if (tok_loc != 0)
+ {
+ // Return the beginning of the string.
+ result = next_start;
+
+ // Insure it's terminated.
+ *tok_loc = '\0';
+ next_start = tok_loc + ACE_OS::strlen (token);
+ }
+ else
+ {
+ result = next_start;
+ next_start = (char *) 0;
+ }
+ }
+
+ return result;
+}
+
+#if defined (ACE_HAS_WCHAR)
+wchar_t *
+ACE_Lib_Find::strsplit_r (wchar_t *str,
+ const wchar_t *token,
+ wchar_t *&next_start)
+{
+ wchar_t *result = 0;
+
+ if (str != 0)
+ next_start = str;
+
+ if (next_start != 0)
+ {
+ wchar_t *tok_loc = ACE_OS::strstr (next_start, token);
+
+ if (tok_loc != 0)
+ {
+ // Return the beginning of the string.
+ result = next_start;
+
+ // Insure it's terminated.
+ *tok_loc = '\0';
+ next_start = tok_loc + ACE_OS::strlen (token);
+ }
+ else
+ {
+ result = next_start;
+ next_start = (wchar_t *) 0;
+ }
+ }
+
+ return result;
+}
+
+size_t
+ACE_Lib_Find::strrepl (wchar_t *s, wchar_t search, wchar_t replace)
+{
+ ACE_TRACE ("ACE_Lib_Find::strrepl");
+
+ size_t replaced = 0;
+
+ for (size_t i = 0; s[i] != '\0'; i++)
+ if (s[i] == search)
+ {
+ s[i] = replace;
+ replaced++;
+ }
+
+ return replaced;
+}
+#endif /* ACE_HAS_WCHAR */
diff --git a/ace/Utils/Lib_Find.h b/ace/Utils/Lib_Find.h
new file mode 100644
index 00000000000..f80b10fab0c
--- /dev/null
+++ b/ace/Utils/Lib_Find.h
@@ -0,0 +1,106 @@
+
+//=============================================================================
+/**
+ * @file Lib_Find.h
+ *
+ * $Id$
+ *
+ * @author Priyanka Gontla <pgontla@ece.uci.edu>
+ */
+//=============================================================================
+
+
+#ifndef ACE_LIB_FIND_H
+#define ACE_LIB_FIND_H
+#include "ace/pre.h"
+
+#include "ace/OS/OS.h"
+
+/**
+ * @class ACE_Lib_Find
+ *
+ * This class includes all the static function calls needed to search
+ * and open shared libraries.
+ */
+class ACE_Export ACE_Lib_Find
+{
+ public:
+
+ // = Methods for searching and opening shared libraries.
+
+ /**
+ * Finds the file <filename> either using an absolute path or using
+ * a relative path in conjunction with ACE_LD_SEARCH_PATH (e.g.,
+ * $LD_LIBRARY_PATH on UNIX or $PATH on Win32). This function will
+ * add appropriate suffix (e.g., .dll on Win32 or .so on UNIX)
+ * according to the OS platform. In addition, this function will
+ * apply the appropriate prefix (e.g., "lib" on UNIX and "" on
+ * Win32) if the <filename> doesn't match directly.
+ */
+ static int ldfind (const ACE_TCHAR *filename,
+ ACE_TCHAR *pathname,
+ size_t maxlen);
+
+ /**
+ * Uses <ldfind> to locate and open the appropriate <filename> and
+ * returns a pointer to the file, else it returns a NULL
+ * pointer. <type> specifies how the file should be open.
+ */
+ static FILE *ldopen (const ACE_TCHAR *filename,
+ const ACE_TCHAR *type);
+
+ /**
+ * Transforms <entry_point> into a form that can be located in a
+ * dynamic library using <dlsym>. For example, with Win32/Borland
+ * extern "C" functions which use the default calling convention
+ * have a '_' prepended. Always returns a buffer that has been
+ * dynamically allocated using <operator new>.
+ */
+ static ACE_TCHAR *ldname (const ACE_TCHAR *entry_point);
+
+ /**
+ * Returns the temporary directory including the trailing slash in
+ * <buffer>. Returns -1 for an error or if the buffer_len is not
+ * long enough.
+ */
+ static int get_temp_dir (ACE_TCHAR *buffer, size_t buffer_len);
+
+ /// Opening the temp file. File is automagically unlinked when it is
+ /// closed. This is useful for have temp files.
+ static ACE_HANDLE open_temp_file (const ACE_TCHAR *name,
+ int mode,
+ int perm = 0);
+
+ // @@ Though the following functions dont come under the same category as
+ // above, these are used only in the functions in this class. So it makes
+ // more sense to move these functions too to this class.
+ //
+ /// Replace all instances of <search> in <s> with <replace>. Returns
+ /// the number of replacements made.
+ static size_t strrepl (char *s, char search, char replace);
+
+ /**
+ * Splits string <s> into pieces separated by the string <token>.
+ * <next_start> is an opaque cookie handed back by the call to store
+ * its state for the next invocation, thus making it re-entrant.
+ * This operates very similar to Perl's <split> function except that
+ * it returns pieces one at a time instead of into an array.
+ */
+ static char *strsplit_r (char *s, const char *token, char *&next_start);
+
+#if defined (ACE_HAS_WCHAR)
+ /// As strrepl, but for wide characters.
+ static size_t strrepl (wchar_t *s, wchar_t search, wchar_t replace);
+
+ /// As strsplit_r, but for wide characters.
+ static wchar_t *strsplit_r (wchar_t *s, const wchar_t *token,
+ wchar_t *&next_start);
+#endif /* ACE_HAS_WCHAR */
+};
+
+#if !defined (ACE_LACKS_INLINE_FUNCTIONS)
+#include "Lib_Find.i"
+#endif /* ACE_LACKS_INLINE_FUNCTIONS */
+
+#include "ace/post.h"
+#endif /* ACE_LIB_FIND_H */
diff --git a/ace/Utils/Lib_Find.i b/ace/Utils/Lib_Find.i
new file mode 100644
index 00000000000..cfa1da318d3
--- /dev/null
+++ b/ace/Utils/Lib_Find.i
@@ -0,0 +1 @@
+// $Id$
diff --git a/ace/Utils/Makefile b/ace/Utils/Makefile
new file mode 100644
index 00000000000..3302acd997e
--- /dev/null
+++ b/ace/Utils/Makefile
@@ -0,0 +1,89 @@
+# $Id$
+
+#----------------------------------------------------------------------------
+# Makefile for the libACE_Utils
+#----------------------------------------------------------------------------
+
+MAKEFILE = Makefile
+LIBOS = libACE_Utils
+LIB = $(LIBOS).a
+SHLIB = $(LIBOS).$(SOEXT)
+
+#----------------------------------------------------------------------------
+# Include macros and targets
+#----------------------------------------------------------------------------
+
+include $(ACE_ROOT)/include/makeinclude/wrapper_macros.GNU
+
+####
+#### ACE_COMPONENTS support.
+####
+FILES += \
+ ACE \
+ Active_Map_Manager\
+ Active_Map_Manager_T\
+ Arg_Shifter\
+ ARGV\
+ Capabilities\
+ Configuration\
+ Configuration_Import_Export\
+ Connection_Recycling_Strategy\
+ Containers\
+ Dirent\
+ Dirent_Selector\
+ Dynamic\
+ Filecache\
+ Flag_Manip\
+ Functor\
+ Functor_T\
+ Future\
+ Future_Set\
+ Get_Opt\
+ Hashable\
+ Hash_Map_Manager\
+ Init_ACE\
+ IO_Cntl_Msg\
+ Lib_Find\
+ Map\
+ Message_Block\
+ Method_Request\
+ Multiplexor\
+ NT_Service\
+ Object_Manager\
+ Pair\
+ Recyclable\
+ Refcountable\
+ Registry\
+ Sample_History\
+ SString\
+ Stats\
+ String_Base_Const\
+ Test_and_Set\
+ Unbounded_Queue\
+ Unbounded_Set
+
+
+LSRC = $(addsuffix .cpp,$(FILES))
+
+include $(ACE_ROOT)/include/makeinclude/macros.GNU
+include $(ACE_ROOT)/include/makeinclude/rules.common.GNU
+include $(ACE_ROOT)/include/makeinclude/rules.nested.GNU
+include $(ACE_ROOT)/include/makeinclude/rules.lib.GNU
+include $(ACE_ROOT)/include/makeinclude/rules.local.GNU
+
+INSTALL =
+
+clean:
+ $(RM) -f $(LIBOS).a $(LIBOS).so
+
+#----------------------------------------------------------------------------
+# Local targets
+#----------------------------------------------------------------------------
+
+
+
+#----------------------------------------------------------------------------
+# Dependencies
+#----------------------------------------------------------------------------
+# DO NOT DELETE THIS LINE -- g++dep uses it.
+# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY.
diff --git a/ace/Utils/Map.cpp b/ace/Utils/Map.cpp
new file mode 100644
index 00000000000..daa8b29dc70
--- /dev/null
+++ b/ace/Utils/Map.cpp
@@ -0,0 +1,19 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// ace
+//
+// = FILENAME
+// Map.cpp
+//
+// = AUTHOR
+// Irfan Pyarali
+//
+// ============================================================================
+
+#include "ace/Map.h"
+
+ACE_RCSID(ace, Map, "$Id$")
+
diff --git a/ace/Utils/Map.h b/ace/Utils/Map.h
new file mode 100644
index 00000000000..a8334f72cb6
--- /dev/null
+++ b/ace/Utils/Map.h
@@ -0,0 +1,28 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Map.h
+ *
+ * $Id$
+ *
+ * @author Irfan Pyarali
+ */
+//=============================================================================
+
+
+#ifndef ACE_MAP_H
+#define ACE_MAP_H
+#include "ace/pre.h"
+
+#include "ace/OS.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+// Include the templates here.
+#include "ace/Map_T.h"
+
+#include "ace/post.h"
+#endif /* ACE_MAP_H */
diff --git a/ace/Utils/Message_Block.cpp b/ace/Utils/Message_Block.cpp
new file mode 100644
index 00000000000..b0b13965ad6
--- /dev/null
+++ b/ace/Utils/Message_Block.cpp
@@ -0,0 +1,1293 @@
+// $Id$
+
+#include "ace/Message_Block.h"
+#include "ace/Synch_T.h"
+
+//#define ACE_ENABLE_TIMEPROBES
+#include "ace/Timeprobe.h"
+
+#if !defined (__ACE_INLINE__)
+#include "ace/Message_Block.i"
+#endif /* __ACE_INLINE__ */
+
+ACE_RCSID(ace, Message_Block, "$Id$")
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Message_Block)
+
+#if defined (ACE_ENABLE_TIMEPROBES)
+
+static const char *ACE_MB_Timeprobe_Description[] =
+{
+ "Message_Block::init_i - enter",
+ "Message_Block::init_i - leave",
+ "Message_Block::init_i - db alloc",
+ "Message_Block::init_i - db ctor",
+ "Data_Block::ctor[1] - enter",
+ "Data_Block::ctor[1] - leave",
+ "Data_Block::ctor[2] - enter",
+ "Data_Block::ctor[2] - leave",
+ "Data_Block::clone - enter",
+ "Data_Block::clone - leave"
+};
+
+enum
+{
+ ACE_MESSAGE_BLOCK_INIT_I_ENTER = 3000,
+ ACE_MESSAGE_BLOCK_INIT_I_LEAVE,
+ ACE_MESSAGE_BLOCK_INIT_I_DB_ALLOC,
+ ACE_MESSAGE_BLOCK_INIT_I_DB_CTOR,
+ ACE_DATA_BLOCK_CTOR1_ENTER,
+ ACE_DATA_BLOCK_CTOR1_LEAVE,
+ ACE_DATA_BLOCK_CTOR2_ENTER,
+ ACE_DATA_BLOCK_CTOR2_LEAVE,
+ ACE_DATA_BLOCK_CLONE_ENTER,
+ ACE_DATA_BLOCK_CLONE_LEAVE
+};
+
+
+// Setup Timeprobes
+ACE_TIMEPROBE_EVENT_DESCRIPTIONS (ACE_MB_Timeprobe_Description,
+ ACE_MESSAGE_BLOCK_INIT_I_ENTER);
+
+#endif /* ACE_ENABLE_TIMEPROBES */
+
+void
+ACE_Message_Block::data_block (ACE_Data_Block *db)
+{
+ ACE_TRACE ("ACE_Message_Block::data_block");
+ if (ACE_BIT_DISABLED (this->flags_,
+ ACE_Message_Block::DONT_DELETE)
+ && this->data_block_ != 0)
+ this->data_block_->release ();
+
+ this->data_block_ = db;
+
+ // Set the read and write pointers in the <Message_Block> to point
+ // to the buffer in the <ACE_Data_Block>.
+ this->rd_ptr (this->data_block ()->base ());
+ this->wr_ptr (this->data_block ()->base ());
+}
+
+int
+ACE_Message_Block::copy (const char *buf, size_t n)
+{
+ ACE_TRACE ("ACE_Message_Block::copy");
+
+ // Note that for this to work correct, end() *must* be >= wr_ptr().
+ size_t len = ACE_static_cast(size_t,
+ this->end () - this->wr_ptr ());
+ if (len < n)
+ return -1;
+ else
+ {
+ (void) ACE_OS::memcpy (this->wr_ptr (),
+ buf,
+ n);
+ this->wr_ptr (n);
+ return 0;
+ }
+}
+
+int
+ACE_Message_Block::copy (const char *buf)
+{
+ ACE_TRACE ("ACE_Message_Block::copy");
+
+ // Note that for this to work correct, end() *must* be >= wr_ptr().
+ size_t len = ACE_static_cast(size_t,
+ (this->end () - this->wr_ptr ()));
+ size_t buflen = ACE_OS::strlen (buf) + 1;
+
+ if (len < buflen)
+ return -1;
+ else
+ {
+ (void) ACE_OS::memcpy (this->wr_ptr (),
+ buf,
+ buflen);
+ this->wr_ptr (buflen);
+ return 0;
+ }
+}
+
+void
+ACE_Message_Block::crunch (void)
+{
+ if (this->rd_ptr () > this->base ())
+ {
+ size_t len = this->length ();
+ (void) ACE_OS::memmove (this->base (),
+ this->rd_ptr (),
+ len);
+ this->rd_ptr (this->base ());
+ this->wr_ptr (this->base () + len);
+ }
+}
+
+void
+ACE_Data_Block::dump (void) const
+{
+ ACE_TRACE ("ACE_Data_Block::dump");
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_LIB_TEXT ("-----( Data Block )-----\n")
+ ACE_LIB_TEXT ("type_ = %d\n")
+ ACE_LIB_TEXT ("cur_size_ = %u\n")
+ ACE_LIB_TEXT ("max_size_ = %u\n")
+ ACE_LIB_TEXT ("flags_ = %u\n")
+ ACE_LIB_TEXT ("base_ = %u\n")
+ ACE_LIB_TEXT ("locking_strategy_ = %u\n")
+ ACE_LIB_TEXT ("reference_count_ = %u\n")
+ ACE_LIB_TEXT ("---------------------------\n"),
+ this->type_,
+ this->cur_size_,
+ this->max_size_,
+ this->flags_,
+ this->base_,
+ this->locking_strategy_,
+ this->reference_count_));
+ this->allocator_strategy_->dump ();
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+void
+ACE_Message_Block::dump (void) const
+{
+ ACE_TRACE ("ACE_Message_Block::dump");
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_LIB_TEXT ("-----( Message Block )-----\n")
+ ACE_LIB_TEXT ("priority_ = %d\n")
+ ACE_LIB_TEXT ("next_ = %u\n")
+ ACE_LIB_TEXT ("prev_ = %u\n")
+ ACE_LIB_TEXT ("cont_ = %u\n")
+ ACE_LIB_TEXT ("rd_ptr_ = %u\n")
+ ACE_LIB_TEXT ("wr_ptr_ = %u\n")
+ ACE_LIB_TEXT ("---------------------------\n"),
+ this->priority_,
+ this->next_,
+ this->prev_,
+ this->cont_,
+ this->rd_ptr_,
+ this->wr_ptr_));
+ this->data_block ()->dump ();
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+int
+ACE_Data_Block::size (size_t length)
+{
+ ACE_TRACE ("ACE_Data_Block::size");
+
+ if (length <= this->max_size_)
+ this->cur_size_ = length;
+ else
+ {
+ // We need to resize!
+ char *buf;
+ ACE_ALLOCATOR_RETURN (buf,
+ (char *) this->allocator_strategy_->malloc (length),
+ -1);
+
+ ACE_OS::memcpy (buf,
+ this->base_,
+ this->cur_size_);
+ if (ACE_BIT_DISABLED (this->flags_,
+ ACE_Message_Block::DONT_DELETE))
+ this->allocator_strategy_->free ((void *) this->base_);
+ else
+ // We now assume ownership.
+ ACE_CLR_BITS (this->flags_,
+ ACE_Message_Block::DONT_DELETE);
+ this->max_size_ = length;
+ this->cur_size_ = length;
+ this->base_ = buf;
+ }
+ return 0;
+}
+
+int
+ACE_Message_Block::size (size_t length)
+{
+ ACE_TRACE ("ACE_Message_Block::size");
+
+ // Resize the underlying <ACE_Data_Block>.
+ if (this->data_block ()->size (length) == -1)
+ return -1;
+
+ return 0;
+}
+
+size_t
+ACE_Message_Block::total_size (void) const
+{
+ ACE_TRACE ("ACE_Message_Block::total_size");
+
+ size_t size = 0;
+
+ for (const ACE_Message_Block *i = this;
+ i != 0;
+ i = i->cont ())
+ size += i->size ();
+
+ return size;
+}
+
+size_t
+ACE_Message_Block::total_length (void) const
+{
+ ACE_TRACE ("ACE_Message_Block::total_length");
+
+ size_t length = 0;
+ for (const ACE_Message_Block *i = this;
+ i != 0;
+ i = i->cont ())
+ length += i->length ();
+
+ return length;
+}
+
+size_t
+ACE_Message_Block::total_capacity (void) const
+{
+ ACE_TRACE ("ACE_Message_Block::total_capacity");
+
+ size_t size = 0;
+
+ for (const ACE_Message_Block *i = this;
+ i != 0;
+ i = i->cont ())
+ size += i->capacity ();
+
+ return size;
+}
+
+ACE_Data_Block::ACE_Data_Block (void)
+ : type_ (ACE_Message_Block::MB_DATA),
+ cur_size_ (0),
+ max_size_ (0),
+ flags_ (ACE_Message_Block::DONT_DELETE),
+ base_ (0),
+ allocator_strategy_ (0),
+ locking_strategy_ (0),
+ reference_count_ (1),
+ data_block_allocator_ (0)
+{
+ ACE_TRACE ("ACE_Data_Block::ACE_Data_Block");
+ ACE_FUNCTION_TIMEPROBE (ACE_DATA_BLOCK_CTOR1_ENTER);
+
+ ACE_ALLOCATOR (this->allocator_strategy_,
+ ACE_Allocator::instance ());
+
+ ACE_ALLOCATOR (this->data_block_allocator_,
+ ACE_Allocator::instance ());
+}
+
+ACE_Data_Block::ACE_Data_Block (size_t size,
+ ACE_Message_Block::ACE_Message_Type msg_type,
+ const char *msg_data,
+ ACE_Allocator *allocator_strategy,
+ ACE_Lock *locking_strategy,
+ ACE_Message_Block::Message_Flags flags,
+ ACE_Allocator *data_block_allocator)
+ : type_ (msg_type),
+ cur_size_ (size),
+ max_size_ (size),
+ flags_ (flags),
+ base_ ((char *) msg_data),
+ allocator_strategy_ (allocator_strategy),
+ locking_strategy_ (locking_strategy),
+ reference_count_ (1),
+ data_block_allocator_ (data_block_allocator)
+{
+ ACE_TRACE ("ACE_Data_Block::ACE_Data_Block");
+ ACE_FUNCTION_TIMEPROBE (ACE_DATA_BLOCK_CTOR2_ENTER);
+
+ // If the user didn't pass one in, let's use the
+ // <ACE_Allocator::instance>.
+ if (this->allocator_strategy_ == 0)
+ ACE_ALLOCATOR (this->allocator_strategy_,
+ ACE_Allocator::instance ());
+
+ if (this->data_block_allocator_ == 0)
+ ACE_ALLOCATOR (this->data_block_allocator_,
+ ACE_Allocator::instance ());
+
+ if (msg_data == 0)
+ ACE_ALLOCATOR (this->base_,
+ (char *) this->allocator_strategy_->malloc (size));
+ else
+ this->base_ = (char *) msg_data;
+}
+
+ACE_Message_Block::ACE_Message_Block (const char *data,
+ size_t size,
+ u_long priority)
+ : flags_ (0),
+ data_block_ (0)
+{
+ ACE_TRACE ("ACE_Message_Block::ACE_Message_Block");
+
+ if (this->init_i (size, // size
+ MB_DATA, // type
+ 0, // cont
+ data, // data
+ 0, // allocator
+ 0, // locking strategy
+ ACE_Message_Block::DONT_DELETE, // flags
+ priority, // priority
+ ACE_Time_Value::zero, // execution time
+ ACE_Time_Value::max_time, // absolute time of deadline
+ 0, // data block
+ 0, // data_block allocator
+ 0) == -1) // message_block allocator
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("ACE_Message_Block")));
+}
+
+ACE_Message_Block::ACE_Message_Block (ACE_Allocator *message_block_allocator)
+ : flags_ (0),
+ data_block_ (0)
+{
+ ACE_TRACE ("ACE_Message_Block::ACE_Message_Block");
+
+ if (this->init_i (0, // size
+ MB_DATA, // type
+ 0, // cont
+ 0, // data
+ 0, // allocator
+ 0, // locking strategy
+ ACE_Message_Block::DONT_DELETE, // flags
+ 0, // priority
+ ACE_Time_Value::zero, // execution time
+ ACE_Time_Value::max_time, // absolute time of deadline
+ 0, // data block
+ 0, // data_block allocator
+ message_block_allocator) == -1) // message_block allocator
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("ACE_Message_Block")));
+}
+
+ACE_Message_Block::ACE_Message_Block (size_t size,
+ ACE_Message_Type msg_type,
+ ACE_Message_Block *msg_cont,
+ const char *msg_data,
+ ACE_Allocator *allocator_strategy,
+ ACE_Lock *locking_strategy,
+ u_long priority,
+ const ACE_Time_Value &execution_time,
+ const ACE_Time_Value &deadline_time,
+ ACE_Allocator *data_block_allocator,
+ ACE_Allocator *message_block_allocator)
+ :flags_ (0),
+ data_block_ (0)
+{
+ ACE_TRACE ("ACE_Message_Block::ACE_Message_Block");
+
+ if (this->init_i (size,
+ msg_type,
+ msg_cont,
+ msg_data,
+ allocator_strategy,
+ locking_strategy,
+ msg_data ? ACE_Message_Block::DONT_DELETE : 0,
+ priority,
+ execution_time,
+ deadline_time,
+ 0, // data block
+ data_block_allocator,
+ message_block_allocator) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("ACE_Message_Block")));
+}
+
+int
+ACE_Message_Block::init (size_t size,
+ ACE_Message_Type msg_type,
+ ACE_Message_Block *msg_cont,
+ const char *msg_data,
+ ACE_Allocator *allocator_strategy,
+ ACE_Lock *locking_strategy,
+ u_long priority,
+ const ACE_Time_Value &execution_time,
+ const ACE_Time_Value &deadline_time,
+ ACE_Allocator *data_block_allocator,
+ ACE_Allocator *message_block_allocator)
+{
+ ACE_TRACE ("ACE_Message_Block::init");
+
+ return this->init_i (size,
+ msg_type,
+ msg_cont,
+ msg_data,
+ allocator_strategy,
+ locking_strategy,
+ msg_data ? ACE_Message_Block::DONT_DELETE : 0,
+ priority,
+ execution_time,
+ deadline_time,
+ 0, // data block
+ data_block_allocator,
+ message_block_allocator);
+}
+
+int
+ACE_Message_Block::init (const char *data,
+ size_t size)
+{
+ ACE_TRACE ("ACE_Message_Block::init");
+ // Should we also initialize all the other fields, as well?
+
+ return this->init_i (size, // size
+ MB_DATA, // type
+ 0, // cont
+ data, // data
+ 0, // allocator
+ 0, // locking strategy
+ ACE_Message_Block::DONT_DELETE, // flags
+ 0, // priority
+ ACE_Time_Value::zero, // execution time
+ ACE_Time_Value::max_time, // absolute time of deadline
+ 0, // data block
+ 0, // data_block allocator
+ 0); // message_block allocator
+}
+
+ACE_Message_Block::ACE_Message_Block (size_t size,
+ ACE_Message_Type msg_type,
+ ACE_Message_Block *msg_cont,
+ const char *msg_data,
+ ACE_Allocator *allocator_strategy,
+ ACE_Lock *locking_strategy,
+ Message_Flags flags,
+ u_long priority,
+ const ACE_Time_Value &execution_time,
+ const ACE_Time_Value &deadline_time,
+ ACE_Data_Block *db,
+ ACE_Allocator *data_block_allocator,
+ ACE_Allocator *message_block_allocator)
+ : flags_ (0),
+ data_block_ (0)
+{
+ ACE_TRACE ("ACE_Message_Block::ACE_Message_Block");
+
+ if (this->init_i (size,
+ msg_type,
+ msg_cont,
+ msg_data,
+ allocator_strategy,
+ locking_strategy,
+ flags,
+ priority,
+ execution_time,
+ deadline_time,
+ db,
+ data_block_allocator,
+ message_block_allocator) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("ACE_Message_Block")));
+}
+
+ACE_Message_Block::ACE_Message_Block (ACE_Data_Block *data_block,
+ ACE_Message_Block::Message_Flags flags,
+ ACE_Allocator *message_block_allocator)
+ : flags_ (flags),
+ data_block_ (0)
+{
+ ACE_TRACE ("ACE_Message_Block::ACE_Message_Block");
+
+ if (this->init_i (0, // size
+ MB_NORMAL, // type
+ 0, // cont
+ 0, // data
+ 0, // allocator
+ 0, // locking strategy
+ 0, // flags
+ 0, // priority
+ ACE_Time_Value::zero, // execution time
+ ACE_Time_Value::max_time, // absolute time of deadline
+ data_block, // data block
+ data_block->data_block_allocator (),
+ message_block_allocator) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("ACE_Message_Block")));
+}
+
+ACE_Message_Block::ACE_Message_Block (const ACE_Message_Block &mb,
+ size_t align)
+ :flags_ (0),
+ data_block_ (0)
+{
+ ACE_TRACE ("ACE_Message_Block::ACE_Message_Block");
+
+ if (ACE_BIT_DISABLED (mb.flags_,
+ ACE_Message_Block::DONT_DELETE))
+ {
+ if (this->init_i (0, // size
+ MB_NORMAL, // type
+ 0, // cont
+ 0, // data
+ 0, // allocator
+ 0, // locking strategy
+ 0, // flags
+ 0, // priority
+ ACE_Time_Value::zero, // execution time
+ ACE_Time_Value::max_time, // absolute time of deadline
+ mb.data_block ()->duplicate (), // data block
+ mb.data_block ()->data_block_allocator (),
+ mb.message_block_allocator_) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("ACE_Message_Block")));
+
+ // Align ourselves
+ char *start = ACE_ptr_align_binary (this->base (),
+ align);
+ // Set our rd & wr pointers
+ this->rd_ptr (start);
+ this->wr_ptr (start);
+
+ }
+ else
+ {
+ if (this->init_i (0, // size
+ MB_NORMAL, // type
+ 0, // cont
+ 0, // data
+ 0, // allocator
+ 0, // locking strategy
+ 0, // flags
+ 0, // priority
+ ACE_Time_Value::zero, // execution time
+ ACE_Time_Value::max_time, // absolute time of deadline
+ mb.data_block ()->clone_nocopy (),// data block
+ mb.data_block ()->data_block_allocator (),
+ mb.message_block_allocator_) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("ACE_Message_Block")));
+
+ // Align ourselves
+ char *start = ACE_ptr_align_binary (this->base (),
+ align);
+ // Set our rd & wr pointers
+ this->rd_ptr (start);
+ this->wr_ptr (start);
+
+ // Get the alignment offset of the incoming ACE_Message_Block
+ start = ACE_ptr_align_binary (mb.base (),
+ align);
+
+
+ // Actual offset for the incoming message block assuming that it
+ // is also aligned to the same "align" byte
+ size_t wr_offset = mb.wr_ptr_ - (start - mb.base ());
+
+ // Copy wr_offset amount of data in to <this->data_block>
+ (void) ACE_OS::memcpy (this->wr_ptr (),
+ start,
+ wr_offset);
+
+ // Dont move the write pointer, just leave it to the application
+ // to do what it wants
+
+ }
+
+
+
+
+}
+
+int
+ACE_Message_Block::init_i (size_t size,
+ ACE_Message_Type msg_type,
+ ACE_Message_Block *msg_cont,
+ const char *msg_data,
+ ACE_Allocator *allocator_strategy,
+ ACE_Lock *locking_strategy,
+ Message_Flags flags,
+ u_long priority,
+ const ACE_Time_Value &execution_time,
+ const ACE_Time_Value &deadline_time,
+ ACE_Data_Block *db,
+ ACE_Allocator *data_block_allocator,
+ ACE_Allocator *message_block_allocator)
+{
+ ACE_TRACE ("ACE_Message_Block::init_i");
+ ACE_FUNCTION_TIMEPROBE (ACE_MESSAGE_BLOCK_INIT_I_ENTER);
+
+ this->rd_ptr_ = 0;
+ this->wr_ptr_ = 0;
+ this->priority_ = priority;
+#if defined (ACE_HAS_TIMED_MESSAGE_BLOCKS)
+ this->execution_time_ = execution_time;
+ this->deadline_time_ = deadline_time;
+#else
+ ACE_UNUSED_ARG (execution_time);
+ ACE_UNUSED_ARG (deadline_time);
+#endif /* ACE_HAS_TIMED_MESSAGE_BLOCKS */
+ this->cont_ = msg_cont;
+ this->next_ = 0;
+ this->prev_ = 0;
+
+ this->message_block_allocator_ = message_block_allocator;
+
+ if (this->data_block_ != 0)
+ {
+ this->data_block_->release ();
+ this->data_block_ = 0;
+ }
+
+ if (db == 0)
+ {
+ if (data_block_allocator == 0)
+ ACE_ALLOCATOR_RETURN (data_block_allocator,
+ ACE_Allocator::instance (),
+ -1);
+
+ ACE_TIMEPROBE (ACE_MESSAGE_BLOCK_INIT_I_DB_ALLOC);
+
+ // Allocate the <ACE_Data_Block> portion, which is reference
+ // counted.
+ ACE_NEW_MALLOC_RETURN (db,
+ ACE_static_cast(ACE_Data_Block *,
+ data_block_allocator->malloc (sizeof (ACE_Data_Block))),
+ ACE_Data_Block (size,
+ msg_type,
+ msg_data,
+ allocator_strategy,
+ locking_strategy,
+ flags,
+ data_block_allocator),
+ -1);
+ ACE_TIMEPROBE (ACE_MESSAGE_BLOCK_INIT_I_DB_CTOR);
+ }
+
+ // Reset the data_block_ pointer.
+ this->data_block (db);
+ return 0;
+}
+
+ACE_Data_Block::~ACE_Data_Block (void)
+{
+ // Sanity check...
+ ACE_ASSERT (this->reference_count_ <= 1);
+
+ // Just to be safe...
+ this->reference_count_ = 0;
+
+ if (ACE_BIT_DISABLED (this->flags_,
+ ACE_Message_Block::DONT_DELETE))
+ {
+ this->allocator_strategy_->free ((void *) this->base_);
+ this->base_ = 0;
+ }
+}
+
+ACE_Data_Block *
+ACE_Data_Block::release_i (void)
+{
+ ACE_TRACE ("ACE_Data_Block::release_i");
+
+ ACE_ASSERT (this->reference_count_ > 0);
+
+ ACE_Data_Block *result = 0;
+
+ // decrement reference count
+ this->reference_count_--;
+
+ if (this->reference_count_ == 0)
+ // this will cause deletion of this
+ result = 0;
+ else
+ result = this;
+
+ return result;
+}
+
+ACE_Data_Block *
+ACE_Data_Block::release_no_delete (ACE_Lock *lock)
+{
+ ACE_TRACE ("ACE_Data_Block::release_no_delete");
+
+ ACE_Data_Block *result = 0;
+ ACE_Lock *lock_to_be_used = 0;
+
+ // Check if we were passed in a lock
+ if (lock != 0)
+ {
+ // Make sure that the lock passed in and our lock are the same
+ if (lock == this->locking_strategy_)
+ // In this case no locking is required.
+ lock_to_be_used = 0;
+
+ // The lock passed in does not match our lock
+ else
+ // Lock to be used is our lock
+ lock_to_be_used = this->locking_strategy_;
+ }
+ // This is the case when no lock was passed in
+ else
+ // Lock to be used is our lock
+ lock_to_be_used = this->locking_strategy_;
+
+ // If there's a locking strategy then we need to acquire the lock
+ // before decrementing the count.
+ if (lock_to_be_used != 0)
+ {
+ ACE_GUARD_RETURN (ACE_Lock, ace_mon, *lock_to_be_used, 0);
+
+ result = this->release_i ();
+ }
+ else
+ result = this->release_i ();
+
+ return result;
+}
+
+ACE_Data_Block *
+ACE_Data_Block::release (ACE_Lock *lock)
+{
+ ACE_TRACE ("ACE_Data_Block::release");
+
+ ACE_Allocator *allocator = this->data_block_allocator_;
+
+ ACE_Data_Block *result = this->release_no_delete (lock);
+
+ // We must delete this outside the scope of the locking_strategy_
+ // since otherwise we'd be trying to "release" through a deleted
+ // pointer!
+ if (result == 0)
+ ACE_DES_FREE (this,
+ allocator->free,
+ ACE_Data_Block);
+ return result;
+}
+
+ACE_Message_Block *
+ACE_Message_Block::release (void)
+{
+ ACE_TRACE ("ACE_Message_Block::release");
+
+ // We want to hold the data block in a temporary variable because we
+ // invoked "delete this;" at some point, so using this->data_block_
+ // could be a bad idea.
+ ACE_Data_Block *tmp = this->data_block ();
+
+ // This flag is set to 1 when we have to destroy the data_block
+ int destroy_dblock = 0;
+
+ ACE_Lock *lock = 0;
+
+ // Do we have a valid data block
+ if (this->data_block ())
+ {
+ // Grab the lock that belongs to my data block
+ lock = this->data_block ()->locking_strategy ();
+
+ // if we have a lock
+ if (lock != 0)
+ {
+ // One guard for all
+ ACE_GUARD_RETURN (ACE_Lock, ace_mon, *lock, 0);
+
+ // Call non-guarded release with <lock>
+ destroy_dblock = this->release_i (lock);
+ }
+ // This is the case when we have a valid data block but no lock
+ else
+ // Call non-guarded release with no lock
+ destroy_dblock = this->release_i (0);
+ }
+ else
+ // This is the case when we don't even have a valid data block
+ destroy_dblock = this->release_i (0);
+
+ if (destroy_dblock != 0)
+ {
+ ACE_Allocator *allocator = tmp->data_block_allocator ();
+ ACE_DES_FREE (tmp,
+ allocator->free,
+ ACE_Data_Block);
+ }
+
+ return 0;
+}
+
+int
+ACE_Message_Block::release_i (ACE_Lock *lock)
+{
+ ACE_TRACE ("ACE_Message_Block::release_i");
+
+ // Free up all the continuation messages.
+ if (this->cont_)
+ {
+ ACE_Message_Block *mb = this->cont_;
+ ACE_Message_Block *tmp;
+
+ do
+ {
+ tmp = mb;
+ mb = mb->cont_;
+ tmp->cont_ = 0;
+
+ ACE_Data_Block *db = tmp->data_block ();
+ if (tmp->release_i (lock) != 0)
+ {
+ ACE_Allocator *allocator = db->data_block_allocator ();
+ ACE_DES_FREE (db,
+ allocator->free,
+ ACE_Data_Block);
+ }
+ }
+ while (mb);
+
+ this->cont_ = 0;
+ }
+
+ int result = 0;
+
+ if (ACE_BIT_DISABLED (this->flags_,
+ ACE_Message_Block::DONT_DELETE) &&
+ this->data_block ())
+ {
+ if (this->data_block ()->release_no_delete (lock) == 0)
+ result = 1;
+ this->data_block_ = 0;
+ }
+
+ // We will now commit suicide: this object *must* have come from the
+ // allocator given.
+ if (this->message_block_allocator_ == 0)
+ delete this;
+ else
+ {
+ ACE_Allocator *allocator = this->message_block_allocator_;
+ ACE_DES_FREE (this,
+ allocator->free,
+ ACE_Message_Block);
+ }
+
+ return result;
+}
+
+/* static */ ACE_Message_Block *
+ACE_Message_Block::release (ACE_Message_Block *mb)
+{
+ ACE_TRACE ("ACE_Message_Block::release");
+
+ if (mb != 0)
+ return mb->release ();
+ else
+ return 0;
+}
+
+ACE_Message_Block::~ACE_Message_Block (void)
+{
+ ACE_TRACE ("ACE_Message_Block::~ACE_Message_Block");
+
+ if (ACE_BIT_DISABLED (this->flags_,
+ ACE_Message_Block::DONT_DELETE)&&
+ this->data_block ())
+ this->data_block ()->release ();
+
+ this->prev_ = 0;
+ this->next_ = 0;
+}
+
+ACE_Data_Block *
+ACE_Data_Block::duplicate (void)
+{
+ ACE_TRACE ("ACE_Data_Block::duplicate");
+
+ // Create a new <ACE_Message_Block>, but share the <base_> pointer
+ // data (i.e., don't copy that).
+ if (this->locking_strategy_)
+ {
+ // We need to acquire the lock before incrementing the count.
+ ACE_GUARD_RETURN (ACE_Lock, ace_mon, *this->locking_strategy_, 0);
+ this->reference_count_++;
+ }
+ else
+ this->reference_count_++;
+
+ return this;
+}
+
+#if defined (ACE_HAS_TIMED_MESSAGE_BLOCKS)
+#define ACE_EXECUTION_TIME this->execution_time_
+#define ACE_DEADLINE_TIME this->deadline_time_
+#else
+#define ACE_EXECUTION_TIME ACE_Time_Value::zero
+#define ACE_DEADLINE_TIME ACE_Time_Value::max_time
+#endif /* ACE_HAS_TIMED_MESSAGE_BLOCKS */
+
+ACE_Message_Block *
+ACE_Message_Block::duplicate (void) const
+{
+ ACE_TRACE ("ACE_Message_Block::duplicate");
+
+ ACE_Message_Block *nb;
+
+ // Create a new <ACE_Message_Block> that contains unique copies of
+ // the message block fields, but a reference counted duplicate of
+ // the <ACE_Data_Block>.
+
+ // If there is no allocator, use the standard new and delete calls.
+ if (this->message_block_allocator_ == 0)
+ ACE_NEW_RETURN (nb,
+ ACE_Message_Block (0, // size
+ ACE_Message_Type (0), // type
+ 0, // cont
+ 0, // data
+ 0, // allocator
+ 0, // locking strategy
+ 0, // flags
+ this->priority_, // priority
+ ACE_EXECUTION_TIME,
+ ACE_DEADLINE_TIME,
+ // Get a pointer to a
+ // "duplicated" <ACE_Data_Block>
+ // (will simply increment the
+ // reference count).
+ this->data_block ()->duplicate (),
+ this->data_block ()->data_block_allocator (),
+ this->message_block_allocator_),
+ 0);
+ else // Otherwise, use the message_block_allocator passed in.
+ ACE_NEW_MALLOC_RETURN (nb,
+ ACE_static_cast(ACE_Message_Block*,
+ message_block_allocator_->malloc (sizeof (ACE_Message_Block))),
+ ACE_Message_Block (0, // size
+ ACE_Message_Type (0), // type
+ 0, // cont
+ 0, // data
+ 0, // allocator
+ 0, // locking strategy
+ 0, // flags
+ this->priority_, // priority
+ ACE_EXECUTION_TIME,
+ ACE_DEADLINE_TIME,
+ // Get a pointer to a
+ // "duplicated" <ACE_Data_Block>
+ // (will simply increment the
+ // reference count).
+ this->data_block ()->duplicate (),
+ this->data_block ()->data_block_allocator (),
+ this->message_block_allocator_),
+ 0);
+
+ // Set the read and write pointers in the new <Message_Block> to the
+ // same relative offset as in the existing <Message_Block>. Note
+ // that we are assuming that the data_block()->base() pointer
+ // doesn't change when it's duplicated.
+ nb->rd_ptr (this->rd_ptr_);
+ nb->wr_ptr (this->wr_ptr_);
+
+ // Increment the reference counts of all the continuation messages.
+ if (this->cont_)
+ {
+ nb->cont_ = this->cont_->duplicate ();
+
+ // If things go wrong, release all of our resources and return
+ // 0.
+ if (nb->cont_ == 0)
+ {
+ nb->release ();
+ nb = 0;
+ }
+ }
+
+ return nb;
+}
+
+ACE_Message_Block *
+ACE_Message_Block::duplicate (const ACE_Message_Block *mb)
+{
+ ACE_TRACE ("ACE_Message_Block::duplicate");
+ if (mb == 0)
+ return 0;
+ else
+ return mb->duplicate ();
+}
+
+ACE_Data_Block *
+ACE_Data_Block::clone (ACE_Message_Block::Message_Flags mask) const
+{
+ ACE_TRACE ("ACE_Data_Block::clone");
+
+ ACE_Data_Block *nb = this->clone_nocopy (mask);
+
+ // Copy all of the payload memory into the new object.
+ if (nb != 0)
+ {
+ ACE_OS::memcpy (nb->base_,
+ this->base_,
+ this->max_size_);
+ }
+
+ return nb;
+}
+
+ACE_Data_Block *
+ACE_Data_Block::clone_nocopy (ACE_Message_Block::Message_Flags mask) const
+{
+ ACE_FUNCTION_TIMEPROBE(ACE_DATA_BLOCK_CLONE_ENTER);
+
+ ACE_TRACE ("ACE_Data_Block::clone_nocopy");
+
+ // You always want to clear this one to prevent memory leaks but you
+ // might add some others later.
+ const ACE_Message_Block::Message_Flags always_clear =
+ ACE_Message_Block::DONT_DELETE;
+
+ ACE_Data_Block *nb;
+
+ ACE_NEW_MALLOC_RETURN (nb,
+ ACE_static_cast(ACE_Data_Block*,
+ this->data_block_allocator_->malloc (sizeof (ACE_Data_Block))),
+ ACE_Data_Block (this->max_size_, // size
+ this->type_, // type
+ 0, // data
+ this->allocator_strategy_, // allocator
+ this->locking_strategy_, // locking strategy
+ this->flags_, // flags
+ this->data_block_allocator_),
+ 0);
+
+
+ // Set new flags minus the mask...
+ nb->clr_flags (mask | always_clear);
+ return nb;
+}
+
+ACE_Message_Block *
+ACE_Message_Block::clone (Message_Flags mask) const
+{
+ ACE_TRACE ("ACE_Message_Block::clone");
+
+ // Get a pointer to a "cloned" <ACE_Data_Block> (will copy the
+ // values rather than increment the reference count).
+ ACE_Data_Block *db = this->data_block ()->clone (mask);
+
+ if (db == 0)
+ return 0;
+
+ ACE_Message_Block *nb;
+
+ if(message_block_allocator_ == 0)
+ {
+ ACE_NEW_RETURN (nb,
+ ACE_Message_Block (0, // size
+ ACE_Message_Type (0), // type
+ 0, // cont
+ 0, // data
+ 0, // allocator
+ 0, // locking strategy
+ 0, // flags
+ this->priority_, // priority
+ ACE_EXECUTION_TIME, // execution time
+ ACE_DEADLINE_TIME, // absolute time to deadline
+ // Get a pointer to a
+ // "duplicated" <ACE_Data_Block>
+ // (will simply increment the
+ // reference count).
+ db,
+ db->data_block_allocator (),
+ this->message_block_allocator_),
+ 0);
+ }
+ else
+ {
+ // This is the ACE_NEW_MALLOC macro with the return check removed.
+ // We need to do it this way because if it fails we need to release
+ // the cloned data block that was created above. If we used
+ // ACE_NEW_MALLOC_RETURN, there would be a memory leak because the
+ // above db pointer would be left dangling.
+ nb = ACE_static_cast(ACE_Message_Block*,message_block_allocator_->malloc (sizeof (ACE_Message_Block)));
+ if(nb != 0)
+ new (nb) ACE_Message_Block (0, // size
+ ACE_Message_Type (0), // type
+ 0, // cont
+ 0, // data
+ 0, // allocator
+ 0, // locking strategy
+ 0, // flags
+ this->priority_, // priority
+ ACE_EXECUTION_TIME, // execution time
+ ACE_DEADLINE_TIME, // absolute time to deadline
+ db,
+ db->data_block_allocator (),
+ this->message_block_allocator_);
+ }
+
+ if (nb == 0)
+ {
+ db->release ();
+ return 0;
+ }
+
+ // Set the read and write pointers in the new <Message_Block> to the
+ // same relative offset as in the existing <Message_Block>.
+ nb->rd_ptr (this->rd_ptr_);
+ nb->wr_ptr (this->wr_ptr_);
+
+ // Clone all the continuation messages if necessary.
+ if (this->cont () != 0
+ && (nb->cont_ = this->cont ()->clone (mask)) == 0)
+ {
+ nb->release ();
+ return 0;
+ }
+ return nb;
+}
+
+// This is private.
+ACE_Message_Block &
+ACE_Message_Block::operator= (const ACE_Message_Block &)
+{
+ ACE_TRACE ("ACE_Message_Block::operator=");
+ return *this;
+}
+
+void
+ACE_Data_Block::base (char *msg_data,
+ size_t msg_length,
+ ACE_Message_Block::Message_Flags msg_flags)
+{
+ if (ACE_BIT_DISABLED (this->flags_,
+ ACE_Message_Block::DONT_DELETE))
+ this->allocator_strategy_->free (this->base_);
+ this->max_size_ = msg_length;
+ this->cur_size_ = msg_length;
+ this->base_ = msg_data;
+ this->flags_ = msg_flags;
+}
+
+// ctor
+
+ACE_Dynamic_Message_Strategy::ACE_Dynamic_Message_Strategy (u_long static_bit_field_mask,
+ u_long static_bit_field_shift,
+ u_long dynamic_priority_max,
+ u_long dynamic_priority_offset)
+ : static_bit_field_mask_ (static_bit_field_mask),
+ static_bit_field_shift_ (static_bit_field_shift),
+ dynamic_priority_max_ (dynamic_priority_max),
+ dynamic_priority_offset_ (dynamic_priority_offset),
+ max_late_ (0, dynamic_priority_offset - 1),
+ min_pending_ (0, dynamic_priority_offset),
+ pending_shift_ (0, dynamic_priority_max)
+{
+}
+
+// dtor
+
+ACE_Dynamic_Message_Strategy::~ACE_Dynamic_Message_Strategy (void)
+{
+}
+
+// Dump the state of the strategy.
+
+void
+ACE_Dynamic_Message_Strategy::dump (void) const
+{
+ ACE_TRACE ("ACE_Dynamic_Message_Strategy::dump");
+
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_LIB_TEXT ("static_bit_field_mask_ = %u\n")
+ ACE_LIB_TEXT ("static_bit_field_shift_ = %u\n")
+ ACE_LIB_TEXT ("dynamic_priority_max_ = %u\n")
+ ACE_LIB_TEXT ("dynamic_priority_offset_ = %u\n")
+ ACE_LIB_TEXT ("max_late_ = [%d sec, %d usec]\n")
+ ACE_LIB_TEXT ("min_pending_ = [%d sec, %d usec]\n")
+ ACE_LIB_TEXT ("pending_shift_ = [%d sec, %d usec]\n"),
+ this->static_bit_field_mask_,
+ this->static_bit_field_shift_,
+ this->dynamic_priority_max_,
+ this->dynamic_priority_offset_,
+ this->max_late_.sec (),
+ this->max_late_.usec (),
+ this->min_pending_.sec (),
+ this->min_pending_.usec (),
+ this->pending_shift_.sec (),
+ this->pending_shift_.usec ()));
+
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+ACE_Deadline_Message_Strategy:: ACE_Deadline_Message_Strategy (u_long static_bit_field_mask,
+ u_long static_bit_field_shift,
+ u_long dynamic_priority_max,
+ u_long dynamic_priority_offset)
+ : ACE_Dynamic_Message_Strategy (static_bit_field_mask,
+ static_bit_field_shift,
+ dynamic_priority_max,
+ dynamic_priority_offset)
+{
+}
+
+ACE_Deadline_Message_Strategy::~ACE_Deadline_Message_Strategy (void)
+{
+}
+
+void
+ACE_Deadline_Message_Strategy::dump (void) const
+{
+ ACE_TRACE ("ACE_Deadline_Message_Strategy::dump");
+
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("ACE_Dynamic_Message_Strategy base class: \n")));
+ this->ACE_Dynamic_Message_Strategy::dump ();
+
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\nderived class: ACE_Deadline_Message_Strategy\n")));
+
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+ACE_Laxity_Message_Strategy::ACE_Laxity_Message_Strategy (u_long static_bit_field_mask,
+ u_long static_bit_field_shift,
+ u_long dynamic_priority_max,
+ u_long dynamic_priority_offset)
+ : ACE_Dynamic_Message_Strategy (static_bit_field_mask,
+ static_bit_field_shift,
+ dynamic_priority_max,
+ dynamic_priority_offset)
+{
+}
+
+ACE_Laxity_Message_Strategy::~ACE_Laxity_Message_Strategy (void)
+{
+}
+
+void
+ACE_Laxity_Message_Strategy::dump (void) const
+{
+ ACE_TRACE ("ACE_Laxity_Message_Strategy::dump");
+
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("ACE_Dynamic_Message_Strategy base class: \n")));
+ this->ACE_Dynamic_Message_Strategy::dump ();
+
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\nderived class: ACE_Laxity_Message_Strategy\n")));
+
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+ // Dump the state of the strategy.
+
+#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION)
+template class ACE_Guard <ACE_Lock>;
+// These specializations aren't needed for the ACE library because
+// Service_Config.cpp has them:
+//
+// template class ACE_Malloc <ACE_LOCAL_MEMORY_POOL, ACE_Null_Mutex>;
+// template class ACE_Allocator_Adapter <ACE_Malloc <ACE_LOCAL_MEMORY_POOL, ACE_Null_Mutex> >;
+#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA)
+#pragma instantiate ACE_Guard <ACE_Lock>
+// These specializations aren't needed for the ACE library because
+// Service_Config.cpp has them:
+//
+// #pragma instantiate ACE_Malloc <ACE_LOCAL_MEMORY_POOL, ACE_Null_Mutex>
+// #pragma instantiate ACE_Allocator_Adapter <ACE_Malloc <ACE_LOCAL_MEMORY_POOL, ACE_Null_Mutex> >
+#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */
diff --git a/ace/Utils/Message_Block.h b/ace/Utils/Message_Block.h
new file mode 100644
index 00000000000..5da92f84636
--- /dev/null
+++ b/ace/Utils/Message_Block.h
@@ -0,0 +1,979 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Message_Block.h
+ *
+ * $Id$
+ *
+ * @author Douglas C. Schmidt <schmidt@cs.wustl.edu>
+ */
+//=============================================================================
+
+#include "ace/ACE.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#ifndef ACE_MESSAGE_BLOCK_H
+#define ACE_MESSAGE_BLOCK_H
+#include "ace/pre.h"
+
+#include "ace/Memory/Malloc.h"
+
+// Forward declaration.
+class ACE_Data_Block;
+class ACE_Lock;
+class ACE_Time_Value;
+
+/**
+ * @class ACE_Message_Block
+ *
+ * @brief Stores messages for use throughout ACE (particularly
+ * <ACE_Message_Queue>).
+ *
+ * An <ACE_Message_Block> is modeled after the message data
+ * structures used in System V STREAMS. Its purpose is to
+ * enable efficient manipulation of arbitrarily-large messages
+ * without incurring much memory copying overhead. Here are the
+ * main characteristics of an <ACE_Message_Block>:
+ * 1. Contains a pointer to a reference-counted
+ * <ACE_Data_Block>, which in turn points to the actual data
+ * buffer. This allows very flexible and efficient sharing of
+ * data by multiple <ACE_Message_Block>s.
+ * 2. One or more <ACE_Message_Blocks> can be linked to form a
+ * ``fragment chain.''
+ * 3. <ACE_Message_Blocks> can be linked together by <prev_> and
+ * <next_> pointers to form a queue of messages (e.g., this is how
+ * <ACE_Message_Queue> works).
+ */
+class ACE_Export ACE_Message_Block
+{
+public:
+ friend class ACE_Data_Block;
+
+ enum
+ {
+ // = Data and proto
+ /// regular datacol messages (regular and priority)
+ MB_DATA = 0x01,
+ /// protocol control
+ MB_PROTO = 0x02,
+
+ // = Control messag
+ /// line breakes (regular and priority)
+ MB_BREAK = 0x03,
+ /// pass file pointer
+ MB_PASSFP = 0x04,
+ /// post an event to an event queue
+ MB_EVENT = 0x05,
+ /// generate process signal
+ MB_SIG = 0x06,
+ /// ioctl; set/get params
+ MB_IOCTL = 0x07,
+ /// set various stream head options
+ MB_SETOPTS = 0x08,
+
+ // = Control messag
+ /// acknowledge ioctles (high priority; go to head of queue)
+ MB_IOCACK = 0x81,
+ /// negative ioctl acknowledge
+ MB_IOCNAK = 0x82,
+ /// priority proto message
+ MB_PCPROTO = 0x83,
+ /// generate process signal
+ MB_PCSIG = 0x84,
+ /// generate read notification
+ MB_READ = 0x85,
+ /// flush your queues
+ MB_FLUSH = 0x86,
+ /// stop transmission immediately
+ MB_STOP = 0x87,
+ /// restart transmission after stop
+ MB_START = 0x88,
+ /// line disconnect
+ MB_HANGUP = 0x89,
+ /// fatal error used to set u.u_error
+ MB_ERROR = 0x8a,
+ /// post an event to an event queue
+ MB_PCEVENT = 0x8b,
+
+ // Message class ma
+ /// Normal priority messagessks
+ MB_NORMAL = 0x00,
+ /// High priority control messages
+ MB_PRIORITY = 0x80,
+ /// User-defined control messages
+ MB_USER = 0x200
+ };
+
+ typedef int ACE_Message_Type;
+ typedef u_long Message_Flags;
+
+ enum
+ {
+ /// Don't delete the data on exit since we don't own it.
+ DONT_DELETE = 01,
+ /// user defined flags start here
+ USER_FLAGS = 0x1000
+ };
+
+ // = Initialization and termination.
+ /// Create an empty message.
+ ACE_Message_Block (ACE_Allocator *message_block_allocator = 0);
+
+ /**
+ * Create an <ACE_Message_Block> that owns the <ACE_Data_Block>
+ * without copying it. If the <flags> is set to DONT_DELETE we
+ * don't delete the ACE_Data_Block. It is left to the client's
+ * responsibility to take care of the memory allocated for the
+ * data_block
+ */
+ ACE_Message_Block (ACE_Data_Block *,
+ Message_Flags flags = 0,
+ ACE_Allocator *message_block_allocator = 0);
+
+ /**
+ * Create a Message Block that assumes ownership of <data> without
+ * copying it (i.e., we don't delete it since we don't malloc it!).
+ * Note that the <size> of the <Message_Block> will be <size>, but
+ * the <length> will be 0 until <wr_ptr> is set.
+ */
+ ACE_Message_Block (const char *data,
+ size_t size = 0,
+ u_long priority = ACE_DEFAULT_MESSAGE_BLOCK_PRIORITY);
+
+ /**
+ * Create an initialized message of type <type> containing <size>
+ * bytes. The <cont> argument initializes the continuation field in
+ * the <Message_Block>. If <data> == 0 then we create and own the
+ * <data>, using <allocator> to get the data if it's non-0. If
+ * <data> != 0 we assume that we have ownership of the <data> till
+ * this object seizes to exist (and don't delete it during
+ * destruction). If <locking_strategy> is non-0 then this is used
+ * to protect regions of code that access shared state (e.g.,
+ * reference counting) from race conditions. Note that the <size>
+ * of the <Message_Block> will be <size>, but the <length> will be 0
+ * until <wr_ptr> is set. The <data_block_allocator> is use to
+ * allocate the data blocks while the <allocator_strategy> is used
+ * to allocate the buffers contained by those. The
+ * <message_block_allocator> is used to allocate new <Message_Block>
+ * objects when a duplicate method is called. If a
+ * <message_block_allocator> is given, this <Message_Block> and
+ * future <Message_Block> objects created by duplicate will be
+ * free'ed into this allocator when they are released. Note: if
+ * you use this allocator, the <Message_Block> you created should
+ * have been created using this allocator because it will be
+ * released to the same allocator.
+ */
+ ACE_Message_Block (size_t size,
+ ACE_Message_Type type = MB_DATA,
+ ACE_Message_Block *cont = 0,
+ const char *data = 0,
+ ACE_Allocator *allocator_strategy = 0,
+ ACE_Lock *locking_strategy = 0,
+ u_long priority = ACE_DEFAULT_MESSAGE_BLOCK_PRIORITY,
+ const ACE_Time_Value &execution_time = ACE_Time_Value::zero,
+ const ACE_Time_Value &deadline_time = ACE_Time_Value::max_time,
+ ACE_Allocator *data_block_allocator = 0,
+ ACE_Allocator *message_block_allocator = 0);
+
+ /**
+ * A copy constructor. This constructor is a bit different. If the
+ * incoming Message Block has a data block from the stack this
+ * constructor does a deep copy ie. allocates a new data block on
+ * the heap and does a copy of the data from the incoming message
+ * block. As a final note, the alignment information is used to
+ * align the data block if it is created afresh. If the incoming
+ * <mb> has a data block has a data block allocated from the heap,
+ * then this constructor just duplicates (ie. a shallow copy) the
+ * data block of the incoming <mb>.
+ */
+ ACE_Message_Block (const ACE_Message_Block &mb,
+ size_t align);
+
+ /**
+ * Create a Message Block that assumes it has ownership of <data>,
+ * but in reality it doesnt (i.e., cannot delete it since it didn't
+ * malloc it!). Note that the <size> of the <Message_Block> will
+ * be <size>, but the <length> will be 0 until <wr_ptr> is set.
+ */
+ int init (const char *data,
+ size_t size = 0);
+
+ /**
+ * Create an initialized message of type <type> containing <size>
+ * bytes. The <cont> argument initializes the continuation field in
+ * the <Message_Block>. If <data> == 0 then we create and own the
+ * <data>, using <allocator> to get the data if it's non-0. If
+ * <data> != 0 we assume that we have ownership of the <data> till
+ * this object seizes to exist (and don't delete it during
+ * destruction). If <locking_strategy> is non-0 then this is used
+ * to protect regions of code that access shared state (e.g.,
+ * reference counting) from race conditions. Note that the <size>
+ * of the <Message_Block> will be <size>, but the <length> will be 0
+ * until <wr_ptr> is set. The <data_block_allocator> is use to
+ * allocate the data blocks while the <allocator_strategy> is used
+ * to allocate the buffers contained by those.
+ */
+ int init (size_t size,
+ ACE_Message_Type type = MB_DATA,
+ ACE_Message_Block *cont = 0,
+ const char *data = 0,
+ ACE_Allocator *allocator_strategy = 0,
+ ACE_Lock *locking_strategy = 0,
+ u_long priority = ACE_DEFAULT_MESSAGE_BLOCK_PRIORITY,
+ const ACE_Time_Value &execution_time = ACE_Time_Value::zero,
+ const ACE_Time_Value &deadline_time = ACE_Time_Value::max_time,
+ ACE_Allocator *data_block_allocator = 0,
+ ACE_Allocator *message_block_allocator = 0);
+
+ /**
+ * Delete all the resources held in the message.
+ *
+ * Note that <release> is designed to release the continuation
+ * chain; the destructor is not. See <release> for details.
+ */
+ virtual ~ACE_Message_Block (void);
+
+ // = Message Type accessors and mutators.
+
+ /// Get type of the message.
+ ACE_Message_Type msg_type (void) const;
+
+ /// Set type of the message.
+ void msg_type (ACE_Message_Type type);
+
+ /// Find out what type of message this is.
+ int is_data_msg (void) const;
+
+ /// Find out what class of message this is (there are two classes,
+ /// <normal> messages and <high-priority> messages).
+ ACE_Message_Type msg_class (void) const;
+
+ // = Message flag accessors and mutators.
+ /// Bitwise-or the <more_flags> into the existing message flags and
+ /// return the new value.
+ Message_Flags set_flags (Message_Flags more_flags);
+
+ /// Clear the message flag bits specified in <less_flags> and return
+ /// the new value.
+ Message_Flags clr_flags (Message_Flags less_flags);
+
+ /// Get the current message flags.
+ Message_Flags flags (void) const;
+
+ // = Data Block flag accessors and mutators.
+ /// Bitwise-or the <more_flags> into the existing message flags and
+ /// return the new value.
+ /* @todo: I think the following set of methods could not be used at
+ * all. May be they are useless. Let us have it so that we dont
+ * mess up memory management of the Message_Block. Somebody correct
+ * me if I am totally totally wrong..
+ */
+ Message_Flags set_self_flags (ACE_Message_Block::Message_Flags more_flags);
+
+ /// Clear the message flag bits specified in <less_flags> and return
+ /// the new value.
+ Message_Flags clr_self_flags (ACE_Message_Block::Message_Flags less_flags);
+
+ /// Get the current message flags.
+ Message_Flags self_flags (void) const;
+
+ /// Get priority of the message.
+ u_long msg_priority (void) const;
+
+ /// Set priority of the message.
+ void msg_priority (u_long priority);
+
+ /// Get execution time associated with the message.
+ const ACE_Time_Value &msg_execution_time (void) const;
+
+ /// Set execution time associated with the message.
+ void msg_execution_time (const ACE_Time_Value &et);
+
+ /// Get absolute time of deadline associated with the message.
+ const ACE_Time_Value &msg_deadline_time (void) const;
+
+ /// Set absolute time of deadline associated with the message.
+ void msg_deadline_time (const ACE_Time_Value &dt);
+
+ // = Deep copy and shallow copy methods.
+
+ /// Return an exact "deep copy" of the message, i.e., create fresh
+ /// new copies of all the Data_Blocks and continuations.
+ virtual ACE_Message_Block *clone (Message_Flags mask = 0) const;
+
+ /// Return a "shallow" copy that increments our reference count by 1.
+ ACE_Message_Block *duplicate (void) const;
+
+
+ /**
+ * Return a "shallow" copy that increments our reference count by 1.
+ * This is similar to CORBA's <_duplicate> method, which is useful
+ * if you want to eliminate lots of checks for NULL <mb> pointers
+ * before calling <_duplicate> on them.
+ */
+ static ACE_Message_Block *duplicate (const ACE_Message_Block *mb);
+
+
+ /**
+ * Decrease the shared ACE_Data_Block's reference count by 1. If the
+ * ACE_Data_Block's reference count goes to 0, it is deleted.
+ * In all cases, this ACE_Message_Block is deleted - it must have come
+ * from the heap, or there will be trouble.
+ *
+ * <release> is designed to release the continuation chain; the
+ * destructor is not. If we make the destructor release the
+ * continuation chain by calling <release> or delete on the message
+ * blocks in the continuation chain, the following code will not
+ * work since the message block in the continuation chain is not off
+ * the heap:
+ *
+ * ACE_Message_Block mb1 (1024);
+ * ACE_Message_Block mb2 (1024);
+ *
+ * mb1.cont (&mb2);
+ *
+ * And hence, call <release> on a dynamically allocated message
+ * block. This will release all the message blocks in the
+ * continuation chain. If you call delete or let the message block
+ * fall off the stack, cleanup of the message blocks in the
+ * continuation chain becomes the responsibility of the user.
+ */
+ ACE_Message_Block *release (void);
+
+ /**
+ * This behaves like the non-static method <release>, except that it
+ * checks if <mb> is 0. This is similar to <CORBA::release>, which
+ * is useful if you want to eliminate lots of checks for NULL
+ * pointers before calling <release> on them. Returns <mb>.
+ */
+ static ACE_Message_Block *release (ACE_Message_Block *mb);
+
+
+ // = Operations on Message data
+
+ /**
+ * Copies <n> bytes from <buf> into the Message_Block starting at
+ * the <wr_ptr> offset. Return 0 and increment <wr_ptr> by <n> if
+ * the method succeeds. Returns -1 if the size of the message is
+ * too small, i.e., for this to work correct, <end> must be >=
+ * <wr_ptr>.
+ */
+ int copy (const char *buf, size_t n);
+
+ /**
+ * Copies <buf> into the Message_Block starting at the <wr_ptr>
+ * offset. This call assumes that <buf> is NUL-terminated. Return
+ * 0 and increment <wr_ptr> by <ACE_OS::strlen (buf) + 1> if the
+ * method succeeds. Returns -1 if the size of the message is too
+ * small, i.e., for this to work correct, <end> must be >= <wr_ptr>.
+ */
+ int copy (const char *buf);
+
+ /// Normalizes data in the top-level <Message_Block> to align with the base,
+ /// i.e., it "shifts" the data pointed to by <rd_ptr> down to the <base> and
+ /// then readjusts <rt_ptr> to point to <base> and <wr_ptr> to point
+ /// to <base> + the length of the moved data.
+ void crunch (void);
+
+ /// Resets the Message Block data to contain nothing, i.e., sets the
+ /// read and write pointers to align with the base.
+ void reset (void);
+
+ /// Get message data.
+ char *base (void) const;
+
+ /// Set message data (doesn't reallocate).
+ void base (char *data,
+ size_t size,
+ Message_Flags = DONT_DELETE);
+
+ /// Return a pointer to 1 past the end of the allocated data in a message.
+ char *end (void) const;
+
+ /**
+ * Return a pointer to 1 past the end of the allotted data in a message.
+ * Allotted data may be less than allocated data if a value smaller than
+ * capacity() to is passed to size().
+ */
+ char *mark (void) const;
+
+ /**
+ * Get the read pointer.
+ * Set the read pointer to <ptr>.
+ * Set the read pointer ahead <n> bytes.
+ */
+ char *rd_ptr (void) const;
+ void rd_ptr (char *ptr);
+ void rd_ptr (size_t n);
+
+ /**
+ * Get the write pointer.
+ * Set the write pointer to <ptr>.
+ * Set the write pointer ahead <n> bytes. This is used to compute
+ * the <length> of a message.
+ */
+ char *wr_ptr (void) const;
+ void wr_ptr (char *ptr);
+ void wr_ptr (size_t n);
+
+ /** @name Message length and size operations
+ *
+ * Message length is (wr_ptr - rd_ptr).
+ *
+ * Message size is capacity of the message, including data outside
+ * the [rd_ptr,wr_ptr] range.
+ */
+ //@{
+ /// Get the length of the message
+ size_t length (void) const;
+
+ /// Set the length of the message
+ void length (size_t n);
+
+ /// Get the length of the <Message_Block>s, including chained
+ /// <Message_Block>s.
+ size_t total_length (void) const;
+
+ /// Get the total number of bytes in all <Message_Block>s, including
+ /// chained <Message_Block>s.
+ size_t total_size (void) const;
+
+ /// Get the number of bytes in the top-level <Message_Block> (i.e.,
+ /// does not consider the bytes in chained <Message_Block>s).
+ size_t size (void) const;
+
+ /**
+ * Set the number of bytes in the top-level <Message_Block>,
+ * reallocating space if necessary. However, the <rd_ptr_> and
+ * <wr_ptr_> remain at the original offsets into the buffer, even if
+ * it is reallocated. Returns 0 if successful, else -1.
+ */
+ int size (size_t length);
+
+ /// Get the number of allocated bytes in all <Message_Block>, including
+ /// chained <Message_Block>s.
+ size_t total_capacity (void) const;
+
+ /// Get the number of allocated bytes in the top-level <Message_Block>.
+ size_t capacity (void) const;
+
+ /// Get the number of bytes available after the <wr_ptr_> in the
+ /// top-level <Message_Block>.
+ size_t space (void) const;
+ //@}
+
+ // = <ACE_Data_Block> methods.
+
+ /**
+ * Get a pointer to the data block. Note that the <ACE_Message_Block>
+ * still references the block; this call does not change the reference
+ * count.
+ */
+ ACE_Data_Block *data_block (void) const;
+
+ /**
+ * Set a new data block pointer. The original <ACE_Data_Block> is released
+ * as a result of this call. If you need to keep the original block, call
+ * <replace_data_block> instead. Upon return, this <ACE_Message_Block>
+ * holds a pointer to the new <ACE_Data_Block>, taking over the reference
+ * you held on it prior to the call.
+ */
+ void data_block (ACE_Data_Block *);
+
+ /// Set a new data block pointer. A pointer to the original <ACE_Data_Block>
+ /// is returned, and not released (as it is with <data_block>).
+ ACE_Data_Block *replace_data_block (ACE_Data_Block*);
+
+ // = The continuation field chains together composite messages.
+ /// Get the continuation field.
+ /// Set the continuation field.
+ ACE_Message_Block *cont (void) const;
+ void cont (ACE_Message_Block *);
+
+ // = Pointer to the <Message_Block> directly ahead in the <ACE_Message_Queue>.
+ /// Get link to next message.
+ /// Set link to next message.
+ ACE_Message_Block *next (void) const;
+ void next (ACE_Message_Block *);
+
+ // = Pointer to the <Message_Block> directly behind in the <ACE_Message_Queue>.
+ /// Get link to prev message.
+ /// Set link to prev message.
+ ACE_Message_Block *prev (void) const;
+ void prev (ACE_Message_Block *);
+
+ // = The locking strategy prevents race conditions.
+ /// Get the locking strategy.
+ /// Set a new locking strategy and return the hold one.
+ ACE_Lock *locking_strategy (void);
+ ACE_Lock *locking_strategy (ACE_Lock *);
+
+ /// Get the current reference count.
+ int reference_count (void) const;
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+protected:
+ // = Internal initialization methods.
+ /// Perform the actual initialization.
+ ACE_Message_Block (size_t size,
+ ACE_Message_Type type,
+ ACE_Message_Block *cont,
+ const char *data,
+ ACE_Allocator *allocator_strategy,
+ ACE_Lock *locking_strategy,
+ Message_Flags flags,
+ u_long priority,
+ const ACE_Time_Value &execution_time,
+ const ACE_Time_Value &deadline_time,
+ ACE_Data_Block *db,
+ ACE_Allocator *data_block_allocator,
+ ACE_Allocator *message_block_allocator);
+
+ /// Internal release implementation
+ /// Returns 1 if the data block has to be destroyed.
+ int release_i (ACE_Lock *lock);
+
+ /// Perform the actual initialization.
+ int init_i (size_t size,
+ ACE_Message_Type type,
+ ACE_Message_Block *cont,
+ const char *data,
+ ACE_Allocator *allocator_strategy,
+ ACE_Lock *locking_strategy,
+ Message_Flags flags,
+ u_long priority,
+ const ACE_Time_Value &execution_time,
+ const ACE_Time_Value &deadline_time,
+ ACE_Data_Block *db,
+ ACE_Allocator *data_block_allocator,
+ ACE_Allocator *message_block_allocator);
+
+ /// Pointer to beginning of next read.
+ size_t rd_ptr_;
+
+ /// Pointer to beginning of next write.
+ size_t wr_ptr_;
+
+ /// Priority of message.
+ u_long priority_;
+
+#if defined (ACE_HAS_TIMED_MESSAGE_BLOCKS)
+ /// execution time associated with the message
+ ACE_Time_Value execution_time_;
+
+ /// absolute deadline time for message
+ ACE_Time_Value deadline_time_;
+#endif /* ACE_HAS_TIMED_MESSAGE_BLOCKS */
+
+ // = Links to other ACE_Message_Block *s.
+ /// Pointer to next message block in the chain.
+ ACE_Message_Block *cont_;
+
+ /// Pointer to next message in the list.
+ ACE_Message_Block *next_;
+
+ /// Pointer to previous message in the list.
+ ACE_Message_Block *prev_;
+
+ /// Misc flags (e.g., DONT_DELETE and USER_FLAGS).
+ ACE_Message_Block::Message_Flags flags_;
+
+ /// Pointer to the reference counted data structure that contains the
+ /// actual memory buffer.
+ ACE_Data_Block *data_block_;
+
+ /// The allocator used to destroy ourselves when release is called
+ /// and create new message blocks on duplicate.
+ ACE_Allocator *message_block_allocator_;
+
+private:
+ // = Disallow these operations for now (use <clone> instead).
+ ACE_Message_Block &operator= (const ACE_Message_Block &);
+ ACE_Message_Block (const ACE_Message_Block &);
+};
+
+/**
+ * @class ACE_Data_Block
+ *
+ * @brief Stores the data payload that is accessed via one or more
+ * <ACE_Message_Block>s.
+ *
+ * This data structure is reference counted to maximize
+ * sharing. It also contains the <locking_strategy_> (which
+ * protects the reference count from race conditions in
+ * concurrent programs) and the <allocation_strategy_> (which
+ * determines what memory pool is used to allocate the memory).
+ */
+class ACE_Export ACE_Data_Block
+{
+public:
+ // = Initialization and termination methods.
+ /// Default "do-nothing" constructor.
+ ACE_Data_Block (void);
+
+ /// Initialize.
+ ACE_Data_Block (size_t size,
+ ACE_Message_Block::ACE_Message_Type msg_type,
+ const char *msg_data,
+ ACE_Allocator *allocator_strategy,
+ ACE_Lock *locking_strategy,
+ ACE_Message_Block::Message_Flags flags,
+ ACE_Allocator *data_block_allocator);
+
+ /// Delete all the resources held in the message.
+ virtual ~ACE_Data_Block (void);
+
+ /// Get type of the message.
+ ACE_Message_Block::ACE_Message_Type msg_type (void) const;
+
+ /// Set type of the message.
+ void msg_type (ACE_Message_Block::ACE_Message_Type type);
+
+ /// Get message data pointer
+ char *base (void) const;
+
+ /// Set message data pointer (doesn't reallocate).
+ void base (char *data,
+ size_t size,
+ ACE_Message_Block::Message_Flags mflags = ACE_Message_Block::DONT_DELETE);
+
+ /// Return a pointer to 1 past the end of the allocated data in a message.
+ char *end (void) const;
+
+ /**
+ * Return a pointer to 1 past the end of the allotted data in a message.
+ * The allotted data may be less than allocated data if <size()> is passed
+ * an argument less than <capacity()>.
+ */
+ char *mark (void) const;
+
+ // = Message size is the total amount of space alloted.
+
+ /// Get the total amount of allotted space in the message. The amount of
+ /// allotted space may be less than allocated space.
+ size_t size (void) const;
+
+ /// Set the total amount of space in the message. Returns 0 if
+ /// successful, else -1.
+ int size (size_t length);
+
+ /// Get the total amount of allocated space.
+ size_t capacity (void) const;
+
+ /**
+ * Return an exact "deep copy" of the message, i.e., create fresh
+ * new copies of all the Data_Blocks and continuations.
+ * Notice that Data_Blocks can act as "Prototypes", i.e. derived
+ * classes can override this method and create instances of
+ * themselves.
+ */
+ virtual ACE_Data_Block *clone (ACE_Message_Block::Message_Flags mask = 0) const;
+
+ /**
+ * As clone above, but it does not copy the contents of the buffer,
+ * i.e., create a new Data_Block of the same dynamic type, with the
+ * same allocator, locking_strategy, and with the same amount of
+ * storage available but the buffer is unitialized.
+ */
+ virtual ACE_Data_Block *clone_nocopy (ACE_Message_Block::Message_Flags mask = 0) const;
+
+ /// Return a "shallow" copy that increments our reference count by 1.
+ ACE_Data_Block *duplicate (void);
+
+ /**
+ * Decrease the shared reference count by 1. If the reference count
+ * is > 0 then return this; else if reference count == 0 then delete
+ * <this> and <mb> and return 0. Behavior is undefined if reference
+ * count < 0.
+ */
+ ACE_Data_Block *release (ACE_Lock *lock = 0);
+
+ // = Message flag accessors and mutators.
+ /// Bitwise-or the <more_flags> into the existing message flags and
+ /// return the new value.
+ ACE_Message_Block::Message_Flags set_flags (ACE_Message_Block::Message_Flags more_flags);
+
+ /// Clear the message flag bits specified in <less_flags> and return
+ /// the new value.
+ ACE_Message_Block::Message_Flags clr_flags (ACE_Message_Block::Message_Flags less_flags);
+
+ /// Get the current message flags.
+ ACE_Message_Block::Message_Flags flags (void) const;
+
+ /// Obtain the allocator strategy.
+ ACE_Allocator *allocator_strategy (void) const;
+
+ // = The locking strategy prevents race conditions.
+ /// Get the locking strategy.
+ /// Set a new locking strategy and return the hold one.
+ ACE_Lock *locking_strategy (void);
+ ACE_Lock *locking_strategy (ACE_Lock *);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Get the current reference count.
+ int reference_count (void) const;
+
+ /// Get the allocator used to create this object
+ ACE_Allocator *data_block_allocator (void) const;
+
+protected:
+ /// Internal release implementation
+ ACE_Data_Block *release_i (void);
+
+ /**
+ * Decrease the reference count, but don't delete the object.
+ * Returns 0 if the object should be removed.
+ * If <lock> is equal to the locking strategy then we assume that
+ * the lock is beign held by the current thread; this is used to
+ * release all the data blocks in a chain while holding a single
+ * lock.
+ */
+ friend class ACE_Message_Block;
+ ACE_Data_Block *release_no_delete (ACE_Lock *lock);
+
+ /// Type of message.
+ ACE_Message_Block::ACE_Message_Type type_;
+
+ /// Current size of message block.
+ size_t cur_size_;
+
+ /// Total size of buffer.
+ size_t max_size_;
+
+ /// Misc flags (e.g., DONT_DELETE and USER_FLAGS).
+ ACE_Message_Block::Message_Flags flags_;
+
+ /// Pointer To beginning of message payload.
+ char *base_;
+
+ // = Strategies.
+ /**
+ * Pointer to the allocator defined for this <ACE_Data_Block>. Note
+ * that this pointer is shared by all owners of this
+ * <ACE_Data_Block>.
+ */
+ ACE_Allocator *allocator_strategy_;
+
+ /**
+ * Pointer to the locking strategy defined for this
+ * <ACE_Data_Block>. This is used to protect regions of code that
+ * access shared <ACE_Data_Block> state. Note that this lock is
+ * shared by all owners of the <ACE_Data_Block>'s data.
+ */
+ ACE_Lock *locking_strategy_;
+
+ /**
+ * Reference count for this <ACE_Data_Block>, which is used to avoid
+ * deep copies (i.e., <clone>). Note that this pointer value is
+ * shared by all owners of the <Data_Block>'s data, i.e., all the
+ * <ACE_Message_Block>s.
+ */
+ int reference_count_;
+
+ /// The allocator use to destroy ourselves.
+ ACE_Allocator *data_block_allocator_;
+
+private:
+ // = Disallow these operations.
+ ACE_Data_Block &operator= (const ACE_Data_Block &);
+ ACE_Data_Block (const ACE_Data_Block &);
+};
+
+/**
+ * @class ACE_Dynamic_Message_Strategy
+ *
+ * @brief An abstract base class which provides dynamic priority
+ * evaluation methods for use by the <ACE_Dynamic_Message_Queue>
+ * class or any other class which needs to manage the priorities
+ * of a collection of <ACE_Message_Block>s dynamically.
+ *
+ * Methods for deadline and laxity based priority evaluation are
+ * provided. These methods assume a specific partitioning of
+ * the message priority number into a higher order dynamic bit
+ * field and a lower order static priority bit field. The
+ * default partitioning assumes an unsigned dynamic message
+ * priority field of 22 bits and an unsigned static message
+ * priority field of 10 bits. This corresponds to the initial
+ * values of the static class members. To provide a different
+ * partitioning, assign a different set of values to the static
+ * class memebers before using the static member functions.
+ */
+class ACE_Export ACE_Dynamic_Message_Strategy
+{
+public:
+
+ // = Message priority status
+
+ // Values are defined as bit flags so that status combinations may
+ // be specified easily.
+
+ enum Priority_Status
+ {
+ /// message can still make its deadline
+ PENDING = 0x01,
+ /// message cannot make its deadline
+ LATE = 0x02,
+ /// message is so late its priority is undefined
+ BEYOND_LATE = 0x04,
+ /// mask to match any priority status
+ ANY_STATUS = 0x07
+ };
+
+ /// ctor
+ ACE_Dynamic_Message_Strategy (u_long static_bit_field_mask,
+ u_long static_bit_field_shift,
+ u_long dynamic_priority_max,
+ u_long dynamic_priority_offset);
+
+ /// virtual dtor
+ virtual ~ACE_Dynamic_Message_Strategy (void);
+
+ /// Updates the message's priority and returns its priority status.
+ Priority_Status priority_status (ACE_Message_Block &mb,
+ const ACE_Time_Value &tv);
+
+ /// Get static bit field mask.
+ u_long static_bit_field_mask (void) const;
+
+ /// Set static bit field mask.
+ void static_bit_field_mask (u_long);
+
+ /// Get left shift value to make room for static bit field.
+ u_long static_bit_field_shift (void) const;
+
+ /// Set left shift value to make room for static bit field.
+ void static_bit_field_shift (u_long);
+
+ /// Get maximum supported priority value.
+ u_long dynamic_priority_max (void) const;
+
+ /// Set maximum supported priority value.
+ void dynamic_priority_max (u_long);
+
+ /// Get offset to boundary between signed range and unsigned range.
+ u_long dynamic_priority_offset (void) const;
+
+ /// Set offset to boundary between signed range and unsigned range.
+ void dynamic_priority_offset (u_long);
+
+ /// Dump the state of the strategy.
+ virtual void dump (void) const;
+
+protected:
+ /// Hook method for dynamic priority conversion.
+ virtual void convert_priority (ACE_Time_Value &priority,
+ const ACE_Message_Block &mb) = 0;
+
+ /// This is a bit mask with all ones in the static bit field.
+ u_long static_bit_field_mask_;
+
+ /**
+ * This is a left shift value to make room for static bit field:
+ * this value should be the logarithm base 2 of
+ * (static_bit_field_mask_ + 1).
+ */
+ u_long static_bit_field_shift_;
+
+ /// Maximum supported priority value.
+ u_long dynamic_priority_max_;
+
+ /// Offset to boundary between signed range and unsigned range.
+ u_long dynamic_priority_offset_;
+
+ /// Maximum late time value that can be represented.
+ ACE_Time_Value max_late_;
+
+ /// Minimum pending time value that can be represented.
+ ACE_Time_Value min_pending_;
+
+ /// Time value by which to shift pending priority.
+ ACE_Time_Value pending_shift_;
+};
+
+/**
+ * @class ACE_Deadline_Message_Strategy
+ *
+ * @brief Deadline based message priority strategy.
+ *
+ * Assigns dynamic message priority according to time to deadline. The
+ * message priority is divided into high and low order bit fields. The
+ * high order bit field is used for dynamic message priority, which is
+ * updated whenever the convert_priority (...) method is called. The
+ * low order bit field is used for static message priority and is left
+ * unchanged. The partitioning of the priority value into high and low
+ * order bit fields is done according to the arguments passed to the
+ * strategy object's constructor.
+ */
+class ACE_Export ACE_Deadline_Message_Strategy : public ACE_Dynamic_Message_Strategy
+{
+public:
+ /// Ctor, with all arguments defaulted.
+ ACE_Deadline_Message_Strategy (u_long static_bit_field_mask = 0x3FFUL, // 2^(10) - 1
+ u_long static_bit_field_shift = 10, // 10 low order bits
+ u_long dynamic_priority_max = 0x3FFFFFUL, // 2^(22)-1
+ u_long dynamic_priority_offset = 0x200000UL); // 2^(22-1)
+
+ /// Virtual dtor.
+ virtual ~ACE_Deadline_Message_Strategy (void);
+
+ /// Dynamic priority conversion function based on time to deadline.
+ virtual void convert_priority (ACE_Time_Value &priority,
+ const ACE_Message_Block &mb);
+
+ /// Dump the state of the strategy.
+ virtual void dump (void) const;
+};
+
+/**
+ * @class ACE_Laxity_Message_Strategy
+ *
+ * @brief Laxity based message priority strategy.
+ *
+ * Assigns dynamic message priority according to laxity (time to
+ * deadline minus worst case execution time). The message priority is
+ * divided into high and low order bit fields. The high order
+ * bit field is used for dynamic message priority, which is
+ * updated whenever the convert_priority (...) method is called. The
+ * low order bit field is used for static message priority and is left
+ * unchanged. The partitioning of the priority value into high and low
+ * order bit fields is done according to the arguments passed to the
+ * strategy object's constructor.
+ */
+class ACE_Export ACE_Laxity_Message_Strategy : public ACE_Dynamic_Message_Strategy
+{
+public:
+ /// Ctor, with all arguments defaulted.
+ ACE_Laxity_Message_Strategy (u_long static_bit_field_mask = 0x3FFUL, // 2^(10) - 1
+ u_long static_bit_field_shift = 10, // 10 low order bits
+ u_long dynamic_priority_max = 0x3FFFFFUL, // 2^(22)-1
+ u_long dynamic_priority_offset = 0x200000UL); // 2^(22-1)
+
+ /// virtual dtor.
+ virtual ~ACE_Laxity_Message_Strategy (void);
+
+ /// Dynamic priority conversion function based on laxity.
+ virtual void convert_priority (ACE_Time_Value &priority,
+ const ACE_Message_Block &mb);
+
+ /// Dump the state of the strategy.
+ virtual void dump (void) const;
+};
+
+#if defined (__ACE_INLINE__)
+#include "ace/Utils/Message_Block.i"
+#endif /* __ACE_INLINE__ */
+
+#include "ace/Utils/Templates/Message_Block_T.h"
+#include "ace/post.h"
+#endif /* ACE_MESSAGE_BLOCK_H */
diff --git a/ace/Utils/Message_Block.i b/ace/Utils/Message_Block.i
new file mode 100644
index 00000000000..c7abe9b214a
--- /dev/null
+++ b/ace/Utils/Message_Block.i
@@ -0,0 +1,627 @@
+/* -*- C++ -*- */
+// $Id$
+
+// Message_Block.i
+
+ACE_INLINE ACE_Data_Block *
+ACE_Message_Block::data_block (void) const
+{
+ ACE_TRACE ("ACE_Message_Block::data_block");
+ return this->data_block_;
+}
+
+ACE_INLINE ACE_Message_Block::Message_Flags
+ACE_Message_Block::set_self_flags (ACE_Message_Block::Message_Flags more_flags)
+{
+ ACE_TRACE ("ACE_Message_Block::set_self_flags");
+ // Later we might mask more_glags so that user can't change internal
+ // ones: more_flags &= ~(USER_FLAGS -1).
+ return ACE_SET_BITS (this->flags_, more_flags);
+}
+
+ACE_INLINE ACE_Message_Block::Message_Flags
+ACE_Message_Block::clr_self_flags (ACE_Message_Block::Message_Flags less_flags)
+{
+ ACE_TRACE ("ACE_Message_Block::clr_self_flags");
+ // Later we might mask more_flags so that user can't change internal
+ // ones: less_flags &= ~(USER_FLAGS -1).
+ return ACE_CLR_BITS (this->flags_, less_flags);
+}
+
+ACE_INLINE ACE_Message_Block::Message_Flags
+ACE_Message_Block::self_flags (void) const
+{
+ ACE_TRACE ("ACE_Message_Block::self_flags");
+ return this->flags_;
+}
+
+
+// This function must comes before ACE_Message_Block::reference_count
+// to avoid a g++ warning.
+ACE_INLINE int
+ACE_Data_Block::reference_count (void) const
+{
+ return reference_count_;
+}
+
+ACE_INLINE int
+ACE_Message_Block::reference_count (void) const
+{
+ return data_block () ? data_block ()->reference_count () : 0;
+}
+
+ACE_INLINE char *
+ACE_Data_Block::base (void) const
+{
+ ACE_TRACE ("ACE_Data_Block::base");
+ return this->base_;
+}
+
+ACE_INLINE size_t
+ACE_Data_Block::size (void) const
+{
+ ACE_TRACE ("ACE_Data_Block::size");
+ return this->cur_size_;
+}
+
+ACE_INLINE size_t
+ACE_Data_Block::capacity (void) const
+{
+ ACE_TRACE ("ACE_Data_Block::capacity");
+ return this->max_size_;
+}
+
+ACE_INLINE ACE_Message_Block::Message_Flags
+ACE_Data_Block::set_flags (ACE_Message_Block::Message_Flags more_flags)
+{
+ ACE_TRACE ("ACE_Data_Block::set_flags");
+ // Later we might mask more_glags so that user can't change internal
+ // ones: more_flags &= ~(USER_FLAGS -1).
+ return ACE_SET_BITS (this->flags_, more_flags);
+}
+
+ACE_INLINE ACE_Message_Block::Message_Flags
+ACE_Data_Block::clr_flags (ACE_Message_Block::Message_Flags less_flags)
+{
+ ACE_TRACE ("ACE_Data_Block::clr_flags");
+ // Later we might mask more_flags so that user can't change internal
+ // ones: less_flags &= ~(USER_FLAGS -1).
+ return ACE_CLR_BITS (this->flags_, less_flags);
+}
+
+ACE_INLINE ACE_Message_Block::Message_Flags
+ACE_Data_Block::flags (void) const
+{
+ ACE_TRACE ("ACE_Data_Block::flags");
+ return this->flags_;
+}
+
+ACE_INLINE ACE_Allocator*
+ACE_Data_Block::data_block_allocator (void) const
+{
+ ACE_TRACE ("ACE_Data_Block::data_block_allocator");
+ return this->data_block_allocator_;
+}
+
+ACE_INLINE ACE_Message_Block::Message_Flags
+ACE_Message_Block::set_flags (ACE_Message_Block::Message_Flags more_flags)
+{
+ ACE_TRACE ("ACE_Message_Block::set_flags");
+ return this->data_block ()->set_flags (more_flags);
+}
+
+ACE_INLINE ACE_Message_Block::Message_Flags
+ACE_Message_Block::clr_flags (ACE_Message_Block::Message_Flags less_flags)
+{
+ ACE_TRACE ("ACE_Message_Block::clr_flags");
+ return this->data_block ()->clr_flags (less_flags);
+}
+
+ACE_INLINE ACE_Message_Block::Message_Flags
+ACE_Message_Block::flags (void) const
+{
+ ACE_TRACE ("ACE_Message_Block::flags");
+ return this->data_block ()->flags ();
+}
+
+// Return the length of the "active" portion of the message.
+
+ACE_INLINE size_t
+ACE_Message_Block::length (void) const
+{
+ ACE_TRACE ("ACE_Message_Block::length");
+ return this->wr_ptr_ - this->rd_ptr_;
+}
+
+// Sets the length of the "active" portion of the message. This is
+// defined as the offset from RD_PTR to WR_PTR.
+
+ACE_INLINE void
+ACE_Message_Block::length (size_t len)
+{
+ ACE_TRACE ("ACE_Message_Block::length");
+ this->wr_ptr_ = this->rd_ptr_ + len;
+}
+
+// Return the length of the potential size of the message.
+
+ACE_INLINE size_t
+ACE_Message_Block::size (void) const
+{
+ ACE_TRACE ("ACE_Message_Block::size");
+ return this->data_block ()->size ();
+}
+
+ACE_INLINE size_t
+ACE_Message_Block::capacity (void) const
+{
+ ACE_TRACE ("ACE_Message_Block::capacity");
+ return this->data_block ()->capacity ();
+}
+
+ACE_INLINE ACE_Message_Block::ACE_Message_Type
+ACE_Data_Block::msg_type (void) const
+{
+ ACE_TRACE ("ACE_Data_Block::msg_type");
+ return this->type_;
+}
+
+ACE_INLINE void
+ACE_Data_Block::msg_type (ACE_Message_Block::ACE_Message_Type t)
+{
+ ACE_TRACE ("ACE_Data_Block::msg_type");
+ this->type_ = t;
+}
+
+ACE_INLINE ACE_Message_Block::ACE_Message_Type
+ACE_Message_Block::msg_type (void) const
+{
+ ACE_TRACE ("ACE_Message_Block::msg_type");
+ return this->data_block ()->msg_type ();
+}
+
+ACE_INLINE void
+ACE_Message_Block::msg_type (ACE_Message_Block::ACE_Message_Type t)
+{
+ ACE_TRACE ("ACE_Message_Block::msg_type");
+ this->data_block ()->msg_type (t);
+}
+
+ACE_INLINE ACE_Message_Block::ACE_Message_Type
+ACE_Message_Block::msg_class (void) const
+{
+ ACE_TRACE ("ACE_Message_Block::msg_class");
+
+ if (this->msg_type () < ACE_Message_Block::MB_PRIORITY)
+ return ACE_Message_Block::MB_NORMAL;
+ else if (this->msg_type () < ACE_Message_Block::MB_USER)
+ return ACE_Message_Block::MB_PRIORITY;
+ else
+ return ACE_Message_Block::MB_USER;
+}
+
+ACE_INLINE int
+ACE_Message_Block::is_data_msg (void) const
+{
+ ACE_TRACE ("ACE_Message_Block::is_data_msg");
+ ACE_Message_Type mt = this->msg_type ();
+ return
+ mt == ACE_Message_Block::MB_DATA
+ || mt == ACE_Message_Block::MB_PROTO
+ || mt == ACE_Message_Block::MB_PCPROTO;
+}
+
+ACE_INLINE u_long
+ACE_Message_Block::msg_priority (void) const
+{
+ ACE_TRACE ("ACE_Message_Block::msg_priority");
+ return this->priority_;
+}
+
+ACE_INLINE void
+ACE_Message_Block::msg_priority (u_long pri)
+{
+ ACE_TRACE ("ACE_Message_Block::msg_priority");
+ this->priority_ = pri;
+}
+
+ACE_INLINE const ACE_Time_Value &
+ACE_Message_Block::msg_execution_time (void) const
+{
+ ACE_TRACE ("ACE_Message_Block::msg_execution_time (void)");
+#if defined (ACE_HAS_TIMED_MESSAGE_BLOCKS)
+ return this->execution_time_;
+#else
+ return ACE_Time_Value::zero;
+#endif /* ACE_HAS_TIMED_MESSAGE_BLOCKS */
+}
+
+ACE_INLINE void
+ACE_Message_Block::msg_execution_time (const ACE_Time_Value &et)
+{
+ ACE_TRACE ("ACE_Message_Block::msg_execution_time (const ACE_Time_Value & et)");
+#if defined (ACE_HAS_TIMED_MESSAGE_BLOCKS)
+ this->execution_time_ = et;
+#else
+ ACE_UNUSED_ARG (et);
+#endif /* ACE_HAS_TIMED_MESSAGE_BLOCKS */
+}
+
+ACE_INLINE const ACE_Time_Value &
+ACE_Message_Block::msg_deadline_time (void) const
+{
+ ACE_TRACE ("ACE_Message_Block::msg_deadline_time (void)");
+
+#if defined (ACE_HAS_TIMED_MESSAGE_BLOCKS)
+ return this->deadline_time_;
+#else
+ return ACE_Time_Value::max_time; // absolute time of deadline
+#endif /* ACE_HAS_TIMED_MESSAGE_BLOCKS */
+}
+
+ACE_INLINE void
+ACE_Message_Block::msg_deadline_time (const ACE_Time_Value &dt)
+{
+ ACE_TRACE ("ACE_Message_Block::msg_deadline_time (const ACE_Time_Value & et)");
+#if defined (ACE_HAS_TIMED_MESSAGE_BLOCKS)
+ this->deadline_time_ = dt;
+#else
+ ACE_UNUSED_ARG (dt);
+#endif /* ACE_HAS_TIMED_MESSAGE_BLOCKS */
+}
+
+ACE_INLINE char *
+ACE_Message_Block::base (void) const
+{
+ ACE_TRACE ("ACE_Message_Block::base");
+ return this->data_block ()->base ();
+}
+
+ACE_INLINE void
+ACE_Message_Block::base (char *msg_data,
+ size_t msg_length,
+ Message_Flags msg_flags)
+{
+ ACE_TRACE ("ACE_Message_Block::base");
+ this->rd_ptr_ = 0;
+ this->wr_ptr_ = 0;
+ this->data_block ()->base (msg_data, msg_length, msg_flags);
+}
+
+ACE_INLINE char *
+ACE_Message_Block::rd_ptr (void) const
+{
+ ACE_TRACE ("ACE_Message_Block::rd_ptr");
+ return this->base () + this->rd_ptr_;
+}
+
+ACE_INLINE void
+ACE_Message_Block::wr_ptr (char *new_ptr)
+{
+ ACE_TRACE ("ACE_Message_Block::wr_ptr");
+ this->wr_ptr_ = new_ptr - this->base ();
+}
+
+// Return a pointer to 1 past the end of the data buffer.
+
+ACE_INLINE char *
+ACE_Data_Block::mark (void) const
+{
+ ACE_TRACE ("ACE_Data_Block::mark");
+ return this->base_ + this->cur_size_;
+}
+
+ACE_INLINE char *
+ACE_Message_Block::mark (void) const
+{
+ ACE_TRACE ("ACE_Message_Block::mark");
+ return this->data_block ()->mark ();
+}
+
+ACE_INLINE char *
+ACE_Data_Block::end (void) const
+{
+ ACE_TRACE ("ACE_Data_Block::end");
+ return this->base_ + this->max_size_;
+}
+
+ACE_INLINE char *
+ACE_Message_Block::end (void) const
+{
+ ACE_TRACE ("ACE_Message_Block::end");
+ return this->data_block ()->end ();
+}
+
+
+ACE_INLINE void
+ACE_Message_Block::rd_ptr (char *new_ptr)
+{
+ ACE_TRACE ("ACE_Message_Block::rd_ptr");
+ this->rd_ptr_ = new_ptr - this->base ();
+}
+
+ACE_INLINE void
+ACE_Message_Block::rd_ptr (size_t n)
+{
+ ACE_TRACE ("ACE_Message_Block::rd_ptr");
+ this->rd_ptr_ += n;
+}
+
+ACE_INLINE char *
+ACE_Message_Block::wr_ptr (void) const
+{
+ ACE_TRACE ("ACE_Message_Block::wr_ptr");
+ return this->base () + this->wr_ptr_;
+}
+
+ACE_INLINE void
+ACE_Message_Block::wr_ptr (size_t n)
+{
+ ACE_TRACE ("ACE_Message_Block::wr_ptr");
+ this->wr_ptr_ += n;
+}
+
+ACE_INLINE void
+ACE_Message_Block::reset (void)
+{
+ ACE_TRACE ("ACE_Message_Block::reset");
+ this->rd_ptr_ = 0;
+ this->wr_ptr_ = 0;
+}
+
+ACE_INLINE size_t
+ACE_Message_Block::space (void) const
+{
+ ACE_TRACE ("ACE_Message_Block::space");
+ return this->mark () - this->wr_ptr ();
+}
+
+ACE_INLINE ACE_Data_Block *
+ACE_Message_Block::replace_data_block (ACE_Data_Block *db)
+{
+ ACE_TRACE ("ACE_Message_Block::replace_data_block");
+ ACE_Data_Block *old = this->data_block_;
+ this->data_block_ = db;
+
+ if (db != 0)
+ {
+ // Set the read and write pointers in the <Message_Block> to point
+ // to the buffer in the <ACE_Data_Block>.
+ this->rd_ptr (this->data_block ()->base ());
+ this->wr_ptr (this->data_block ()->base ());
+ }
+
+ return old;
+}
+
+ACE_INLINE void
+ACE_Message_Block::cont (ACE_Message_Block *cont_msg)
+{
+ ACE_TRACE ("ACE_Message_Block::cont");
+ this->cont_ = cont_msg;
+}
+
+ACE_INLINE ACE_Message_Block *
+ACE_Message_Block::cont (void) const
+{
+ ACE_TRACE ("ACE_Message_Block::cont");
+ return this->cont_;
+}
+
+ACE_INLINE void
+ACE_Message_Block::next (ACE_Message_Block *next_msg)
+{
+ ACE_TRACE ("ACE_Message_Block::next");
+ this->next_ = next_msg;
+}
+
+ACE_INLINE ACE_Message_Block *
+ACE_Message_Block::next (void) const
+{
+ ACE_TRACE ("ACE_Message_Block::next");
+ return this->next_;
+}
+
+ACE_INLINE void
+ACE_Message_Block::prev (ACE_Message_Block *next_msg)
+{
+ ACE_TRACE ("ACE_Message_Block::prev");
+ this->prev_ = next_msg;
+}
+
+ACE_INLINE ACE_Message_Block *
+ACE_Message_Block::prev (void) const
+{
+ ACE_TRACE ("ACE_Message_Block::prev");
+ return this->prev_;
+}
+
+ACE_INLINE ACE_Allocator *
+ACE_Data_Block::allocator_strategy (void) const
+{
+ ACE_TRACE ("ACE_Data_Block::allocator_strategy");
+ return this->allocator_strategy_;
+}
+
+ACE_INLINE ACE_Lock *
+ACE_Data_Block::locking_strategy (void)
+{
+ ACE_TRACE ("ACE_Data_Block::locking_strategy");
+ return this->locking_strategy_;
+}
+
+ACE_INLINE ACE_Lock *
+ACE_Data_Block::locking_strategy (ACE_Lock *nls)
+{
+ ACE_TRACE ("ACE_Data_Block::locking_strategy");
+ ACE_Lock *ols = this->locking_strategy_;
+
+ this->locking_strategy_ = nls;
+ return ols;
+}
+
+ACE_INLINE ACE_Lock *
+ACE_Message_Block::locking_strategy (void)
+{
+ ACE_TRACE ("ACE_Message_Block::locking_strategy");
+ return this->data_block ()->locking_strategy ();
+}
+
+ACE_INLINE ACE_Lock *
+ACE_Message_Block::locking_strategy (ACE_Lock *nls)
+{
+ ACE_TRACE ("ACE_Message_Block::locking_strategy");
+ ACE_Lock *ols = this->data_block ()->locking_strategy ();
+ this->data_block ()->locking_strategy (nls);
+ return ols;
+}
+
+
+////////////////////////////////////////
+// class ACE_Dynamic_Message_Strategy //
+////////////////////////////////////////
+
+ACE_INLINE u_long
+ACE_Dynamic_Message_Strategy::static_bit_field_mask (void) const
+{
+ return static_bit_field_mask_;
+}
+ // get static bit field mask
+
+ACE_INLINE void
+ACE_Dynamic_Message_Strategy::static_bit_field_mask (u_long ul)
+{
+ static_bit_field_mask_ = ul;
+}
+ // set static bit field mask
+
+ACE_INLINE u_long
+ACE_Dynamic_Message_Strategy::static_bit_field_shift (void) const
+{
+ return static_bit_field_shift_;
+}
+ // get left shift value to make room for static bit field
+
+ACE_INLINE void
+ACE_Dynamic_Message_Strategy::static_bit_field_shift (u_long ul)
+{
+ static_bit_field_shift_ = ul;
+}
+ // set left shift value to make room for static bit field
+
+ACE_INLINE u_long
+ACE_Dynamic_Message_Strategy::dynamic_priority_max (void) const
+{
+ return dynamic_priority_max_;
+}
+ // get maximum supported priority value
+
+ACE_INLINE void
+ACE_Dynamic_Message_Strategy::dynamic_priority_max (u_long ul)
+{
+ // pending_shift_ depends on dynamic_priority_max_: for performance
+ // reasons, the value in pending_shift_ is (re)calculated only when
+ // dynamic_priority_max_ is initialized or changes, and is stored
+ // as a class member rather than being a derived value.
+ dynamic_priority_max_ = ul;
+ pending_shift_ = ACE_Time_Value (0, ul);
+}
+ // set maximum supported priority value
+
+ACE_INLINE u_long
+ACE_Dynamic_Message_Strategy::dynamic_priority_offset (void) const
+{
+ return dynamic_priority_offset_;
+}
+ // get offset for boundary between signed range and unsigned range
+
+ACE_INLINE void
+ACE_Dynamic_Message_Strategy::dynamic_priority_offset (u_long ul)
+{
+ // max_late_ and min_pending_ depend on dynamic_priority_offset_:
+ // for performance reasons, the values in max_late_ and min_pending_
+ // are (re)calculated only when dynamic_priority_offset_ is
+ // initialized or changes, and are stored as a class member rather
+ // than being derived each time one of their values is needed.
+ dynamic_priority_offset_ = ul;
+ max_late_ = ACE_Time_Value (0, ul - 1);
+ min_pending_ = ACE_Time_Value (0, ul);
+}
+ // set offset for boundary between signed range and unsigned range
+
+
+ACE_INLINE ACE_Dynamic_Message_Strategy::Priority_Status
+ACE_Dynamic_Message_Strategy::priority_status (ACE_Message_Block & mb,
+ const ACE_Time_Value & tv)
+{
+ // default the message to have pending priority status
+ Priority_Status status = ACE_Dynamic_Message_Strategy::PENDING;
+
+ // start with the passed absolute time as the message's priority, then
+ // call the polymorphic hook method to (at least partially) convert
+ // the absolute time and message attributes into the message's priority
+ ACE_Time_Value priority (tv);
+ convert_priority (priority, mb);
+
+ // if the priority is negative, the message is pending
+ if (priority < ACE_Time_Value::zero)
+ {
+ // priority for pending messages must be shifted
+ // upward above the late priority range
+ priority += pending_shift_;
+ if (priority < min_pending_)
+ priority = min_pending_;
+ }
+ // otherwise, if the priority is greater than the maximum late
+ // priority value that can be represented, it is beyond late
+ else if (priority > max_late_)
+ {
+ // all messages that are beyond late are assigned lowest priority (zero)
+ mb.msg_priority (0);
+ return ACE_Dynamic_Message_Strategy::BEYOND_LATE;
+ }
+ // otherwise, the message is late, but its priority is correct
+ else
+ status = ACE_Dynamic_Message_Strategy::LATE;
+
+ // use (fast) bitwise operators to isolate and replace
+ // the dynamic portion of the message's priority
+ mb.msg_priority((mb.msg_priority() & static_bit_field_mask_) |
+ ((priority.usec () + ACE_ONE_SECOND_IN_USECS * priority.sec ()) <<
+ static_bit_field_shift_));
+
+ return status;
+}
+ // returns the priority status of the message
+
+
+
+/////////////////////////////////////////
+// class ACE_Deadline_Message_Strategy //
+/////////////////////////////////////////
+
+ACE_INLINE void
+ACE_Deadline_Message_Strategy::convert_priority (ACE_Time_Value & priority,
+ const ACE_Message_Block & mb)
+{
+ // Convert absolute time passed in tv to negative time
+ // to deadline of mb with respect to that absolute time.
+ priority -= mb.msg_deadline_time ();
+}
+ // dynamic priority conversion function based on time to deadline
+
+
+///////////////////////////////////////
+// class ACE_Laxity_Message_Strategy //
+///////////////////////////////////////
+
+ACE_INLINE void
+ACE_Laxity_Message_Strategy::convert_priority (ACE_Time_Value & priority,
+ const ACE_Message_Block & mb)
+{
+ // Convert absolute time passed in tv to negative
+ // laxity of mb with respect to that absolute time.
+ priority += mb.msg_execution_time ();
+ priority -= mb.msg_deadline_time ();
+}
+ // dynamic priority conversion function based on laxity
diff --git a/ace/Utils/Method_Request.cpp b/ace/Utils/Method_Request.cpp
new file mode 100644
index 00000000000..003d5acc4f7
--- /dev/null
+++ b/ace/Utils/Method_Request.cpp
@@ -0,0 +1,27 @@
+// Method_Request.cpp
+// $Id$
+
+#include "ace/Method_Request.h"
+
+ACE_RCSID(ace, Method_Request, "$Id$")
+
+ACE_Method_Request::ACE_Method_Request (u_long prio)
+ : priority_ (prio)
+{
+}
+
+ACE_Method_Request::~ACE_Method_Request (void)
+{
+}
+
+u_long
+ACE_Method_Request::priority (void) const
+{
+ return this->priority_;
+}
+
+void
+ACE_Method_Request::priority (u_long prio)
+{
+ this->priority_ = prio;
+}
diff --git a/ace/Utils/Method_Request.h b/ace/Utils/Method_Request.h
new file mode 100644
index 00000000000..b545648712a
--- /dev/null
+++ b/ace/Utils/Method_Request.h
@@ -0,0 +1,66 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Method_Request.h
+ *
+ * $Id$
+ *
+ * @author Andres Kruse <Andres.Kruse@cern.ch>
+ * @author Douglas C. Schmidt <schmidt@cs.wustl.edu>
+ */
+//=============================================================================
+
+
+#ifndef ACE_METHOD_REQUEST_H
+#define ACE_METHOD_REQUEST_H
+#include "ace/pre.h"
+
+#include "ace/OS.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+/**
+ * @class ACE_Method_Request
+ *
+ * @brief Reifies a method into a request. Subclasses provide
+ * the necessary state and behavior.
+ *
+ * A <Method_Request> is inserted in the <Activation_Queue>,
+ * where it is subsequently removed by a <Scheduler>, which
+ * invokes the <call> method.
+ */
+class ACE_Export ACE_Method_Request
+{
+public:
+ // = Initialization and termination methods.
+ /// Constructor.
+ ACE_Method_Request (u_long priority = 0);
+
+ /// Destructor.
+ virtual ~ACE_Method_Request (void);
+
+ // = Accessors.
+ /// Get priority.
+ u_long priority (void) const;
+
+ /// Set priority.
+ void priority (u_long);
+
+ // = Invocation method (must be overridden by subclasses).
+ /// Invoked when the <Method_Request> is scheduled to run.
+ virtual int call (void) = 0;
+
+protected:
+ /// The priority of the request.
+ u_long priority_;
+
+private:
+ ACE_UNIMPLEMENTED_FUNC (void operator= (const ACE_Method_Request &))
+ ACE_UNIMPLEMENTED_FUNC (ACE_Method_Request (const ACE_Method_Request &))
+};
+
+#include "ace/post.h"
+#endif /* ACE_METHOD_REQUEST_H */
diff --git a/ace/Utils/Multiplexor.cpp b/ace/Utils/Multiplexor.cpp
new file mode 100644
index 00000000000..e4d33295b31
--- /dev/null
+++ b/ace/Utils/Multiplexor.cpp
@@ -0,0 +1,14 @@
+// Multiplexor.cpp
+// $Id$
+
+#if defined (ACE_HAS_THREADS)
+
+#include "ace/Multiplexor.h"
+
+ACE_RCSID(ace, Multiplexor, "$Id$")
+
+#if !defined (__ACE_INLINE__)
+#include "ace/Multiplexor.i"
+#endif /* __ACE_INLINE__ */
+
+#endif /* ACE_HAS_THREADS */
diff --git a/ace/Utils/Multiplexor.h b/ace/Utils/Multiplexor.h
new file mode 100644
index 00000000000..9e99d231681
--- /dev/null
+++ b/ace/Utils/Multiplexor.h
@@ -0,0 +1,81 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Multiplexor.h
+ *
+ * $Id$
+ *
+ * Define the ACE_Driver and ACE_Multiplexor container classes.
+ * Note that these classes have never been implemented due to lack
+ * of need.
+ *
+ *
+ * @author Doug Schmidt
+ */
+//=============================================================================
+
+
+#ifndef ACE_MULTIPLEXOR_H
+#define ACE_MULTIPLEXOR_H
+#include "ace/pre.h"
+
+#include "ace/Module.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "ace/Map_Manager.h"
+
+#if defined (ACE_HAS_THREADS)
+
+#if 0
+/**
+ * @class ACE_Driver
+ *
+ *
+ */
+class ACE_Export ACE_Driver
+{
+public:
+ ACE_Driver (void);
+ ~ACE_Driver (void);
+
+ virtual int link_from_below (ACE_Module *mod);
+ virtual ACE_Module *alloc_module (ACE_Driver *) = 0;
+ virtual int unlink_from_below (ACE_Module *);
+};
+
+/**
+ * @class ACE_Multiplexor
+ *
+ *
+ */
+class ACE_Export ACE_Multiplexor
+{
+public:
+ // = Constructors and destructors
+ ACE_Multiplexor (void);
+ ~ACE_Multiplexor (void);
+
+ virtual int link_from_above (ACE_Driver &ld);
+ virtual int link_from_above (ACE_Multiplexor &lm);
+ virtual int link_from_below (ACE_Module *mod);
+ virtual ACE_Module *alloc_lower_module (ACE_Multiplexor *) = 0;
+ virtual ACE_Module *alloc_upper_module (ACE_Multiplexor *) = 0;
+
+ virtual int unlink_from_above (ACE_Driver &ld);
+ virtual int unlink_from_above (ACE_Multiplexor &lm);
+ virtual int unlink_from_below (ACE_Module *mod);
+};
+
+#if defined (__ACE_INLINE__)
+#include "ace/Multiplexor.i"
+#endif /* __ACE_INLINE__ */
+
+#endif /* 0 */
+
+#endif /* ACE_HAS_THREADS */
+#include "ace/post.h"
+#endif /* ACE_MULTIPLEXOR_H */
diff --git a/ace/Utils/Multiplexor.i b/ace/Utils/Multiplexor.i
new file mode 100644
index 00000000000..1763c13ab4c
--- /dev/null
+++ b/ace/Utils/Multiplexor.i
@@ -0,0 +1,88 @@
+/* -*- C++ -*- */
+// $Id$
+
+// Multiplexor.i
+
+int
+Driver::link_from_below (ACE_Module *stream_head)
+{
+ ACE_TRACE ("Driver::link_from_below");
+ ACE_Module *stream_tail = this->alloc_module (this);
+
+ stream_head->link (stream_tail);
+ if (stream_tail->reader ()->open () == -1
+ || stream_tail->writer ()->open () == -1)
+ {
+ stream_tail->close ();
+ return -1;
+ }
+ return 0;
+}
+
+int
+Driver::unlink_from_below (ACE_Module *)
+{
+ ACE_TRACE ("Driver::unlink_from_below");
+ return -1;
+}
+
+ACE_Multiplexor::ACE_Multiplexor (void)
+{
+ ACE_TRACE ("ACE_Multiplexor::ACE_Multiplexor");
+}
+
+ACE_Multiplexor::~ACE_Multiplexor (void)
+{
+ ACE_TRACE ("ACE_Multiplexor::~ACE_Multiplexor");
+}
+
+int
+ACE_Multiplexor::link_from_above (Driver &ld)
+{
+ ACE_TRACE ("ACE_Multiplexor::link_from_above");
+ return ld.link_from_below (this->alloc_lower_module (this));
+}
+
+int
+ACE_Multiplexor::link_from_above (ACE_Multiplexor &lm)
+{
+ ACE_TRACE ("ACE_Multiplexor::link_from_above");
+ return lm.link_from_below (this->alloc_lower_module (this));
+}
+
+int
+ACE_Multiplexor::link_from_below (ACE_Module *stream_head)
+{
+ ACE_TRACE ("ACE_Multiplexor::link_from_below");
+ ACE_Module *stream_tail = this->alloc_upper_module (this);
+
+ stream_head->link (stream_tail);
+ if (stream_tail->reader ()->open () == -1
+ || stream_tail->writer ()->open () == -1)
+ {
+ stream_tail->close ();
+ return -1;
+ }
+ return 0;
+}
+
+int
+ACE_Multiplexor::unlink_from_above (Driver &)
+{
+ ACE_TRACE ("ACE_Multiplexor::unlink_from_above");
+ return -1;
+}
+
+int
+ACE_Multiplexor::unlink_from_above (ACE_Multiplexor &)
+{
+ ACE_TRACE ("ACE_Multiplexor::unlink_from_above");
+ return -1;
+}
+
+int
+ACE_Multiplexor::unlink_from_below (ACE_Module *)
+{
+ ACE_TRACE ("ACE_Multiplexor::unlink_from_below");
+ return -1;
+}
diff --git a/ace/Utils/NT_Service.cpp b/ace/Utils/NT_Service.cpp
new file mode 100644
index 00000000000..a1989ec4957
--- /dev/null
+++ b/ace/Utils/NT_Service.cpp
@@ -0,0 +1,516 @@
+// $Id$
+
+// NT_Service.cpp
+
+#include "ace/config-all.h"
+#if defined (ACE_WIN32) && !defined (ACE_HAS_PHARLAP)
+
+#include "ace/NT_Service.h"
+#include "ace/Service_Object.h"
+
+#if !defined (__ACE_INLINE__)
+#include "ace/NT_Service.i"
+#endif /* __ACE_INLINE__ */
+
+ACE_ALLOC_HOOK_DEFINE(ACE_NT_Service)
+
+// ACE_NT_Service destructor.
+
+ACE_NT_Service::~ACE_NT_Service (void)
+{
+ if (svc_sc_handle_ != 0)
+ {
+ CloseServiceHandle (svc_sc_handle_);
+ svc_sc_handle_ = 0;
+ }
+ delete [] desc_;
+ delete [] name_;
+ delete [] host_;
+}
+
+// This default implementation of ACE_NT_Service::open sets the
+// service's status to START_PENDING with the estimated time until
+// STARTED set to the value given when this object was constructed.
+// Then the svc function is called, which implements the guts of the
+// service. Note that this function is running in a thread created by
+// the OS, not by ACE_Thread_Manager. The thread manager does not
+// know anything about this thread. The service can, however, use
+// ACE_Thread_Manager to start more threads if desired. When the svc
+// function returns, the service status is set to STOPPED, and exit
+// codes set based on errno/GetLastError if the svc function returns
+// -1.
+//
+// The svc function is expected to set the service status to SERVICE_RUNNING
+// after it initializes.
+//
+// The handle_control function will be called for each time there is a
+// request for the service. It is up to that function and svc to
+// cooperate to both respond appropriately to the request (by at least
+// updating the service's status) and to fulfill the request.
+
+int
+ACE_NT_Service::open (void *args)
+{
+ ACE_UNUSED_ARG (args);
+ report_status (SERVICE_START_PENDING, 0);
+
+ int svc_return = this->svc ();
+ if (svc_return == 0)
+ {
+ this->svc_status_.dwWin32ExitCode = NO_ERROR;
+ this->svc_status_.dwServiceSpecificExitCode = 0;
+ }
+ else
+ {
+ if (errno == 0)
+ {
+ this->svc_status_.dwWin32ExitCode = GetLastError ();
+ }
+ else
+ {
+ this->svc_status_.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
+ this->svc_status_.dwServiceSpecificExitCode = errno;
+ }
+ }
+
+ report_status (SERVICE_STOPPED, 0);
+
+ return svc_return;
+
+}
+
+void
+ACE_NT_Service::handle_control (DWORD control_code)
+{
+ switch(control_code)
+ {
+ case SERVICE_CONTROL_SHUTDOWN:
+ case SERVICE_CONTROL_STOP:
+ stop_requested (control_code);
+ break;
+
+ case SERVICE_CONTROL_PAUSE:
+ pause_requested (control_code);
+ break;
+
+ case SERVICE_CONTROL_CONTINUE:
+ continue_requested (control_code);
+ break;
+
+ case SERVICE_CONTROL_INTERROGATE:
+ interrogate_requested (control_code);
+ break;
+ }
+}
+
+void
+ACE_NT_Service::stop_requested (DWORD)
+{
+ this->report_status (SERVICE_STOP_PENDING);
+ /* how to cancel? */
+}
+
+void
+ACE_NT_Service::pause_requested (DWORD)
+{
+ this->report_status (SERVICE_PAUSE_PENDING);
+ this->suspend ();
+ report_status (SERVICE_PAUSED);
+}
+
+void
+ACE_NT_Service::continue_requested (DWORD)
+{
+ this->report_status (SERVICE_CONTINUE_PENDING);
+ this->resume ();
+ report_status (SERVICE_RUNNING);
+}
+
+void
+ACE_NT_Service::interrogate_requested (DWORD)
+{
+ this->report_status (0);
+}
+
+void
+ACE_NT_Service::name (const ACE_TCHAR *name, const ACE_TCHAR *desc)
+{
+ delete [] desc_;
+ delete [] name_;
+
+ if (desc == 0)
+ desc = name;
+
+ name_ = ACE::strnew (name);
+ desc_ = ACE::strnew (desc);
+}
+
+void
+ACE_NT_Service::host (const ACE_TCHAR *host)
+{
+ delete [] host_;
+
+ if (svc_sc_handle_ != 0)
+ {
+ CloseServiceHandle (svc_sc_handle_);
+ svc_sc_handle_ = 0;
+ }
+
+ if (host == 0)
+ {
+ host_ = 0;
+ }
+ else
+ {
+ host_ = ACE::strnew (host);
+ }
+}
+
+int
+ACE_NT_Service::insert (DWORD start_type,
+ DWORD error_control,
+ const ACE_TCHAR *exe_path,
+ const ACE_TCHAR *group_name,
+ LPDWORD tag_id,
+ const ACE_TCHAR *dependencies,
+ const ACE_TCHAR *account_name,
+ const ACE_TCHAR *password)
+{
+ ACE_TCHAR this_exe[MAXPATHLEN];
+
+ if (exe_path == 0)
+ {
+ if (ACE_TEXT_GetModuleFileName (0, this_exe, sizeof this_exe) == 0)
+ return -1;
+ exe_path = this_exe;
+ }
+
+ SC_HANDLE sc_mgr = ACE_TEXT_OpenSCManager (this->host (),
+ 0,
+ SC_MANAGER_ALL_ACCESS);
+ if (sc_mgr == 0)
+ return -1;
+
+ SC_HANDLE sh = ACE_TEXT_CreateService (sc_mgr,
+ this->name (),
+ this->desc (),
+ SERVICE_ALL_ACCESS,
+ svc_status_.dwServiceType,
+ start_type,
+ error_control,
+ exe_path,
+ group_name,
+ tag_id,
+ dependencies,
+ account_name,
+ password);
+ CloseServiceHandle (sc_mgr);
+ if (sh == 0)
+ return -1;
+
+ this->svc_sc_handle_ = sh;
+
+ return 0;
+
+}
+
+int
+ACE_NT_Service::remove (void)
+{
+ if (this->svc_sc_handle () == 0)
+ return -1;
+
+ if (DeleteService (this->svc_sc_handle()) == 0
+ && GetLastError () != ERROR_SERVICE_MARKED_FOR_DELETE)
+ return -1;
+
+ return 0;
+}
+
+// Sets the startup type for the service. Returns -1 on error, 0 on
+// success.
+int
+ACE_NT_Service::startup (DWORD startup)
+{
+ SC_HANDLE svc = this->svc_sc_handle ();
+ if (svc == 0)
+ return -1;
+
+ BOOL ok =
+ ChangeServiceConfig (svc,
+ (DWORD) SERVICE_NO_CHANGE,// No change to service type
+ startup, // New startup type
+ (DWORD) SERVICE_NO_CHANGE,// No change to error ctrl
+ 0, // No change to pathname
+ 0, // No change to load group
+ 0, // No change to tag
+ 0, // No change to dependencies
+ 0, 0, // No change to acct/passwd
+ 0); // No change to name
+
+ return ok ? 0 : -1;
+}
+
+// Returns the current startup type.
+
+DWORD
+ACE_NT_Service::startup (void)
+{
+ // The query buffer will hold strings as well as the defined struct.
+ // The string pointers in the struct point to other areas in the
+ // passed memory area, so it has to be large enough to hold the
+ // struct plus all the strings.
+ char cfgbuff[1024];
+ LPQUERY_SERVICE_CONFIG cfg;
+ DWORD cfgsize, needed_size;
+
+ SC_HANDLE svc = this->svc_sc_handle ();
+ if (svc == 0)
+ {
+ // To distinguish this error from the QueryServiceConfig failure
+ // below, return the DWORD equivalent of -2, rather than -1.
+ return MAXDWORD - 1;
+ }
+ cfgsize = sizeof cfgbuff;
+ cfg = (LPQUERY_SERVICE_CONFIG) cfgbuff;
+ BOOL ok = QueryServiceConfig (svc, cfg, cfgsize, &needed_size);
+ if (ok)
+ return cfg->dwStartType;
+ // Zero is a valid return value for QueryServiceConfig, so if
+ // QueryServiceConfig fails, return the DWORD equivalent of -1.
+ return MAXDWORD;
+
+}
+
+int
+ACE_NT_Service::start_svc (ACE_Time_Value *wait_time,
+ DWORD *svc_state,
+ DWORD argc, const ACE_TCHAR **argv)
+{
+ SC_HANDLE svc = this->svc_sc_handle ();
+ if (svc == 0)
+ return -1;
+
+ if (!ACE_TEXT_StartService (svc, argc, argv))
+ return -1;
+
+ wait_for_service_state (SERVICE_RUNNING, wait_time);
+ if (svc_state != 0)
+ *svc_state = this->svc_status_.dwCurrentState;
+
+ return 0;
+}
+
+int
+ACE_NT_Service::stop_svc (ACE_Time_Value *wait_time,
+ DWORD *svc_state)
+{
+ SC_HANDLE svc = this->svc_sc_handle ();
+ if (svc == 0)
+ return -1;
+
+ if (!ControlService (svc,
+ SERVICE_CONTROL_STOP,
+ &this->svc_status_))
+ return -1;
+
+ wait_for_service_state (SERVICE_STOPPED,
+ wait_time);
+ if (svc_state != 0)
+ *svc_state = this->svc_status_.dwCurrentState;
+
+ return 0;
+}
+
+int
+ACE_NT_Service::pause_svc (ACE_Time_Value *wait_time,
+ DWORD *svc_state)
+{
+ SC_HANDLE svc = this->svc_sc_handle ();
+ if (svc == 0)
+ return -1;
+
+ if (!ControlService (svc,
+ SERVICE_CONTROL_PAUSE,
+ &this->svc_status_))
+ return -1;
+
+ wait_for_service_state (SERVICE_PAUSED,
+ wait_time);
+ if (svc_state != 0)
+ *svc_state = this->svc_status_.dwCurrentState;
+
+ return 0;
+}
+
+int
+ACE_NT_Service::continue_svc (ACE_Time_Value *wait_time,
+ DWORD *svc_state)
+{
+ SC_HANDLE svc = this->svc_sc_handle ();
+ if (svc == 0)
+ return -1;
+
+ if (!ControlService (svc,
+ SERVICE_CONTROL_CONTINUE,
+ &this->svc_status_))
+ return -1;
+
+ wait_for_service_state (SERVICE_RUNNING,
+ wait_time);
+ if (svc_state != 0)
+ *svc_state = this->svc_status_.dwCurrentState;
+
+ return 0;
+}
+
+DWORD
+ACE_NT_Service::state (ACE_Time_Value *wait_hint)
+{
+ DWORD curr_state;
+
+ if (this->state (&curr_state,
+ wait_hint) == -1)
+ return 0;
+ return curr_state;
+}
+
+int
+ACE_NT_Service::state (DWORD *pstate,
+ ACE_Time_Value *wait_hint)
+{
+ SC_HANDLE svc = this->svc_sc_handle ();
+
+ if (svc == 0)
+ return -1;
+
+ // Need to create a temporary copy of this variable since the
+ // QueryServiceStatus call will modify the setting depending on the
+ // current state of the Service. If the service is currently
+ // STOPPED, the value will be cleared.
+ DWORD controls_accepted = svc_status_.dwControlsAccepted;
+
+ if (QueryServiceStatus (svc,
+ &this->svc_status_) == 0)
+ return -1;
+
+ if (wait_hint != 0)
+ wait_hint->msec (this->svc_status_.dwWaitHint);
+
+ *pstate = this->svc_status_.dwCurrentState;
+ this->svc_status_.dwControlsAccepted = controls_accepted;
+ return 0;
+}
+
+// test_access
+//
+// Open a new handle, ignoring any handle open in svc_sc_handle_.
+// This function's results are returned without leaving the handle
+// open.
+
+int
+ACE_NT_Service::test_access (DWORD desired_access)
+{
+ int status = -1; // Guilty until proven innocent
+
+ SC_HANDLE sc_mgr = ACE_TEXT_OpenSCManager (this->host (),
+ 0,
+ GENERIC_READ);
+ if (sc_mgr != 0)
+ {
+ SC_HANDLE handle = ACE_TEXT_OpenService (sc_mgr,
+ this->name (),
+ desired_access);
+ CloseServiceHandle (sc_mgr);
+ if (handle != 0)
+ {
+ status = 0;
+ CloseServiceHandle (handle);
+ }
+ }
+
+ return status;
+}
+
+// report_status
+//
+// Reports the current status. If new_status is not 0, it sets the
+// status to the new value before reporting. NOTE - this assumes that
+// no actual service status values have the value 0. This is true in
+// WinNT 4. If the status is a 'pending' type, the supplied time hint
+// is used unless it's 0, in which case the existing hint is used.
+// The dwWaitHint is not updated by this function. The checkpoint is
+// incremented by one after a pending report.
+
+int
+ACE_NT_Service::report_status (DWORD new_status,
+ DWORD time_hint)
+{
+ int bump_checkpoint = 0;
+ int retval = 0;
+ DWORD save_controls = 0;
+
+ if (new_status != 0)
+ this->svc_status_.dwCurrentState = new_status;
+ switch (this->svc_status_.dwCurrentState)
+ {
+ case SERVICE_START_PENDING:
+ save_controls = this->svc_status_.dwControlsAccepted;
+ this->svc_status_.dwControlsAccepted = 0;
+ /* Fall through */
+ case SERVICE_STOP_PENDING:
+ case SERVICE_CONTINUE_PENDING:
+ case SERVICE_PAUSE_PENDING:
+ this->svc_status_.dwWaitHint = time_hint ? time_hint : this->start_time_;
+ bump_checkpoint = 1;
+ break;
+
+ default:
+ this->svc_status_.dwCheckPoint = 0;
+ }
+
+ retval = SetServiceStatus (this->svc_handle_,
+ &this->svc_status_) ? 0 : -1;
+
+ if (save_controls != 0)
+ this->svc_status_.dwControlsAccepted = save_controls;
+
+ if (bump_checkpoint)
+ ++this->svc_status_.dwCheckPoint;
+
+ return retval;
+}
+
+SC_HANDLE
+ACE_NT_Service::svc_sc_handle (void)
+{
+ if (svc_sc_handle_ == 0)
+ {
+ SC_HANDLE sc_mgr = ACE_TEXT_OpenSCManager (this->host (),
+ 0,
+ SC_MANAGER_ALL_ACCESS);
+ if (sc_mgr != 0)
+ {
+ svc_sc_handle_ = ACE_TEXT_OpenService (sc_mgr,
+ this->name (),
+ SERVICE_ALL_ACCESS);
+ CloseServiceHandle (sc_mgr);
+ }
+ }
+
+ return svc_sc_handle_;
+}
+
+void
+ACE_NT_Service::wait_for_service_state (DWORD desired_state,
+ ACE_Time_Value *wait_time)
+{
+ // Doing the right thing with these needs to be added.
+ ACE_UNUSED_ARG (desired_state);
+ ACE_UNUSED_ARG (wait_time);
+
+ QueryServiceStatus (this->svc_sc_handle_,
+ &this->svc_status_);
+}
+
+#endif /* ACE_WIN32 && !ACE_HAS_PHARLAP */
diff --git a/ace/Utils/NT_Service.h b/ace/Utils/NT_Service.h
new file mode 100644
index 00000000000..e7dd1db2410
--- /dev/null
+++ b/ace/Utils/NT_Service.h
@@ -0,0 +1,398 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file NT_Service.h
+ *
+ * $Id$
+ *
+ * @author Steve Huston <shuston@riverace.com>
+ */
+//=============================================================================
+
+#ifndef ACE_NT_SERVICE_H
+#define ACE_NT_SERVICE_H
+#include "ace/pre.h"
+
+#include "ace/config-all.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#if defined (ACE_WIN32) && !defined (ACE_HAS_PHARLAP)
+
+#include "ace/Service_Object.h"
+#include "ace/Synch.h"
+#include "ace/Task.h"
+
+// ACE_NT_SERVICE_START_TIMEOUT is an estimate of the number of
+// milliseconds your service will take to start. Default is 5
+// seconds; you can pass a different value (or set one) when you
+// create the ACE_NT_Service object for your service.
+#if !defined ACE_NT_SERVICE_START_TIMEOUT
+#define ACE_NT_SERVICE_START_TIMEOUT 5000
+#endif /* ACE_NT_SERVICE_TIMEOUT */
+
+/**
+ * @class ACE_NT_Service
+ *
+ * @brief Provide the base class which defines the interface for controlling
+ * an NT service.
+ *
+ * NT Services can be implemented using the framework defined by
+ * the ACE_NT_Service class, and the macros defined in this file.
+ * Some quick refresher notes on NT Services:
+ *
+ * - The main program defines an array of entries describing the
+ * services offered. The ACE_NT_SERVICE_ENTRY macro can help with
+ * this.
+ * - For each service, a separate ServiceMain and Handler function
+ * need to be defined. These are taken care of by the
+ * ACE_NT_SERVICE_DEFINE macro.
+ * - When the main program/thread calls
+ * StartServiceCtrlDispatcher, NT creates a thread for each
+ * service, and runs the ServiceMain function for the service in
+ * that new thread. When that thread exits, the service is gone.
+ *
+ * To use this facility, you could derive a class from
+ * ACE_Service_Object (if you want to start via ACE's service
+ * configurator), or use any other class to run when the image
+ * starts (assuming that NT runs the image). You must set up an
+ * NT SERVICE_TABLE_ENTRY array to define your service(s). You
+ * can use the ACE_NT_SERVICE_... macros defined below for this.
+ *
+ * A SERVICE_TABLE might look like this:
+ * ACE_NT_SERVICE_REFERENCE(Svc1); // If service is in another file
+ * SERVICE_TABLE_ENTRY myServices[] = {
+ * ACE_NT_SERVICE_ENTRY ("MyNeatService", Svc1),
+ * { 0, 0 } };
+ *
+ * In the file where your service(s) are implemented, use the
+ * ACE_NT_SERVICE_DEFINE macro to set up the following:
+ * 1. A pointer to the service's implementation object (must be derived
+ * from ACE_NT_Service).
+ * 2. The service's Handler function (forwards all requests to the
+ * ACE_NT_Service-derived object's handle_control function).
+ * 3. The service's ServiceMain function. Creates a new instance
+ * of the ACE_NT_Service-derived class SVCCLASS, unless one has
+ * been created already.
+ *
+ * If you are using all the default constructor values, you can
+ * let the generated ServiceMain function create the object, else
+ * you need to create it by hand before calling
+ * StartServiceCtrlDispatcher. Set the pointer so ServiceMain
+ * won't create another one. Another reason you may want to do
+ * the object creation yourself is if you want to also implement
+ * suspend and resume functions (the ones inherited from
+ * ACE_Service_Object) to do something intelligent to the services
+ * which are running, like call their handle_control functions to
+ * request suspend and resume actions, similar to what NT would do
+ * if a Services control panel applet would do if the user clicks
+ * on Suspend.
+ */
+class ACE_Export ACE_NT_Service : public ACE_Task<ACE_MT_SYNCH>
+{
+
+public:
+ // = Initialization and termination methods.
+ /// Constructor primarily for use when running the service.
+ ACE_NT_Service (DWORD start_timeout = ACE_NT_SERVICE_START_TIMEOUT,
+ DWORD service_type = SERVICE_WIN32_OWN_PROCESS,
+ DWORD controls_mask = SERVICE_ACCEPT_STOP);
+
+ /// Constructor primarily for use when inserting/removing/controlling
+ /// the service.
+ ACE_NT_Service (const ACE_TCHAR *name,
+ const ACE_TCHAR *desc = 0,
+ DWORD start_timeout = ACE_NT_SERVICE_START_TIMEOUT,
+ DWORD service_type = SERVICE_WIN32_OWN_PROCESS,
+ DWORD controls_mask = SERVICE_ACCEPT_STOP);
+
+ virtual ~ACE_NT_Service (void);
+
+ // = Functions to operate the service
+
+ /**
+ * Hook called to open the service. By default, will set the status
+ * to <START>_PENDING, <svc>, <wait>, then set the status to
+ * STOPPED.
+ */
+ virtual int open (void *args = 0);
+
+ /**
+ * The actual service implementation. This function need not be overridden
+ * by applications that are just using SCM capabilities, but must be
+ * by subclasses when actually running the service. It is expected that
+ * this function will set the status to RUNNING.
+ */
+ virtual int svc (void);
+
+ /**
+ * This function is called in response to a request from the Service
+ * Dispatcher. It must interact with the <svc> function to effect the
+ * requested control operation. The default implementation handles
+ * all requests as follows:
+ * SERVICE_CONTROL_STOP: set stop pending, set cancel flag
+ * SERVICE_CONTROL_PAUSE: set pause pending, <suspend>, set paused
+ * SERVICE_CONTROL_CONTINUE: set continue pending, <resume>, set running
+ * SERVICE_CONTROL_INTERROGATE: reports current status
+ * SERVICE_CONTROL_SHUTDOWN: same as SERVICE_CONTROL_STOP.
+ */
+ virtual void handle_control (DWORD control_code);
+
+ /// Set the svc_handle_ member. This is only a public function because
+ /// the macro-generated service function calls it.
+ void svc_handle (const SERVICE_STATUS_HANDLE new_svc_handle);
+
+
+ // = Methods which can be used to do SCP-like functions. The first group
+ // are used to register/insert and remove the service's definition in the
+ // SCM registry.
+
+ /// Sets the name and description for the service.
+ /// If desc is 0, it takes the same value as name.
+ void name (const ACE_TCHAR *name, const ACE_TCHAR *desc = 0);
+
+ /// Get the service name.
+ const ACE_TCHAR *name (void) const;
+
+ /// Get the service description.
+ const ACE_TCHAR *desc (void) const;
+
+ /// Sets the host machine
+ void host (const ACE_TCHAR *host);
+
+ /// Get the host machine.
+ const ACE_TCHAR *host (void) const;
+
+ /**
+ * Insert (create) the service in the NT Service Control Manager,
+ * with the given creation values. exe_path defaults to the path name
+ * of the program that calls the function. All other 0-defaulted arguments
+ * pass 0 into the service creation, taking NT_specified defaults.
+ * Returns -1 on error, 0 on success.
+ */
+ int insert (DWORD start_type = SERVICE_DEMAND_START,
+ DWORD error_control = SERVICE_ERROR_IGNORE,
+ const ACE_TCHAR *exe_path = 0,
+ const ACE_TCHAR *group_name = 0,
+ LPDWORD tag_id = 0,
+ const ACE_TCHAR *dependencies = 0,
+ const ACE_TCHAR *account_name = 0,
+ const ACE_TCHAR *password = 0);
+
+ /**
+ * Remove the service from the NT Service Control Manager. Returns -1 on
+ * error, 0 on success. This just affects the SCM and registry - the
+ * can and will keep running fine if it is already running.
+ */
+ int remove (void);
+
+ /// Sets the startup type for the service. Returns -1 on error, 0 on success.
+ int startup (DWORD startup);
+
+ /// Returns the current startup type.
+ DWORD startup (void);
+
+
+ // = Methods which control the service's execution.
+
+ // These methods to start/pause/resume/stop/check the service all
+ // have the following common behavior with respect to <wait_time>
+ // and return value. <wait_time> is a pointer to an ACE_Time_Value
+ // object. If not supplied (a zero pointer) the function will wait
+ // indefinitely for the action to be finalized (service reach
+ // running state, completely shut down, etc.) or get "stuck" before
+ // returning. If the time is supplied, it specifies how long to
+ // wait for the service to reach a steady state, and on return, it
+ // is updated to the service's last reported wait hint. So, if you
+ // want to control the waiting yourself (for example, you want to
+ // react to UI events during the wait) specify a <wait_time> of (0,
+ // 0) and use the updated time to know when to check the service's
+ // state again. NOTE!!!! The wait_time things don't work yet. The
+ // calls always check status once, and do not wait for it to change.
+ //
+ // The return value from start_svc, stop_svc, pause_svc,
+ // continue_svc is 0 if the request to NT to effect the change was
+ // made successfully. The service may refuse to change, or not do
+ // what you wanted; so if you need to know, supply a <svc_state>
+ // pointer to receive the service's reported last state on return
+ // and check it to see if it's what you want. The functions only
+ // return -1 when the actual request to the service is refused -
+ // this would include privilege restrictions and if the service is
+ // not configured to receive the request (this is most likely to
+ // happen in the case of pause and continue).
+
+ /**
+ * Start the service (must have been inserted before). wait_time is
+ * the time to wait for the service to reach a steady state before
+ * returning. If it is 0, the function waits as long as it takes
+ * for the service to reach the 'running' state, or gets stuck in
+ * some other state, or exits. If <wait_time> is supplied, it is
+ * updated on return to hold the service's last reported wait hint.
+ * svc_state can be used to receive the state which the service
+ * settled in. If the value is 0, the service never ran. argc/argv
+ * are passed to the service's ServiceMain function when it starts.
+ * Returns 0 for success, -1 for error.
+ */
+ int start_svc (ACE_Time_Value *wait_time = 0,
+ DWORD *svc_state = 0,
+ DWORD argc = 0, const ACE_TCHAR **argv = 0);
+
+ /**
+ * Requests the service to stop. Will wait up to <wait_time> for
+ * the service to actually stop. If not specified, the function
+ * waits until the service either stops or gets stuck in some other
+ * state before it stops. If <svc_state> is specified, it receives
+ * the last reported state of the service. Returns 0 if the request
+ * was made successfully, -1 if not.
+ */
+ int stop_svc (ACE_Time_Value *wait_time = 0, DWORD *svc_state = 0);
+
+ /// Pause the service.
+ int pause_svc (ACE_Time_Value *wait_time = 0, DWORD *svc_state = 0);
+
+ /// Continue the service.
+ int continue_svc (ACE_Time_Value *wait_time = 0, DWORD *svc_state = 0);
+
+ /**
+ * Get the current state for the service. If <wait_hint> is not 0,
+ * it receives the service's reported wait hint. Note that this
+ * function returns 0 on failure (not -1 as is usual in ACE). A
+ * zero return would (probably) only be returned if there is either
+ * no service with the given name in the SCM database, or the caller
+ * does not have sufficient rights to access the service state. The
+ * set of valid service state values are all greater than 0.
+ */
+ DWORD state (ACE_Time_Value *wait_hint = 0);
+
+ /// A version of <state> that returns -1 for failure, 0 for success.
+ /// The DWORD pointed to by pstate receives the state value.
+ int state (DWORD *pstate, ACE_Time_Value *wait_hint = 0);
+
+ /**
+ * Test access to the object's service in the SCM. The service must
+ * already have been inserted in the SCM database. This function
+ * has no affect on the service itself. Returns 0 if the specified
+ * access is allowed, -1 otherwise (either the access is denied, or
+ * there is a problem with the service's definition - check
+ * ACE_OS::last_error to get the specific error indication.
+ */
+ int test_access (DWORD desired_access = SERVICE_ALL_ACCESS);
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+protected:
+ int report_status (DWORD new_status, DWORD time_hint = 0);
+
+ /**
+ * Return the svc_sc_handle_ member. If the member is null, it
+ * retrieves the handle from the Service Control Manager and caches
+ * it.
+ */
+ SC_HANDLE svc_sc_handle (void);
+
+ /**
+ * Waits for the service to reach <desired_state> or get
+ * (apparently) stuck before it reaches that state. Will wait at
+ * most <wait_time> to get to the desired state. If <wait_time> is
+ * 0, then the function keeps waiting until the desired state is
+ * reached or the service doesn't update its state any further. The
+ * svc_status_ class member is updated upon return. NOTE - the
+ * timeout doesn't currently work - it always acts like
+ * ACE_Time_Value::zero is passed - it checks the state once but
+ * doesn't wait after that.
+ */
+ void wait_for_service_state (DWORD desired_state, ACE_Time_Value *wait_time);
+
+ /// Called by <handle_control> when a stop/shutdown was requested.
+ virtual void stop_requested (DWORD control_code);
+
+ /// Called by <handle_control> when a pause was requested.
+ virtual void pause_requested (DWORD control_code);
+
+ /// Called by <handle_control> when a continue was requested.
+ virtual void continue_requested (DWORD control_code);
+
+ /// Called by <handle_control> when a interrogate was requested.
+ virtual void interrogate_requested (DWORD control_code);
+
+protected:
+ /// Estimate of init time needed
+ /// Service handle - doesn't need close.
+ DWORD start_time_;
+ SERVICE_STATUS_HANDLE svc_handle_;
+ SERVICE_STATUS svc_status_;
+
+ /// Service's SCM handle
+ SC_HANDLE svc_sc_handle_;
+ ACE_TCHAR *name_;
+ ACE_TCHAR *desc_;
+ ACE_TCHAR *host_;
+
+};
+
+// These macros help to get things set up correctly at compile time
+// and to take most of the grudge work out of creating the proper
+// functions and doing the registrations.
+//
+// ACE_NT_SERVICE_DEFINE - defines the 'ServiceMain' function which NT will
+// call in its own thread when the service control
+// dispatcher starts.
+
+#define ACE_NT_SERVICE_DEFINE(SVCNAME, SVCCLASS, SVCDESC) \
+ ACE_NT_Service * _ace_nt_svc_obj_##SVCNAME = 0; \
+ VOID WINAPI ace_nt_svc_handler_##SVCNAME (DWORD fdwControl) { \
+ _ace_nt_svc_obj_##SVCNAME->handle_control(fdwControl); \
+ } \
+ VOID WINAPI ace_nt_svc_main_##SVCNAME (DWORD dwArgc, \
+ ACE_TCHAR **lpszArgv) { \
+ int delete_svc_obj = 0; \
+ if (_ace_nt_svc_obj_##SVCNAME == 0) { \
+ ACE_NEW (_ace_nt_svc_obj_##SVCNAME, SVCCLASS); \
+ if (_ace_nt_svc_obj_##SVCNAME == 0) \
+ return; \
+ delete_svc_obj = 1; \
+ } \
+ _ace_nt_svc_obj_##SVCNAME->init(dwArgc, lpszArgv); \
+ _ace_nt_svc_obj_##SVCNAME->svc_handle( \
+ ACE_TEXT_RegisterServiceCtrlHandler(SVCDESC, \
+ &ace_nt_svc_handler_##SVCNAME)); \
+ _ace_nt_svc_obj_##SVCNAME->open(); \
+ _ace_nt_svc_obj_##SVCNAME->wait(); \
+ _ace_nt_svc_obj_##SVCNAME->fini(); \
+ if (delete_svc_obj) { \
+ delete _ace_nt_svc_obj_##SVCNAME; \
+ _ace_nt_svc_obj_##SVCNAME = 0; \
+ } \
+ return; \
+ }
+
+#define ACE_NT_SERVICE_REFERENCE(SVCNAME) \
+extern ACE_NT_Service * _ace_nt_svc_obj_##SVCNAME; \
+extern VOID WINAPI ace_nt_svc_main_##SVCNAME (DWORD dwArgc, \
+ ACE_TCHAR **lpszArgv);
+
+#define ACE_NT_SERVICE_ENTRY(SVCDESC, SVCNAME) \
+ { SVCDESC, &ace_nt_svc_main_##SVCNAME }
+
+#define ACE_NT_SERVICE_RUN(SVCNAME, SVCINSTANCE, RET) \
+ ACE_TEXT_SERVICE_TABLE_ENTRY _ace_nt_svc_table[2] = \
+ { \
+ ACE_NT_SERVICE_ENTRY(ACE_TEXT (#SVCNAME), SVCNAME), \
+ { 0, 0 } \
+ }; \
+ _ace_nt_svc_obj_##SVCNAME = SVCINSTANCE; \
+ ACE_OS::last_error (0); \
+ int RET = ACE_TEXT_StartServiceCtrlDispatcher(_ace_nt_svc_table);
+
+#if defined (__ACE_INLINE__)
+#include "ace/NT_Service.i"
+#endif /* __ACE_INLINE__ */
+
+#endif /* ACE_WIN32 && !ACE_HAS_PHARLAP */
+
+#include "ace/post.h"
+#endif /* ACE_SERVICE_OBJECT_H */
diff --git a/ace/Utils/NT_Service.i b/ace/Utils/NT_Service.i
new file mode 100644
index 00000000000..5a465066727
--- /dev/null
+++ b/ace/Utils/NT_Service.i
@@ -0,0 +1,79 @@
+/* -*- C++ -*- */
+// $Id$
+
+ACE_INLINE
+ACE_NT_Service::ACE_NT_Service (DWORD start_timeout,
+ DWORD service_type,
+ DWORD controls_mask) :
+ start_time_(start_timeout),
+ svc_handle_(0),
+ svc_sc_handle_(0),
+ name_(0),
+ desc_(0),
+ host_(0)
+{
+ svc_status_.dwServiceType = service_type;
+ svc_status_.dwCurrentState = 0;
+ svc_status_.dwControlsAccepted = controls_mask;
+ svc_status_.dwWin32ExitCode = NO_ERROR;
+ svc_status_.dwServiceSpecificExitCode = 0;
+ svc_status_.dwCheckPoint = 0;
+}
+
+
+ACE_INLINE
+ACE_NT_Service::ACE_NT_Service (const ACE_TCHAR *name,
+ const ACE_TCHAR *desc,
+ DWORD start_timeout,
+ DWORD service_type,
+ DWORD controls_mask) :
+ start_time_(start_timeout),
+ svc_handle_(0),
+ svc_sc_handle_(0),
+ name_(ACE::strnew(name)),
+ desc_(ACE::strnew(desc)),
+ host_(0)
+{
+ svc_status_.dwServiceType = service_type;
+ svc_status_.dwCurrentState = 0;
+ svc_status_.dwControlsAccepted = controls_mask;
+ svc_status_.dwWin32ExitCode = NO_ERROR;
+ svc_status_.dwServiceSpecificExitCode = 0;
+ svc_status_.dwCheckPoint = 0;
+}
+
+
+ACE_INLINE int
+ACE_NT_Service::svc (void)
+{
+ return -1;
+}
+
+
+ACE_INLINE
+const ACE_TCHAR *
+ACE_NT_Service::name (void) const
+{
+ return name_;
+}
+
+ACE_INLINE
+const ACE_TCHAR *
+ACE_NT_Service::desc (void) const
+{
+ return desc_;
+}
+
+ACE_INLINE
+const ACE_TCHAR *
+ACE_NT_Service::host (void) const
+{
+ return host_;
+}
+
+ACE_INLINE void
+ACE_NT_Service::svc_handle(const SERVICE_STATUS_HANDLE new_svc_handle)
+{
+ this->svc_handle_ = new_svc_handle;
+ return;
+}
diff --git a/ace/Utils/Object_Manager.cpp b/ace/Utils/Object_Manager.cpp
new file mode 100644
index 00000000000..8b865c4038d
--- /dev/null
+++ b/ace/Utils/Object_Manager.cpp
@@ -0,0 +1,874 @@
+// $Id$
+
+#include "ace/Object_Manager.h"
+#if !defined (ACE_LACKS_ACE_TOKEN)
+# include "ace/Token_Manager.h"
+#endif /* ! ACE_LACKS_ACE_TOKEN */
+#if defined (ACE_LACKS_ACE_SVCCONF)
+# if !defined (ACE_HAS_WINCE)
+# include "ace/Proactor.h"
+# endif /* !ACE_HAS_WINCE */
+# include "ace/Reactor.h"
+# include "ace/Thread_Manager.h"
+#else /* ! ACE_LACKS_ACE_SVCCONF */
+# include "ace/Service_Manager.h"
+# include "ace/Service_Config.h"
+#endif /* ! ACE_LACKS_ACE_SVCCONF */
+#include "ace/Signal.h"
+#include "ace/Log_Msg.h"
+#include "ace/Containers.h"
+#include "ace/Synch.h"
+#include "ace/Malloc.h"
+#include "ace/Signal.h"
+
+#if !defined (__ACE_INLINE__)
+# include "ace/Object_Manager.i"
+#endif /* __ACE_INLINE__ */
+
+ACE_RCSID(ace, Object_Manager, "$Id$")
+
+#if ! defined (ACE_APPLICATION_PREALLOCATED_OBJECT_DEFINITIONS)
+# define ACE_APPLICATION_PREALLOCATED_OBJECT_DEFINITIONS
+#endif /* ACE_APPLICATION_PREALLOCATED_OBJECT_DEFINITIONS */
+
+#if ! defined (ACE_APPLICATION_PREALLOCATED_ARRAY_DEFINITIONS)
+# define ACE_APPLICATION_PREALLOCATED_ARRAY_DEFINITIONS
+#endif /* ACE_APPLICATION_PREALLOCATED_ARRAY_DEFINITIONS */
+
+#if ! defined (ACE_APPLICATION_PREALLOCATED_OBJECT_DELETIONS)
+# define ACE_APPLICATION_PREALLOCATED_OBJECT_DELETIONS
+#endif /* ACE_APPLICATION_PREALLOCATED_OBJECT_DELETIONS */
+
+#if ! defined (ACE_APPLICATION_PREALLOCATED_ARRAY_DELETIONS)
+# define ACE_APPLICATION_PREALLOCATED_ARRAY_DELETIONS
+#endif /* ACE_APPLICATION_PREALLOCATED_ARRAY_DELETIONS */
+
+// Singleton pointer.
+ACE_Object_Manager *ACE_Object_Manager::instance_ = 0;
+
+void *ACE_Object_Manager::preallocated_object[
+ ACE_Object_Manager::ACE_PREALLOCATED_OBJECTS] = { 0 };
+
+void *ACE_Object_Manager::preallocated_array[
+ ACE_Object_Manager::ACE_PREALLOCATED_ARRAYS] = { 0 };
+
+// Handy macros for use by ACE_Object_Manager constructor to
+// preallocate or delete an object or array, either statically (in
+// global data) or dynamically (on the heap).
+#if defined (ACE_HAS_STATIC_PREALLOCATION)
+# define ACE_PREALLOCATE_OBJECT(TYPE, ID)\
+ {\
+ static ACE_Cleanup_Adapter<TYPE> obj;\
+ preallocated_object[ID] = &obj;\
+ }
+# define ACE_PREALLOCATE_ARRAY(TYPE, ID, COUNT)\
+ {\
+ static ACE_Cleanup_Adapter<TYPE> obj[COUNT];\
+ preallocated_array[ID] = &obj;\
+ }
+#else
+# define ACE_PREALLOCATE_OBJECT(TYPE, ID)\
+ {\
+ ACE_Cleanup_Adapter<TYPE> *obj_p;\
+ ACE_NEW_RETURN (obj_p, ACE_Cleanup_Adapter<TYPE>, -1);\
+ preallocated_object[ID] = obj_p;\
+ }
+# define ACE_PREALLOCATE_ARRAY(TYPE, ID, COUNT)\
+ {\
+ ACE_Cleanup_Adapter<TYPE[COUNT]> *array_p;\
+ ACE_NEW_RETURN (array_p, ACE_Cleanup_Adapter<TYPE[COUNT]>, -1);\
+ preallocated_array[ID] = array_p;\
+ }
+# define ACE_DELETE_PREALLOCATED_OBJECT(TYPE, ID)\
+ ace_cleanup_destroyer (\
+ (ACE_Cleanup_Adapter<TYPE> *) preallocated_object[ID], 0);\
+ preallocated_object[ID] = 0;
+# define ACE_DELETE_PREALLOCATED_ARRAY(TYPE, ID, COUNT)\
+ delete (ACE_Cleanup_Adapter<TYPE[COUNT]> *) preallocated_array[ID];\
+ preallocated_array[ID] = 0;
+#endif /* ACE_HAS_STATIC_PREALLOCATION */
+
+#if !defined (ACE_LACKS_ACE_SVCCONF)
+
+class ACE_Object_Manager_Preallocations
+{
+ // = TITLE
+ // Performs preallocations of certain statically allocated
+ // services needed by ACE.
+public:
+ ACE_Object_Manager_Preallocations (void);
+ ~ACE_Object_Manager_Preallocations (void);
+
+private:
+ ACE_Static_Svc_Descriptor ace_svc_desc_ACE_Service_Manager;
+};
+
+// We can't use the ACE_SVC_FACTORY_DECLARE macro here because this
+// needs to be in the ACE_Export context rather than the
+// ACE_Svc_Export context.
+//extern "C" ACE_Export
+//ACE_Service_Object *
+//_make_ACE_Service_Manager (ACE_Service_Object_Exterminator *);
+
+ACE_Object_Manager_Preallocations::ACE_Object_Manager_Preallocations (void)
+{
+ ACE_STATIC_SVC_DEFINE (ACE_Service_Manager_initializer,
+ ACE_LIB_TEXT ("ACE_Service_Manager"),
+ ACE_SVC_OBJ_T,
+ &ACE_SVC_NAME (ACE_Service_Manager),
+ ACE_Service_Type::DELETE_THIS |
+ ACE_Service_Type::DELETE_OBJ,
+ 0)
+
+ // Initialize the static service objects using the descriptors created
+ // above.
+ ace_svc_desc_ACE_Service_Manager =
+ ace_svc_desc_ACE_Service_Manager_initializer;
+
+ // Add to the list of static configured services.
+ ACE_Service_Config::static_svcs ()->
+ insert (&ace_svc_desc_ACE_Service_Manager);
+}
+
+ACE_Object_Manager_Preallocations::~ACE_Object_Manager_Preallocations (void)
+{
+}
+
+#endif /* ! ACE_LACKS_ACE_SVCCONF */
+
+int
+ACE_Object_Manager::starting_up (void)
+{
+ return ACE_Object_Manager::instance_ ? instance_->starting_up_i () : 1;
+}
+
+int
+ACE_Object_Manager::shutting_down (void)
+{
+ return ACE_Object_Manager::instance_ ? instance_->shutting_down_i () : 1;
+}
+
+#if defined (ACE_DISABLE_WIN32_ERROR_WINDOWS)
+// Instead of popping up a window for exceptions, just print something out
+LONG _stdcall ACE_UnhandledExceptionFilter (PEXCEPTION_POINTERS pExceptionInfo)
+{
+ DWORD dwExceptionCode = pExceptionInfo->ExceptionRecord->ExceptionCode;
+
+ if (dwExceptionCode == EXCEPTION_ACCESS_VIOLATION)
+ ACE_ERROR ((LM_ERROR, ACE_LIB_TEXT ("\nERROR: ACCESS VIOLATION\n")));
+ else
+ ACE_ERROR ((LM_ERROR, ACE_LIB_TEXT ("\nERROR: UNHANDLED EXCEPTION\n")));
+
+ return EXCEPTION_EXECUTE_HANDLER;
+}
+#endif /* ACE_DISABLE_WIN32_ERROR_WINDOWS */
+
+// Initialize an ACE_Object_Manager. There can be instances of this object
+// other than The Instance. This can happen if a user creates one for some
+// reason. All objects set up their per-object information and managed
+// objects, but only The Instance sets up the static preallocated objects and
+// the (static) ACE_Service_Config signal handler.
+int
+ACE_Object_Manager::init (void)
+{
+ if (starting_up_i ())
+ {
+ // First, indicate that the ACE_Object_Manager instance is being
+ // initialized.
+ object_manager_state_ = OBJ_MAN_INITIALIZING;
+
+ // Only The Instance sets up with ACE_OS_Object_Manager and initializes
+ // the preallocated objects.
+ if (this == instance_)
+ {
+ // Make sure that the ACE_OS_Object_Manager has been created,
+ // and register with it for chained fini ().
+ ACE_OS_Object_Manager::instance ()->next_ = this;
+
+# if !defined (ACE_LACKS_ACE_SVCCONF)
+ // Construct the ACE_Service_Config's signal handler.
+ ACE_NEW_RETURN (ace_service_config_sig_handler_,
+ ACE_Sig_Adapter (&ACE_Service_Config::handle_signal), -1);
+ ACE_Service_Config::signal_handler (ace_service_config_sig_handler_);
+# endif /* ! ACE_LACKS_ACE_SVCCONF */
+
+ // Allocate the preallocated (hard-coded) object instances.
+ ACE_PREALLOCATE_OBJECT (ACE_SYNCH_RW_MUTEX, ACE_FILECACHE_LOCK)
+# if defined (ACE_HAS_THREADS)
+ ACE_PREALLOCATE_OBJECT (ACE_Recursive_Thread_Mutex,
+ ACE_STATIC_OBJECT_LOCK)
+# endif /* ACE_HAS_THREADS */
+# if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0)
+ ACE_PREALLOCATE_OBJECT (ACE_Thread_Mutex,
+ ACE_MT_CORBA_HANDLER_LOCK)
+ ACE_PREALLOCATE_OBJECT (ACE_Thread_Mutex, ACE_DUMP_LOCK)
+ ACE_PREALLOCATE_OBJECT (ACE_Recursive_Thread_Mutex,
+ ACE_SIG_HANDLER_LOCK)
+ ACE_PREALLOCATE_OBJECT (ACE_Null_Mutex, ACE_SINGLETON_NULL_LOCK)
+ ACE_PREALLOCATE_OBJECT (ACE_Recursive_Thread_Mutex,
+ ACE_SINGLETON_RECURSIVE_THREAD_LOCK)
+ ACE_PREALLOCATE_OBJECT (ACE_Thread_Mutex, ACE_THREAD_EXIT_LOCK)
+#if !defined (ACE_LACKS_ACE_TOKEN) && defined (ACE_HAS_TOKENS_LIBRARY)
+ ACE_PREALLOCATE_OBJECT (ACE_TOKEN_CONST::MUTEX,
+ ACE_TOKEN_MANAGER_CREATION_LOCK)
+ ACE_PREALLOCATE_OBJECT (ACE_TOKEN_CONST::MUTEX,
+ ACE_TOKEN_INVARIANTS_CREATION_LOCK)
+#endif /* ! ACE_LACKS_ACE_TOKEN && ACE_HAS_TOKENS_LIBRARY */
+ ACE_PREALLOCATE_OBJECT (ACE_Thread_Mutex,
+ ACE_PROACTOR_EVENT_LOOP_LOCK)
+# endif /* ACE_MT_SAFE */
+ }
+
+ if (this == instance_)
+ {
+ // Hooks for preallocated objects and arrays provided by application.
+ ACE_APPLICATION_PREALLOCATED_OBJECT_DEFINITIONS
+ ACE_APPLICATION_PREALLOCATED_ARRAY_DEFINITIONS
+
+# if defined (ACE_HAS_TSS_EMULATION)
+ // Initialize the main thread's TS storage.
+ ACE_TSS_Emulation::tss_open (ts_storage_);
+# endif /* ACE_HAS_TSS_EMULATION */
+
+#if defined (ACE_DISABLE_WIN32_ERROR_WINDOWS)
+#if defined (_DEBUG) && defined (_MSC_VER)
+ // This will keep the ACE_Assert window
+ _CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_FILE );
+ _CrtSetReportFile( _CRT_ERROR, _CRTDBG_FILE_STDERR );
+#endif /* _DEBUG && _MSC_VER */
+
+ // And this will catch all unhandled exceptions.
+ SetUnhandledExceptionFilter (&ACE_UnhandledExceptionFilter);
+#endif /* ACE_DISABLE_WIN32_ERROR_WINDOWS */
+
+
+
+# if !defined (ACE_LACKS_ACE_SVCCONF)
+ ACE_NEW_RETURN (preallocations_,
+ ACE_Object_Manager_Preallocations,
+ -1);
+# endif /* ! ACE_LACKS_ACE_SVCCONF */
+
+ // Open the main thread's ACE_Log_Msg.
+ (void) ACE_LOG_MSG;
+ }
+
+ // Finally, indicate that the ACE_Object_Manager instance has
+ // been initialized.
+ object_manager_state_ = OBJ_MAN_INITIALIZED;
+
+ return 0;
+ } else {
+ // Had already initialized.
+ return 1;
+ }
+}
+
+ACE_Object_Manager::ACE_Object_Manager (void)
+ // With ACE_HAS_TSS_EMULATION, ts_storage_ is initialized by the call to
+ // ACE_OS::tss_open () in the function body.
+ : exit_info_ ()
+#if !defined (ACE_LACKS_ACE_SVCCONF)
+ , preallocations_ (0)
+ , ace_service_config_sig_handler_ (0)
+#endif /* ! ACE_LACKS_ACE_SVCCONF */
+#if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0)
+ , singleton_null_lock_ (0)
+ , singleton_recursive_lock_ (0)
+# endif /* ACE_MT_SAFE */
+{
+#if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0)
+ ACE_NEW (internal_lock_, ACE_Recursive_Thread_Mutex);
+# endif /* ACE_MT_SAFE */
+
+ // If instance_ was not 0, then another ACE_Object_Manager has
+ // already been instantiated (it is likely to be one initialized by way
+ // of library/DLL loading). Let this one go through construction in
+ // case there really is a good reason for it (like, ACE is a static/archive
+ // library, and this one is the non-static instance (with
+ // ACE_HAS_NONSTATIC_OBJECT_MANAGER, or the user has a good reason for
+ // creating a separate one) but the original one will be the one retrieved
+ // from calls to ACE_Object_Manager::instance().
+
+ // Be sure that no further instances are created via instance ().
+ if (instance_ == 0)
+ instance_ = this;
+
+ init ();
+}
+
+ACE_Object_Manager::~ACE_Object_Manager (void)
+{
+ dynamically_allocated_ = 0; // Don't delete this again in fini()
+ fini ();
+}
+
+ACE_Object_Manager *
+ACE_Object_Manager::instance (void)
+{
+ // This function should be called during construction of static
+ // instances, or before any other threads have been created in
+ // the process. So, it's not thread safe.
+
+ if (instance_ == 0)
+ {
+ ACE_Object_Manager *instance_pointer;
+
+ ACE_NEW_RETURN (instance_pointer,
+ ACE_Object_Manager,
+ 0);
+ ACE_ASSERT (instance_pointer == instance_);
+
+ instance_pointer->dynamically_allocated_ = 1;
+
+ return instance_pointer;
+ }
+ else
+ return instance_;
+}
+
+int
+ACE_Object_Manager::at_exit_i (void *object,
+ ACE_CLEANUP_FUNC cleanup_hook,
+ void *param)
+{
+ ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon,
+ *instance_->internal_lock_, -1));
+
+ if (shutting_down_i ())
+ {
+ errno = EAGAIN;
+ return -1;
+ }
+
+ if (exit_info_.find (object))
+ {
+ // The object has already been registered.
+ errno = EEXIST;
+ return -1;
+ }
+
+ return exit_info_.at_exit_i (object, cleanup_hook, param);
+}
+
+#if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0)
+
+int
+ACE_Object_Manager::get_singleton_lock (ACE_Null_Mutex *&lock)
+{
+ if (starting_up () || shutting_down ())
+ {
+ // The preallocated lock has not been constructed yet.
+ // Therefore, the program is single-threaded at this point. Or,
+ // the ACE_Object_Manager instance has been destroyed, so the
+ // preallocated lock is not available. Allocate a lock to use,
+ // for interface compatibility, though there should be no
+ // contention on it.
+ if (ACE_Object_Manager::instance ()->singleton_null_lock_ == 0)
+ {
+ ACE_NEW_RETURN (ACE_Object_Manager::instance ()->
+ singleton_null_lock_,
+ ACE_Cleanup_Adapter<ACE_Null_Mutex>,
+ -1);
+
+ // Can't register with the ACE_Object_Manager here! The
+ // lock's declaration is visible to the ACE_Object_Manager
+ // destructor, so it will clean it up as a special case.
+ }
+
+ if (ACE_Object_Manager::instance ()->singleton_null_lock_ != 0)
+ lock = &ACE_Object_Manager::instance ()->singleton_null_lock_->
+ object ();
+ }
+ else
+ // Use the Object_Manager's preallocated lock.
+ lock = ACE_Managed_Object<ACE_Null_Mutex>::get_preallocated_object
+ (ACE_Object_Manager::ACE_SINGLETON_NULL_LOCK);
+
+ return 0;
+}
+
+int
+ACE_Object_Manager::get_singleton_lock (ACE_Thread_Mutex *&lock)
+{
+ if (lock == 0)
+ {
+ if (starting_up () || shutting_down ())
+ {
+ // The Object_Manager and its internal lock have not been
+ // constructed yet. Therefore, the program is single-
+ // threaded at this point. Or, the ACE_Object_Manager
+ // instance has been destroyed, so the internal lock is not
+ // available. Either way, we can not use double-checked
+ // locking. So, we'll leak the lock.
+ ACE_NEW_RETURN (lock,
+ ACE_Thread_Mutex,
+ -1);
+ }
+ else
+ {
+ // Allocate a new lock, but use double-checked locking to
+ // ensure that only one thread allocates it.
+ ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex,
+ ace_mon,
+ *ACE_Object_Manager::instance ()->
+ internal_lock_,
+ -1));
+
+ if (lock == 0)
+ {
+ ACE_Cleanup_Adapter<ACE_Thread_Mutex> *lock_adapter;
+ ACE_NEW_RETURN (lock_adapter,
+ ACE_Cleanup_Adapter<ACE_Thread_Mutex>,
+ -1);
+ lock = &lock_adapter->object ();
+
+ // Register the lock for destruction at program
+ // termination. This call will cause us to grab the
+ // ACE_Object_Manager::instance ()->internal_lock_
+ // again; that's why it is a recursive lock.
+ ACE_Object_Manager::at_exit (lock_adapter);
+ }
+ }
+ }
+
+ return 0;
+}
+
+int
+ACE_Object_Manager::get_singleton_lock (ACE_Mutex *&lock)
+{
+ if (lock == 0)
+ {
+ if (starting_up () || shutting_down ())
+ {
+ // The Object_Manager and its internal lock have not been
+ // constructed yet. Therefore, the program is single-
+ // threaded at this point. Or, the ACE_Object_Manager
+ // instance has been destroyed, so the internal lock is not
+ // available. Either way, we can not use double-checked
+ // locking. So, we'll leak the lock.
+
+ ACE_NEW_RETURN (lock,
+ ACE_Mutex,
+ -1);
+ }
+ else
+ {
+ // Allocate a new lock, but use double-checked locking to
+ // ensure that only one thread allocates it.
+ ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex,
+ ace_mon,
+ *ACE_Object_Manager::instance ()->
+ internal_lock_,
+ -1));
+
+ if (lock == 0)
+ {
+ ACE_Cleanup_Adapter<ACE_Mutex> *lock_adapter;
+ ACE_NEW_RETURN (lock_adapter,
+ ACE_Cleanup_Adapter<ACE_Mutex>,
+ -1);
+ lock = &lock_adapter->object ();
+
+ // Register the lock for destruction at program
+ // termination. This call will cause us to grab the
+ // ACE_Object_Manager::instance ()->internal_lock_
+ // again; that's why it is a recursive lock.
+ ACE_Object_Manager::at_exit (lock_adapter);
+ }
+ }
+ }
+
+ return 0;
+}
+
+int
+ACE_Object_Manager::get_singleton_lock (ACE_Recursive_Thread_Mutex *&lock)
+{
+ if (starting_up () || shutting_down ())
+ {
+ // The preallocated lock has not been constructed yet.
+ // Therefore, the program is single-threaded at this point. Or,
+ // the ACE_Object_Manager instance has been destroyed, so the
+ // preallocated lock is not available. Allocate a lock to use,
+ // for interface compatibility, though there should be no
+ // contention on it.
+ if (ACE_Object_Manager::instance ()->singleton_recursive_lock_ == 0)
+ ACE_NEW_RETURN (ACE_Object_Manager::instance ()->
+ singleton_recursive_lock_,
+ ACE_Cleanup_Adapter<ACE_Recursive_Thread_Mutex>,
+ -1);
+
+ // Can't register with the ACE_Object_Manager here! The lock's
+ // declaration is visible to the ACE_Object_Manager destructor,
+ // so it will clean it up as a special case.
+
+ if (ACE_Object_Manager::instance ()->singleton_recursive_lock_ != 0)
+ lock = &ACE_Object_Manager::instance ()->singleton_recursive_lock_->
+ object ();
+ }
+ else
+ {
+ // Use the Object_Manager's preallocated lock.
+ lock = ACE_Managed_Object<ACE_Recursive_Thread_Mutex>::
+ get_preallocated_object (ACE_Object_Manager::
+ ACE_SINGLETON_RECURSIVE_THREAD_LOCK);
+ }
+
+ return 0;
+}
+
+int
+ACE_Object_Manager::get_singleton_lock (ACE_RW_Thread_Mutex *&lock)
+{
+ if (lock == 0)
+ {
+ if (starting_up () || shutting_down ())
+ {
+ // The Object_Manager and its internal lock have not been
+ // constructed yet. Therefore, the program is single-
+ // threaded at this point. Or, the ACE_Object_Manager
+ // instance has been destroyed, so the internal lock is not
+ // available. Either way, we can not use double-checked
+ // locking. So, we'll leak the lock.
+
+ ACE_NEW_RETURN (lock,
+ ACE_RW_Thread_Mutex,
+ -1);
+ }
+ else
+ {
+ // Allocate a new lock, but use double-checked locking to
+ // ensure that only one thread allocates it.
+ ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex,
+ ace_mon,
+ *ACE_Object_Manager::instance ()->
+ internal_lock_,
+ -1));
+
+ if (lock == 0)
+ {
+ ACE_Cleanup_Adapter<ACE_RW_Thread_Mutex> *lock_adapter;
+ ACE_NEW_RETURN (lock_adapter,
+ ACE_Cleanup_Adapter<ACE_RW_Thread_Mutex>,
+ -1);
+ lock = &lock_adapter->object ();
+
+
+ // Register the lock for destruction at program
+ // termination. This call will cause us to grab the
+ // ACE_Object_Manager::instance ()->internal_lock_
+ // again; that's why it is a recursive lock.
+ ACE_Object_Manager::at_exit (lock_adapter);
+ }
+ }
+ }
+
+ return 0;
+}
+#endif /* ACE_MT_SAFE */
+
+// NOTE: this function needs to appear _after_ the
+// get_singleton_lock () functions in order to compile with
+// g++ 2.7.2.3.
+//
+// Clean up an ACE_Object_Manager. There can be instances of this object
+// other than The Instance. This can happen if (on Win32) the ACE DLL
+// causes one to be created, or if a user creates one for some reason.
+// Only The Instance cleans up the static preallocated objects. All objects
+// clean up their per-object information and managed objects.
+int
+ACE_Object_Manager::fini (void)
+{
+ if (shutting_down_i ())
+ // Too late. Or, maybe too early. Either fini () has already
+ // been called, or init () was never called.
+ return object_manager_state_ == OBJ_MAN_SHUT_DOWN ? 1 : -1;
+
+ // No mutex here. Only the main thread should destroy the singleton
+ // ACE_Object_Manager instance.
+
+ // First, indicate that this ACE_Object_Manager instance is being
+ // shut down.
+ object_manager_state_ = OBJ_MAN_SHUTTING_DOWN;
+
+ // Call all registered cleanup hooks, in reverse order of
+ // registration.
+ exit_info_.call_hooks ();
+
+ if (this == instance_)
+ {
+#if !defined (ACE_LACKS_ACE_SVCCONF)
+ delete preallocations_;
+ preallocations_ = 0;
+#endif /* ! ACE_LACKS_ACE_SVCCONF */
+
+ ACE_Trace::stop_tracing ();
+
+#if defined (ACE_LACKS_ACE_SVCCONF)
+
+ ACE_Reactor::close_singleton ();
+
+# if (((defined (ACE_HAS_WINNT)) && (ACE_HAS_WINNT == 1)) || (defined (ACE_HAS_AIO_CALLS)))
+ ACE_Proactor::close_singleton ();
+# endif /* !ACE_HAS_WINCE */
+
+
+# if ! defined (ACE_THREAD_MANAGER_LACKS_STATICS)
+ ACE_Thread_Manager::close_singleton ();
+# endif /* ! ACE_THREAD_MANAGER_LACKS_STATICS */
+
+#else /* ! ACE_LACKS_ACE_SVCCONF */
+
+ // Close and possibly delete all service instances in the Service
+ // Repository.
+ ACE_Service_Config::fini_svcs ();
+
+#endif /* ! ACE_LACKS_ACE_SVCCONF */
+
+
+
+ // Close the main thread's TSS, including its Log_Msg instance.
+ ACE_OS::cleanup_tss (1 /* main thread */);
+
+ //
+ // Note: Do not access Log Msg after this since it is gone
+ //
+
+#if !defined (ACE_LACKS_ACE_SVCCONF)
+ // Unlink all services in the Service Repository and close/delete
+ // all ACE library services and singletons.
+ ACE_Service_Config::close ();
+#endif /* ! ACE_LACKS_ACE_SVCCONF */
+
+ // Close the ACE_Allocator.
+ ACE_Allocator::close_singleton ();
+
+#if ! defined (ACE_HAS_STATIC_PREALLOCATION)
+ // Hooks for deletion of preallocated objects and arrays provided by
+ // application.
+ ACE_APPLICATION_PREALLOCATED_ARRAY_DELETIONS
+ ACE_APPLICATION_PREALLOCATED_OBJECT_DELETIONS
+
+ // Cleanup the dynamically preallocated arrays.
+ // (none)
+
+ // Cleanup the dynamically preallocated objects.
+ ACE_DELETE_PREALLOCATED_OBJECT (ACE_SYNCH_RW_MUTEX, ACE_FILECACHE_LOCK)
+#if defined (ACE_HAS_THREADS)
+ ACE_DELETE_PREALLOCATED_OBJECT (ACE_Recursive_Thread_Mutex,
+ ACE_STATIC_OBJECT_LOCK)
+#endif /* ACE_HAS_THREADS */
+# if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0)
+ ACE_DELETE_PREALLOCATED_OBJECT (ACE_Thread_Mutex,
+ ACE_MT_CORBA_HANDLER_LOCK)
+ ACE_DELETE_PREALLOCATED_OBJECT (ACE_Thread_Mutex, ACE_DUMP_LOCK)
+ ACE_DELETE_PREALLOCATED_OBJECT (ACE_Recursive_Thread_Mutex,
+ ACE_SIG_HANDLER_LOCK)
+ ACE_DELETE_PREALLOCATED_OBJECT (ACE_Null_Mutex,
+ ACE_SINGLETON_NULL_LOCK)
+ ACE_DELETE_PREALLOCATED_OBJECT (ACE_Recursive_Thread_Mutex,
+ ACE_SINGLETON_RECURSIVE_THREAD_LOCK)
+ ACE_DELETE_PREALLOCATED_OBJECT (ACE_Thread_Mutex, ACE_THREAD_EXIT_LOCK)
+#if !defined (ACE_LACKS_ACE_TOKEN) && defined (ACE_HAS_TOKENS_LIBRARY)
+ ACE_DELETE_PREALLOCATED_OBJECT (ACE_TOKEN_CONST::MUTEX,
+ ACE_TOKEN_MANAGER_CREATION_LOCK)
+ ACE_DELETE_PREALLOCATED_OBJECT (ACE_TOKEN_CONST::MUTEX,
+ ACE_TOKEN_INVARIANTS_CREATION_LOCK)
+#endif /* ! ACE_LACKS_ACE_TOKEN && ACE_HAS_TOKENS_LIBRARY */
+ ACE_DELETE_PREALLOCATED_OBJECT (ACE_Thread_Mutex,
+ ACE_PROACTOR_EVENT_LOOP_LOCK)
+# endif /* ACE_MT_SAFE */
+#endif /* ! ACE_HAS_STATIC_PREALLOCATION */
+
+#if defined (ACE_HAS_THREADS)
+ ACE_Static_Object_Lock::cleanup_lock ();
+#endif /* ACE_HAS_THREADS */
+ }
+
+#if !defined (ACE_LACKS_ACE_SVCCONF)
+ delete ace_service_config_sig_handler_;
+ ace_service_config_sig_handler_ = 0;
+#endif /* ! ACE_LACKS_ACE_SVCCONF */
+
+#if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0)
+ delete internal_lock_;
+ internal_lock_ = 0;
+
+ delete singleton_null_lock_;
+ singleton_null_lock_ = 0;
+
+ delete singleton_recursive_lock_;
+ singleton_recursive_lock_ = 0;
+#endif /* ACE_MT_SAFE */
+
+ // Indicate that this ACE_Object_Manager instance has been shut down.
+ object_manager_state_ = OBJ_MAN_SHUT_DOWN;
+
+ // Then, ensure that the ACE_OS_Object_Manager gets shut down.
+ if (this == instance_ && ACE_OS_Object_Manager::instance_)
+ ACE_OS_Object_Manager::instance_->fini ();
+
+ if (dynamically_allocated_)
+ {
+ delete this;
+ }
+
+ if (this == instance_)
+ instance_ = 0;
+
+ return 0;
+}
+
+
+#if !defined (ACE_HAS_NONSTATIC_OBJECT_MANAGER)
+class ACE_Export ACE_Object_Manager_Manager
+ // = TITLE
+ // Ensure that the <ACE_Object_Manager> gets initialized at
+ // program startup, and destroyed at program termination.
+ //
+ // = DESCRIPTION
+ // Without ACE_HAS_NONSTATIC_OBJECT_MANAGER, a static instance of this
+ // class is created. Therefore, it gets created before main ()
+ // is called. And it gets destroyed after main () returns.
+{
+public:
+ ACE_Object_Manager_Manager (void);
+ ~ACE_Object_Manager_Manager (void);
+
+private:
+ ACE_thread_t saved_main_thread_id_;
+ // Save the main thread ID, so that destruction can be suppressed.
+};
+
+ACE_Object_Manager_Manager::ACE_Object_Manager_Manager (void)
+ : saved_main_thread_id_ (ACE_OS::thr_self ())
+{
+ // Ensure that the Object_Manager gets initialized before any
+ // application threads have been spawned. Because this will be called
+ // during construction of static objects, that should always be the
+ // case.
+ (void) ACE_Object_Manager::instance ();
+}
+
+ACE_Object_Manager_Manager::~ACE_Object_Manager_Manager (void)
+{
+ if (ACE_OS::thr_equal (ACE_OS::thr_self (),
+ saved_main_thread_id_))
+ {
+ delete ACE_Object_Manager::instance_;
+ ACE_Object_Manager::instance_ = 0;
+ }
+ // else if this destructor is not called by the main thread, then do
+ // not delete the ACE_Object_Manager. That causes problems, on
+ // WIN32 at least.
+}
+
+static ACE_Object_Manager_Manager ACE_Object_Manager_Manager_instance;
+#endif /* ! ACE_HAS_NONSTATIC_OBJECT_MANAGER */
+
+#if defined (ACE_HAS_THREADS)
+
+// hack to get around errors while compiling using split-cpp
+#if !defined (ACE_IS_SPLITTING)
+// This is global so that it doesn't have to be declared in the header
+// file. That would cause nasty circular include problems.
+typedef ACE_Cleanup_Adapter<ACE_Recursive_Thread_Mutex> ACE_Static_Object_Lock_Type;
+static ACE_Static_Object_Lock_Type *ACE_Static_Object_Lock_lock = 0;
+#endif /* ! ACE_IS_SPLITTING */
+
+// ACE_SHOULD_MALLOC_STATIC_OBJECT_LOCK isn't (currently) used by ACE.
+// But, applications may find it useful for avoiding recursive calls
+// if they have overridden operator new. Thanks to Jody Hagins
+// <jody@atdesk.com> for contributing it.
+
+ACE_Recursive_Thread_Mutex *
+ACE_Static_Object_Lock::instance (void)
+{
+ if (ACE_Object_Manager::starting_up () ||
+ ACE_Object_Manager::shutting_down ())
+ {
+ // The preallocated ACE_STATIC_OBJECT_LOCK has not been
+ // constructed yet. Therefore, the program is single-threaded
+ // at this point. Or, the ACE_Object_Manager instance has been
+ // destroyed, so the preallocated lock is not available.
+ // Allocate a lock to use, for interface compatibility, though
+ // there should be no contention on it.
+ if (ACE_Static_Object_Lock_lock == 0)
+ {
+# if defined (ACE_SHOULD_MALLOC_STATIC_OBJECT_LOCK)
+ // Allocate a buffer with malloc, and then use placement
+ // new for the object, on the malloc'd buffer.
+ void *buffer =
+ ACE_OS::malloc (sizeof (*ACE_Static_Object_Lock_lock));
+ if (buffer == 0)
+ {
+ return 0;
+ }
+ ACE_NEW_RETURN (ACE_Static_Object_Lock_lock,
+ (buffer) ACE_Static_Object_Lock_Type (),
+ 0);
+# else /* ! ACE_SHOULD_MALLOC_STATIC_OBJECT_LOCK */
+ ACE_NEW_RETURN (ACE_Static_Object_Lock_lock,
+ ACE_Cleanup_Adapter<ACE_Recursive_Thread_Mutex>,
+ 0);
+# endif /* ! ACE_SHOULD_MALLOC_STATIC_OBJECT_LOCK */
+ }
+
+ // Can't register with the ACE_Object_Manager here! The lock's
+ // declaration is visible to the ACE_Object_Manager destructor,
+ // so it will clean it up as a special case.
+
+ return &ACE_Static_Object_Lock_lock->object ();
+ }
+ else
+ // Return the preallocated ACE_STATIC_OBJECT_LOCK.
+ return
+ ACE_Managed_Object<ACE_Recursive_Thread_Mutex>::get_preallocated_object
+ (ACE_Object_Manager::ACE_STATIC_OBJECT_LOCK);
+}
+
+void
+ACE_Static_Object_Lock::cleanup_lock (void)
+{
+# if defined(ACE_SHOULD_MALLOC_STATIC_OBJECT_LOCK)
+ // It was malloc'd, so we need to explicitly call the dtor
+ // and then free the memory.
+ ACE_DES_FREE (ACE_Static_Object_Lock_lock,
+ ACE_OS::free,
+ ACE_Static_Object_Lock_Type);
+# else /* ! ACE_SHOULD_MALLOC_STATIC_OBJECT_LOCK */
+ delete ACE_Static_Object_Lock_lock;
+# endif /* ! ACE_SHOULD_MALLOC_STATIC_OBJECT_LOCK */
+ ACE_Static_Object_Lock_lock = 0;
+}
+#endif /* ACE_HAS_THREADS */
+
+#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION)
+# if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0)
+ template class ACE_Cleanup_Adapter<ACE_Null_Mutex>;
+ template class ACE_Cleanup_Adapter<ACE_Mutex>;
+ template class ACE_Cleanup_Adapter<ACE_Recursive_Thread_Mutex>;
+ template class ACE_Cleanup_Adapter<ACE_Thread_Mutex>;
+ template class ACE_Managed_Object<ACE_Null_Mutex>;
+ template class ACE_Managed_Object<ACE_Mutex>;
+ template class ACE_Managed_Object<ACE_Recursive_Thread_Mutex>;
+ template class ACE_Managed_Object<ACE_Thread_Mutex>;
+# endif /* ACE_MT_SAFE */
+ template class ACE_Cleanup_Adapter<ACE_SYNCH_RW_MUTEX>;
+ template class ACE_Managed_Object<ACE_SYNCH_RW_MUTEX>;
+#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA)
+# if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0)
+# pragma instantiate ACE_Cleanup_Adapter<ACE_Null_Mutex>
+# pragma instantiate ACE_Cleanup_Adapter<ACE_Mutex>
+# pragma instantiate ACE_Cleanup_Adapter<ACE_Recursive_Thread_Mutex>
+# pragma instantiate ACE_Cleanup_Adapter<ACE_Thread_Mutex>
+# pragma instantiate ACE_Managed_Object<ACE_Null_Mutex>
+# pragma instantiate ACE_Managed_Object<ACE_Mutex>
+# pragma instantiate ACE_Managed_Object<ACE_Recursive_Thread_Mutex>
+# pragma instantiate ACE_Managed_Object<ACE_Thread_Mutex>
+# endif /* ACE_MT_SAFE */
+# pragma instantiate ACE_Cleanup_Adapter<ACE_SYNCH_RW_MUTEX>
+# pragma instantiate ACE_Managed_Object<ACE_SYNCH_RW_MUTEX>
+#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */
diff --git a/ace/Utils/Object_Manager.h b/ace/Utils/Object_Manager.h
new file mode 100644
index 00000000000..91307cfd635
--- /dev/null
+++ b/ace/Utils/Object_Manager.h
@@ -0,0 +1,480 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Object_Manager.h
+ *
+ * $Id$
+ *
+ * @author David L. Levine <levine@cs.wustl.edu>
+ * @author Matthias Kerkhoff
+ * @author and Per Andersson
+ */
+//=============================================================================
+
+#ifndef ACE_OBJECT_MANAGER_H
+#define ACE_OBJECT_MANAGER_H
+#include "ace/pre.h"
+
+#include "ace/OS/OS.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+// Forward declarations.
+class ACE_Object_Manager_Preallocations;
+class ACE_Sig_Adapter;
+class ACE_Sig_Set;
+#if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0)
+ class ACE_Mutex;
+ class ACE_Null_Mutex;
+ class ACE_Thread_Mutex;
+ class ACE_Recursive_Thread_Mutex;
+ class ACE_RW_Thread_Mutex;
+#endif /* ACE_MT_SAFE */
+
+class ACE_Cleanup_Info_Node;
+template <class T> class ACE_Cleanup_Adapter;
+
+
+// Configuration parameters.
+#if !defined (ACE_MAX_MANAGED_OBJECTS)
+# define ACE_MAX_MANAGED_OBJECTS 128
+#endif /* ! ACE_MAX_MANAGED_OBJECTS */
+
+#if !defined (ACE_APPLICATION_PREALLOCATED_OBJECT_DECLARATIONS)
+# define ACE_APPLICATION_PREALLOCATED_OBJECT_DECLARATIONS
+#endif /* ! ACE_APPLICATION_PREALLOCATED_OBJECT_DECLARATIONS */
+
+#if !defined (ACE_APPLICATION_PREALLOCATED_ARRAY_DECLARATIONS)
+# define ACE_APPLICATION_PREALLOCATED_ARRAY_DECLARATIONS
+#endif /* ! ACE_APPLICATION_PREALLOCATED_ARRAY_DECLARATIONS */
+
+
+/**
+ * @class ACE_Object_Manager
+ *
+ * @brief Manager for ACE library services and singleton cleanup.
+ *
+ * The <ACE_Object_Manager> manages cleanup of objects, typically
+ * singletons, at program termination. In addition to managing
+ * the cleanup of the ACE library, it provides an interface for
+ * application to register objects to be cleaned up.
+ * This class also shuts down ACE library services, so that they
+ * can reclaim their storage, at program termination. It works
+ * by creating a static instance whose destructor gets called
+ * along with those of all other static objects. Hooks are
+ * provided for application code to register objects and arrays
+ * for cleanup, e.g., destruction. The order of such cleanup
+ * calls is in the reverse order of registration, i.e., that
+ * last object/array to register gets cleaned up first.
+ * The <ACE_Object_Manager> API includes <ACE_Managed_Object>. That
+ * class is contained in a separate file because it is a
+ * template class, and some compilers require that template and
+ * non-template class definitions appear in separate files.
+ * Please see ace/Managed_Object.h for a description of that
+ * part of the API. In summary, <ACE_Managed_Object> provides two
+ * adapters, the <ACE_Cleanup_Adapter> and <ACE_Managed_Object>
+ * template classes for adapting objects of any type to be
+ * easily managed by the <ACE_Object_Manager>. There are several
+ * mechanisms for adapting objects and arrays for cleanup at
+ * program termination, in roughly increasing order of ease-of-use:
+ * 1) Derive the object's class from <ACE_Cleanup>.
+ * 2) Allow the <ACE_Object_Manager> to both dynamically allocate
+ * and deallocate the object.
+ * 3) Provide an <ACE_CLEANUP_FUNC> cleanup hook for the object or
+ * array.
+ * 4) Allow the <ACE_Object_Manager> to both preallocate the object
+ * or array, either statically in global data or dynamically on
+ * the heap, when its singleton instance is construction.
+ *
+ * There are also several mechanisms for registering objects and
+ * arrays for cleanup. In decreasing order of flexibility and
+ * complexity (with the exception of the last mechanism):
+ *
+ * 1) ACE_Object_Manager::at_exit (void *object,
+ * ACE_CLEANUP_FUNC cleanup_hook,
+ * void *param);
+ * can be used to register any object or array for any
+ * cleanup activity at program termination.
+ * 2) ACE_Object_Manager::at_exit (ACE_Cleanup *object,
+ * void *param = 0);
+ * can be used to register an <ACE_Cleanup> object
+ * for any cleanup activity at program termination.
+ * The final mechanism is not general purpose, but can only
+ * be used to allocate objects and arrays at program startup:
+ * 3) ACE_Managed_Object::get_preallocated_object
+ * (ACE_Object_Manager::Preallocated_Object id);
+ * and
+ * ACE_Managed_Object::get_preallocated_array
+ * (ACE_Object_Manager::Preallocated_Array id);
+ * can only be used to allocate objects at program startup,
+ * either in global data or on the heap (selected at compile
+ * time). These are intended to replace static locks, etc.
+ * Instead of creating a static <ACE_Object_Manager> instance, one
+ * can alternatively be created on the stack of the main program
+ * thread. It is created just after entry to ::main (int, char
+ * *[]), and before any existing code in that function is
+ * executed. To enable this alternative, add #define
+ * ACE_HAS_NONSTATIC_OBJECT_MANAGER before including the platform
+ * specific config-* file in ace/config.h prior to
+ * building the ACE library and your applications. This #define
+ * is enabled in some config files that are supplied with ACE.
+ *
+ * To ensure a static object manager is used, #undef
+ * ACE_HAS_NONSTATIC_OBJECT_MANAGER *after* including the platform
+ * specific config-* file.
+ * Note that the ACE_Object_Manager _must_ be created before
+ * any threads are spawned by the program.
+ * If ACE_HAS_NONSTATIC_OBJECT_MANAGER is not #defined, the ACE
+ * library creates a static, singleton <ACE_Object_Manager> instance.
+ * The instance is placed in global program data, and constructed
+ * via a static object constructor. If ACE_HAS_NONSTATIC_OBJECT_MANAGER
+ * is #defined, the <ACE_Object_Manager> instance is created on the stack
+ * of the main program thread, as noted above.
+ *
+ * With ACE_HAS_NONSTATIC_OBJECT_MANAGER enabled, the ACE
+ * library has no static objects that require destruction.
+ * However, there are two drawbacks to using it:
+ * 1) main (int, char *[]) must be declared with arguments, even
+ * if they're not used. All of ACE is converted to this, so
+ * just applications have to be concerned with it.
+ * 2) If there any static objects that depend on those that are
+ * cleaned up by the Object_Manager, they'll get cleaned up too
+ * late. The ACE tests do not violate this requirement.
+ * However, applications may have trouble with it.
+ * NOTE on the use of <::exit> -- <::exit> does not destroy
+ * automatic objects. Therefore, if
+ * ACE_HAS_NONSTATIC_OBJECT_MANAGER is enabled, the
+ * <ACE_Object_Manager> instance will *not* be destroyed if
+ * <::exit> is called! However, <ACE_OS::exit> will properly
+ * destroy the ACE_Object_Manager. It is highly recommended
+ * that <ACE_OS::exit> be used instead of <::exit>.
+ *
+ * However, <::exit> and <ACE_OS::exit> are tricky to use
+ * properly, especially in multithread programs. It is much
+ * safer to throw an exception (or simulate that effect) that
+ * will be caught by <main> instead of calling exit. Then,
+ * <main> can perform any necessary application-specific cleanup
+ * and return the status value. In addition, it's usually best
+ * to avoid calling <::exit> and <ACE_OS::exit> from threads
+ * other than the main thread. Thanks to Jeff Greif
+ * <jmg@trivida.com> for pointing out that <::exit> doesn't
+ * destroy automatic objects, and for developing the
+ * recommendations in this paragraph.
+ *
+ * Instead of creating a static <ACE_Object_Manager>, or letting
+ * ACE create it on the stack of <main> for you, another
+ * alternative is to #define
+ * ACE_DOESNT_INSTANTIATE_NONSTATIC_OBJECT_MANAGER. With that
+ * #define, the application must create the ACE_Object_Manager.
+ * The recommended way is to call <ACE::init> at the start of
+ * the program, and call <ACE::fini> at the end. Alternatively,
+ * the application could explicity construct an
+ * <ACE_Object_Manager>.
+ */
+class ACE_Export ACE_Object_Manager : public ACE_Object_Manager_Base
+{
+
+public:
+ /**
+ * Explicitly initialize (construct the singleton instance of) the
+ * ACE_Object_Manager. Returns 0 on success, -1 on failure, and 1
+ * if it had already been called.
+ */
+ virtual int init (void);
+
+ /**
+ * Explicitly destroy the singleton instance of the
+ * ACE_Object_Manager. Returns 0 on success, -1 on failure, and 1
+ * if it had already been called.
+ */
+ virtual int fini (void);
+
+ /**
+ * Returns 1 before the ACE_Object_Manager has been constructed.
+ * This flag can be used to determine if the program is constructing
+ * static objects. If no static object spawns any threads, the
+ * program will be single-threaded when this flag returns 1. (Note
+ * that the program still might construct some static objects when
+ * this flag returns 0, if ACE_HAS_NONSTATIC_OBJECT_MANAGER is not
+ * defined.)
+ */
+ static int starting_up (void);
+
+ /**
+ * Returns 1 after the ACE_Object_Manager has been destroyed. This
+ * flag can be used to determine if the program is in the midst of
+ * destroying static objects. (Note that the program might destroy
+ * some static objects before this flag can return 1, if
+ * ACE_HAS_NONSTATIC_OBJECT_MANAGER is not defined.)
+ */
+ static int shutting_down (void);
+
+ /**
+ * Register an ACE_Cleanup object for cleanup at process
+ * termination. The object is deleted via the
+ * <ace_cleanup_destroyer>. If you need more flexiblity, see the
+ * <other at_exit> method below. For OS's that do not have
+ * processes, cleanup takes place at the end of <main>. Returns 0
+ * on success. On failure, returns -1 and sets errno to: EAGAIN if
+ * shutting down, ENOMEM if insufficient virtual memory, or EEXIST
+ * if the object (or array) had already been registered.
+ */
+ static int at_exit (ACE_Cleanup *object, void *param = 0);
+
+ /**
+ * Register an object (or array) for cleanup at process termination.
+ * "cleanup_hook" points to a (global, or static member) function
+ * that is called for the object or array when it to be destroyed.
+ * It may perform any necessary cleanup specific for that object or
+ * its class. "param" is passed as the second parameter to the
+ * "cleanup_hook" function; the first parameter is the object (or
+ * array) to be destroyed. "cleanup_hook", for example, may delete
+ * the object (or array). For OS's that do not have processes, this
+ * function is the same as <at_thread_exit>. Returns 0 on success.
+ * On failure, returns -1 and sets errno to: EAGAIN if shutting
+ * down, ENOMEM if insufficient virtual memory, or EEXIST if the
+ * object (or array) had already been registered.
+ */
+ static int at_exit (void *object,
+ ACE_CLEANUP_FUNC cleanup_hook,
+ void *param);
+
+#if 0 /* not implemented yet */
+ /// Similar to <at_exit>, except that the cleanup_hook is called
+ /// when the current thread exits instead of when the program terminates.
+ static int at_thread_exit (void *object,
+ ACE_CLEANUP_FUNC cleanup_hook,
+ void *param);
+#endif /* 0 */
+
+ enum Preallocated_Object
+ {
+ ACE_FILECACHE_LOCK,
+#if defined (ACE_HAS_THREADS)
+ ACE_STATIC_OBJECT_LOCK,
+#endif /* ACE_HAS_THREADS */
+#if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0)
+ ACE_MT_CORBA_HANDLER_LOCK,
+ ACE_DUMP_LOCK,
+ ACE_SIG_HANDLER_LOCK,
+ ACE_SINGLETON_NULL_LOCK,
+ ACE_SINGLETON_RECURSIVE_THREAD_LOCK,
+ ACE_THREAD_EXIT_LOCK,
+#if !defined (ACE_LACKS_ACE_TOKEN)
+ ACE_TOKEN_MANAGER_CREATION_LOCK,
+ ACE_TOKEN_INVARIANTS_CREATION_LOCK,
+#endif /* ! ACE_LACKS_ACE_TOKEN */
+ ACE_PROACTOR_EVENT_LOOP_LOCK,
+#endif /* ACE_MT_SAFE */
+
+ // Hook for preallocated objects provided by application.
+ ACE_APPLICATION_PREALLOCATED_OBJECT_DECLARATIONS
+
+ ACE_PREALLOCATED_OBJECTS // This enum value must be last!
+ };
+ // Unique identifiers for preallocated objects. Please see
+ // ace/Managed_Object.h for information on accessing preallocated
+ // objects.
+
+ enum Preallocated_Array
+ {
+ // There currently are no preallocated arrays in the ACE
+ // library. If the application doesn't have any, make sure
+ // the the preallocated_array size is at least one by declaring
+ // this dummy . . .
+ ACE_EMPTY_PREALLOCATED_ARRAY,
+
+ // Hook for preallocated arrays provided by application.
+ ACE_APPLICATION_PREALLOCATED_ARRAY_DECLARATIONS
+
+ ACE_PREALLOCATED_ARRAYS // This enum value must be last!
+ };
+ // Unique identifiers for preallocated arrays. Please see
+ // ace/Managed_Object.h for information on accessing preallocated
+ // arrays.
+
+ /**
+ * Accesses a default signal set used, for example, in ACE_Sig_Guard
+ * methods.
+ * Deprecated: use ACE_Object_Manager::default_mask () instead.
+ */
+ static ACE_Sig_Set &default_mask (void);
+
+private:
+ /// For at_exit support.
+ ACE_OS_Exit_Info exit_info_;
+
+#if !defined (ACE_LACKS_ACE_SVCCONF)
+ /// Preallocated objects collection.
+ ACE_Object_Manager_Preallocations *preallocations_;
+
+ /// ACE_Service_Config signal handler.
+ ACE_Sig_Adapter *ace_service_config_sig_handler_;
+#endif /* ! ACE_LACKS_ACE_SVCCONF */
+
+ /// Register an object or array for deletion at program termination.
+ /// See description of static version above for return values.
+ int at_exit_i (void *object, ACE_CLEANUP_FUNC cleanup_hook, void *param);
+
+#if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0)
+public:
+ // = The <get_singleton_lock> accessors are for internal
+ // use by ACE_Singleton _only_.
+
+ /**
+ * Accesses an <ACE_Null_Mutex> to be used for construction of
+ * <ACE_Singletons>. Returns 0, and the lock in the argument, on
+ * success; returns -1 on failure.
+ */
+ static int get_singleton_lock (ACE_Null_Mutex *&);
+
+ /**
+ * Accesses a non-recursive <ACE_Thread_Mutex> to be used for
+ * construction of <ACE_Singletons>. Returns 0, and the lock in the
+ * argument, on success; returns -1 on failure.
+ */
+ static int get_singleton_lock (ACE_Thread_Mutex *&);
+
+ /**
+ * Accesses a non-recursive <ACE_Mutex> to be used for construction
+ * of <ACE_Singletons>. Returns 0, and the lock in the argument, on
+ * success; returns -1 on failure.
+ */
+ static int get_singleton_lock (ACE_Mutex *&);
+
+ /**
+ * Accesses a recursive <ACE_Recursive_Thread_Mutex> to be used for
+ * construction of <ACE_Singletons>. Returns 0, and the lock in the
+ * argument, on success; returns -1 on failure.
+ */
+ static int get_singleton_lock (ACE_Recursive_Thread_Mutex *&);
+
+ /**
+ * Accesses a readers/writer <ACE_RW_Thread_Mutex> to be used for
+ * construction of <ACE_Singletons>. Returns 0, and the lock in the
+ * argument, on success; returns -1 on failure.
+ */
+ static int get_singleton_lock (ACE_RW_Thread_Mutex *&);
+#endif /* ACE_MT_SAFE */
+
+public:
+ // For internal use only by ACE_Managed_Objects.
+
+ /**
+ * Accessor to singleton instance. Because static member functions
+ * are provided in the interface, this should not be public. However,
+ * it is public so that ACE_Managed_Object<TYPE> can access it.
+ */
+ static ACE_Object_Manager *instance (void);
+
+ /// Table of preallocated objects.
+ static void *preallocated_object[ACE_PREALLOCATED_OBJECTS];
+
+ /// Table of preallocated arrays.
+ static void *preallocated_array[ACE_PREALLOCATED_ARRAYS];
+
+public:
+ // Application code should not use these explicitly, so they're
+ // hidden here. They're public so that the ACE_Object_Manager can
+ // be constructed/destructed in <main> with
+ // ACE_HAS_NONSTATIC_OBJECT_MANAGER.
+ ACE_Object_Manager (void);
+ ~ACE_Object_Manager (void);
+
+private:
+ /// Singleton pointer.
+ static ACE_Object_Manager *instance_;
+
+#if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0)
+ /// Lock that is used to guard internal structures.
+ ACE_Recursive_Thread_Mutex *internal_lock_;
+
+ /// Null lock for guarding singleton creation.
+ ACE_Cleanup_Adapter<ACE_Null_Mutex> *singleton_null_lock_;
+
+ /// Lock for guarding singleton creation, when Object_Manager
+ /// hasn't been started up, or has already been shut down.
+ ACE_Cleanup_Adapter<ACE_Recursive_Thread_Mutex> *singleton_recursive_lock_;
+#endif /* ACE_MT_SAFE */
+
+#if defined (ACE_HAS_TSS_EMULATION)
+ // Main thread's thread-specific storage array.
+ void *ts_storage_[ACE_TSS_Emulation::ACE_TSS_THREAD_KEYS_MAX];
+#endif /* ACE_HAS_TSS_EMULATION */
+
+#if !defined (ACE_HAS_NONSTATIC_OBJECT_MANAGER)
+ friend class ACE_Object_Manager_Manager;
+#endif /* ACE_HAS_NONSTATIC_OBJECT_MANAGER */
+
+ // Disallow copying by not implementing the following . . .
+ ACE_Object_Manager (const ACE_Object_Manager &);
+ ACE_Object_Manager &operator= (const ACE_Object_Manager &);
+};
+
+
+#if defined (ACE_HAS_THREADS)
+
+class ACE_Recursive_Thread_Mutex;
+
+/**
+ * @class ACE_Static_Object_Lock
+ *
+ * @brief Provide an interface to access a global lock.
+ *
+ * This class is used to serialize the creation of static
+ * singleton objects. It really isn't needed any more, because
+ * anyone can access ACE_STATIC_OBJECT_LOCK directly. But, it
+ * is retained for backward compatibility.
+ */
+class ACE_Export ACE_Static_Object_Lock
+{
+public:
+ /// Static lock access point.
+ static ACE_Recursive_Thread_Mutex *instance (void);
+
+ /// For use only by ACE_Object_Manager to clean up lock if it
+ /// what dynamically allocated.
+ static void cleanup_lock (void);
+};
+
+#endif /* ACE_HAS_THREADS */
+
+
+#if defined (__ACE_INLINE__)
+#include "Object_Manager.i"
+#endif /* __ACE_INLINE__ */
+
+#include "Managed_Object.h"
+
+#if !defined (ACE_LACKS_ACE_SVCCONF)
+// We can't use the ACE_SVC_FACTORY_DECLARE macro here because this
+// needs to be in the ACE_Export context rather than the
+// ACE_Svc_Export context.
+class ACE_Service_Object;
+extern "C" ACE_Export
+ACE_Service_Object *
+_make_ACE_Service_Manager (ACE_Service_Object_Exterminator *);
+#endif /* ! ACE_LACKS_ACE_SVCCONF */
+
+// hack to get around errors while compiling using split-cpp
+#if defined (ACE_HAS_THREADS)
+
+# if defined (ACE_IS_SPLITTING)
+typedef ACE_Cleanup_Adapter<ACE_Recursive_Thread_Mutex> ACE_Static_Object_Lock_Type;
+
+# if defined (__GNUC__)
+// With g++, suppress the warning that this is unused.
+static ACE_Static_Object_Lock_Type *ACE_Static_Object_Lock_lock __attribute__ ((unused)) = 0;
+# else
+static ACE_Static_Object_Lock_Type *ACE_Static_Object_Lock_lock = 0;
+# endif /* __GNUC__ */
+
+# endif /* ACE_IS_SPLITTING */
+
+#endif /* ACE_HAS_THREADS */
+
+#include "ace/post.h"
+#endif /* ACE_OBJECT_MANAGER_H */
diff --git a/ace/Utils/Object_Manager.i b/ace/Utils/Object_Manager.i
new file mode 100644
index 00000000000..a93cbc208b1
--- /dev/null
+++ b/ace/Utils/Object_Manager.i
@@ -0,0 +1,35 @@
+/* -*- C++ -*- */
+// $Id$
+
+ACE_INLINE
+int
+ACE_Object_Manager::at_exit (ACE_Cleanup *object,
+ void *param)
+{
+ return ACE_Object_Manager::instance ()->at_exit_i (
+ object,
+ (ACE_CLEANUP_FUNC) ace_cleanup_destroyer,
+ param);
+}
+
+ACE_INLINE
+int
+ACE_Object_Manager::at_exit (void *object,
+ ACE_CLEANUP_FUNC cleanup_hook,
+ void *param)
+{
+ return ACE_Object_Manager::instance ()->at_exit_i (
+ object,
+ cleanup_hook,
+ param);
+}
+
+ACE_INLINE
+ACE_Sig_Set &
+ACE_Object_Manager::default_mask (void)
+{
+ // A safe cast, but this static method shouldn't be used anyways.
+ // Use ACE_Object_Manager::default_mask () instead.
+ return *ACE_reinterpret_cast (ACE_Sig_Set *,
+ ACE_OS_Object_Manager::default_mask ());
+}
diff --git a/ace/Utils/Pair.cpp b/ace/Utils/Pair.cpp
new file mode 100644
index 00000000000..7b595e8b3c7
--- /dev/null
+++ b/ace/Utils/Pair.cpp
@@ -0,0 +1,19 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// ace
+//
+// = FILENAME
+// Pair.cpp
+//
+// = AUTHOR
+// Irfan Pyarali
+//
+// ============================================================================
+
+#include "ace/Pair.h"
+
+ACE_RCSID(ace, Pair, "$Id$")
+
diff --git a/ace/Utils/Pair.h b/ace/Utils/Pair.h
new file mode 100644
index 00000000000..4fb5693e948
--- /dev/null
+++ b/ace/Utils/Pair.h
@@ -0,0 +1,28 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Pair.h
+ *
+ * $Id$
+ *
+ * @author Irfan Pyarali
+ */
+//=============================================================================
+
+
+#ifndef ACE_PAIR_H
+#define ACE_PAIR_H
+#include "ace/pre.h"
+
+#include "ace/OS.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+// Include the templates here.
+#include "ace/Pair_T.h"
+
+#include "ace/post.h"
+#endif /* ACE_PAIR_H */
diff --git a/ace/Utils/Recyclable.cpp b/ace/Utils/Recyclable.cpp
new file mode 100644
index 00000000000..483852486f1
--- /dev/null
+++ b/ace/Utils/Recyclable.cpp
@@ -0,0 +1,19 @@
+//$Id$
+#include "ace/Recyclable.h"
+
+
+#if !defined (__ACE_INLINE__)
+#include "ace/Recyclable.inl"
+#endif /* __ACE_INLINE __ */
+
+ACE_RCSID(ace, Recyclable, "$Id$")
+
+
+ACE_Recyclable::ACE_Recyclable (ACE_Recyclable_State initial_state)
+ : recycle_state_ (initial_state)
+{
+}
+
+ACE_Recyclable::~ACE_Recyclable (void)
+{
+}
diff --git a/ace/Utils/Recyclable.h b/ace/Utils/Recyclable.h
new file mode 100644
index 00000000000..bcf47ef937b
--- /dev/null
+++ b/ace/Utils/Recyclable.h
@@ -0,0 +1,78 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Recyclable.h
+ *
+ * $Id$
+ *
+ * @author Doug Schmidt
+ */
+//=============================================================================
+#ifndef ACE_RECYCLABLE_H
+#define ACE_RECYCLABLE_H
+#include "ace/pre.h"
+#include "ace/config-all.h"
+
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+
+
+/// States of a recyclable object.
+enum ACE_Recyclable_State
+{
+ /// Idle and can be purged.
+ ACE_RECYCLABLE_IDLE_AND_PURGABLE,
+
+ /// Idle but cannot be purged.
+ ACE_RECYCLABLE_IDLE_BUT_NOT_PURGABLE,
+
+ /// Can be purged, but is not idle (mostly for debugging).
+ ACE_RECYCLABLE_PURGABLE_BUT_NOT_IDLE,
+
+ /// Busy (i.e., cannot be recycled or purged).
+ ACE_RECYCLABLE_BUSY,
+
+ /// Closed.
+ ACE_RECYCLABLE_CLOSED,
+
+ /// Unknown state.
+ ACE_RECYCLABLE_UNKNOWN
+};
+
+/**
+ * @class ACE_Recyclable
+ *
+ * @brief
+ *
+ *
+ */
+
+class ACE_Export ACE_Recyclable
+{
+public:
+ /// Destructor.
+ virtual ~ACE_Recyclable (void);
+
+ // = Set/Get the recyclable bit
+ ACE_Recyclable_State recycle_state (void) const;
+ void recycle_state (ACE_Recyclable_State new_state);
+
+protected:
+ /// Protected constructor.
+ ACE_Recyclable (ACE_Recyclable_State initial_state);
+
+ /// Our state.
+ ACE_Recyclable_State recycle_state_;
+};
+
+
+#if defined (__ACE_INLINE__)
+#include "ace/Recyclable.inl"
+#endif /* __ACE_INLINE __ */
+
+#include "ace/post.h"
+#endif /*ACE_RECYCLABLE_STATE_H*/
diff --git a/ace/Utils/Recyclable.inl b/ace/Utils/Recyclable.inl
new file mode 100644
index 00000000000..c9a4318b2dc
--- /dev/null
+++ b/ace/Utils/Recyclable.inl
@@ -0,0 +1,19 @@
+/* -*- C++ -*- */
+//$Id$
+
+
+
+ACE_INLINE ACE_Recyclable_State
+ACE_Recyclable::recycle_state (void) const
+{
+ return this->recycle_state_;
+}
+
+ACE_INLINE void
+ACE_Recyclable::recycle_state (ACE_Recyclable_State new_state)
+{
+ if (this->recycle_state_ == ACE_RECYCLABLE_CLOSED)
+ return;
+
+ this->recycle_state_ = new_state;
+}
diff --git a/ace/Utils/Refcountable.cpp b/ace/Utils/Refcountable.cpp
new file mode 100644
index 00000000000..19c95cb990a
--- /dev/null
+++ b/ace/Utils/Refcountable.cpp
@@ -0,0 +1,8 @@
+//$Id$
+#include "ace/Refcountable.h"
+
+#if !defined (__ACE_INLINE__)
+#include "ace/Refcountable.inl"
+#endif /* __ACE_INLINE __ */
+
+ACE_RCSID(ace, Refcountable, "$Id$")
diff --git a/ace/Utils/Refcountable.h b/ace/Utils/Refcountable.h
new file mode 100644
index 00000000000..d194dd13a84
--- /dev/null
+++ b/ace/Utils/Refcountable.h
@@ -0,0 +1,58 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Refcountable.h
+ *
+ * $Id$
+ *
+ * @author Doug Schmidt
+ */
+//=============================================================================
+#ifndef ACE_REFCOUNTABLE_H
+#define ACE_REFCOUNTABLE_H
+#include "ace/pre.h"
+
+#include "ace/config-all.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+
+/**
+ * @class ACE_Refcountable
+ *
+ * @brief
+ *
+ *
+ */
+
+class ACE_Export ACE_Refcountable
+{
+public:
+ /// Destructor.
+ virtual ~ACE_Refcountable (void);
+
+ // = Increment/Decrement refcount
+ int increment (void);
+ int decrement (void);
+
+ /// Returns the current refcount.
+ int refcount (void) const;
+
+protected:
+ /// Protected constructor.
+ ACE_Refcountable (int refcount);
+
+ /// Current refcount.
+ int refcount_;
+};
+
+
+#if defined (__ACE_INLINE__)
+#include "ace/Refcountable.inl"
+#endif /* __ACE_INLINE __ */
+
+#include "ace/post.h"
+#endif /*ACE_REFCOUNTABLE_H*/
diff --git a/ace/Utils/Refcountable.inl b/ace/Utils/Refcountable.inl
new file mode 100644
index 00000000000..e36d0992705
--- /dev/null
+++ b/ace/Utils/Refcountable.inl
@@ -0,0 +1,30 @@
+/* -*- C++ -*- */
+//$Id$
+ACE_INLINE
+ACE_Refcountable::ACE_Refcountable (int refcount)
+ : refcount_ (refcount)
+{
+}
+
+ACE_INLINE
+ACE_Refcountable::~ACE_Refcountable (void)
+{
+}
+
+ACE_INLINE int
+ACE_Refcountable::increment (void)
+{
+ return ++this->refcount_;
+}
+
+ACE_INLINE int
+ACE_Refcountable::decrement (void)
+{
+ return --this->refcount_;
+}
+
+ACE_INLINE int
+ACE_Refcountable::refcount (void) const
+{
+ return this->refcount_;
+}
diff --git a/ace/Utils/Refcounted_Auto_Ptr.h b/ace/Utils/Refcounted_Auto_Ptr.h
new file mode 100644
index 00000000000..bb1ce9f9af4
--- /dev/null
+++ b/ace/Utils/Refcounted_Auto_Ptr.h
@@ -0,0 +1,192 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Refcounted_Auto_Ptr.h
+ *
+ * $Id$
+ *
+ * @author John Tucker <JTucker@infoglide.com>
+ */
+//=============================================================================
+
+#ifndef ACE_REFCOUNTED_AUTO_PTR_H
+#define ACE_REFCOUNTED_AUTO_PTR_H
+#include "ace/pre.h"
+
+#include "ace/OS.h"
+#include "ace/Auto_Ptr.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+// Forward decl.
+template <class X, class ACE_LOCK> class ACE_Refcounted_Auto_Ptr_Rep;
+template <class X, class ACE_LOCK> class ACE_Refcounted_Auto_Ptr;
+
+/**
+ * @class ACE_Refcounted_Auto_Ptr
+ *
+ * @brief This class implements support for a reference counted auto_ptr.
+ * Assigning or copying instances of an ACE_Refcounted_Auto_Ptr
+ * will automatically increment the reference count. When the last
+ * instance that references a ACE_Refcounted_Auto_Ptr instance is
+ * destroyed or overwritten, it will invoke delete on its underlying
+ * pointer.
+ */
+template <class X, class ACE_LOCK>
+class ACE_Refcounted_Auto_Ptr
+{
+public:
+
+ // = Initialization and termination methods.
+
+ /// Constructor that initializes an <ACE_Refcounted_Auto_Ptr> to
+ /// point to the result <r> immediately.
+ ACE_Refcounted_Auto_Ptr (X *p = 0);
+
+ /// Copy constructor binds <this> and <r> to the same
+ /// <ACE_Refcounted_Auto_Ptr_Rep>. An <ACE_Refcounted_Auto_Ptr_Rep>
+ /// is created if necessary.
+ ACE_Refcounted_Auto_Ptr (const ACE_Refcounted_Auto_Ptr<X, ACE_LOCK> &r);
+
+ /// Destructor.
+ virtual ~ACE_Refcounted_Auto_Ptr (void);
+
+ /// Assignment operator that binds <this> and <r> to the same
+ /// <ACE_Refcounted_Auto_Ptr_Rep>. An <ACE_Refcounted_Auto_Ptr_Rep>
+ /// is created if necessary.
+ void operator = (const ACE_Refcounted_Auto_Ptr<X, ACE_LOCK> &r);
+
+ /// Equality operator that returns 1 if both
+ /// ACE_Refcounted_Auto_Ptr<X, ACE_LOCK> objects point to the same
+ /// ACE_Refcounted_Auto_Ptr_Rep<X, ACE_LOCK> object. Attention: It
+ /// also returns 1 if both objects have just been instantiated and
+ /// not used yet.
+ int operator == (const ACE_Refcounted_Auto_Ptr<X, ACE_LOCK> &r) const;
+
+ /// Inequality operator, which is the opposite of equality.
+ int operator != (const ACE_Refcounted_Auto_Ptr<X, ACE_LOCK> &r) const;
+
+ /// Redirection operator
+ X *operator-> (void) const;
+
+ // = Accessor methods.
+
+ X &operator *() const;
+
+ /// Sets the pointer value to 0 and returns its old value.
+ X *release (void);
+
+ /// Invokes delete on the previous pointer value and then sets the
+ /// pointer value to the specified value.
+ void reset (X *p = 0);
+
+ /// Get the pointer value.
+ X *get (void);
+
+ /// Get the reference count value.
+ int count (void) const;
+
+ // = Utility method.
+
+ /// Allows us to check for NULL on all ACE_Refcounted_Auto_Ptr objects.
+ int null (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+private:
+ /// the ACE_Refcounted_Auto_Ptr_Rep
+ typedef ACE_Refcounted_Auto_Ptr_Rep<X, ACE_LOCK> AUTO_REFCOUNTED_PTR_REP;
+
+ /// Protect operations on the <ACE_Refcounted_Auto_Ptr>.
+ AUTO_REFCOUNTED_PTR_REP *rep_;
+};
+
+/**
+ * @class ACE_Refcounted_Auto_Ptr_Rep
+ *
+ * @brief An ACE_Refcounted_Auto_Ptr_Rep<X, ACE_LOCK> object
+ * incapsulates a pointer to an object of type X. It is pointed to by
+ * ACE_Refcounted_Auto_Ptr<X, ACE_LOCK> object[s] and only accessible
+ * through them.
+ */
+template <class X, class ACE_LOCK>
+class ACE_Refcounted_Auto_Ptr_Rep
+{
+private:
+ friend class ACE_Refcounted_Auto_Ptr<X, ACE_LOCK>;
+
+ /// Sets the pointer value to 0 and returns its old value.
+ X *release (void);
+
+ /// Invokes delete on the previous pointer value and then
+ /// sets the pointer value to the specified value.
+ void reset (X *p = 0);
+
+ /// Get the pointer value.
+ X *get (void);
+
+ /// Get the reference count value.
+ int count (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+ // = Encapsulate reference count and object lifetime of instances.
+ // These methods must go after the others to work around a bug with
+ // Borland's C++ Builder...
+
+ /// Allocate a new ACE_Refcounted_Auto_Ptr_Rep<X, ACE_LOCK> instance,
+ /// returning NULL if it cannot be created.
+ static ACE_Refcounted_Auto_Ptr_Rep<X, ACE_LOCK> *internal_create (X *p);
+
+ /// Create a ACE_Refcounted_Auto_Ptr_Rep<X, ACE_LOCK> and initialize
+ /// the reference count.
+ static ACE_Refcounted_Auto_Ptr_Rep<X, ACE_LOCK> *create (X *p);
+
+ /// Increase the reference count and return argument. Uses the
+ /// attribute "ace_lock_" to synchronize reference count updating.
+ ///
+ /// Precondition (rep != 0).
+ static ACE_Refcounted_Auto_Ptr_Rep<X, ACE_LOCK> *attach (ACE_Refcounted_Auto_Ptr_Rep<X, ACE_LOCK> *&rep);
+
+ /// Decreases the reference count and and deletes rep if there are no
+ /// more references to rep.
+ ///
+ /// Precondition (rep != 0)
+ static void detach (ACE_Refcounted_Auto_Ptr_Rep<X, ACE_LOCK> *&rep);
+
+ /// Decreases the rep's reference count and and deletes rep if there
+ /// are no more references to rep. Then assigns new_rep to rep.
+ ///
+ /// Precondition (rep != 0 && new_rep != 0)
+ static void assign (ACE_Refcounted_Auto_Ptr_Rep<X, ACE_LOCK> *&rep,
+ ACE_Refcounted_Auto_Ptr_Rep<X, ACE_LOCK> *new_rep);
+
+ /// Pointer to the result.
+ ACE_Auto_Basic_Ptr<X> ptr_;
+
+ /// Reference count.
+ int ref_count_;
+
+ // = Mutex variable to protect the <ptr_>.
+
+ /// Synchronization variable for the MT_SAFE <ACE_Hash_Map_Manager_Ex>.
+ ACE_LOCK lock_;
+
+private:
+ /// Allows us to check for NULL on all ACE_Refcounted_Auto_Ptr objects.
+ int null (void) const;
+
+ // = Constructor and destructor private.
+ ACE_Refcounted_Auto_Ptr_Rep (X *p = 0);
+ ~ACE_Refcounted_Auto_Ptr_Rep (void);
+};
+
+#include "ace/Refcounted_Auto_Ptr.i"
+
+#include "ace/post.h"
+#endif /* ACE_AUTO_PTR_H */
diff --git a/ace/Utils/Refcounted_Auto_Ptr.i b/ace/Utils/Refcounted_Auto_Ptr.i
new file mode 100644
index 00000000000..8fe557b3dde
--- /dev/null
+++ b/ace/Utils/Refcounted_Auto_Ptr.i
@@ -0,0 +1,222 @@
+/* -*- C++ -*- */
+// $Id$
+
+// Refcounted_Auto_Ptr.i
+
+#include "Synch_T.h"
+
+template <class X, class ACE_LOCK> inline int
+ACE_Refcounted_Auto_Ptr_Rep<X, ACE_LOCK>::count (void) const
+{
+ ACE_GUARD_RETURN (ACE_LOCK, guard, ACE_const_cast (ACE_LOCK &, this->lock_), 0);
+ return this->ref_count_;
+}
+
+template <class X, class ACE_LOCK> inline int
+ACE_Refcounted_Auto_Ptr<X, ACE_LOCK>::count (void) const
+{
+ return this->rep_->count ();
+}
+
+template <class X, class ACE_LOCK> inline int
+ACE_Refcounted_Auto_Ptr_Rep<X, ACE_LOCK>::null (void) const
+{
+ ACE_GUARD_RETURN (ACE_LOCK, guard,
+ ACE_const_cast (ACE_LOCK&, this->lock_), 0);
+
+ return this->ptr_.get() == 0;
+}
+
+template <class X, class ACE_LOCK> inline int
+ACE_Refcounted_Auto_Ptr<X, ACE_LOCK>::null (void) const
+{
+ return this->rep_->null ();
+}
+
+template <class X, class ACE_LOCK> inline ACE_Refcounted_Auto_Ptr_Rep<X, ACE_LOCK> *
+ACE_Refcounted_Auto_Ptr_Rep<X, ACE_LOCK>::internal_create (X *p)
+{
+ ACE_Refcounted_Auto_Ptr_Rep<X, ACE_LOCK> *temp = 0;
+ ACE_NEW_RETURN (temp,
+ (ACE_Refcounted_Auto_Ptr_Rep<X, ACE_LOCK>) (p),
+ 0);
+ return temp;
+}
+
+template <class X, class ACE_LOCK> inline ACE_Refcounted_Auto_Ptr_Rep<X, ACE_LOCK> *
+ACE_Refcounted_Auto_Ptr_Rep<X, ACE_LOCK>::create (X *p)
+{
+ // Yes set ref count to zero.
+ ACE_Refcounted_Auto_Ptr_Rep<X, ACE_LOCK> *temp = internal_create (p);
+#if defined (ACE_NEW_THROWS_EXCEPTIONS)
+ if (temp == 0)
+ ACE_throw_bad_alloc;
+#else
+ ACE_ASSERT (temp != 0);
+#endif /* ACE_NEW_THROWS_EXCEPTIONS */
+ return temp;
+}
+
+template <class X, class ACE_LOCK> inline ACE_Refcounted_Auto_Ptr_Rep<X, ACE_LOCK> *
+ACE_Refcounted_Auto_Ptr_Rep<X, ACE_LOCK>::attach (ACE_Refcounted_Auto_Ptr_Rep<X, ACE_LOCK>*& rep)
+{
+ ACE_ASSERT (rep != 0);
+
+ ACE_GUARD_RETURN (ACE_LOCK, guard, rep->lock_, rep);
+
+ ++rep->ref_count_;
+
+ return rep;
+}
+
+template <class X, class ACE_LOCK> inline void
+ACE_Refcounted_Auto_Ptr_Rep<X, ACE_LOCK>::detach (ACE_Refcounted_Auto_Ptr_Rep<X, ACE_LOCK>*& rep)
+{
+ ACE_ASSERT (rep != 0);
+ ACE_Refcounted_Auto_Ptr_Rep<X, ACE_LOCK> *rep_del = 0;
+
+ {
+ ACE_GUARD (ACE_LOCK, guard, rep->lock_);
+
+ if (rep->ref_count_-- == 0)
+ // Since rep contains the lock held by the ACE_Guard, the guard
+ // needs to be released before freeing the memory holding the
+ // lock. So save the pointer to free, then release, then free.
+ rep_del = rep;
+ } // Release the lock
+ if (0 != rep_del)
+ delete rep;
+}
+
+template <class X, class ACE_LOCK> inline void
+ACE_Refcounted_Auto_Ptr_Rep<X, ACE_LOCK>::assign (ACE_Refcounted_Auto_Ptr_Rep<X, ACE_LOCK>*& rep,
+ ACE_Refcounted_Auto_Ptr_Rep<X, ACE_LOCK>* new_rep)
+{
+ ACE_ASSERT (rep != 0);
+ ACE_ASSERT (new_rep != 0);
+
+ ACE_Refcounted_Auto_Ptr_Rep<X, ACE_LOCK> *old = 0;
+ {
+ // detached old last for exception safety
+ ACE_GUARD (ACE_LOCK, guard, rep->lock_);
+ old = rep;
+ rep = new_rep;
+
+ if (old->ref_count_-- > 0)
+ return;
+
+ } // The lock is released before deleting old rep object below.
+
+ delete old;
+}
+
+template <class X, class ACE_LOCK> inline
+ACE_Refcounted_Auto_Ptr_Rep<X, ACE_LOCK>::ACE_Refcounted_Auto_Ptr_Rep (X *p)
+ : ptr_ (p),
+ ref_count_ (0)
+{
+}
+
+template <class X, class ACE_LOCK> inline
+ACE_Refcounted_Auto_Ptr_Rep<X, ACE_LOCK>::~ACE_Refcounted_Auto_Ptr_Rep (void)
+{
+}
+
+template<class X, class ACE_LOCK> inline X *
+ACE_Refcounted_Auto_Ptr_Rep<X, ACE_LOCK>::release (void)
+{
+ ACE_GUARD_RETURN (ACE_LOCK, guard, this->lock_, 0);
+
+ return this->ptr_.release ();
+}
+
+template<class X, class ACE_LOCK> inline void
+ACE_Refcounted_Auto_Ptr_Rep<X, ACE_LOCK>::reset (X *p)
+{
+ ACE_GUARD (ACE_LOCK, guard, this->lock_);
+
+ this->ptr_.reset (p);
+}
+
+template <class X, class ACE_LOCK> inline X *
+ACE_Refcounted_Auto_Ptr_Rep<X, ACE_LOCK>::get (void)
+{
+ ACE_GUARD_RETURN (ACE_LOCK, guard, this->lock_, 0);
+
+ return this->ptr_.get ();
+}
+
+template <class X, class ACE_LOCK> inline
+ACE_Refcounted_Auto_Ptr<X, ACE_LOCK>::ACE_Refcounted_Auto_Ptr (X *p)
+ : rep_ (AUTO_REFCOUNTED_PTR_REP::create (p))
+{
+}
+
+template <class X, class ACE_LOCK> inline
+ACE_Refcounted_Auto_Ptr<X, ACE_LOCK>::ACE_Refcounted_Auto_Ptr (const ACE_Refcounted_Auto_Ptr<X, ACE_LOCK> &r)
+ : rep_ (AUTO_REFCOUNTED_PTR_REP::attach (((ACE_Refcounted_Auto_Ptr<X, ACE_LOCK> &) r).rep_))
+{
+}
+
+template <class X, class ACE_LOCK> inline
+ACE_Refcounted_Auto_Ptr<X, ACE_LOCK>::~ACE_Refcounted_Auto_Ptr (void)
+{
+ AUTO_REFCOUNTED_PTR_REP::detach (rep_);
+}
+
+template <class X, class ACE_LOCK> inline int
+ACE_Refcounted_Auto_Ptr<X, ACE_LOCK>::operator== (const ACE_Refcounted_Auto_Ptr<X, ACE_LOCK> &r) const
+{
+ return r.rep_ == this->rep_;
+}
+
+template <class X, class ACE_LOCK> inline int
+ACE_Refcounted_Auto_Ptr<X, ACE_LOCK>::operator!= (const ACE_Refcounted_Auto_Ptr<X, ACE_LOCK> &r) const
+{
+ return r.rep_ != this->rep_;
+}
+
+template <class X, class ACE_LOCK> inline X *
+ACE_Refcounted_Auto_Ptr<X, ACE_LOCK>::operator-> (void) const
+{
+ return this->rep_->get();
+}
+
+template<class X, class ACE_LOCK> inline X &
+ACE_Refcounted_Auto_Ptr<X, ACE_LOCK>::operator *() const
+{
+ return *this->rep_->get ();
+}
+
+template <class X, class ACE_LOCK> inline X*
+ACE_Refcounted_Auto_Ptr<X, ACE_LOCK>::get (void)
+{
+ // We return the ACE_Future_rep.
+ return this->rep_->get ();
+}
+
+template<class X, class ACE_LOCK> inline X *
+ACE_Refcounted_Auto_Ptr<X, ACE_LOCK>::release (void)
+{
+ return this->rep_->release ();
+}
+
+template<class X, class ACE_LOCK> inline void
+ACE_Refcounted_Auto_Ptr<X, ACE_LOCK>::reset (X *p)
+{
+ this->rep_->reset (p);
+}
+
+template <class X, class ACE_LOCK> inline void
+ACE_Refcounted_Auto_Ptr<X, ACE_LOCK>::operator = (const ACE_Refcounted_Auto_Ptr<X, ACE_LOCK> &rhs)
+{
+ // assignment:
+ //
+ // bind <this> to the same <ACE_Refcounted_Auto_Ptr_Rep> as <r>.
+
+ // This will work if &r == this, by first increasing the ref count
+ ACE_Refcounted_Auto_Ptr<X, ACE_LOCK> &r = (ACE_Refcounted_Auto_Ptr<X, ACE_LOCK> &) rhs;
+ AUTO_REFCOUNTED_PTR_REP::assign (this->rep_,
+ AUTO_REFCOUNTED_PTR_REP::attach (r.rep_));
+}
+
diff --git a/ace/Utils/Registry.cpp b/ace/Utils/Registry.cpp
new file mode 100644
index 00000000000..16e4b7ef32d
--- /dev/null
+++ b/ace/Utils/Registry.cpp
@@ -0,0 +1,1142 @@
+// $Id$
+
+#include "ace/Registry.h"
+
+ACE_RCSID(ace, Registry, "$Id$")
+
+#if defined (ACE_WIN32)
+
+// Funky macro to deal with strange error passing semantics
+// of Win32 Reg*() functions
+#define ACE_REGISTRY_CALL_RETURN(X) \
+ do { \
+ if (X != ERROR_SUCCESS) \
+ { \
+ errno = X; \
+ return -1; \
+ } \
+ else \
+ return 0; \
+ } while (0)
+
+
+// Separator for components in a name
+/* static */
+const ACE_TCHAR *ACE_Registry::STRING_SEPARATOR = ACE_LIB_TEXT ("\\");
+
+int
+ACE_Registry::Name_Component::operator== (const Name_Component &rhs) const
+{
+ return
+ rhs.id_ == this->id_ &&
+ rhs.kind_ == this->kind_;
+}
+
+int
+ACE_Registry::Name_Component::operator!= (const Name_Component &rhs) const
+{
+ return !this->operator== (rhs);
+}
+
+// Simple binding constructor
+ACE_Registry::Binding::Binding ()
+ : name_ (),
+ type_ (INVALID)
+{
+}
+
+
+// Binding constructor
+// (Name version)
+ACE_Registry::Binding::Binding (const Name &name,
+ Binding_Type type)
+ : name_ (ACE_Registry::make_string (name)),
+ type_ (type)
+{
+}
+
+
+// Binding constructor
+// (String version)
+ACE_Registry::Binding::Binding (const ACE_TString &name,
+ Binding_Type type)
+ : name_ (name),
+ type_ (type)
+{
+}
+
+
+int
+ACE_Registry::Binding::operator== (const Binding &rhs) const
+{
+ return
+ rhs.name_ == this->name_ &&
+ rhs.type_ == this->type_;
+}
+
+int
+ACE_Registry::Binding::operator!= (const Binding &rhs) const
+{
+ return !this->operator== (rhs);
+}
+
+// Name accessor
+// (Name version)
+void
+ACE_Registry::Binding::name (Name &name)
+{
+ name = ACE_Registry::make_name (this->name_);
+}
+
+
+// Name accessors
+// (String version)
+void
+ACE_Registry::Binding::name (ACE_TString &name)
+{
+ name = this->name_;
+}
+
+
+// Name accessors
+// (String version)
+ACE_TString
+ACE_Registry::Binding::name (void)
+{
+ return this->name_;
+}
+
+
+// Type accessor
+ACE_Registry::Binding_Type
+ACE_Registry::Binding::type (void)
+{
+ return this->type_;
+}
+
+
+// Simple object constructor
+ACE_Registry::Object::Object (void *data,
+ u_long size,
+ u_long type)
+ : data_ (data),
+ size_ (size),
+ type_ (type)
+{
+}
+
+// Object accessors and set methods
+void
+ACE_Registry::Object::data (void *data)
+{
+ this->data_ = data;
+}
+
+
+void *
+ACE_Registry::Object::data (void) const
+{
+ return this->data_;
+}
+
+
+void
+ACE_Registry::Object::size (u_long size)
+{
+ this->size_ = size;
+}
+
+
+u_long
+ACE_Registry::Object::size (void) const
+{
+ return this->size_;
+}
+
+
+void
+ACE_Registry::Object::type (u_long type)
+{
+ this->type_ = type;
+}
+
+
+u_long
+ACE_Registry::Object::type (void) const
+{
+ return this->type_;
+}
+
+
+// Simple context constructor
+ACE_Registry::Naming_Context::Naming_Context (void)
+ : key_ ((HKEY) 0),
+ parent_key_ ((HKEY) 0),
+ name_ ()
+{
+}
+
+
+// Context constructor
+ACE_Registry::Naming_Context::Naming_Context (const HKEY &key)
+ : key_ (key),
+ parent_key_ ((HKEY) 0),
+ name_ ()
+{
+}
+
+
+ACE_Registry::Naming_Context::Naming_Context (const Naming_Context &rhs)
+ : key_ (rhs.key_),
+ parent_key_ (rhs.parent_key_),
+ name_ (rhs.name_)
+{
+ // This is incorrect.
+ // Rather than copying key, we should call ::DuplicateHandle()
+ // But since this is private (and not used), I don't care much
+}
+
+
+const ACE_Registry::Naming_Context &
+ACE_Registry::Naming_Context::operator= (const Naming_Context &rhs)
+{
+ ACE_UNUSED_ARG(rhs);
+
+ // Not implemented
+ return *this;
+}
+
+
+// Destructor
+ACE_Registry::Naming_Context::~Naming_Context ()
+{
+ this->close ();
+}
+
+
+// Insert <object> with <name> into <this> context
+// (Name version)
+int
+ACE_Registry::Naming_Context::bind_new (const Name &name,
+ const Object &object)
+{
+ return this->bind_new (ACE_Registry::make_string (name), object);
+}
+
+
+// Insert <object> with <name> into <this> context
+// (String version)
+int
+ACE_Registry::Naming_Context::bind_new (const ACE_TString &name,
+ const Object &object)
+{
+ // temporary object
+ Object temp;
+ long result = this->resolve (name, temp);
+ if (result == 0)
+ // resolve succeeded
+ result = -1;
+ else
+ // resolve failed
+ result = this->bind (name, object);
+ return result;
+}
+
+
+// Insert or update <object> with <name> into <this> context
+// (Name version)
+int
+ACE_Registry::Naming_Context::bind (const Name &name,
+ const Object &object)
+{
+ return this->bind (ACE_Registry::make_string (name), object);
+}
+
+
+// Insert or update <object> with <name> into <this> context
+// (String version)
+int
+ACE_Registry::Naming_Context::bind (const ACE_TString &name,
+ const Object &object)
+{
+ long result = ACE_TEXT_RegSetValueEx (this->key_,
+ name.c_str (),
+ 0,
+ object.type (),
+ (const BYTE *) object.data (),
+ object.size ());
+ ACE_REGISTRY_CALL_RETURN (result);
+}
+
+
+// Update <object> with <name> in <this> context
+// (Name version)
+int
+ACE_Registry::Naming_Context::rebind (const Name &name,
+ const Object &new_object)
+{
+ return this->rebind (ACE_Registry::make_string (name), new_object);
+}
+
+
+// Update <object> with <name> in <this> context
+// (String version)
+int
+ACE_Registry::Naming_Context::rebind (const ACE_TString &name,
+ const Object &new_object)
+{
+ Object old_object;
+ // find the old one first
+ long result = this->resolve (name, old_object);
+ if (result == 0)
+ // no need to delete first
+ result = this->bind (name, new_object);
+ return result;
+}
+
+
+// Find <object> with <name> in <this> context
+// (Name version)
+int
+ACE_Registry::Naming_Context::resolve (const Name &name,
+ Object &object)
+{
+ return this->resolve (ACE_Registry::make_string (name), object);
+}
+
+
+// Find <object> with <name> in <this> context
+// (String version)
+int
+ACE_Registry::Naming_Context::resolve (const ACE_TString &name,
+ Object &object)
+{
+ // Get object state
+ u_long type;
+ void *data = object.data ();
+ u_long size = object.size ();
+
+ long result = ACE_TEXT_RegQueryValueEx (this->key_,
+ name.c_str (),
+ 0,
+ &type,
+ (BYTE *)data,
+ &size);
+ if (result == ERROR_SUCCESS)
+ {
+ // Reset object state
+ // No need to set object.data()
+ object.type (type);
+ object.size (size);
+ }
+
+ ACE_REGISTRY_CALL_RETURN (result);
+}
+
+
+// Remove object with <name> in <this> context
+// (Name version)
+int
+ACE_Registry::Naming_Context::unbind (const Name &name)
+{
+ return this->unbind (ACE_Registry::make_string (name));
+}
+
+
+// Remove object with <name> in <this> context
+// (String version)
+int
+ACE_Registry::Naming_Context::unbind (const ACE_TString &name)
+{
+ long result = ACE_TEXT_RegDeleteValue (this->key_,
+ name.c_str ());
+
+ ACE_REGISTRY_CALL_RETURN (result);
+}
+
+
+// Create new <naming_context> relative to <this> context
+// This method may not mean a lot in this implementation
+int
+ACE_Registry::Naming_Context::new_context (Naming_Context &naming_context)
+{
+ // Make sure that we reset the state and close keys
+ return naming_context.close ();
+}
+
+
+// Insert <naming_context> with <name> relative to <this> context
+// (Name version)
+int
+ACE_Registry::Naming_Context::bind_new_context (const Name &name,
+ Naming_Context &naming_context,
+ u_long persistence,
+ u_long security_access,
+ LPSECURITY_ATTRIBUTES security_attributes)
+{
+ return this->bind_new_context (ACE_Registry::make_string (name),
+ naming_context,
+ persistence,
+ security_access,
+ security_attributes);
+}
+
+
+// Insert <naming_context> with <name> relative to <this> context
+// (String version)
+int
+ACE_Registry::Naming_Context::bind_new_context (const ACE_TString &name,
+ Naming_Context &naming_context,
+ u_long persistence,
+ u_long security_access,
+ LPSECURITY_ATTRIBUTES security_attributes)
+{
+ u_long reason;
+
+ long result = ACE_TEXT_RegCreateKeyEx (this->key_,
+ name.c_str (),
+ 0,
+ 0,
+ persistence,
+ security_access,
+ security_attributes,
+ &naming_context.key_,
+ &reason);
+ if (result == ERROR_SUCCESS)
+ // If create succeeds
+ {
+ if (reason == REG_CREATED_NEW_KEY)
+ // If new key: success
+ {
+ // Set the correct parent
+ naming_context.parent (this->key_);
+ // Set the correct name
+ naming_context.name (name);
+ }
+ else
+ // reason == REG_OPENED_EXISTING_KEY
+ // Failed to make new key
+ {
+ // reset result to failure
+ result = -1;
+ // Close the key first
+ ::RegCloseKey (naming_context.key_);
+ // Reset key
+ naming_context.key_ = (HKEY) 0;
+ }
+ }
+
+ ACE_REGISTRY_CALL_RETURN (result);
+}
+
+
+// Insert or update <naming_context> with <name> relative to <this> context
+// (Name version)
+int
+ACE_Registry::Naming_Context::bind_context (const Name &name,
+ /* const */ Naming_Context &naming_context,
+ u_long persistence,
+ u_long security_access,
+ LPSECURITY_ATTRIBUTES security_attributes)
+{
+ return this->bind_context (ACE_Registry::make_string (name),
+ naming_context,
+ persistence,
+ security_access,
+ security_attributes);
+}
+
+
+// Insert or update <naming_context> with <name> relative to <this> context
+// (String version)
+int
+ACE_Registry::Naming_Context::bind_context (const ACE_TString &name,
+ /* const */ Naming_Context &naming_context,
+ u_long persistence,
+ u_long security_access,
+ LPSECURITY_ATTRIBUTES security_attributes)
+{
+ u_long reason;
+
+ long result = ACE_TEXT_RegCreateKeyEx (this->key_,
+ name.c_str (),
+ 0,
+ 0,
+ persistence,
+ security_access,
+ security_attributes,
+ &naming_context.key_,
+ &reason);
+ if (result == ERROR_SUCCESS)
+ {
+ // Set the correct parent
+ naming_context.parent (this->key_);
+ // Set the correct name
+ naming_context.name (name);
+ }
+
+ ACE_REGISTRY_CALL_RETURN (result);
+}
+
+
+// Rename <naming_context> to <name>
+// (Name version)
+int
+ACE_Registry::Naming_Context::rebind_context (const Name &name,
+ /* const */ Naming_Context &new_naming_context)
+{
+ return this->rebind_context (ACE_Registry::make_string (name),
+ new_naming_context);
+}
+
+
+// Rename <naming_context> to <name>
+// (String version)
+int
+ACE_Registry::Naming_Context::rebind_context (const ACE_TString &name,
+ /* const */ Naming_Context &new_naming_context)
+{
+ Naming_Context old_naming_context;
+ // find the old one first
+ long result = this->resolve_context (name,
+ old_naming_context);
+ if (result == 0)
+ {
+ // naming_context is found: delete entry
+ result = this->unbind_context (name);
+ if (result == 0)
+ {
+ // successful deletion; rebind
+ // beware of race conditions here
+ // (lets resolve this later)
+ result = this->bind_new_context (name, new_naming_context);
+ }
+ }
+ return result;
+}
+
+
+// Remove naming_context with <name> from <this> context
+// (Name version)
+int
+ACE_Registry::Naming_Context::unbind_context (const Name &name)
+{
+ return this->unbind_context (ACE_Registry::make_string (name));
+}
+
+
+// Remove naming_context with <name> from <this> context
+// (String version)
+int
+ACE_Registry::Naming_Context::unbind_context (const ACE_TString &name)
+{
+ long result = ACE_TEXT_RegDeleteKey (this->key_,
+ name.c_str ());
+
+ ACE_REGISTRY_CALL_RETURN (result);
+}
+
+
+// Find <naming_context> with <name> in <this> context
+// (Name version)
+int
+ACE_Registry::Naming_Context::resolve_context (const Name &name,
+ Naming_Context &naming_context,
+ u_long security_access)
+{
+ return this->resolve_context (ACE_Registry::make_string (name),
+ naming_context,
+ security_access);
+}
+
+
+// Find <naming_context> with <name> in <this> context
+// (String version)
+int
+ACE_Registry::Naming_Context::resolve_context (const ACE_TString &name,
+ Naming_Context &naming_context,
+ u_long security_access)
+{
+ long result = ACE_TEXT_RegOpenKeyEx (this->key_,
+ name.c_str (),
+ 0,
+ security_access,
+ &naming_context.key_);
+ if (result == ERROR_SUCCESS)
+ {
+ // set the correct parent
+ naming_context.parent (this->key_);
+ // set the correct name
+ naming_context.name (name);
+ }
+
+ ACE_REGISTRY_CALL_RETURN (result);
+}
+
+
+// Same as unbind_context() with <this> as naming_context
+int
+ACE_Registry::Naming_Context::destroy (void)
+{
+ // hopefully the parent_key_ is still open
+ long result = ACE_TEXT_RegDeleteKey (this->parent_key_,
+ this->name_.c_str ());
+
+ ACE_REGISTRY_CALL_RETURN (result);
+}
+
+
+// Sync content of context to disk
+int
+ACE_Registry::Naming_Context::flush (void)
+{
+ long result = ::RegFlushKey (this->key_);
+ ACE_REGISTRY_CALL_RETURN (result);
+}
+
+
+// Close the handle of the context
+int
+ACE_Registry::Naming_Context::close (void)
+{
+ long result = this->key_ ? ::RegCloseKey (this->key_) : ERROR_SUCCESS;
+ ACE_REGISTRY_CALL_RETURN (result);
+}
+
+
+// Convert a <name> to a <string>
+ACE_TString
+ACE_Registry::make_string (const Name &const_name)
+{
+ ACE_TString string;
+ Name &name = ACE_const_cast (Name &, const_name);
+
+ // Iterator through the components of name
+ for (Name::iterator iterator = name.begin ();
+ iterator != name.end ();
+ iterator++)
+ {
+ if (iterator != name.begin ())
+ // If this is not the first component, we will add separators
+ string += ACE_Registry::STRING_SEPARATOR;
+ const Name_Component &component = *iterator;
+ // Add to string
+ string += component.id_;
+ }
+
+ return string;
+}
+
+
+// Convert a <string> to a <name>
+ACE_Registry::Name
+ACE_Registry::make_name (const ACE_TString &string)
+{
+ int new_position = 0;
+ int last_position = 0;
+ Name name;
+
+ // Rememeber: NPOS is -1
+ while (new_position != ACE_TString::npos)
+ {
+ Name_Component component;
+ // Find the separator
+ new_position = string.find (ACE_Registry::STRING_SEPARATOR, new_position);
+ if (new_position != ACE_TString::npos)
+ // If we have not gone past the end
+ {
+ // Get the substring
+ component.id_ = string.substr (last_position,
+ new_position - last_position);
+ // Skip past the seperator
+ new_position += ACE_OS::strlen (ACE_Registry::STRING_SEPARATOR);
+ }
+ else
+ {
+ // Get the last substring
+ component.id_ = string.substr (last_position);
+ }
+ // Update positions
+ last_position = new_position;
+ // Insert component into name
+ name.insert (component);
+ }
+
+ return name;
+}
+
+
+// Set key
+void
+ACE_Registry::Naming_Context::key (HKEY key)
+{
+ this->key_ = key;
+}
+
+
+// Get key
+HKEY
+ACE_Registry::Naming_Context::key (void)
+{
+ return this->key_;
+}
+
+
+// Set parent
+void
+ACE_Registry::Naming_Context::parent (HKEY parent)
+{
+ this->parent_key_ = parent;
+}
+
+
+// Get parent
+HKEY
+ACE_Registry::Naming_Context::parent (void)
+{
+ return this->parent_key_;
+}
+
+
+// Set name
+// (Name version)
+void
+ACE_Registry::Naming_Context::name (const Name &name)
+{
+ this->name_ = ACE_Registry::make_string (name);
+}
+
+
+// Get name
+// (Name version)
+void
+ACE_Registry::Naming_Context::name (Name &name)
+{
+ name = ACE_Registry::make_name (this->name_);
+}
+
+
+// Set name
+// (String version)
+void
+ACE_Registry::Naming_Context::name (const ACE_TString &name)
+{
+ this->name_ = name;
+}
+
+
+// Get name
+// (String version)
+ACE_TString
+ACE_Registry::Naming_Context::name (void)
+{
+ return this->name_;
+}
+
+
+// Get name
+// (String version)
+void
+ACE_Registry::Naming_Context::name (ACE_TString &name)
+{
+ name = this->name_;
+}
+
+
+// listing function: iterator creator
+// This is useful when there are many objects and contexts
+// in <this> context and you only want to look at a few entries
+// at a time
+int
+ACE_Registry::Naming_Context::list (u_long how_many,
+ Binding_List &list,
+ Binding_Iterator &iter)
+{
+ // Empty list
+ static const ACE_Registry::Binding_List empty_list;
+ // Make sure that the list is empty
+ list = empty_list;
+
+ // Correctly initalize the iterator
+ iter.reset ();
+
+ // Make sure that the iterator uses <this> naming context
+ iter.naming_context (*this);
+
+ // Start iterations from the objects
+ iter.current_enumeration (iter.object_iteration_);
+
+ // Get the next <how_many> values
+ long result = iter.next_n (how_many,
+ list);
+ return result;
+}
+
+
+// listing function: iterator creator
+// This gives back a listing of all entries in <this> context.
+int
+ACE_Registry::Naming_Context::list (Binding_List &list)
+{
+ // Empty list
+ static const ACE_Registry::Binding_List empty_list;
+ // Make sure that the list is empty
+ list = empty_list;
+
+ // Create an iterator
+ ACE_Registry::Binding_Iterator iterator;
+
+ // Make sure that the iterator uses <this> naming context
+ iterator.naming_context (*this);
+
+ // Start iterations from the objects
+ iterator.current_enumeration (iterator.object_iteration_);
+
+ long result = 0;
+ while (1)
+ {
+ ACE_Registry::Binding binding;
+ result = iterator.next_one (binding);
+ if (result == 0)
+ list.insert (binding);
+ else
+ break;
+ }
+ return 0;
+}
+
+
+// Default constructor
+ACE_Registry::Binding_Iterator::Binding_Iterator ()
+ : object_iteration_ (*this),
+ context_iteration_ (*this),
+ iteration_complete_ (*this)
+{
+ this->reset ();
+}
+
+
+void
+ACE_Registry::Binding_Iterator::reset ()
+{
+ this->current_enumeration_ = &this->iteration_complete_;
+ this->iteration_complete_.reset ();
+ this->object_iteration_.reset ();
+ this->context_iteration_.reset ();
+}
+
+
+void
+ACE_Registry::Binding_Iterator::Iteration_State::reset ()
+{
+ this->index_ = 0;
+}
+
+
+ACE_Registry::Binding_Iterator::Iteration_State::Iteration_State (Binding_Iterator &iter)
+ : parent_ (&iter),
+ index_ (0)
+{
+}
+
+
+ACE_Registry::Binding_Iterator::Object_Iteration::Object_Iteration (Binding_Iterator &iter)
+ : Iteration_State (iter)
+{
+}
+
+
+ACE_Registry::Binding_Iterator::Context_Iteration::Context_Iteration (Binding_Iterator &iter)
+ : Iteration_State (iter)
+{
+}
+
+
+ACE_Registry::Binding_Iterator::Iteration_Complete::Iteration_Complete (Binding_Iterator &iter)
+ : Iteration_State (iter)
+{
+}
+
+
+// Next entry
+int
+ACE_Registry::Binding_Iterator::next_one (Binding &binding)
+{
+ u_long how_many = 1;
+ Binding_List list;
+
+ // Get next n (where n is one)
+ long result = this->next_n (how_many, list);
+
+ if (result == 0)
+ // Success
+ binding = (*list.begin ());
+
+ return result;
+}
+
+
+// Next <how_many> entries
+int
+ACE_Registry::Binding_Iterator::next_n (u_long how_many,
+ Binding_List &list)
+{
+ // Empty list
+ static const ACE_Registry::Binding_List empty_list;
+ // Make sure that the list is empty
+ list = empty_list;
+
+ return this->current_enumeration_->next_n (how_many, list);
+}
+
+
+// Destroy iterator
+int
+ACE_Registry::Binding_Iterator::destroy (void)
+{
+ this->reset ();
+ return 0;
+}
+
+
+// Set/Get naming_context
+void
+ACE_Registry::Binding_Iterator::naming_context (Naming_Context &naming_context)
+{
+ this->naming_context_ = &naming_context;
+}
+
+
+ACE_Registry::Naming_Context &
+ACE_Registry::Binding_Iterator::naming_context (void)
+{
+ return *this->naming_context_;
+}
+
+
+// Set/Get current enumeration
+void
+ACE_Registry::Binding_Iterator::current_enumeration (Iteration_State &current_enumeration)
+{
+ this->current_enumeration_ = &current_enumeration;
+}
+
+
+ACE_Registry::Binding_Iterator::Iteration_State &
+ACE_Registry::Binding_Iterator::current_enumeration (void)
+{
+ return *this->current_enumeration_;
+}
+
+
+int
+ACE_Registry::Binding_Iterator::Object_Iteration::next_n (u_long how_many,
+ Binding_List &list)
+{
+ // Make a copy
+ u_long requested = how_many;
+
+ // While there are more entries to be added to the list
+ while (how_many > 0)
+ {
+ ACE_TCHAR string [ACE_Registry::Naming_Context::MAX_OBJECT_NAME_SIZE];
+ u_long size = sizeof string / sizeof (ACE_TCHAR);
+ long result = ACE_TEXT_RegEnumValue (this->parent_->naming_context ().key (),
+ this->index_,
+ string,
+ &size,
+ 0,
+ 0,
+ 0,
+ 0);
+ switch (result)
+ {
+ case ERROR_SUCCESS:
+ // Object found
+ {
+ // Readjust counters
+ this->index_++;
+ how_many--;
+
+ // Add to list
+ // Create binding
+ Binding binding (string, OBJECT);
+ // Add to binding list
+ list.insert (binding);
+ }
+ // Continue to add to list
+ break;
+
+ case ERROR_NO_MORE_ITEMS:
+ // Enumeration of objects complete
+ // Reset index
+ this->index_ = 0;
+
+ // Current enumeration will become CONTEXTS
+ this->parent_->current_enumeration (this->parent_->context_iteration_);
+ result = this->parent_->current_enumeration ().next_n (how_many,
+ list);
+ // If we were able to add objects
+ if (requested != how_many)
+ return 0;
+ else
+ return result;
+
+ default:
+ // Strange error
+ // Reset index
+ this->index_ = 0;
+ // Current enumeration will become COMPLETE
+ this->parent_->current_enumeration (this->parent_->iteration_complete_);
+ // strange error
+ return -1;
+ }
+ }
+ // If we reach here, all of <how_many> pairs were added to the list
+ // Since more entries may be available
+ // current enumeration will remain OBJECTS
+ return 0;
+}
+
+
+int
+ACE_Registry::Binding_Iterator::Context_Iteration::next_n (u_long how_many,
+ Binding_List &list)
+{
+ // Make a copy
+ u_long requested = how_many;
+
+ // While there are more entries to be added to the list
+ while (how_many > 0)
+ {
+ ACE_TCHAR string [ACE_Registry::Naming_Context::MAX_CONTEXT_NAME_SIZE];
+ u_long size = sizeof string / sizeof (ACE_TCHAR);
+ long result = ACE_TEXT_RegEnumKeyEx (this->parent_->naming_context (). key (),
+ this->index_,
+ string,
+ &size,
+ 0,
+ 0,
+ 0,
+ 0);
+ switch (result)
+ {
+ case ERROR_SUCCESS:
+ // Object found
+ {
+ // Readjust counters
+ this->index_++;
+ how_many--;
+
+ // Add to list
+ // Create binding
+ Binding binding (string, CONTEXT);
+ // Add to binding list
+ list.insert (binding);
+ }
+ // Continue to add to list
+ break;
+
+ case ERROR_NO_MORE_ITEMS:
+ // Enumeration of objects complete
+
+ /* FALL THROUGH */
+
+ default:
+ // Strange error
+
+ // Reset index
+ this->index_ = 0;
+ // Current enumeration will become CONTEXTS
+ this->parent_->current_enumeration (this->parent_->iteration_complete_);
+
+ // If we were able to add contexts
+ if (requested != how_many)
+ return 0;
+ else
+ return -1;
+ }
+ }
+ // If we reach here, all of <how_many> pairs were added to the list
+ // Since more entries may be available
+ // current enumeration will remain CONTEXTS
+ return 0;
+}
+
+
+int
+ACE_Registry::Binding_Iterator::Iteration_Complete::next_n (u_long how_many,
+ Binding_List &list)
+{
+ ACE_UNUSED_ARG(list);
+ ACE_UNUSED_ARG(how_many);
+
+ // No more values
+ return -1;
+}
+
+
+// Factory method to connect to predefined registries
+// This method works for both remote and local machines
+// However, for remote machines CLASSES_ROOT and CURRENT_USER
+// types are not allowed
+/* static */
+int
+ACE_Predefined_Naming_Contexts::connect (ACE_Registry::Naming_Context &naming_context,
+ HKEY predefined,
+ const ACE_TCHAR *machine_name)
+{
+ long result = -1;
+
+ if (machine_name != 0 && ACE_OS::strcmp (ACE_LIB_TEXT ("localhost"), machine_name) == 0)
+ machine_name = 0;
+
+ if (predefined == HKEY_LOCAL_MACHINE || predefined == HKEY_USERS)
+ result = ACE_TEXT_RegConnectRegistry (ACE_const_cast(ACE_TCHAR *, machine_name),
+ predefined,
+ &naming_context.key_);
+ if (predefined == HKEY_CURRENT_USER || predefined == HKEY_CLASSES_ROOT)
+ // Make sure that for these types, the machine is local
+ if (machine_name == 0 ||
+ ACE_Predefined_Naming_Contexts::is_local_host (machine_name))
+ {
+ naming_context.key_ = predefined;
+ result = 0;
+ }
+ else
+ result = -1;
+
+ ACE_REGISTRY_CALL_RETURN (result);
+}
+
+// Check if <machine_name> is the local host
+/* static */
+int
+ACE_Predefined_Naming_Contexts::is_local_host (const ACE_TCHAR *machine_name)
+{
+ ACE_TCHAR local_host[MAXHOSTNAMELEN];
+ int result = ACE_OS::hostname (local_host, sizeof local_host / sizeof (ACE_TCHAR));
+ if (result == 0)
+ result = !ACE_OS::strcmp (local_host, machine_name);
+ else
+ result = 0;
+ return result;
+}
+
+#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION)
+template class ACE_Node<ACE_Registry::Binding>;
+template class ACE_Unbounded_Set<ACE_Registry::Binding>;
+template class ACE_Unbounded_Set_Iterator<ACE_Registry::Binding>;
+template class ACE_Node<ACE_Registry::Name_Component>;
+template class ACE_Unbounded_Set<ACE_Registry::Name_Component>;
+template class ACE_Unbounded_Set_Iterator<ACE_Registry::Name_Component>;
+#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA)
+#pragma instantiate ACE_Node<ACE_Registry::Binding>
+#pragma instantiate ACE_Unbounded_Set<ACE_Registry::Binding>
+#pragma instantiate ACE_Unbounded_Set_Iterator<ACE_Registry::Binding>
+#pragma instantiate ACE_Node<ACE_Registry::Name_Component>
+#pragma instantiate ACE_Unbounded_Set<ACE_Registry::Name_Component>
+#pragma instantiate ACE_Unbounded_Set_Iterator<ACE_Registry::Name_Component>
+#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */
+
+#endif /* ACE_WIN32 */
diff --git a/ace/Utils/Registry.h b/ace/Utils/Registry.h
new file mode 100644
index 00000000000..c1fc45c5a19
--- /dev/null
+++ b/ace/Utils/Registry.h
@@ -0,0 +1,560 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Registry.h
+ *
+ * $Id$
+ *
+ * @author Irfan Pyarali (irfan@cs.wustl.edu)
+ */
+//=============================================================================
+
+
+#ifndef ACE_REGISTRY_H
+#define ACE_REGISTRY_H
+#include "ace/pre.h"
+
+#include "ace/OS.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#if defined (ACE_WIN32)
+// This only works on Win32 platforms
+
+#include "ace/Containers.h"
+#include "ace/SString.h"
+
+/**
+ * @class ACE_Registry
+ *
+ * @brief A Name Server implementation
+ *
+ * The registry interface is inspired by the interface
+ * specified in the CORBA Naming Service Specification.
+ * The implementation is done through Win32 <Reg*> functions.
+ * Other than providing an OO wrapper for the Win32 <Reg*>
+ * functions, ACE_Registry provides an abstraction for iteration
+ * over the elements of the Registry.
+ */
+class ACE_Export ACE_Registry
+{
+public:
+
+ /// International string
+ struct ACE_Export Name_Component
+ {
+ ACE_TString id_;
+ ACE_TString kind_;
+
+ int operator== (const Name_Component &rhs) const;
+ int operator!= (const Name_Component &rhs) const;
+ // Comparison
+ };
+ // The <id_> field is used,
+ // but the <kind_> field is currently ignored
+
+ // A Name is an ordered collections of components (ids)
+ typedef ACE_Unbounded_Set<Name_Component> Name;
+
+ /// Separator for components in a name
+ static const ACE_TCHAR *STRING_SEPARATOR;
+
+ /// Convert a <name> to a <string>
+ static ACE_TString make_string (const Name &name);
+
+ /// Convert a <string> to a <name>
+ static Name make_name (const ACE_TString &string);
+
+ /// There are two types of bindings
+ enum Binding_Type {INVALID, OBJECT, CONTEXT};
+
+ struct ACE_Export Binding
+ {
+ /// Empty (default) constructor
+ Binding (void);
+
+ /// Constructor
+ /// (Name version)
+ Binding (const Name &binding_name,
+ Binding_Type binding_type);
+
+ /// Constructor
+ /// (String version)
+ Binding (const ACE_TString &binding_name,
+ Binding_Type binding_type);
+
+ int operator== (const Binding &rhs) const;
+ int operator!= (const Binding &rhs) const;
+ // Comparison
+
+ /// Name accessor
+ /// (Name version)
+ void name (Name &name);
+
+ /// Name accessors
+ /// (String version)
+ void name (ACE_TString &name);
+ ACE_TString name (void);
+
+ /// Type accessor
+ Binding_Type type (void);
+
+ private:
+ /// A binding has a name
+ ACE_TString name_;
+
+ /// .... and a type
+ Binding_Type type_;
+ };
+
+ // A list of bindings
+ typedef ACE_Unbounded_Set<Binding> Binding_List;
+
+ /**
+ * @class Binding_Iterator;
+ *
+ * Forward declaration of iterator
+ */
+ class Binding_Iterator;
+
+ /**
+ * @class Object
+ *
+ * @brief An object representation
+ *
+ * In CORBA, all objects inherit from (CORBA::Object).
+ * For the registry, this is used as a wrapper for an
+ * instance of a built-in data type.
+ * Think about an object as being similar to a file
+ * in a file system.
+ */
+ class ACE_Export Object
+ {
+ public:
+ /// Default constructor
+ Object (void *data = 0,
+ u_long size = 0,
+ u_long type = REG_NONE);
+
+ /// Set/Get data
+ void data (void *data);
+ void *data (void) const;
+
+ /// Set/Get size
+ void size (u_long size);
+ u_long size (void) const;
+
+ /// Set/Get type
+ void type (u_long type);
+ u_long type (void) const;
+
+ private:
+ /// Pointer to data
+ void *data_;
+
+ /// Size of the data
+ u_long size_;
+
+ /// Type of data
+ u_long type_;
+ };
+
+ /**
+ * @class Naming_Context
+ *
+ * @brief An context representation
+ *
+ * Think about a context as being similar to a directory
+ * in a file system.
+ */
+ class ACE_Export Naming_Context
+ {
+ public:
+ /// Friend factory
+ friend class ACE_Predefined_Naming_Contexts;
+
+ enum {
+ /// Max sizes of names
+ /// (Not too sure about this value)
+ MAX_OBJECT_NAME_SIZE = BUFSIZ,
+
+ /// Max size of context name
+ MAX_CONTEXT_NAME_SIZE = MAXPATHLEN + 1
+ };
+
+ /// Empty constructor: keys will be NULL
+ Naming_Context (void);
+
+ /// Constructor: key_ will be set to <key>
+ Naming_Context (const HKEY &key);
+
+ /// Destructor will call <Naming_Context::close>.
+ ~Naming_Context (void);
+
+ // The following interfaces are for objects
+
+ /**
+ * Insert <object> with <name> into <this> context
+ * This will fail if <name> already exists
+ * (Name version)
+ */
+ int bind_new (const Name &name,
+ const Object &object);
+
+ /**
+ * Insert <object> with <name> into <this> context
+ * This will fail if <name> already exists
+ * (String version)
+ */
+ int bind_new (const ACE_TString &name,
+ const Object &object);
+
+ /**
+ * Insert or update <object> with <name> into <this> context
+ * This will not fail if <name> already exists
+ * (Name version)
+ */
+ int bind (const Name &name,
+ const Object &object);
+
+ /**
+ * Insert or update <object> with <name> into <this> context
+ * This will not fail if <name> already exists
+ * (String version)
+ */
+ int bind (const ACE_TString &name,
+ const Object &object);
+
+ /// Update <object> with <name> in <this> context
+ /// (Name version)
+ int rebind (const Name &name,
+ const Object &object);
+
+ /// Update <object> with <name> in <this> context
+ int rebind (const ACE_TString &name,
+ const Object &object);
+
+ /// Find <object> with <name> in <this> context
+ /// (Name version)
+ int resolve (const Name &name,
+ Object &object);
+
+ /// Find <object> with <name> in <this> context
+ int resolve (const ACE_TString &name,
+ Object &object);
+
+ /// Delete object with <name> in <this> context
+ /// (Name version)
+ int unbind (const Name &name);
+
+ /// Delete object with <name> in <this> context
+ int unbind (const ACE_TString &name);
+
+
+ // The following interfaces are for Naming Context
+
+ /// Create new <naming_context>
+ int new_context (Naming_Context &naming_context);
+
+ /**
+ * Insert <naming_context> with <name> relative to <this> context
+ * This will fail if <name> already exists
+ * (Name version)
+ */
+ int bind_new_context (const Name &name,
+ Naming_Context &naming_context,
+ u_long persistence = REG_OPTION_NON_VOLATILE,
+ u_long security_access = KEY_ALL_ACCESS,
+ LPSECURITY_ATTRIBUTES security_attributes = 0);
+
+ /// Insert <naming_context> with <name> relative to <this> context
+ /// This will fail if <name> already exists
+ int bind_new_context (const ACE_TString &name,
+ Naming_Context &naming_context,
+ u_long persistence = REG_OPTION_NON_VOLATILE,
+ u_long security_access = KEY_ALL_ACCESS,
+ LPSECURITY_ATTRIBUTES security_attributes = 0);
+
+ /**
+ * Insert or update <naming_context> with <name> relative to <this> context
+ * This will not fail if <name> already exists
+ * (Name version)
+ */
+ int bind_context (const Name &name,
+ /* const */ Naming_Context &naming_context,
+ u_long persistence = REG_OPTION_NON_VOLATILE,
+ u_long security_access = KEY_ALL_ACCESS,
+ LPSECURITY_ATTRIBUTES security_attributes = 0);
+
+ /// Insert or update <naming_context> with <name> relative to <this> context
+ /// This will not fail if <name> already exists
+ int bind_context (const ACE_TString &name,
+ /* const */ Naming_Context &naming_context,
+ u_long persistence = REG_OPTION_NON_VOLATILE,
+ u_long security_access = KEY_ALL_ACCESS,
+ LPSECURITY_ATTRIBUTES security_attributes = 0);
+
+ /// Rename <naming_context> to <name>
+ /// (Name version)
+ int rebind_context (const Name &name,
+ /* const */ Naming_Context &naming_context);
+
+ /// Rename <naming_context> to <name>
+ int rebind_context (const ACE_TString &name,
+ /* const */ Naming_Context &naming_context);
+
+ /// Find <naming_context> with <name> in <this> context
+ /// (Name version)
+ int resolve_context (const Name &name,
+ Naming_Context &naming_context,
+ u_long security_access = KEY_ALL_ACCESS);
+
+ /// Find <naming_context> with <name> in <this> context
+ int resolve_context (const ACE_TString &name,
+ Naming_Context &naming_context,
+ u_long security_access = KEY_ALL_ACCESS);
+
+ /// Remove naming_context with <name> from <this> context
+ /// (Name version)
+ int unbind_context (const Name &name);
+
+ /// Remove naming_context with <name> from <this> context
+ int unbind_context (const ACE_TString &name);
+
+ /// Same as <unbind_context> with <this> as naming_context
+ int destroy (void);
+
+ /**
+ * listing function: iterator creator
+ * This is useful when there are many objects and contexts
+ * in <this> context and you only want to look at a few entries
+ * at a time
+ */
+ int list (u_long how_many,
+ Binding_List &list,
+ Binding_Iterator &iterator);
+
+ /// listing function: iterator creator
+ /// This gives back a listing of all entries in <this> context.
+ int list (Binding_List &list);
+
+
+ // Some other necessary functions which are
+ // not part of the CORBA interface
+
+ /// Sync content of context to disk
+ int flush (void);
+
+ /// Close the handle of the context
+ /// Note: <close> does not call <flush>
+ int close (void);
+
+
+ // Accessors
+
+ /// Get key
+ HKEY key (void);
+
+ // void parent (HKEY parent);
+ /// Get parent
+ HKEY parent (void);
+
+ /// Get name
+ /// (Name version)
+ void name (Name &name);
+
+ /// Get name
+ /// (String version)
+ void name (ACE_TString &name);
+ ACE_TString name (void);
+
+ protected:
+ /// Set key
+ void key (HKEY key);
+
+ /// Set parent
+ void parent (HKEY parent);
+
+ /// Set name
+ /// (Name version)
+ void name (const Name &name);
+
+ /// Set name
+ /// (String version)
+ void name (const ACE_TString &name);
+
+ private:
+ /// Disallow copy constructors
+ Naming_Context (const Naming_Context &rhs);
+
+ /// Disallow assignment
+ const Naming_Context &operator= (const Naming_Context &rhs);
+
+ /// Key for self
+ HKEY key_;
+
+ /// Key for parent
+ HKEY parent_key_;
+
+ /// Name of self
+ ACE_TString name_;
+ };
+
+ /**
+ * @class Binding_Iterator
+ *
+ * @brief An iterator
+ *
+ * Useful when iteratorating over a few entries at a time
+ */
+ class ACE_Export Binding_Iterator
+ {
+ public:
+ /// Friend factory
+ friend class Naming_Context;
+
+ /// Default constructor
+ Binding_Iterator (void);
+
+ /// Next entry
+ int next_one (Binding &binding);
+
+ /// Next <how_many> entries
+ int next_n (u_long how_many,
+ Binding_List &list);
+
+ /// Cleanup
+ int destroy (void);
+
+ /// Reset the internal state of the iterator
+ void reset (void);
+
+ /// Get naming_context that the iterator is iterating over
+ Naming_Context &naming_context (void);
+
+ private:
+
+ /// Set naming_context that the iterator is iterating over
+ void naming_context (Naming_Context& naming_context);
+
+ /// Reference to context
+ Naming_Context *naming_context_;
+
+ public:
+ // This should really be private
+ // But the compiler is broken
+
+/**
+ * @class Iteration_State
+ Base class for state
+ */
+ class ACE_Export Iteration_State
+ {
+ public:
+ Iteration_State (Binding_Iterator &iterator);
+
+ /// Next <how_many> entries
+ virtual int next_n (u_long how_many,
+ Binding_List &list) = 0;
+
+ /// Reset state
+ void reset (void);
+
+ protected:
+ /// Pointer to parent iterator
+ Binding_Iterator *parent_;
+
+ u_long index_;
+ };
+
+ private:
+ class ACE_Export Object_Iteration : public Iteration_State
+ {
+ public:
+ Object_Iteration (Binding_Iterator &iterator);
+
+ /// Next <how_many> entries
+ int next_n (u_long how_many,
+ Binding_List &list);
+ };
+
+ class ACE_Export Context_Iteration : public Iteration_State
+ {
+ public:
+ Context_Iteration (Binding_Iterator &iterator);
+
+ /// Next <how_many> entries
+ int next_n (u_long how_many,
+ Binding_List &list);
+ };
+
+ class ACE_Export Iteration_Complete : public Iteration_State
+ {
+ public:
+ Iteration_Complete (Binding_Iterator &iterator);
+
+ /// Next <how_many> entries
+ int next_n (u_long how_many,
+ Binding_List &list);
+ };
+
+ /// Friend states
+ friend class Iteration_State;
+ friend class Object_Iteration;
+ friend class Context_Iteration;
+ friend class Iteration_Complete;
+
+ /// Instances of all states
+ Object_Iteration object_iteration_;
+ Context_Iteration context_iteration_;
+ Iteration_Complete iteration_complete_;
+
+ /// Pointer to current state
+ Iteration_State *current_enumeration_;
+
+ /// Set/Get current_enumeration
+ void current_enumeration (Iteration_State& current_enumeration);
+ Iteration_State &current_enumeration (void);
+ };
+};
+
+/**
+ * @class ACE_Predefined_Naming_Contexts
+ *
+ * @brief A factory for predefined registries, which exist by default
+ * on Win32 platforms
+ *
+ * This factory can connect to both local and remote
+ * predefined registries.
+ */
+class ACE_Export ACE_Predefined_Naming_Contexts
+{
+public:
+ /**
+ * Factory method for connecting to predefined registries. This
+ * method works for both remote and local machines. However, for
+ * remote machines, HKEY_CLASSES_ROOT and HKEY_CURRENT_USER types
+ * are not allowed
+ */
+ static int connect (ACE_Registry::Naming_Context &naming_context,
+ HKEY predefined = HKEY_LOCAL_MACHINE,
+ const ACE_TCHAR *machine_name = 0);
+
+private:
+ /// Check if <machine_name> is the local host
+ static int is_local_host (const ACE_TCHAR *machine_name);
+};
+
+// Fix me! Shouldn't have to define this stuff
+
+#if defined (ACE_HAS_BROKEN_NESTED_TEMPLATES)
+ typedef ACE_Registry::Name_Component Name_Component;
+ typedef ACE_Registry::Binding Binding;
+#endif /* ACE_HAS_BROKEN_NESTED_TEMPLATES */
+
+#endif /* ACE_WIN32 */
+#include "ace/post.h"
+#endif /* ACE_REGISTRY_H */
diff --git a/ace/Utils/SString.cpp b/ace/Utils/SString.cpp
new file mode 100644
index 00000000000..770f5704ab2
--- /dev/null
+++ b/ace/Utils/SString.cpp
@@ -0,0 +1,549 @@
+// $Id$
+
+#include "ace/Malloc.h"
+#if !defined (ACE_HAS_WINCE)
+# include "ace/Service_Config.h"
+#endif /* !ACE_HAS_WINCE */
+#include "ace/SString.h"
+#include "ace/Auto_Ptr.h"
+
+#if !defined (ACE_LACKS_IOSTREAM_TOTALLY)
+# include "ace/streams.h"
+#endif /* ! ACE_LACKS_IOSTREAM_TOTALLY */
+
+#if !defined (__ACE_INLINE__)
+#include "ace/SString.i"
+#endif /* __ACE_INLINE__ */
+
+ACE_RCSID(ace, SString, "SString.cpp,v 4.61 2001/03/04 00:55:30 brunsch Exp")
+
+ACE_Tokenizer::ACE_Tokenizer (ACE_TCHAR *buffer)
+ : buffer_ (buffer),
+ index_ (0),
+ preserves_index_ (0),
+ delimiter_index_ (0)
+{
+}
+
+int
+ACE_Tokenizer::delimiter (ACE_TCHAR d)
+{
+ if (delimiter_index_ == MAX_DELIMITERS)
+ return -1;
+
+ delimiters_[delimiter_index_].delimiter_ = d;
+ delimiters_[delimiter_index_].replace_ = 0;
+ delimiter_index_++;
+ return 0;
+}
+
+int
+ACE_Tokenizer::delimiter_replace (ACE_TCHAR d,
+ ACE_TCHAR replacement)
+{
+ // Make it possible to replace delimiters on-the-fly, e.g., parse
+ // string until certain token count and then copy rest of the
+ // original string.
+ for (int i = 0; i < delimiter_index_; i++)
+ if (delimiters_[i].delimiter_ == d)
+ {
+ delimiters_[i].replacement_ = replacement;
+ delimiters_[i].replace_ = 1;
+ return 0;
+ }
+
+ if (delimiter_index_ >= MAX_DELIMITERS)
+ return -1;
+
+ delimiters_[delimiter_index_].delimiter_ = d;
+ delimiters_[delimiter_index_].replacement_ = replacement;
+ delimiters_[delimiter_index_].replace_ = 1;
+ delimiter_index_++;
+ return 0;
+}
+
+int
+ACE_Tokenizer::preserve_designators (ACE_TCHAR start,
+ ACE_TCHAR stop,
+ int strip)
+{
+ if (preserves_index_ == MAX_PRESERVES)
+ return -1;
+
+ preserves_[preserves_index_].start_ = start;
+ preserves_[preserves_index_].stop_ = stop;
+ preserves_[preserves_index_].strip_ = strip;
+ preserves_index_++;
+ return 0;
+}
+
+int
+ACE_Tokenizer::is_delimiter (ACE_TCHAR d,
+ int &replace,
+ ACE_TCHAR &r)
+{
+ replace = 0;
+
+ for (int x = 0; x < delimiter_index_; x++)
+ if (delimiters_[x].delimiter_ == d)
+ {
+ if (delimiters_[x].replace_)
+ {
+ r = delimiters_[x].replacement_;
+ replace = 1;
+ }
+ return 1;
+ }
+
+ return 0;
+}
+
+int
+ACE_Tokenizer::is_preserve_designator (ACE_TCHAR start,
+ ACE_TCHAR &stop,
+ int &strip)
+{
+ for (int x = 0; x < preserves_index_; x++)
+ if (preserves_[x].start_ == start)
+ {
+ stop = preserves_[x].stop_;
+ strip = preserves_[x].strip_;
+ return 1;
+ }
+
+ return 0;
+}
+
+ACE_TCHAR *
+ACE_Tokenizer::next (void)
+{
+ // Check if the previous pass was the last one in the buffer.
+ if (index_ == -1)
+ {
+ index_ = 0;
+ return 0;
+ }
+
+ ACE_TCHAR replacement;
+ int replace;
+ ACE_TCHAR *next_token;
+
+ // Skip all leading delimiters.
+ for (;;)
+ {
+ // Check for end of string.
+ if (buffer_[index_] == '\0')
+ {
+ // If we hit EOS at the start, return 0.
+ index_ = 0;
+ return 0;
+ }
+
+ if (this->is_delimiter (buffer_[index_],
+ replace,
+ replacement))
+ index_++;
+ else
+ break;
+ }
+
+ // When we reach this point, buffer_[index_] is a non-delimiter and
+ // not EOS - the start of our next_token.
+ next_token = buffer_ + index_;
+
+ // A preserved region is it's own token.
+ ACE_TCHAR stop;
+ int strip;
+ if (this->is_preserve_designator (buffer_[index_],
+ stop,
+ strip))
+ {
+ while (++index_)
+ {
+ if (buffer_[index_] == '\0')
+ {
+ index_ = -1;
+ goto EXIT_LABEL;
+ }
+
+ if (buffer_[index_] == stop)
+ break;
+ }
+
+ if (strip)
+ {
+ // Skip start preserve designator.
+ next_token += 1;
+ // Zap the stop preserve designator.
+ buffer_[index_] = '\0';
+ // Increment to the next token.
+ index_++;
+ }
+
+ goto EXIT_LABEL;
+ }
+
+ // Step through finding the next delimiter or EOS.
+ for (;;)
+ {
+ // Advance pointer.
+ index_++;
+
+ // Check for delimiter.
+ if (this->is_delimiter (buffer_[index_],
+ replace,
+ replacement))
+ {
+ // Replace the delimiter.
+ if (replace != 0)
+ buffer_[index_] = replacement;
+
+ // Move the pointer up and return.
+ index_++;
+ goto EXIT_LABEL;
+ }
+
+ // A preserve designator signifies the end of this token.
+ if (this->is_preserve_designator (buffer_[index_],
+ stop,
+ strip))
+ goto EXIT_LABEL;
+
+ // Check for end of string.
+ if (buffer_[index_] == '\0')
+ {
+ index_ = -1;
+ goto EXIT_LABEL;
+ }
+ }
+
+EXIT_LABEL:
+ return next_token;
+}
+
+// ************************************************************
+
+#if !defined (ACE_LACKS_IOSTREAM_TOTALLY)
+ACE_OSTREAM_TYPE &
+operator<< (ACE_OSTREAM_TYPE &os, const ACE_CString &cs)
+{
+ if (cs.fast_rep () != 0)
+ os << cs.fast_rep ();
+ return os;
+}
+
+ACE_OSTREAM_TYPE &
+operator<< (ACE_OSTREAM_TYPE &os, const ACE_WString &ws)
+{
+ // @@ Need to figure out how to print the "wide" string
+ // on platforms that don't support "wide" strings.
+#if defined (ACE_HAS_WCHAR)
+ os << ACE_Wide_To_Ascii (ws.fast_rep ()).char_rep ();
+#else
+ ACE_UNUSED_ARG (ws);
+ os << "(*non-printable string*)";
+#endif
+ return os;
+}
+
+ACE_OSTREAM_TYPE &
+operator<< (ACE_OSTREAM_TYPE &os, const ACE_SString &ss)
+{
+ if (ss.fast_rep () != 0)
+ os << ss.fast_rep ();
+ return os;
+}
+#endif /* !ACE_LACKS_IOSTREAM_TOTALLY */
+
+char *
+ACE_NS_WString::char_rep (void) const
+{
+ ACE_TRACE ("ACE_NS_WString::char_rep");
+ if (this->len_ <= 0)
+ return 0;
+ else
+ {
+ char *t;
+
+ ACE_NEW_RETURN (t,
+ char[this->len_ + 1],
+ 0);
+
+ for (size_t i = 0; i < this->len_; i++)
+ // Note that this cast may lose data if wide chars are
+ // actually used!
+ t[i] = char (this->rep_[i]);
+
+ t[this->len_] = '\0';
+ return t;
+ }
+}
+
+ACE_USHORT16 *
+ACE_NS_WString::ushort_rep (void) const
+{
+ ACE_TRACE ("ACE_NS_WString::ushort_rep");
+ if (this->len_ <= 0)
+ return 0;
+ else
+ {
+ ACE_USHORT16 *t;
+
+ ACE_NEW_RETURN (t,
+ ACE_USHORT16[this->len_ + 1],
+ 0);
+
+ for (size_t i = 0; i < this->len_; i++)
+ // Note that this cast may lose data if wide chars are
+ // actually used!
+ t[i] = (ACE_USHORT16)this->rep_[i];
+
+ t[this->len_] = 0;
+ return t;
+ }
+}
+
+const int ACE_SString::npos = -1;
+
+ACE_ALLOC_HOOK_DEFINE(ACE_SString)
+
+ACE_NS_WString::ACE_NS_WString (const char *s,
+ ACE_Allocator *alloc)
+ : ACE_WString (alloc)
+{
+ if (s == 0)
+ return;
+
+ this->len_ = this->buf_len_ = ACE_OS_String::strlen (s);
+
+ if (this->buf_len_ == 0)
+ return;
+
+ ACE_ALLOCATOR (this->rep_,
+ (ACE_WSTRING_TYPE *)
+ this->allocator_->malloc ((this->buf_len_ + 1) *
+ sizeof (ACE_WSTRING_TYPE)));
+ this->release_ = 1;
+ for (size_t i = 0; i <= this->buf_len_; i++)
+ this->rep_[i] = s[i];
+}
+
+#if defined (ACE_WSTRING_HAS_USHORT_SUPPORT)
+ACE_NS_WString::ACE_NS_WString (const ACE_USHORT16 *s,
+ size_t len,
+ ACE_Allocator *alloc)
+ : ACE_WString (alloc)
+{
+ if (s == 0)
+ return;
+
+ this->buf_len_ = len;
+
+ if (this->buf_len_ == 0)
+ return;
+
+ ACE_ALLOCATOR (this->rep_,
+ (ACE_WSTRING_TYPE *)
+ this->allocator_->malloc ((this->buf_len_) *
+ sizeof (ACE_WSTRING_TYPE)));
+ this->release_ = 1;
+ for (size_t i = 0; i <= this->buf_len_; i++)
+ this->rep_[i] = s[i];
+}
+#endif /* ACE_WSTRING_HAS_USHORT_SUPPORT */
+
+void
+ACE_SString::dump (void) const
+{
+ ACE_TRACE ("ACE_SString::dump");
+}
+
+// Copy constructor.
+
+ACE_SString::ACE_SString (const ACE_SString &s)
+ : allocator_ (s.allocator_),
+ len_ (s.len_)
+{
+ ACE_TRACE ("ACE_SString::ACE_SString");
+
+ if (this->allocator_ == 0)
+ this->allocator_ = ACE_Allocator::instance ();
+
+ this->rep_ = (char *) this->allocator_->malloc (s.len_ + 1);
+ ACE_OS::memcpy ((void *) this->rep_,
+ (const void *) s.rep_,
+ this->len_);
+ this->rep_[this->len_] = '\0';
+}
+
+// Default constructor.
+
+ACE_SString::ACE_SString (ACE_Allocator *alloc)
+ : allocator_ (alloc),
+ len_ (0),
+ rep_ (0)
+
+{
+ ACE_TRACE ("ACE_SString::ACE_SString");
+
+ if (this->allocator_ == 0)
+ this->allocator_ = ACE_Allocator::instance ();
+
+ this->len_ = 0;
+ this->rep_ = (char *) this->allocator_->malloc (this->len_ + 1);
+ this->rep_[this->len_] = '\0';
+}
+
+// Set the underlying pointer (does not copy memory).
+
+void
+ACE_SString::rep (char *s)
+{
+ ACE_TRACE ("ACE_SString::rep");
+
+ this->rep_ = s;
+
+ if (s == 0)
+ this->len_ = 0;
+ else
+ this->len_ = ACE_OS::strlen (s);
+}
+
+// Constructor that actually copies memory.
+
+ACE_SString::ACE_SString (const char *s,
+ ACE_Allocator *alloc)
+ : allocator_ (alloc)
+{
+ ACE_TRACE ("ACE_SString::ACE_SString");
+
+ if (this->allocator_ == 0)
+ this->allocator_ = ACE_Allocator::instance ();
+
+ if (s == 0)
+ {
+ this->len_ = 0;
+ this->rep_ = (char *) this->allocator_->malloc (this->len_ + 1);
+ this->rep_[this->len_] = '\0';
+ }
+ else
+ {
+ this->len_ = ACE_OS::strlen (s);
+ this->rep_ = (char *) this->allocator_->malloc (this->len_ + 1);
+ ACE_OS::strcpy (this->rep_, s);
+ }
+}
+
+ACE_SString::ACE_SString (char c,
+ ACE_Allocator *alloc)
+ : allocator_ (alloc)
+{
+ ACE_TRACE ("ACE_SString::ACE_SString");
+
+ if (this->allocator_ == 0)
+ this->allocator_ = ACE_Allocator::instance ();
+
+ this->len_ = 1;
+ this->rep_ = (char *) this->allocator_->malloc (this->len_ + 1);
+ this->rep_[0] = c;
+ this->rep_[this->len_] = '\0';
+}
+
+// Constructor that actually copies memory.
+
+ACE_SString::ACE_SString (const char *s,
+ size_t len,
+ ACE_Allocator *alloc)
+ : allocator_ (alloc)
+{
+ ACE_TRACE ("ACE_SString::ACE_SString");
+
+ if (this->allocator_ == 0)
+ this->allocator_ = ACE_Allocator::instance ();
+
+ if (s == 0)
+ {
+ this->len_ = 0;
+ this->rep_ = (char *) this->allocator_->malloc (this->len_ + 1);
+ this->rep_[this->len_] = '\0';
+ }
+ else
+ {
+ this->len_ = len;
+ this->rep_ = (char *) this->allocator_->malloc (this->len_ + 1);
+ ACE_OS::memcpy (this->rep_, s, len);
+ this->rep_[len] = '\0'; // Make sure to NUL terminate this!
+ }
+}
+
+// Assignment operator (does copy memory).
+
+ACE_SString &
+ACE_SString::operator= (const ACE_SString &s)
+{
+ ACE_TRACE ("ACE_SString::operator=");
+ // Check for identify.
+
+ if (this != &s)
+ {
+ // Only reallocate if we don't have enough space...
+ if (this->len_ < s.len_)
+ {
+ this->allocator_->free (this->rep_);
+ this->rep_ = (char *) this->allocator_->malloc (s.len_ + 1);
+ }
+ this->len_ = s.len_;
+ ACE_OS::strcpy (this->rep_, s.rep_);
+ }
+
+ return *this;
+}
+
+// Return substring.
+ACE_SString
+ACE_SString::substring (size_t offset,
+ ssize_t length) const
+{
+ ACE_SString nil;
+ size_t count = length;
+
+ // case 1. empty string
+ if (len_ == 0)
+ return nil;
+
+ // case 2. start pos l
+ if (offset >= len_)
+ return nil;
+
+ // get all remaining bytes
+ if (length == -1)
+ count = len_ - offset;
+
+ return ACE_SString (&rep_[offset], count, this->allocator_);
+}
+
+#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION)
+template class ACE_String_Base<char>;
+template ACE_String_Base<char> operator + (const ACE_String_Base<char> &,
+ const ACE_String_Base<char> &);
+template ACE_String_Base<char> operator + (const ACE_String_Base<char> &,
+ const char *);
+template ACE_String_Base<char> operator + (const char *,
+ const ACE_String_Base<char> &);
+template class ACE_String_Base<ACE_WSTRING_TYPE>;
+template ACE_String_Base<ACE_WSTRING_TYPE> operator + (const ACE_String_Base<ACE_WSTRING_TYPE> &,
+ const ACE_String_Base<ACE_WSTRING_TYPE> &);
+template ACE_String_Base<ACE_WSTRING_TYPE> operator + (const ACE_String_Base<ACE_WSTRING_TYPE> &,
+ const ACE_WSTRING_TYPE *);
+template ACE_String_Base<ACE_WSTRING_TYPE> operator + (const ACE_WSTRING_TYPE *,
+ const ACE_String_Base<ACE_WSTRING_TYPE> &);
+#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA)
+#pragma instantiate ACE_String_Base<char>
+#pragma instantiate ACE_String_Base<char> operator + (const ACE_String_Base<char> &, const ACE_String_Base<char> &)
+#pragma instantiate ACE_String_Base<char> operator + (const ACE_String_Base<char> &, const char *)
+#pragma instantiate ACE_String_Base<char> operator + (const char *,ACE_String_Base<char> &)
+#pragma instantiate ACE_String_Base<ACE_WSTRING_TYPE>
+#pragma instantiate ACE_String_Base<ACE_WSTRING_TYPE> operator + (const ACE_String_Base<ACE_WSTRING_TYPE> &, const ACE_String_Base<ACE_WSTRING_TYPE> &)
+#pragma instantiate ACE_String_Base<ACE_WSTRING_TYPE> operator + (const ACE_String_Base<ACE_WSTRING_TYPE> &, const ACE_WSTRING_TYPE *)
+#pragma instantiate ACE_String_Base<ACE_WSTRING_TYPE> operator + (const ACE_WSTRING_TYPE *,ACE_String_Base<ACE_WSTRING_TYPE> &)
+#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */
diff --git a/ace/Utils/SString.h b/ace/Utils/SString.h
new file mode 100644
index 00000000000..ead805a494f
--- /dev/null
+++ b/ace/Utils/SString.h
@@ -0,0 +1,479 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file SString.h
+ *
+ * $Id$
+ *
+ * @author Douglas C. Schmidt (schmidt@cs.wustl.edu)
+ */
+//=============================================================================
+
+#ifndef ACE_SSTRING_H
+#define ACE_SSTRING_H
+#include "ace/pre.h"
+
+#include "ace/String_Base.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+typedef ACE_WCHAR_T ACE_WSTRING_TYPE;
+
+#if !defined (ACE_DEFAULT_GROWSIZE)
+#define ACE_DEFAULT_GROWSIZE 32
+#endif /* ACE_DEFAULT_GROWSIZE */
+
+typedef ACE_String_Base<char> ACE_CString;
+
+typedef ACE_String_Base<ACE_WSTRING_TYPE> ACE_WString;
+
+#if !defined (ACE_LACKS_IOSTREAM_TOTALLY)
+ACE_Export ACE_OSTREAM_TYPE &operator << (ACE_OSTREAM_TYPE &, const ACE_CString &);
+ACE_Export ACE_OSTREAM_TYPE &operator << (ACE_OSTREAM_TYPE &, const ACE_WString &);
+#endif /* ! ACE_LACKS_IOSTREAM_TOTALLY */
+
+/**
+ * @brief This class retain the backward compatibility for
+ * Naming_Conext and related classes. The only addition to
+ * ACE_WString is a very naive "wchar" to "char" conversion function.
+ */
+class ACE_Export ACE_NS_WString : public ACE_WString
+{
+public:
+ /// Default constructor.
+ ACE_NS_WString (ACE_Allocator *alloc = 0);
+
+ /// Constructor that copies <s> into dynamically allocated memory.
+ ACE_NS_WString (const char *s,
+ ACE_Allocator *alloc = 0);
+
+ /// Constructor that copies <s> into dynamically allocated memory.
+ ACE_NS_WString (const ACE_WSTRING_TYPE *s,
+ ACE_Allocator *alloc = 0);
+
+#if defined (ACE_WSTRING_HAS_USHORT_SUPPORT)
+ /// Constructor that takes in a ushort16 string (mainly used by the
+ /// ACE Name_Space classes)
+ ACE_NS_WString (const ACE_USHORT16 *s,
+ size_t len,
+ ACE_Allocator *alloc = 0);
+#endif /* ACE_WSTRING_HAS_USHORT_SUPPORT */
+
+ /// Constructor that copies <len> ACE_WSTRING_TYPE's of <s> into dynamically
+ /// allocated memory (will NUL terminate the result).
+ ACE_NS_WString (const ACE_WSTRING_TYPE *s,
+ size_t len,
+ ACE_Allocator *alloc = 0);
+
+ /// Constructor that dynamically allocates memory for <len> + 1
+ /// ACE_WSTRING_TYPE characters. The newly created memory is set memset to 0.
+ ACE_NS_WString (size_t len, ACE_Allocator *alloc = 0);
+
+ /// Copy constructor.
+ ACE_NS_WString (const ACE_NS_WString &s);
+
+ /// Constructor that copies <c> into dynamically allocated memory.
+ ACE_NS_WString (ACE_WSTRING_TYPE c, ACE_Allocator *alloc = 0);
+
+ /// Transform into a copy of the ASCII character representation.
+ /// (caller must delete)
+ char *char_rep (void) const;
+
+ /// Transform into a copy of a USHORT16 representation (caller must
+ /// delete). Note, behavior is undefined when sizeof (wchar_t) != 2.
+ ACE_USHORT16 *ushort_rep (void) const;
+};
+
+ACE_Export ACE_INLINE
+ACE_NS_WString operator + (const ACE_NS_WString &,
+ const ACE_NS_WString &);
+/**
+ * @class ACE_SString
+ *
+ * @brief A very Simple String <ACE_SString> class. This is not a
+ * general-purpose string class, and you should probably consider
+ * using <ACE_CString> is you don't understand why this class
+ * exists...
+ *
+ * This class is optimized for efficiency, so it doesn't provide
+ * any internal locking.
+ * CAUTION: This class is only intended for use with applications
+ * that understand how it works. In particular, its destructor
+ * does not deallocate its memory when it is destroyed... We need
+ * this class since the <ACE_Map_Manager> requires an object that
+ * supports the operator == and operator !=. This class uses an
+ * <ACE_Allocator> to allocate memory. The user can make this a
+ * persistant class by providing an <ACE_Allocator> with a
+ * persistable memory pool.
+ */
+class ACE_Export ACE_SString
+{
+public:
+ /// No position constant
+ static const int npos;
+
+ /// Default constructor.
+ ACE_SString (ACE_Allocator *alloc = 0);
+
+ /// Constructor that copies <s> into dynamically allocated memory.
+ ACE_SString (const char *s, ACE_Allocator *alloc = 0);
+
+ /// Constructor that copies <len> chars of <s> into dynamically
+ /// allocated memory (will NUL terminate the result).
+ ACE_SString (const char *s, size_t len, ACE_Allocator *alloc = 0);
+
+ /// Copy constructor.
+ ACE_SString (const ACE_SString &);
+
+ /// Constructor that copies <c> into dynamically allocated memory.
+ ACE_SString (char c, ACE_Allocator *alloc = 0);
+
+ /// Default dtor.
+ ~ACE_SString (void);
+
+ /// Return the <slot'th> character in the string (doesn't perform
+ /// bounds checking).
+ char operator [] (size_t slot) const;
+
+ /// Return the <slot'th> character by reference in the string
+ /// (doesn't perform bounds checking).
+ char &operator [] (size_t slot);
+
+ /// Assignment operator (does copy memory).
+ ACE_SString &operator = (const ACE_SString &);
+
+ /**
+ * Return a substring given an offset and length, if length == -1
+ * use rest of str return empty substring if offset or offset/length
+ * are invalid
+ */
+ ACE_SString substring (size_t offset, ssize_t length = -1) const;
+
+ /// Same as substring
+ ACE_SString substr (size_t offset, ssize_t length = -1) const;
+
+ /// Returns a hash value for this string.
+ u_long hash (void) const;
+
+ /// Return the length of the string.
+ size_t length (void) const;
+
+ /// Set the underlying pointer. Since this does not copy memory or
+ /// delete existing memory use with extreme caution!!!
+ void rep (char *s);
+
+ /// Get the underlying pointer.
+ const char *rep (void) const;
+
+ /// Get the underlying pointer.
+ const char *fast_rep (void) const;
+
+ /// Same as STL String's <c_str> and <fast_rep>.
+ const char *c_str (void) const;
+
+ /// Comparison operator that will match substrings. Returns the
+ /// slot of the first location that matches, else -1.
+ int strstr (const ACE_SString &s) const;
+
+ /// Find <str> starting at pos. Returns the slot of the first
+ /// location that matches (will be >= pos), else npos.
+ int find (const ACE_SString &str, int pos = 0) const;
+
+ /// Find <s> starting at pos. Returns the slot of the first
+ /// location that matches (will be >= pos), else npos.
+ int find (const char *s, int pos = 0) const;
+
+ /// Find <c> starting at pos. Returns the slot of the first
+ /// location that matches (will be >= pos), else npos.
+ int find (char c, int pos = 0) const;
+
+ /// Find <c> starting at pos (counting from the end). Returns the
+ /// slot of the first location that matches, else npos.
+ int rfind (char c, int pos = npos) const;
+
+ /// Equality comparison operator (must match entire string).
+ int operator == (const ACE_SString &s) const;
+
+ /// Less than comparison operator.
+ int operator < (const ACE_SString &s) const;
+
+ /// Greater than comparison operator.
+ int operator > (const ACE_SString &s) const;
+
+ /// Inequality comparison operator.
+ int operator != (const ACE_SString &s) const;
+
+ /// Performs a <strcmp>-style comparison.
+ int compare (const ACE_SString &s) const;
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+private:
+ /// Pointer to a memory allocator.
+ ACE_Allocator *allocator_;
+
+ /// Length of the ACE_SString (not counting the trailing '\0').
+ size_t len_;
+
+ /// Pointer to data.
+ char *rep_;
+};
+
+#if !defined (ACE_LACKS_IOSTREAM_TOTALLY)
+ACE_Export ACE_OSTREAM_TYPE &operator << (ACE_OSTREAM_TYPE &, const ACE_SString &);
+#endif /* ! ACE_LACKS_IOSTREAM_TOTALLY */
+
+// This allows one to use W or C String based on the Unicode
+// setting
+#if defined (ACE_USES_WCHAR)
+typedef ACE_WString ACE_TString;
+#else /* ACE_USES_WCHAR */
+typedef ACE_CString ACE_TString;
+#endif /* ACE_USES_WCHAR */
+
+
+// ************************************************************
+
+/**
+ * @class ACE_Tokenizer
+ *
+ * @brief Tokenizer
+ *
+ * Tokenizes a buffer. Allows application to set delimiters and
+ * preserve designators. Does not allow special characters, yet
+ * (e.g., printf ("\"like a quoted string\"")).
+ */
+class ACE_Export ACE_Tokenizer
+{
+public:
+ /**
+ * \a buffer will be parsed. Notice that ACE_Tokenizer will modify
+ * \a buffer if you use <code> delimiter_replace </code> or <code>
+ * preserve_designators </code> to do character substitution.
+ * NOTE: You should NOT pass a constant string or string literal
+ * to this constructor, since ACE_Tokenizer will try to modify
+ * the string.
+ * \sa preserve_designators
+ * \sa preserve_designators
+ */
+ ACE_Tokenizer (ACE_TCHAR *buffer);
+
+ /**
+ * \a d is a delimiter.
+ * \return Returns 0 on success, -1 if there is no memory left.
+ *
+ * <B>Example:</B>
+ * \verbatim
+ char buf[30];
+ ACE_OS::strcpy(buf, "William/Joseph/Hagins");
+
+ ACE_Tokenizer tok (buf);
+ tok.delimiter ('/');
+ for (char *p = tok.next (); p; p = tok.next ())
+ cout << p << endl;
+ \endverbatim
+ *
+ * This will print out:
+ * \verbatim
+ William/Joseph/Hagins
+ Joseph/Hagins
+ Hagins \endverbatim
+ */
+ int delimiter (ACE_TCHAR d);
+
+ /**
+ * \a d is a delimiter and, when found, will be replaced by
+ * \a replacement.
+ * \return 0 on success, -1 if there is no memory left.
+ *
+ * <B>Example:</B>
+ * \verbatim
+ char buf[30];
+ ACE_OS::strcpy(buf, "William/Joseph/Hagins");
+
+ ACE_Tokenizer tok (buf);
+ tok.delimiter_replace ('/', 0);
+ for (char *p = tok.next (); p; p = tok.next ())
+ cout << p << endl;
+ \endverbatim
+ *
+ * This will print out:
+ * \verbatim
+ William
+ Joseph
+ Hagins \endverbatim
+ */
+ int delimiter_replace (ACE_TCHAR d, ACE_TCHAR replacement);
+
+ /**
+ * Extract string between a pair of designator characters.
+ * For instance, quotes, or '(' and ')'.
+ * \a start specifies the begin designator.
+ * \a stop specifies the end designator.
+ * \a strip If \a strip == 1, then the preserve
+ * designators will be stripped from the tokens returned by next.
+ * \return 0 on success, -1 if there is no memory left.
+ *
+ * <B>Example with strip = 0:</B>
+ * \verbatim
+ char buf[30];
+ ACE_OS::strcpy(buf, "William(Joseph)Hagins");
+
+ ACE_Tokenizer tok (buf);
+ tok.preserve_designators ('(', ')', 0);
+ for (char *p = tok.next (); p; p = tok.next ())
+ cout << p << endl;
+ \endverbatim
+ *
+ * This will print out:
+ * \verbatim
+ William(Joseph)Hagins
+ (Joseph)Hagins
+ )Hagins \endverbatim
+ *
+ * <B>Example with strip = 1:</B>
+ * \verbatim
+ char buf[30];
+ ACE_OS::strcpy(buf, "William(Joseph)Hagins");
+
+ ACE_Tokenizer tok (buf);
+ tok.preserve_designators ('(', ')', 1);
+ for (char *p = tok.next (); p; p = tok.next ())
+ cout << p << endl;
+ \endverbatim
+ *
+ * This will print out:
+ * \verbatim
+ William
+ Joseph
+ Hagins \endverbatim
+ */
+ int preserve_designators (ACE_TCHAR start, ACE_TCHAR stop, int strip=1);
+
+ /// Returns the next token.
+ ACE_TCHAR *next (void);
+
+ enum {
+ MAX_DELIMITERS=16,
+ MAX_PRESERVES=16
+ };
+
+protected:
+ /// Returns 1 if <d> is a delimiter, 0 otherwise. If <d> should be
+ /// replaced with <r>, <replace> is set to 1, otherwise 0.
+ int is_delimiter (ACE_TCHAR d, int &replace, ACE_TCHAR &r);
+
+ /**
+ * If <start> is a start preserve designator, returns 1 and sets
+ * <stop> to the stop designator. Returns 0 if <start> is not a
+ * preserve designator.
+ */
+ int is_preserve_designator (ACE_TCHAR start, ACE_TCHAR &stop, int &strip);
+
+ ACE_TCHAR *buffer_;
+ int index_;
+
+ /**
+ * @class Preserve_Entry
+ *
+ * @brief Preserve Entry
+ *
+ * Defines a set of characters that designate an area that
+ * should not be parsed, but should be treated as a complete
+ * token. For instance, in: (this is a preserve region), start
+ * would be a left paren -(- and stop would be a right paren
+ * -)-. The strip determines whether the designators should be
+ * removed from the token.
+ */
+ class Preserve_Entry
+ {
+ public:
+ /**
+ * E.g., "(".
+ * E.g., ")".
+ * Whether the designators should be removed from the token.
+ */
+ ACE_TCHAR start_;
+ ACE_TCHAR stop_;
+ int strip_;
+ };
+
+ /// The application can specify MAX_PRESERVES preserve designators.
+ Preserve_Entry preserves_[MAX_PRESERVES];
+
+ /// Pointer to the next free spot in preserves_.
+ int preserves_index_;
+
+ /**
+ * @class Delimiter_Entry
+ *
+ * @brief Delimiter Entry
+ *
+ * Describes a delimiter for the tokenizer.
+ */
+ class Delimiter_Entry
+ {
+ public:
+ /**
+ * Most commonly a space ' '.
+ * What occurrences of delimiter_ should be replaced with.
+ * Whether replacement_ should be used. This should be replaced
+ * with a technique that sets replacement_ = delimiter by
+ * default. I'll do that next iteration.
+ */
+ ACE_TCHAR delimiter_;
+ ACE_TCHAR replacement_;
+ int replace_;
+ };
+
+ /// The tokenizer allows MAX_DELIMITERS number of delimiters.
+ Delimiter_Entry delimiters_[MAX_DELIMITERS];
+
+ /// Pointer to the next free space in delimiters_.
+ int delimiter_index_;
+};
+
+// ****************************************************************
+
+/**
+ * @class ACE_Auto_String_Free
+ *
+ * @brief Simple class to automatically de-allocate strings
+ *
+ * Keeps a pointer to a string and deallocates it (using
+ * <ACE_OS::free>) on its destructor.
+ * If you need to delete using "delete[]" the
+ * ACE_Auto_Array_Ptr<char*> is your choice.
+ * The class plays the same role as auto_ptr<>
+ */
+class ACE_Export ACE_Auto_String_Free
+{
+public:
+ ACE_EXPLICIT ACE_Auto_String_Free (char* p = 0);
+ ACE_Auto_String_Free (ACE_Auto_String_Free &rhs);
+ ACE_Auto_String_Free& operator= (ACE_Auto_String_Free &rhs);
+ ~ACE_Auto_String_Free (void);
+
+ char* operator* () const;
+ char operator[] (int i) const;
+ char* get (void) const;
+ char* release (void);
+ void reset (char* p = 0);
+
+private:
+ char* p_;
+};
+
+#if defined (__ACE_INLINE__)
+#include "ace/SString.i"
+#endif /* __ACE_INLINE__ */
+
+#include "ace/post.h"
+#endif /* ACE_SSTRING_H */
diff --git a/ace/Utils/SString.i b/ace/Utils/SString.i
new file mode 100644
index 00000000000..247812da5a4
--- /dev/null
+++ b/ace/Utils/SString.i
@@ -0,0 +1,284 @@
+/* -*- C++ -*- */
+// $Id$
+
+#include "ace/Malloc_Base.h"
+
+ACE_INLINE
+ACE_NS_WString::ACE_NS_WString (ACE_Allocator *alloc)
+ : ACE_WString (alloc)
+{
+}
+
+ACE_INLINE
+ACE_NS_WString::ACE_NS_WString (const ACE_WSTRING_TYPE *s,
+ size_t len,
+ ACE_Allocator *alloc)
+ : ACE_WString (s, len, alloc)
+{
+}
+
+ACE_INLINE
+ACE_NS_WString::ACE_NS_WString (const ACE_WSTRING_TYPE *s,
+ ACE_Allocator *alloc)
+ : ACE_WString (s, alloc)
+{
+}
+
+ACE_INLINE
+ACE_NS_WString::ACE_NS_WString (size_t len, ACE_Allocator *alloc)
+ : ACE_WString (len, alloc)
+{
+}
+
+ACE_INLINE
+ACE_NS_WString::ACE_NS_WString (const ACE_NS_WString &s)
+ : ACE_WString (s)
+{
+}
+
+ACE_INLINE
+ACE_NS_WString::ACE_NS_WString (ACE_WSTRING_TYPE c, ACE_Allocator *alloc)
+ : ACE_WString (c, alloc)
+{
+}
+
+ACE_INLINE ACE_NS_WString
+operator+ (const ACE_NS_WString &s, const ACE_NS_WString &t)
+{
+ ACE_NS_WString temp (s);
+ temp += t;
+ return temp;
+}
+
+ACE_INLINE
+ACE_SString::~ACE_SString (void)
+{
+}
+
+ACE_INLINE ACE_SString
+ACE_SString::substr (size_t offset,
+ ssize_t length) const
+{
+ return this->substring (offset, length);
+}
+
+// Return the <slot'th> character in the string.
+
+ACE_INLINE char
+ACE_SString::operator[] (size_t slot) const
+{
+ ACE_TRACE ("ACE_SString::operator[]");
+ return this->rep_[slot];
+}
+
+// Return the <slot'th> character in the string by reference.
+
+ACE_INLINE char &
+ACE_SString::operator[] (size_t slot)
+{
+ ACE_TRACE ("ACE_SString::operator[]");
+ return this->rep_[slot];
+}
+
+// Get the underlying pointer (does not make a copy, so beware!).
+
+ACE_INLINE const char *
+ACE_SString::rep (void) const
+{
+ ACE_TRACE ("ACE_SString::rep");
+ return this->rep_;
+}
+
+// Get the underlying pointer (does not make a copy, so beware!).
+
+ACE_INLINE const char *
+ACE_SString::fast_rep (void) const
+{
+ ACE_TRACE ("ACE_SString::fast_rep");
+ return this->rep_;
+}
+
+// Get the underlying pointer (does not make a copy, so beware!).
+
+ACE_INLINE const char *
+ACE_SString::c_str (void) const
+{
+ ACE_TRACE ("ACE_SString::c_str");
+ return this->rep_;
+}
+
+// Comparison operator.
+
+ACE_INLINE int
+ACE_SString::operator== (const ACE_SString &s) const
+{
+ ACE_TRACE ("ACE_SString::operator==");
+ return this->len_ == s.len_
+ && ACE_OS::strcmp (this->rep_, s.rep_) == 0;
+}
+
+// Less than comparison operator.
+
+ACE_INLINE int
+ACE_SString::operator < (const ACE_SString &s) const
+{
+ ACE_TRACE ("ACE_SString::operator <");
+
+ return (this->rep_ && s.rep_)
+ ? ACE_OS::strcmp (this->rep_, s.rep_) < 0
+ : ((s.rep_) ? 1 : 0 );
+}
+
+// Greater than comparison operator.
+
+ACE_INLINE int
+ACE_SString::operator > (const ACE_SString &s) const
+{
+ ACE_TRACE ("ACE_SString::operator >");
+
+ return (this->rep_ && s.rep_)
+ ? ACE_OS::strcmp (this->rep_, s.rep_) > 0
+ : ((this->rep_) ? 1 : 0 );
+}
+
+// Comparison operator.
+
+ACE_INLINE int
+ACE_SString::operator!= (const ACE_SString &s) const
+{
+ ACE_TRACE ("ACE_SString::operator!=");
+ return !(*this == s);
+}
+
+ACE_INLINE int
+ACE_SString::compare (const ACE_SString &s) const
+{
+ ACE_TRACE ("ACE_SString::compare");
+ return ACE_OS::strcmp (this->rep_, s.rep_);
+}
+
+ACE_INLINE int
+ACE_SString::find (const char *s, int pos) const
+{
+ char *substr = this->rep_ + pos;
+ char *pointer = ACE_OS::strstr (substr, s);
+ if (pointer == 0)
+ return ACE_SString::npos;
+ else
+ return pointer - this->rep_;
+}
+
+ACE_INLINE int
+ACE_SString::find (char c, int pos) const
+{
+ char *substr = this->rep_ + pos;
+ char *pointer = ACE_OS::strchr (substr, c);
+ if (pointer == 0)
+ return ACE_SString::npos;
+ else
+ return pointer - this->rep_;
+}
+
+ACE_INLINE int
+ACE_SString::strstr (const ACE_SString &s) const
+{
+ ACE_TRACE ("ACE_SString::strstr");
+
+ return this->find (s.rep_);
+}
+
+ACE_INLINE int
+ACE_SString::find (const ACE_SString &str, int pos) const
+{
+ return this->find (str.rep_, pos);
+}
+
+ACE_INLINE int
+ACE_SString::rfind (char c, int pos) const
+{
+ if (pos == ACE_SString::npos)
+ pos = this->len_;
+
+ for (int i = pos - 1; i >= 0; i--)
+ if (this->rep_[i] == c)
+ return i;
+
+ return ACE_SString::npos;
+}
+
+ACE_INLINE u_long
+ACE_SString::hash (void) const
+{
+ return ACE::hash_pjw (this->rep_);
+}
+
+ACE_INLINE size_t
+ACE_SString::length (void) const
+{
+ ACE_TRACE ("ACE_SString::length");
+ return this->len_;
+}
+
+ACE_INLINE
+ACE_Auto_String_Free::ACE_Auto_String_Free (char* p)
+ : p_ (p)
+{
+}
+
+ACE_INLINE
+ACE_Auto_String_Free::ACE_Auto_String_Free (ACE_Auto_String_Free& rhs)
+ : p_ (rhs.p_)
+{
+ rhs.p_ = 0;
+}
+
+ACE_INLINE void
+ACE_Auto_String_Free::reset (char* p)
+{
+ if (this->p_ != 0)
+ ACE_OS::free (this->p_);
+ this->p_ = p;
+}
+
+ACE_INLINE ACE_Auto_String_Free&
+ACE_Auto_String_Free::operator= (ACE_Auto_String_Free& rhs)
+{
+ if (this != &rhs)
+ {
+ this->reset (rhs.p_);
+ rhs.p_ = 0;
+ }
+ return *this;
+}
+
+ACE_INLINE
+ACE_Auto_String_Free::~ACE_Auto_String_Free (void)
+{
+ this->reset (0);
+}
+
+ACE_INLINE char*
+ACE_Auto_String_Free::operator* (void) const
+{
+ return this->p_;
+}
+
+ACE_INLINE char
+ACE_Auto_String_Free::operator[] (int i) const
+{
+ return this->p_[i];
+}
+
+ACE_INLINE char*
+ACE_Auto_String_Free::get (void) const
+{
+ return this->p_;
+}
+
+ACE_INLINE char*
+ACE_Auto_String_Free::release (void)
+{
+ char* p = this->p_;
+ this->p_ = 0;
+ return p;
+}
diff --git a/ace/Utils/Sample_History.cpp b/ace/Utils/Sample_History.cpp
new file mode 100644
index 00000000000..f6c08c55afe
--- /dev/null
+++ b/ace/Utils/Sample_History.cpp
@@ -0,0 +1,56 @@
+// $Id$
+
+#include "ace/Sample_History.h"
+#include "ace/Basic_Stats.h"
+#include "ace/Log_Msg.h"
+
+#if !defined (__ACE_INLINE__)
+#include "ace/Sample_History.inl"
+#endif /* __ACE_INLINE__ */
+
+ACE_RCSID(ace, Sample_History, "$Id$")
+
+ACE_Sample_History::ACE_Sample_History (size_t max_samples)
+ : max_samples_ (max_samples)
+ , sample_count_ (0)
+{
+ ACE_NEW(this->samples_, ACE_UINT64[this->max_samples_]);
+}
+
+ACE_Sample_History::~ACE_Sample_History (void)
+{
+ delete[] this->samples_;
+}
+
+size_t
+ACE_Sample_History::max_samples (void) const
+{
+ return this->max_samples_;
+}
+
+size_t
+ACE_Sample_History::sample_count (void) const
+{
+ return this->sample_count_;
+}
+
+void
+ACE_Sample_History::dump_samples (const ACE_TCHAR *msg,
+ ACE_UINT32 scale_factor) const
+{
+ for (size_t i = 0; i != this->sample_count_; ++i)
+ {
+ ACE_UINT64 x = this->samples_[i] / scale_factor;
+ ACE_UINT32 val = ACE_CU64_TO_CU32 (x);
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT("%s: %d %u\n"), msg, i, val));
+ }
+}
+
+void
+ACE_Sample_History::collect_basic_stats (ACE_Basic_Stats &stats) const
+{
+ for (size_t i = 0; i != this->sample_count_; ++i)
+ {
+ stats.sample (this->samples_[i]);
+ }
+}
diff --git a/ace/Utils/Sample_History.h b/ace/Utils/Sample_History.h
new file mode 100644
index 00000000000..8d5dc913b52
--- /dev/null
+++ b/ace/Utils/Sample_History.h
@@ -0,0 +1,86 @@
+
+//=============================================================================
+/**
+ * @file Sample_History.h
+ *
+ * $Id$
+ *
+ * @author Carlos O'Ryan <coryan@uci.edu>
+ */
+//=============================================================================
+
+
+#ifndef ACE_SAMPLE_HISTORY_H
+#define ACE_SAMPLE_HISTORY_H
+#include "ace/pre.h"
+
+#include "ace/config-all.h"
+#include "ace/Basic_Types.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+class ACE_Basic_Stats;
+
+/// Save multiple samples in an array
+/**
+ * Save multiple samples (usually latency numbers), into an array, and
+ * later print them in several formats.
+ */
+class ACE_Export ACE_Sample_History
+{
+public:
+ /// Constructor
+ /**
+ * The number of samples is pre-allocated, and cannot changes once
+ * the class is initialized.
+ */
+ ACE_Sample_History (size_t max_samples);
+
+ /// Destructor
+ ~ACE_Sample_History (void);
+
+ /// Record one sample.
+ /**
+ * Return 0 on success, -1 if the sample could not be stored
+ */
+ int sample (ACE_UINT64 value);
+
+ /// Returns the maximum number of samples
+ size_t max_samples (void) const;
+
+ /// Returns the current number of samples
+ size_t sample_count (void) const;
+
+ /// Dump all the samples
+ /**
+ * Prints out all the samples, using @param msg as a prefix for each
+ * message.
+ */
+ void dump_samples (const ACE_TCHAR *msg,
+ ACE_UINT32 scale_factor) const;
+
+ /// Collect the summary for all the samples
+ void collect_basic_stats (ACE_Basic_Stats &) const;
+
+ /// Get a sample
+ ACE_UINT64 get_sample (size_t i) const;
+
+private:
+ /// The maximum number of samples
+ size_t max_samples_;
+
+ /// The current number of samples
+ size_t sample_count_;
+
+ /// The samples
+ ACE_UINT64 *samples_;
+};
+
+#if defined (__ACE_INLINE__)
+#include "ace/Sample_History.inl"
+#endif /* __ACE_INLINE__ */
+
+#include "ace/post.h"
+#endif /* ACE_SAMPLE_HISTORY_H */
diff --git a/ace/Utils/Sample_History.inl b/ace/Utils/Sample_History.inl
new file mode 100644
index 00000000000..e3882a28bc3
--- /dev/null
+++ b/ace/Utils/Sample_History.inl
@@ -0,0 +1,20 @@
+// $Id$
+
+ACE_INLINE int
+ACE_Sample_History::sample (ACE_UINT64 value)
+{
+ if (this->sample_count_ >= this->max_samples_)
+ return -1;
+
+ this->samples_[this->sample_count_++] = value;
+ return 0;
+}
+
+ACE_INLINE ACE_UINT64
+ACE_Sample_History::get_sample (size_t i) const
+{
+ if (this->sample_count_ <= i)
+ return 0;
+
+ return this->samples_[i];
+}
diff --git a/ace/Utils/Stats.cpp b/ace/Utils/Stats.cpp
new file mode 100644
index 00000000000..f9d60fbcd78
--- /dev/null
+++ b/ace/Utils/Stats.cpp
@@ -0,0 +1,612 @@
+// $Id$
+
+#include "ace/Stats.h"
+#include "ace/High_Res_Timer.h"
+
+#if !defined (__ACE_INLINE__)
+# include "ace/Stats.i"
+#endif /* __ACE_INLINE__ */
+
+ACE_RCSID(ace, Stats, "$Id$")
+
+ACE_UINT32
+ACE_Stats_Value::fractional_field (void) const
+{
+ if (precision () == 0)
+ {
+ return 1;
+ }
+ else
+ {
+ ACE_UINT32 field = 10;
+ for (u_int i = 0; i < precision () - 1; ++i)
+ {
+ field *= 10;
+ }
+
+ return field;
+ }
+}
+
+int
+ACE_Stats::sample (const ACE_INT32 value)
+{
+ if (samples_.enqueue_tail (value) == 0)
+ {
+ ++number_of_samples_;
+ if (number_of_samples_ == 0)
+ {
+ // That's a lot of samples :-)
+ overflow_ = EFAULT;
+ return -1;
+ }
+
+ if (value < min_)
+ min_ = value;
+
+ if (value > max_)
+ max_ = value;
+
+ return 0;
+ }
+ else
+ {
+ // Probably failed due to running out of memory when trying to
+ // enqueue the new value.
+ overflow_ = errno;
+ return -1;
+ }
+}
+
+void
+ACE_Stats::mean (ACE_Stats_Value &m,
+ const ACE_UINT32 scale_factor)
+{
+ if (number_of_samples_ > 0)
+ {
+#if defined ACE_LACKS_LONGLONG_T
+ // If ACE_LACKS_LONGLONG_T, then ACE_UINT64 is a user-defined class.
+ // To prevent having to construct a static of that class, declare it
+ // on the stack, and construct it, in each function that needs it.
+ const ACE_U_LongLong ACE_STATS_INTERNAL_OFFSET (0, 8);
+#else /* ! ACE_LACKS_LONGLONG_T */
+ const ACE_UINT64 ACE_STATS_INTERNAL_OFFSET =
+ ACE_UINT64_LITERAL (0x100000000);
+#endif /* ! ACE_LACKS_LONGLONG_T */
+
+ ACE_UINT64 sum = ACE_STATS_INTERNAL_OFFSET;
+ ACE_Unbounded_Queue_Iterator<ACE_INT32> i (samples_);
+ while (! i.done ())
+ {
+ ACE_INT32 *sample;
+ if (i.next (sample))
+ {
+ sum += *sample;
+ i.advance ();
+ }
+ }
+
+ // sum_ was initialized with ACE_STATS_INTERNAL_OFFSET, so
+ // subtract that off here.
+ quotient (sum - ACE_STATS_INTERNAL_OFFSET,
+ number_of_samples_ * scale_factor,
+ m);
+ }
+ else
+ {
+ m.whole (0);
+ m.fractional (0);
+ }
+}
+
+int
+ACE_Stats::std_dev (ACE_Stats_Value &std_dev,
+ const ACE_UINT32 scale_factor)
+{
+ if (number_of_samples_ <= 1)
+ {
+ std_dev.whole (0);
+ std_dev.fractional (0);
+ }
+ else
+ {
+ const ACE_UINT32 field = std_dev.fractional_field ();
+
+ // The sample standard deviation is:
+ //
+ // sqrt (sum (sample_i - mean)^2 / (number_of_samples_ - 1))
+
+ ACE_UINT64 mean_scaled;
+ // Calculate the mean, scaled, so that we don't lose its
+ // precision.
+ ACE_Stats_Value avg (std_dev.precision ());
+ mean (avg, 1u);
+ avg.scaled_value (mean_scaled);
+
+ // Calculate the summation term, of squared differences from the
+ // mean.
+ ACE_UINT64 sum_of_squares = 0;
+ ACE_Unbounded_Queue_Iterator<ACE_INT32> i (samples_);
+ while (! i.done ())
+ {
+ ACE_INT32 *sample;
+ if (i.next (sample))
+ {
+ const ACE_UINT64 original_sum_of_squares = sum_of_squares;
+
+ // Scale up by field width so that we don't lose the
+ // precision of the mean. Carefully . . .
+ const ACE_UINT64 product (*sample * field);
+
+ ACE_UINT64 difference;
+ // NOTE: please do not reformat this code! It //
+ // works with the Diab compiler the way it is! //
+ if (product >= mean_scaled) //
+ { //
+ difference = product - mean_scaled; //
+ } //
+ else //
+ { //
+ difference = mean_scaled - product; //
+ } //
+ // NOTE: please do not reformat this code! It //
+ // works with the Diab compiler the way it is! //
+
+ // Square using 64-bit arithmetic.
+ sum_of_squares += difference * ACE_U64_TO_U32 (difference);
+ i.advance ();
+
+ if (sum_of_squares < original_sum_of_squares)
+ {
+ overflow_ = ENOSPC;
+ return -1;
+ }
+ }
+ }
+
+ // Divide the summation by (number_of_samples_ - 1), to get the
+ // variance. In addition, scale the variance down to undo the
+ // mean scaling above. Otherwise, it can get too big.
+ ACE_Stats_Value variance (std_dev.precision ());
+ quotient (sum_of_squares,
+ (number_of_samples_ - 1) * field * field,
+ variance);
+
+ // Take the square root of the variance to get the standard
+ // deviation. First, scale up . . .
+ ACE_UINT64 scaled_variance;
+ variance.scaled_value (scaled_variance);
+
+ // And scale up, once more, because we'll be taking the square
+ // root.
+ scaled_variance *= field;
+ ACE_Stats_Value unscaled_standard_deviation (std_dev.precision ());
+ square_root (scaled_variance,
+ unscaled_standard_deviation);
+
+ // Unscale.
+ quotient (unscaled_standard_deviation,
+ scale_factor * field,
+ std_dev);
+ }
+
+ return 0;
+}
+
+
+void
+ACE_Stats::reset (void)
+{
+ overflow_ = 0u;
+ number_of_samples_ = 0u;
+ min_ = 0x7FFFFFFF;
+ max_ = -0x8000 * 0x10000;
+ samples_.reset ();
+}
+
+int
+ACE_Stats::print_summary (const u_int precision,
+ const ACE_UINT32 scale_factor,
+ FILE *file) const
+{
+ ACE_TCHAR mean_string [128];
+ ACE_TCHAR std_dev_string [128];
+ ACE_TCHAR min_string [128];
+ ACE_TCHAR max_string [128];
+ int success = 0;
+
+ for (int tmp_precision = precision;
+ ! overflow_ && ! success && tmp_precision >= 0;
+ --tmp_precision)
+ {
+ // Build a format string, in case the C library doesn't support %*u.
+ ACE_TCHAR format[32];
+ if (tmp_precision == 0)
+ ACE_OS::sprintf (format, ACE_LIB_TEXT ("%%%d"), tmp_precision);
+ else
+ ACE_OS::sprintf (format, ACE_LIB_TEXT ("%%d.%%0%du"), tmp_precision);
+
+ ACE_Stats_Value u (tmp_precision);
+ ((ACE_Stats *) this)->mean (u, scale_factor);
+ ACE_OS::sprintf (mean_string, format, u.whole (), u.fractional ());
+
+ ACE_Stats_Value sd (tmp_precision);
+ if (((ACE_Stats *) this)->std_dev (sd, scale_factor))
+ {
+ success = 0;
+ continue;
+ }
+ else
+ {
+ success = 1;
+ }
+ ACE_OS::sprintf (std_dev_string, format, sd.whole (), sd.fractional ());
+
+ ACE_Stats_Value minimum (tmp_precision), maximum (tmp_precision);
+ if (min_ != 0)
+ {
+ const ACE_UINT64 m (min_);
+ quotient (m, scale_factor, minimum);
+ }
+ if (max_ != 0)
+ {
+ const ACE_UINT64 m (max_);
+ quotient (m, scale_factor, maximum);
+ }
+ ACE_OS::sprintf (min_string, format,
+ minimum.whole (), minimum.fractional ());
+ ACE_OS::sprintf (max_string, format,
+ maximum.whole (), maximum.fractional ());
+ }
+
+ if (success == 1)
+ {
+ ACE_OS::fprintf (file, ACE_LIB_TEXT ("samples: %u (%s - %s); mean: ")
+ ACE_LIB_TEXT ("%s; std dev: %s\n"),
+ samples (), min_string, max_string,
+ mean_string, std_dev_string);
+ return 0;
+ }
+ else
+ {
+#if !defined (ACE_HAS_WINCE)
+ ACE_OS::fprintf (file,
+ ACE_LIB_TEXT ("ACE_Stats::print_summary: OVERFLOW: %s\n"),
+ strerror (overflow_));
+#else
+ // WinCE doesn't have strerror ;(
+ ACE_OS::fprintf (file,
+ ACE_LIB_TEXT ("ACE_Stats::print_summary: OVERFLOW\n"));
+#endif /* ACE_HAS_WINCE */
+ return -1;
+ }
+}
+
+void
+ACE_Stats::quotient (const ACE_UINT64 dividend,
+ const ACE_UINT32 divisor,
+ ACE_Stats_Value &quotient)
+{
+ // The whole part of the division comes from simple integer division.
+ quotient.whole (ACE_static_cast (ACE_UINT32,
+ divisor == 0 ? 0 : dividend / divisor));
+
+ if (quotient.precision () > 0 || divisor == 0)
+ {
+ const ACE_UINT32 field = quotient.fractional_field ();
+
+ // Fractional = (dividend % divisor) * 10^precision / divisor
+
+ // It would be nice to add round-up term:
+ // Fractional = (dividend % divisor) * 10^precision / divisor +
+ // 10^precision/2 / 10^precision
+ // = ((dividend % divisor) * 10^precision + divisor) /
+ // divisor
+ quotient.fractional (ACE_static_cast (ACE_UINT32,
+ dividend % divisor * field / divisor));
+ }
+ else
+ {
+ // No fractional portion is requested, so don't bother
+ // calculating it.
+ quotient.fractional (0);
+ }
+}
+
+void
+ACE_Stats::quotient (const ACE_Stats_Value &dividend,
+ const ACE_UINT32 divisor,
+ ACE_Stats_Value &quotient)
+{
+ // The whole part of the division comes from simple integer division.
+ quotient.whole (divisor == 0 ? 0 : dividend.whole () / divisor);
+
+ if (quotient.precision () > 0 || divisor == 0)
+ {
+ const ACE_UINT32 field = quotient.fractional_field ();
+
+ // Fractional = (dividend % divisor) * 10^precision / divisor.
+ quotient.fractional (dividend.whole () % divisor * field / divisor +
+ dividend.fractional () / divisor);
+ }
+ else
+ {
+ // No fractional portion is requested, so don't bother
+ // calculating it.
+ quotient.fractional (0);
+ }
+}
+
+void
+ACE_Stats::square_root (const ACE_UINT64 n,
+ ACE_Stats_Value &square_root)
+{
+ ACE_UINT32 floor = 0;
+ ACE_UINT32 ceiling = 0xFFFFFFFFu;
+ ACE_UINT32 mid = 0;
+ u_int i;
+
+ // The maximum number of iterations is log_2 (2^64) == 64.
+ for (i = 0; i < 64; ++i)
+ {
+ mid = (ceiling - floor) / 2 + floor;
+ if (floor == mid)
+ // Can't divide the interval any further.
+ break;
+ else
+ {
+ // Multiply carefully to avoid overflow.
+ ACE_UINT64 mid_squared = mid; mid_squared *= mid;
+ if (mid_squared == n)
+ break;
+ else if (mid_squared < n)
+ floor = mid;
+ else
+ ceiling = mid;
+ }
+ }
+
+ square_root.whole (mid);
+ ACE_UINT64 mid_squared = mid; mid_squared *= mid;
+
+ if (square_root.precision () && mid_squared < n)
+ {
+ // (mid * 10^precision + fractional)^2 ==
+ // n^2 * 10^(precision * 2)
+
+ const ACE_UINT32 field = square_root.fractional_field ();
+
+ floor = 0;
+ ceiling = field;
+ mid = 0;
+
+ // Do the 64-bit arithmetic carefully to avoid overflow.
+ ACE_UINT64 target = n;
+ target *= field;
+ target *= field;
+
+ ACE_UINT64 difference = 0;
+
+ for (i = 0; i < square_root.precision (); ++i)
+ {
+ mid = (ceiling - floor) / 2 + floor;
+
+ ACE_UINT64 current = square_root.whole () * field + mid;
+ current *= square_root.whole () * field + mid;
+
+ if (floor == mid)
+ {
+ difference = target - current;
+ break;
+ }
+ else if (current <= target)
+ floor = mid;
+ else
+ ceiling = mid;
+ }
+
+ // Check to see if the fractional part should be one greater.
+ ACE_UINT64 next = square_root.whole () * field + mid + 1;
+ next *= square_root.whole () * field + mid + 1;
+
+ square_root.fractional (next - target < difference ? mid + 1 : mid);
+ }
+ else
+ {
+ // No fractional portion is requested, so don't bother
+ // calculating it.
+ square_root.fractional (0);
+ }
+}
+
+// ****************************************************************
+
+ACE_Throughput_Stats::ACE_Throughput_Stats (void)
+ : ACE_Basic_Stats ()
+ , throughput_last_ (0)
+#if 0
+ // @@TODO: This is what I really wanted to compute, but it just
+ // does not work.
+ , throughput_sum_x_ (0)
+ , throughput_sum_x2_ (0)
+ , throughput_sum_y_ (0)
+ , throughput_sum_y2_ (0)
+ , throughput_sum_xy_ (0)
+#endif /* 0 */
+{
+}
+
+void
+ACE_Throughput_Stats::sample (ACE_UINT64 throughput,
+ ACE_UINT64 latency)
+{
+ this->ACE_Basic_Stats::sample (latency);
+
+ if (this->samples_count () == 1u)
+ {
+
+ this->throughput_last_ = throughput;
+#if 0
+ // @@TODO: This is what I really wanted to compute, but it just
+ // does not work.
+ this->throughput_sum_y_ = this->samples_count_;
+ this->throughput_sum_y2_ = this->samples_count_ * this->samples_count_;
+ this->throughput_sum_x_ = throughput;
+ this->throughput_sum_x2_ = throughput * throughput;
+ this->throughput_sum_xy_ = throughput * this->samples_count_;
+
+ printf ("%f %qu\n", throughput / 400000000.0, this->samples_count_);
+#endif /* 0 */
+ }
+ else
+ {
+ this->throughput_last_ = throughput;
+
+#if 0
+ // @@TODO: This is what I really wanted to compute, but it just
+ // does not work.
+ this->throughput_sum_y_ += this->samples_count_;
+ this->throughput_sum_y2_ += this->samples_count_ * this->samples_count_;
+ this->throughput_sum_x_ += throughput;
+ this->throughput_sum_x2_ += throughput * throughput;
+ this->throughput_sum_xy_ += throughput * this->samples_count_;
+
+ printf ("%f %qu\n", throughput / 400000000.0, this->samples_count_);
+#endif /* 0 */
+ }
+}
+
+void
+ACE_Throughput_Stats::accumulate (const ACE_Throughput_Stats &rhs)
+{
+ if (rhs.samples_count () == 0u)
+ return;
+
+ this->ACE_Basic_Stats::accumulate (rhs);
+
+ if (this->samples_count () == 0u)
+ {
+ this->throughput_last_ = rhs.throughput_last_;
+#if 0
+ // @@TODO: This is what I really wanted to compute, but it just
+ // does not work.
+ this->throughput_sum_x_ = rhs.throughput_sum_x_;
+ this->throughput_sum_x2_ = rhs.throughput_sum_x2_;
+ this->throughput_sum_y_ = rhs.throughput_sum_y_;
+ this->throughput_sum_y2_ = rhs.throughput_sum_y2_;
+ this->throughput_sum_xy_ = rhs.throughput_sum_xy_;
+#endif /* 0 */
+
+ return;
+ }
+
+
+ if (this->throughput_last_ < rhs.throughput_last_)
+ this->throughput_last_ = rhs.throughput_last_;
+
+#if 0
+ // @@TODO: This is what I really wanted to compute, but it just
+ // does not work.
+ this->throughput_sum_x_ += rhs.throughput_sum_x_;
+ this->throughput_sum_x2_ += rhs.throughput_sum_x2_;
+ this->throughput_sum_y_ += rhs.throughput_sum_y_;
+ this->throughput_sum_y2_ += rhs.throughput_sum_y2_;
+ this->throughput_sum_xy_ += rhs.throughput_sum_xy_;
+#endif /* 0 */
+}
+
+void
+ACE_Throughput_Stats::dump_results (const ACE_TCHAR* msg,
+ ACE_UINT32 sf)
+{
+ if (this->samples_count () == 0u)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_LIB_TEXT ("%s : no data collected\n"), msg));
+ return;
+ }
+
+ this->ACE_Basic_Stats::dump_results (msg, sf);
+
+ ACE_Throughput_Stats::dump_throughput (msg, sf,
+ this->throughput_last_,
+ this->samples_count ());
+
+#if 0
+ // @@TODO: This is what I really wanted to generate, but it just
+ // doesn't work.
+ double t_sum_x =
+ ACE_CU64_TO_CU32 (this->throughput_sum_x_);// / sf);
+ //t_sum_x /= 1000000.0;
+ double t_sum_y =
+ ACE_CU64_TO_CU32 (this->throughput_sum_y_);
+ double t_sum_x2 =
+ ACE_CU64_TO_CU32 (this->throughput_sum_x2_);// / (sf*sf));
+ //t_sum_x2 /= 1000000.0;
+ //t_sum_x2 /= 1000000.0;
+ double t_sum_y2 =
+ ACE_CU64_TO_CU32 (this->throughput_sum_y2_);
+ double t_sum_xy =
+ ACE_CU64_TO_CU32 (this->throughput_sum_xy_);// / sf);
+ //t_sum_xy /= 1000000.0;
+ double t_avgx = t_sum_x / this->samples_count ();
+ double t_avgy = t_sum_y / this->samples_count ();
+
+ double t_a =
+ (this->samples_count () * t_sum_xy - t_sum_x * t_sum_y)
+ / (this->samples_count () * t_sum_x2 - t_sum_x * t_sum_x);
+ double t_b = (t_avgy - t_a * t_avgx);
+
+ t_a *= 1000000.0;
+
+ double d_r =
+ (t_sum_xy - t_avgx * t_sum_y - t_avgy * t_sum_x
+ + this->samples_count () * t_avgx * t_avgy);
+ double n_r =
+ (t_sum_x2
+ - this->samples_count () * t_avgx * t_avgx)
+ * (t_sum_y2
+ - this->samples_count () * t_avgy * t_avgy);
+ double t_r = d_r * d_r / n_r;
+
+ // ACE_DEBUG ((LM_DEBUG,
+ // "%s throughput: %.2f/%.2f/%.2f/%.6f/%.2f (avg/a/b/r/elapsed)\n",
+ // msg, t_avg, t_a, t_b, t_r, seconds));
+ // ACE_DEBUG ((LM_DEBUG,
+ // "%s data: %.2f/%.2f/%.2f/%.6f/%.2f (x/x2/y/y2/xy)\n",
+ // msg, t_sum_x, t_sum_x2, t_sum_y, t_sum_y2, t_sum_xy));
+#endif
+}
+
+void
+ACE_Throughput_Stats::dump_throughput (const ACE_TCHAR *msg,
+ ACE_UINT32 sf,
+ ACE_UINT64 elapsed_time,
+ ACE_UINT32 samples_count)
+{
+ double seconds =
+#if defined ACE_LACKS_LONGLONG_T
+ elapsed_time / sf;
+#else /* ! ACE_LACKS_LONGLONG_T */
+ ACE_static_cast (double,
+ ACE_UINT64_DBLCAST_ADAPTER(elapsed_time / sf));
+#endif /* ! ACE_LACKS_LONGLONG_T */
+ seconds /= ACE_HR_SCALE_CONVERSION;
+ double t_avg = samples_count / seconds;
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_LIB_TEXT ("%s throughput: %.2f (events/second)\n"),
+ msg, t_avg));
+}
+
+// ****************************************************************
+
+#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION)
+template class ACE_Node <ACE_INT32>;
+template class ACE_Unbounded_Queue <ACE_INT32>;
+template class ACE_Unbounded_Queue_Iterator <ACE_INT32>;
+#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA)
+#pragma instantiate ACE_Node <ACE_INT32>
+#pragma instantiate ACE_Unbounded_Queue <ACE_INT32>
+#pragma instantiate ACE_Unbounded_Queue_Iterator <ACE_INT32>
+#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */
diff --git a/ace/Utils/Stats.h b/ace/Utils/Stats.h
new file mode 100644
index 00000000000..999fd6da7fa
--- /dev/null
+++ b/ace/Utils/Stats.h
@@ -0,0 +1,270 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Stats.h
+ *
+ * $Id$
+ *
+ * @author David L. Levine
+ */
+//=============================================================================
+
+
+#ifndef ACE_STATS_H
+#define ACE_STATS_H
+#include "ace/pre.h"
+
+#include "ace/ACE.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "ace/Unbounded_Queue.h"
+#include "ace/Log_Msg.h"
+#include "ace/Basic_Stats.h"
+
+/**
+ * @class ACE_Stats_Value
+ *
+ * @brief Helper class for ACE_Stats.
+ *
+ * Container struct for 64-bit signed quantity and its
+ * precision. It would be nicer to use a fixed-point class, but
+ * this is sufficient. Users typically don't need to use this
+ * class directly; see ACE_Stats below.
+ */
+class ACE_Export ACE_Stats_Value
+{
+public:
+ /**
+ * Constructor, which requires precision in terms of number of
+ * decimal digits. The more variation in the data, and the greater
+ * the data values, the smaller the precision must be to avoid
+ * overflow in the standard deviation calculation. 3 might be a
+ * good value, or maybe 4. 5 will probably be too large for
+ * non-trivial data sets.
+ */
+ ACE_Stats_Value (const u_int precision);
+
+ /// Accessor for precision.
+ u_int precision (void) const;
+
+ /// Set the whole_ field.
+ void whole (const ACE_UINT32);
+
+ /// Accessor for the whole_ field.
+ ACE_UINT32 whole (void) const;
+
+ /// Set the fractional_ field.
+ void fractional (const ACE_UINT32);
+
+ /// Accessor for the fractional_ field.
+ ACE_UINT32 fractional (void) const;
+
+ /// Calculates the maximum value of the fractional portion, given its
+ /// precision.
+ ACE_UINT32 fractional_field (void) const;
+
+ /**
+ * Access the value as an _unsigned_ 64 bit quantity. It scales the
+ * value up by <precision> decimal digits, so that no precision will
+ * be lost. It assumes that <whole_> is >= 0.
+ */
+ void scaled_value (ACE_UINT64 &) const;
+
+ /// Print to stdout.
+ void dump (void) const;
+
+private:
+ /// The integer portion of the value.
+ ACE_UINT32 whole_;
+
+ /// The fractional portion of the value.
+ ACE_UINT32 fractional_;
+
+ /**
+ * The number of decimal digits of precision represented by
+ * <fractional_>. Not declared const, so the only way to change it
+ * is via the assignment operator.
+ */
+ u_int precision_;
+
+ ACE_UNIMPLEMENTED_FUNC (ACE_Stats_Value (void))
+};
+
+/**
+ * @class ACE_Stats
+ *
+ * @brief Provides simple statistical analysis.
+ *
+ * Simple statistical analysis package. Prominent features are:
+ * -# It does not use any floating point arithmetic.
+ * -# It handles positive and/or negative sample values. The
+ * sample value type is ACE_INT32.
+ * -# It uses 64 bit unsigned, but not 64 bit signed, quantities
+ * internally.
+ * -# It checks for overflow of internal state.
+ * -# It has no static variables of other than built-in types.
+ *
+ * Example usage:
+ *
+ * @verbatim
+ * ACE_Stats stats;
+ * for (u_int i = 0; i < n; ++i)
+ * {
+ * const ACE_UINT32 sample = ...;
+ * stats.sample (sample);
+ * }
+ * stats.print_summary (3);
+ * @endverbatim
+ */
+class ACE_Export ACE_Stats
+{
+public:
+ /// Default constructor.
+ ACE_Stats (void);
+
+ /// Provide a new sample. Returns 0 on success, -1 if it fails due
+ /// to running out of memory, or to rolling over of the sample count.
+ int sample (const ACE_INT32 value);
+
+ /// Access the number of samples provided so far.
+ ACE_UINT32 samples (void) const;
+
+ /// Value of the minimum sample provided so far.
+ ACE_INT32 min_value (void) const;
+
+ /// Value of the maximum sample provided so far.
+ ACE_INT32 max_value (void) const;
+
+ /**
+ * Access the mean of all samples provided so far. The fractional
+ * part is to the specified number of digits. E.g., 3 fractional
+ * digits specifies that the fractional part is in thousandths.
+ */
+ void mean (ACE_Stats_Value &mean,
+ const ACE_UINT32 scale_factor = 1);
+
+ /// Access the standard deviation, whole and fractional parts. See
+ /// description of <mean> method for argument descriptions.
+ int std_dev (ACE_Stats_Value &std_dev,
+ const ACE_UINT32 scale_factor = 1);
+
+ /**
+ * Print summary statistics. If scale_factor is not 1, then the
+ * results are divided by it, i.e., each of the samples is scaled
+ * down by it. If internal overflow is reached with the specified
+ * scale factor, it successively tries to reduce it. Returns -1 if
+ * there is overflow even with a 0 scale factor.
+ */
+ int print_summary (const u_int precision,
+ const ACE_UINT32 scale_factor = 1,
+ FILE * = stdout) const;
+
+ /// Initialize internal state.
+ void reset (void);
+
+ /// Utility division function, for ACE_UINT64 dividend.
+ static void quotient (const ACE_UINT64 dividend,
+ const ACE_UINT32 divisor,
+ ACE_Stats_Value &quotient);
+
+ /// Utility division function, for ACE_Stats_Value dividend.
+ static void quotient (const ACE_Stats_Value &dividend,
+ const ACE_UINT32 divisor,
+ ACE_Stats_Value &quotient);
+
+ /**
+ * Sqrt function, which uses an oversimplified version of Newton's
+ * method. It's not fast, but it doesn't require floating point
+ * support.
+ */
+ static void square_root (const ACE_UINT64 n,
+ ACE_Stats_Value &square_root);
+
+ /// Print summary statistics to stdout.
+ void dump (void) const;
+
+private:
+ /// Internal indication of whether there has been overflow. Contains
+ /// the errno corresponding to the cause of overflow.
+ u_int overflow_;
+
+ /// Number of samples.
+ ACE_UINT32 number_of_samples_;
+
+ /// Minimum sample value.
+ ACE_INT32 min_;
+
+ /// Maximum sample value.
+ ACE_INT32 max_;
+
+ /// The samples.
+ ACE_Unbounded_Queue <ACE_INT32> samples_;
+};
+
+// ****************************************************************
+
+
+/// A simple class to make throughput and latency analysis.
+/**
+ *
+ * Keep the relevant information to perform throughput and latency
+ * analysis, including:
+ * -# Minimum, Average and Maximum latency
+ * -# Jitter for the latency
+ * -# Linear regression for throughput
+ * -# Accumulate results from several samples to obtain aggregated
+ * results, across several threads or experiments.
+ *
+ * @todo The idea behind this class was to use linear regression to
+ * determine if the throughput was linear or exhibited jitter.
+ * Unfortunately it never worked quite right, so only average
+ * throughput is computed.
+ */
+class ACE_Export ACE_Throughput_Stats : public ACE_Basic_Stats
+{
+public:
+ /// Constructor
+ ACE_Throughput_Stats (void);
+
+ /// Store one sample
+ void sample (ACE_UINT64 throughput, ACE_UINT64 latency);
+
+ /// Update the values to reflect the stats in @param throughput
+ void accumulate (const ACE_Throughput_Stats &throughput);
+
+ /// Print down the stats
+ void dump_results (const ACE_TCHAR* msg, ACE_UINT32 scale_factor);
+
+ /// Dump the average throughput stats.
+ static void dump_throughput (const ACE_TCHAR *msg,
+ ACE_UINT32 scale_factor,
+ ACE_UINT64 elapsed_time,
+ ACE_UINT32 samples_count);
+private:
+ /// The last throughput measurement.
+ ACE_UINT64 throughput_last_;
+
+#if 0
+ /// These are the fields that we should keep to perform linear
+ /// regression
+ //@{
+ ///@}
+ ACE_UINT64 throughput_sum_x_;
+ ACE_UINT64 throughput_sum_x2_;
+ ACE_UINT64 throughput_sum_y_;
+ ACE_UINT64 throughput_sum_y2_;
+ ACE_UINT64 throughput_sum_xy_;
+#endif /* 0 */
+};
+
+
+#if defined (__ACE_INLINE__)
+# include "ace/Stats.i"
+#endif /* __ACE_INLINE__ */
+
+#include "ace/post.h"
+#endif /* ! ACE_STATS_H */
diff --git a/ace/Utils/Stats.i b/ace/Utils/Stats.i
new file mode 100644
index 00000000000..c97c0d29ca6
--- /dev/null
+++ b/ace/Utils/Stats.i
@@ -0,0 +1,95 @@
+/* -*- C++ -*- */
+// $Id$
+
+ACE_INLINE
+ACE_Stats_Value::ACE_Stats_Value (const u_int precision)
+ : whole_ (0),
+ fractional_ (0),
+ precision_ (precision)
+{
+}
+
+ACE_INLINE
+u_int
+ACE_Stats_Value::precision (void) const
+{
+ return precision_;
+}
+
+ACE_INLINE
+void
+ACE_Stats_Value::whole (const ACE_UINT32 value)
+{
+ whole_ = value;
+}
+
+ACE_INLINE
+ACE_UINT32
+ACE_Stats_Value::whole (void) const
+{
+ return whole_;
+}
+
+ACE_INLINE
+void
+ACE_Stats_Value::fractional (const ACE_UINT32 value)
+{
+ fractional_ = value;
+}
+
+ACE_INLINE
+ACE_UINT32
+ACE_Stats_Value::fractional (void) const
+{
+ return fractional_;
+}
+
+ACE_INLINE
+void
+ACE_Stats_Value::scaled_value (ACE_UINT64 &sv) const
+{
+ sv = whole () * fractional_field () + fractional ();
+}
+
+ACE_INLINE
+void
+ACE_Stats_Value::dump (void) const
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_LIB_TEXT ("precision: %u digits; whole: %u, fractional: %u\n"),
+ precision_, whole_, fractional_));
+}
+
+ACE_INLINE
+ACE_Stats::ACE_Stats (void)
+{
+ reset ();
+}
+
+ACE_INLINE
+ACE_UINT32
+ACE_Stats::samples (void) const
+{
+ return number_of_samples_;
+}
+
+ACE_INLINE
+ACE_INT32
+ACE_Stats::min_value (void) const
+{
+ return min_;
+}
+
+ACE_INLINE
+ACE_INT32
+ACE_Stats::max_value (void) const
+{
+ return max_;
+}
+
+ACE_INLINE
+void
+ACE_Stats::dump (void) const
+{
+ print_summary (3u);
+}
diff --git a/ace/Utils/String_Base_Const.cpp b/ace/Utils/String_Base_Const.cpp
new file mode 100644
index 00000000000..914c18a0341
--- /dev/null
+++ b/ace/Utils/String_Base_Const.cpp
@@ -0,0 +1,5 @@
+// $Id$
+
+#include "ace/String_Base_Const.h"
+
+int ACE_String_Base_Const::npos = -1;
diff --git a/ace/Utils/String_Base_Const.h b/ace/Utils/String_Base_Const.h
new file mode 100644
index 00000000000..3f37b92e11c
--- /dev/null
+++ b/ace/Utils/String_Base_Const.h
@@ -0,0 +1,32 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file String_Base_Const.h
+ *
+ * $Id$
+ *
+ * @author Nanbor Wang <nanbor@cs.wustl.edu>
+ */
+//=============================================================================
+
+#if !defined ACE_STRING_BASE_CONST_H
+#define ACE_STRING_BASE_CONST_H
+
+#include "ace/pre.h"
+#include "ace/config-all.h"
+
+/**
+ * @class ACE_String_Base_Const
+ *
+ * @brief This class defines a constant for ACE_String_Base to
+ * circumvent a bug in SunCC 6.0.
+ */
+class ACE_Export ACE_String_Base_Const
+{
+public:
+ static int npos;
+};
+
+#include "ace/post.h"
+#endif /* ACE_STRING_BASE_CONST_H */
diff --git a/ace/Utils/Templates/Array_Base.cpp b/ace/Utils/Templates/Array_Base.cpp
new file mode 100644
index 00000000000..00bf8193bf0
--- /dev/null
+++ b/ace/Utils/Templates/Array_Base.cpp
@@ -0,0 +1,204 @@
+// $Id$
+
+#ifndef ACE_ARRAY_BASE_C
+#define ACE_ARRAY_BASE_C
+
+#include "ace/Array_Base.h"
+#include "ace/Malloc_Base.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#if !defined (__ACE_INLINE__)
+#include "ace/Array_Base.inl"
+#endif /* __ACE_INLINE__ */
+
+ACE_RCSID(ace, Array_Base, "$Id$")
+
+
+// Dynamically initialize an array.
+
+template <class T>
+ACE_Array_Base<T>::ACE_Array_Base (size_t size,
+ ACE_Allocator *alloc)
+ : max_size_ (size),
+ cur_size_ (size),
+ allocator_ (alloc)
+{
+ if (this->allocator_ == 0)
+ this->allocator_ = ACE_Allocator::instance ();
+
+ if (size != 0)
+ {
+ ACE_ALLOCATOR (this->array_,
+ (T *) this->allocator_->malloc (size * sizeof (T)));
+ for (size_t i = 0; i < size; ++i)
+ new (&array_[i]) T;
+ }
+ else
+ this->array_ = 0;
+}
+
+template <class T>
+ACE_Array_Base<T>::ACE_Array_Base (size_t size,
+ const T &default_value,
+ ACE_Allocator *alloc)
+ : max_size_ (size),
+ cur_size_ (size),
+ allocator_ (alloc)
+{
+ if (this->allocator_ == 0)
+ this->allocator_ = ACE_Allocator::instance ();
+
+ if (size != 0)
+ {
+ ACE_ALLOCATOR (this->array_,
+ (T *) this->allocator_->malloc (size * sizeof (T)));
+ for (size_t i = 0; i < size; ++i)
+ new (&array_[i]) T (default_value);
+ }
+ else
+ this->array_ = 0;
+}
+
+// The copy constructor (performs initialization).
+
+template <class T>
+ACE_Array_Base<T>::ACE_Array_Base (const ACE_Array_Base<T> &s)
+ : max_size_ (s.size ()),
+ cur_size_ (s.size ()),
+ allocator_ (s.allocator_)
+{
+ if (this->allocator_ == 0)
+ this->allocator_ = ACE_Allocator::instance ();
+
+ ACE_ALLOCATOR (this->array_,
+ (T *) this->allocator_->malloc (s.size () * sizeof (T)));
+ for (size_t i = 0; i < this->size (); i++)
+ new (&this->array_[i]) T (s.array_[i]);
+}
+
+// Assignment operator (performs assignment).
+
+template <class T> void
+ACE_Array_Base<T>::operator= (const ACE_Array_Base<T> &s)
+{
+ // Check for "self-assignment".
+
+ if (this != &s)
+ {
+ if (this->max_size_ < s.size ())
+ {
+ ACE_DES_ARRAY_FREE (this->array_,
+ this->max_size_,
+ this->allocator_->free,
+ T);
+ ACE_ALLOCATOR (this->array_,
+ (T *) this->allocator_->malloc (s.size () * sizeof (T)));
+ this->max_size_ = s.size ();
+ }
+ else
+ {
+ ACE_DES_ARRAY_NOFREE (this->array_,
+ s.size (),
+ T);
+ }
+
+ this->cur_size_ = s.size ();
+
+ for (size_t i = 0; i < this->size (); i++)
+ new (&this->array_[i]) T (s.array_[i]);
+ }
+}
+
+// Set an item in the array at location slot.
+
+template <class T> int
+ACE_Array_Base<T>::set (const T &new_item, size_t slot)
+{
+ if (this->in_range (slot))
+ {
+ this->array_[slot] = new_item;
+ return 0;
+ }
+ else
+ return -1;
+}
+
+// Get an item in the array at location slot.
+
+template <class T> int
+ACE_Array_Base<T>::get (T &item, size_t slot) const
+{
+ if (this->in_range (slot))
+ {
+ // Copies the item. If you don't want to copy, use operator []
+ // instead (but then you'll be responsible for range checking).
+ item = this->array_[slot];
+ return 0;
+ }
+ else
+ return -1;
+}
+
+template<class T> int
+ACE_Array_Base<T>::max_size (size_t new_size)
+{
+ if (new_size > this->max_size_)
+ {
+ T *tmp;
+
+ ACE_ALLOCATOR_RETURN (tmp,
+ (T *) this->allocator_->malloc (new_size * sizeof (T)),
+ -1);
+ for (size_t i = 0; i < this->cur_size_; ++i)
+ new (&tmp[i]) T (this->array_[i]);
+
+ // Initialize the new portion of the array that exceeds the
+ // previously allocated section.
+ for (size_t j = this->cur_size_; j < new_size; j++)
+ new (&tmp[j]) T;
+
+ ACE_DES_ARRAY_FREE (this->array_,
+ this->max_size_,
+ this->allocator_->free,
+ T);
+ this->array_ = tmp;
+ this->max_size_ = new_size;
+ this->cur_size_ = new_size;
+ }
+
+ return 0;
+}
+
+template<class T> int
+ACE_Array_Base<T>::size (size_t new_size)
+{
+ int r = this->max_size (new_size);
+ if (r != 0)
+ return r;
+ this->cur_size_ = new_size;
+ return 0;
+}
+
+// ****************************************************************
+
+template <class T> int
+ACE_Array_Iterator<T>::next (T *&item)
+{
+ // ACE_TRACE ("ACE_Array_Iterator<T>::next");
+
+ if (this->done ())
+ {
+ item = 0;
+ return 0;
+ }
+ else
+ {
+ item = &array_[current_];
+ return 1;
+ }
+}
+
+#endif /* ACE_ARRAY_BASE_C */
diff --git a/ace/Utils/Templates/Array_Base.h b/ace/Utils/Templates/Array_Base.h
new file mode 100644
index 00000000000..de2a4a46136
--- /dev/null
+++ b/ace/Utils/Templates/Array_Base.h
@@ -0,0 +1,206 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Array_Base.h
+ *
+ * $Id$
+ *
+ * @author Douglas C. Schmidt <schmidt@cs.wustl.edu>
+ */
+//=============================================================================
+
+#ifndef ACE_ARRAY_BASE_H
+#define ACE_ARRAY_BASE_H
+#include "ace/pre.h"
+
+#include "ace/config-all.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+class ACE_Allocator;
+
+// Forward declaration.
+template <class T> class ACE_Array_Iterator;
+
+/**
+ * @class ACE_Array_Base
+ *
+ * @brief Implement a simple dynamic array
+ *
+ * This parametric class implements a simple dynamic array;
+ * resizing must be controlled by the user. No comparison or find
+ * operations are implemented.
+ */
+template<class T>
+class ACE_Array_Base
+{
+public:
+
+ // Define a "trait"
+ typedef T TYPE;
+ typedef ACE_Array_Iterator<T> ITERATOR;
+
+ // = Initialization and termination methods.
+
+ /// Dynamically create an uninitialized array.
+ ACE_Array_Base (size_t size = 0,
+ ACE_Allocator *alloc = 0);
+
+ /// Dynamically initialize the entire array to the <default_value>.
+ ACE_Array_Base (size_t size,
+ const T &default_value,
+ ACE_Allocator *alloc = 0);
+
+ /**
+ * The copy constructor performs initialization by making an exact
+ * copy of the contents of parameter <s>, i.e., *this == s will
+ * return true.
+ */
+ ACE_Array_Base (const ACE_Array_Base<T> &s);
+
+ /**
+ * Assignment operator performs an assignment by making an exact
+ * copy of the contents of parameter <s>, i.e., *this == s will
+ * return true. Note that if the <max_size_> of <array_> is >= than
+ * <s.max_size_> we can copy it without reallocating. However, if
+ * <max_size_> is < <s.max_size_> we must delete the <array_>,
+ * reallocate a new <array_>, and then copy the contents of <s>.
+ */
+ void operator= (const ACE_Array_Base<T> &s);
+
+ /// Clean up the array (e.g., delete dynamically allocated memory).
+ ~ACE_Array_Base (void);
+
+ // = Set/get methods.
+
+ /// Set item in the array at location <slot>. Doesn't
+ /// perform range checking.
+ T &operator [] (size_t slot);
+
+ /// Get item in the array at location <slot>. Doesn't
+ /// perform range checking.
+ const T &operator [] (size_t slot) const;
+
+ /// Set an item in the array at location <slot>. Returns
+ /// -1 if <slot> is not in range, else returns 0.
+ int set (const T &new_item, size_t slot);
+
+ /**
+ * Get an item in the array at location <slot>. Returns -1 if
+ * <slot> is not in range, else returns 0. Note that this function
+ * copies the item. If you want to avoid the copy, you can use
+ * the const operator [], but then you'll be responsible for range checking.
+ */
+ int get (T &item, size_t slot) const;
+
+ /// Returns the <cur_size_> of the array.
+ size_t size (void) const;
+
+ /**
+ * Changes the size of the array to match <new_size>.
+ * It copies the old contents into the new array.
+ * Return -1 on failure.
+ */
+ int size (size_t new_size);
+
+ /// Returns the <max_size_> of the array.
+ size_t max_size (void) const;
+
+ /**
+ * Changes the size of the array to match <new_size>.
+ * It copies the old contents into the new array.
+ * Return -1 on failure.
+ * It does not affect new_size
+ */
+ int max_size (size_t new_size);
+
+private:
+ /// Returns 1 if <slot> is within range, i.e., 0 >= <slot> <
+ /// <cur_size_>, else returns 0.
+ int in_range (size_t slot) const;
+
+ /// Maximum size of the array, i.e., the total number of <T> elements
+ /// in <array_>.
+ size_t max_size_;
+
+ /**
+ * Current size of the array. This starts out being == to
+ * <max_size_>. However, if we are assigned a smaller array, then
+ * <cur_size_> will become less than <max_size_>. The purpose of
+ * keeping track of both sizes is to avoid reallocating memory if we
+ * don't have to.
+ */
+ size_t cur_size_;
+
+ /// Pointer to the array's storage buffer.
+ T *array_;
+
+ /// Allocation strategy of the ACE_Array_Base.
+ ACE_Allocator *allocator_;
+
+ friend class ACE_Array_Iterator<T>;
+};
+
+// ****************************************************************
+
+/**
+ * @class ACE_Array_Iterator
+ *
+ * @brief Implement an iterator over an ACE_Array.
+ *
+ * This iterator is safe in the face of array element deletions.
+ * But it is NOT safe if the array is resized (via the ACE_Array
+ * assignment operator) during iteration. That would be very
+ * odd, and dangerous.
+ */
+template <class T>
+class ACE_Array_Iterator
+{
+public:
+ // = Initialization method.
+ ACE_Array_Iterator (ACE_Array_Base<T> &);
+
+ // = Iteration methods.
+
+ /// Pass back the <next_item> that hasn't been seen in the Array.
+ /// Returns 0 when all items have been seen, else 1.
+ int next (T *&next_item);
+
+ /// Move forward by one element in the Array. Returns 0 when all the
+ /// items in the Array have been seen, else 1.
+ int advance (void);
+
+ /// Returns 1 when all items have been seen, else 0.
+ int done (void) const;
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+private:
+ /// Pointer to the current item in the iteration.
+ size_t current_;
+
+ /// Pointer to the Array we're iterating over.
+ ACE_Array_Base<T> &array_;
+};
+
+#if defined (__ACE_INLINE__)
+#include "ace/Array_Base.inl"
+#endif /* __ACE_INLINE__ */
+
+#if defined (ACE_TEMPLATES_REQUIRE_SOURCE)
+#include "ace/Array_Base.cpp"
+#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */
+
+#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA)
+#pragma implementation ("Array_Base.cpp")
+#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */
+
+#include "ace/post.h"
+#endif /* ACE_ARRAY_BASE_H */
diff --git a/ace/Utils/Templates/Array_Base.inl b/ace/Utils/Templates/Array_Base.inl
new file mode 100644
index 00000000000..b682fec615f
--- /dev/null
+++ b/ace/Utils/Templates/Array_Base.inl
@@ -0,0 +1,84 @@
+/* -*- C++ -*- */
+// $Id$
+
+// Clean up the array (e.g., delete dynamically allocated memory).
+
+template <class T> ACE_INLINE
+ACE_Array_Base<T>::~ACE_Array_Base (void)
+{
+ ACE_DES_ARRAY_FREE (this->array_,
+ this->max_size_,
+ this->allocator_->free,
+ T);
+}
+
+template <class T> ACE_INLINE size_t
+ACE_Array_Base<T>::size (void) const
+{
+ return this->cur_size_;
+}
+
+template <class T> ACE_INLINE size_t
+ACE_Array_Base<T>::max_size (void) const
+{
+ return this->max_size_;
+}
+
+template <class T> ACE_INLINE int
+ACE_Array_Base<T>::in_range (size_t index) const
+{
+ return index < this->cur_size_;
+}
+
+template <class T> ACE_INLINE T &
+ACE_Array_Base<T>::operator[] (size_t index)
+{
+ return this->array_[index];
+}
+
+template <class T> ACE_INLINE const T &
+ACE_Array_Base<T>::operator[] (size_t index) const
+{
+ return this->array_[index];
+}
+
+// ****************************************************************
+
+template <class T> ACE_INLINE void
+ACE_Array_Iterator<T>::dump (void) const
+{
+ // ACE_TRACE ("ACE_Array_Iterator<T>::dump");
+}
+
+template <class T> ACE_INLINE
+ACE_Array_Iterator<T>::ACE_Array_Iterator (ACE_Array_Base<T> &a)
+ : current_ (0),
+ array_ (a)
+{
+ // ACE_TRACE ("ACE_Array_Iterator<T>::ACE_Array_Iterator");
+}
+
+template <class T> ACE_INLINE int
+ACE_Array_Iterator<T>::advance (void)
+{
+ // ACE_TRACE ("ACE_Array_Iterator<T>::advance");
+
+ if (this->current_ < array_.size ())
+ {
+ ++this->current_;
+ return 1;
+ }
+ else
+ {
+ // Already finished iterating.
+ return 0;
+ }
+}
+
+template <class T> ACE_INLINE int
+ACE_Array_Iterator<T>::done (void) const
+{
+ ACE_TRACE ("ACE_Array_Iterator<T>::done");
+
+ return this->current_ >= array_.size ();
+}
diff --git a/ace/Utils/Templates/Auto_IncDec_T.cpp b/ace/Utils/Templates/Auto_IncDec_T.cpp
new file mode 100644
index 00000000000..2ca06874a2e
--- /dev/null
+++ b/ace/Utils/Templates/Auto_IncDec_T.cpp
@@ -0,0 +1,30 @@
+// $Id$
+
+#ifndef ACE_AUTO_INCDEC_T_C
+#define ACE_AUTO_INCDEC_T_C
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "ace/Auto_IncDec_T.h"
+#include "ace/Log_Msg.h"
+
+ACE_RCSID(ace, Auto_IncDec_T, "Auto_IncDec_T.cpp, by Edan Ayal")
+
+#if !defined (__ACE_INLINE__)
+#include "ace/Auto_IncDec_T.i"
+#endif /* __ACE_INLINE__ */
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Auto_IncDec)
+
+template <class ACE_SAFELY_INCREMENTABLE_DECREMENTABLE> void
+ACE_Auto_IncDec<ACE_SAFELY_INCREMENTABLE_DECREMENTABLE>::dump (void) const
+{
+// ACE_TRACE ("ACE_Auto_IncDec<ACE_SAFELY_INCREMENTABLE_DECREMENTABLE>::dump");
+
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+#endif /* ACE_AUTO_INCDEC_T_C */
diff --git a/ace/Utils/Templates/Auto_IncDec_T.h b/ace/Utils/Templates/Auto_IncDec_T.h
new file mode 100644
index 00000000000..f2a10e498f8
--- /dev/null
+++ b/ace/Utils/Templates/Auto_IncDec_T.h
@@ -0,0 +1,84 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Auto_IncDec_T.h
+ *
+ * $Id$
+ *
+ * @author Edan Ayal <EdanA@cti2.com>
+ */
+//=============================================================================
+
+
+#ifndef ACE_AUTO_INCDEC_T_H
+#define ACE_AUTO_INCDEC_T_H
+#include "ace/pre.h"
+
+#include "ace/OS.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+/**
+ * @class ACE_Auto_IncDec
+ *
+ * @brief This class automatically increments and decrements a
+ * parameterized counter.
+ *
+ * This data structure is meant to be used within a method,
+ * function, or scope. The actual parameter given for the
+ * <ACE_SAFELY_INCREMENTABLE_DECREMENTABLE> template parameter
+ * must provide at least opertaors ++ and --.
+ */
+template <class ACE_SAFELY_INCREMENTABLE_DECREMENTABLE>
+class ACE_Auto_IncDec
+{
+public:
+ // = Initialization and termination methods.
+ /// Implicitly increment the counter.
+ ACE_Auto_IncDec (ACE_SAFELY_INCREMENTABLE_DECREMENTABLE &counter);
+
+ /// Implicitly decrement the counter.
+ ~ACE_Auto_IncDec (void);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+protected:
+ /// Reference to the <ACE_SAFELY_INCREMENTABLE_DECREMENTABLE> counter
+ /// we're incrementing/decrementing.
+ ACE_SAFELY_INCREMENTABLE_DECREMENTABLE &counter_;
+
+private:
+ // = Prevent assignment and initialization.
+ ACE_UNIMPLEMENTED_FUNC (void operator= (const
+ ACE_Auto_IncDec<ACE_SAFELY_INCREMENTABLE_DECREMENTABLE> &))
+ ACE_UNIMPLEMENTED_FUNC (ACE_Auto_IncDec (const
+ ACE_Auto_IncDec<ACE_SAFELY_INCREMENTABLE_DECREMENTABLE> &))
+};
+
+#if defined (__ACE_INLINE__)
+#include "ace/Auto_IncDec_T.i"
+// On non-Win32 platforms, this code will be inlined
+#endif /* __ACE_INLINE__ */
+
+#if defined (ACE_TEMPLATES_REQUIRE_SOURCE)
+#include "ace/Auto_IncDec_T.cpp"
+// On Win32 platforms, this code will be included as template source
+// code and will not be inlined. Therefore, we first turn off
+// ACE_INLINE, set it to be nothing, include the code, and then turn
+// ACE_INLINE back to its original setting. All this nonsense is
+// necessary, since the generic template code that needs to be
+// specialized cannot be inlined, else the compiler will ignore the
+// specialization code. Also, the specialization code *must* be
+// inlined or the compiler will ignore the specializations.
+#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */
+
+#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA)
+#pragma implementation ("Auto_IncDec_T.cpp")
+#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */
+
+#include "ace/post.h"
+#endif /* ACE_AUTO_INCDEC_T_H */
diff --git a/ace/Utils/Templates/Auto_IncDec_T.i b/ace/Utils/Templates/Auto_IncDec_T.i
new file mode 100644
index 00000000000..96658ed76c5
--- /dev/null
+++ b/ace/Utils/Templates/Auto_IncDec_T.i
@@ -0,0 +1,21 @@
+/* -*- C++ -*- */
+// $Id$
+
+// Implicitly and automatically increment the counter.
+
+template <class ACE_SAFELY_INCREMENTABLE_DECREMENTABLE> ACE_INLINE
+ACE_Auto_IncDec<ACE_SAFELY_INCREMENTABLE_DECREMENTABLE>::ACE_Auto_IncDec
+ (ACE_SAFELY_INCREMENTABLE_DECREMENTABLE &counter)
+ : counter_ (counter)
+{
+ ++this->counter_;
+}
+
+// Implicitly and automatically decrement the counter.
+
+template <class ACE_SAFELY_INCREMENTABLE_DECREMENTABLE> ACE_INLINE
+ACE_Auto_IncDec<ACE_SAFELY_INCREMENTABLE_DECREMENTABLE>::~ACE_Auto_IncDec (void)
+{
+ --this->counter_;
+}
+
diff --git a/ace/Utils/Templates/Auto_Ptr.cpp b/ace/Utils/Templates/Auto_Ptr.cpp
new file mode 100644
index 00000000000..888a65d02e7
--- /dev/null
+++ b/ace/Utils/Templates/Auto_Ptr.cpp
@@ -0,0 +1,42 @@
+// Auto_Ptr.cpp
+// $Id$
+
+#if !defined (ACE_AUTO_PTR_C)
+#define ACE_AUTO_PTR_C
+
+#include "ace/Auto_Ptr.h"
+
+#if !defined (__ACE_INLINE__)
+#include "ace/Auto_Ptr.i"
+#endif /* __ACE_INLINE__ */
+
+ACE_RCSID(ace, Auto_Ptr, "$Id$")
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Auto_Basic_Ptr)
+
+template<class X> void
+ACE_Auto_Basic_Ptr<X>::dump (void) const
+{
+ ACE_TRACE ("ACE_Auto_Basic_Ptr<X>::dump");
+}
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Auto_Basic_Array_Ptr)
+
+template<class X> void
+ACE_Auto_Basic_Array_Ptr<X>::dump (void) const
+{
+ ACE_TRACE ("ACE_Auto_Basic_Array_Ptr<X>::dump");
+}
+
+#if defined (__MINGW32__)
+# if defined (ACE_HAS_STANDARD_CPP_LIBRARY) && \
+ (ACE_HAS_STANDARD_CPP_LIBRARY != 0)
+# if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION)
+template alloc;
+# elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA)
+#pragma instantiate alloc
+# endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */
+# endif /* ACE_HAS_STANDARD_CPP_LIBRARY != 0 */
+#endif /* __MINGW32__ */
+
+#endif /* ACE_AUTO_PTR_C */
diff --git a/ace/Utils/Templates/Auto_Ptr.h b/ace/Utils/Templates/Auto_Ptr.h
new file mode 100644
index 00000000000..aa7e0eec35d
--- /dev/null
+++ b/ace/Utils/Templates/Auto_Ptr.h
@@ -0,0 +1,172 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Auto_Ptr.h
+ *
+ * $Id$
+ *
+ * @author Doug Schmidt <schmidt@uci.edu>
+ * @author Irfan Pyarali <irfan@cs.wustl.edu>
+ * @author Jack Reeves <jack@fx.com>
+ * @author Dr. Harald M. Mueller <mueller@garwein.hai.siemens.co.at>
+ */
+//=============================================================================
+
+#ifndef ACE_AUTO_PTR_H
+#define ACE_AUTO_PTR_H
+#include "ace/pre.h"
+
+#include "ace/OS.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+/**
+ * @class ACE_Auto_Basic_Ptr
+ *
+ * @brief Implements the draft C++ standard auto_ptr abstraction.
+ * This class allows one to work on non-object (basic) types
+ */
+template <class X>
+class ACE_Auto_Basic_Ptr
+{
+public:
+ // = Initialization and termination methods
+ ACE_EXPLICIT ACE_Auto_Basic_Ptr (X *p = 0) : p_ (p) {}
+
+ ACE_Auto_Basic_Ptr (ACE_Auto_Basic_Ptr<X> &ap);
+ ACE_Auto_Basic_Ptr<X> &operator= (ACE_Auto_Basic_Ptr<X> &rhs);
+ ~ACE_Auto_Basic_Ptr (void);
+
+ // = Accessor methods.
+ X &operator *() const;
+ X *get (void) const;
+ X *release (void);
+ void reset (X *p = 0);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+protected:
+ X *p_;
+};
+
+#if !defined (ACE_LACKS_AUTO_PTR) && \
+ defined (ACE_HAS_STANDARD_CPP_LIBRARY) && \
+ (ACE_HAS_STANDARD_CPP_LIBRARY != 0)
+#include <memory>
+#if defined (ACE_USES_STD_NAMESPACE_FOR_STDCPP_LIB) && \
+ (ACE_USES_STD_NAMESPACE_FOR_STDCPP_LIB != 0)
+using std::auto_ptr;
+#endif /* ACE_USES_STD_NAMESPACE_FOR_STDCPP_LIB */
+#else /* ACE_HAS_STANDARD_CPP_LIBRARY */
+
+/**
+ * @class auto_ptr
+ *
+ * @brief Implements the draft C++ standard auto_ptr abstraction.
+ */
+template <class X>
+class auto_ptr : public ACE_Auto_Basic_Ptr <X>
+{
+public:
+ // = Initialization and termination methods
+ ACE_EXPLICIT auto_ptr (X *p = 0) : ACE_Auto_Basic_Ptr<X> (p) {}
+
+ X *operator-> () const;
+};
+
+#endif /* ACE_HAS_STANDARD_CPP_LIBRARY */
+
+/**
+ * @class ACE_Auto_Basic_Array_Ptr
+ *
+ * @brief Implements an extension to the draft C++ standard auto_ptr
+ * abstraction. This class allows one to work on non-object
+ * (basic) types that must be treated as an array, e.g.,
+ * deallocated via "delete [] foo".
+ */
+template<class X>
+class ACE_Auto_Basic_Array_Ptr
+{
+public:
+ // = Initialization and termination methods.
+ ACE_EXPLICIT ACE_Auto_Basic_Array_Ptr (X *p = 0) : p_ (p) {}
+
+ ACE_Auto_Basic_Array_Ptr (ACE_Auto_Basic_Array_Ptr<X> &ap);
+ ACE_Auto_Basic_Array_Ptr<X> &operator= (ACE_Auto_Basic_Array_Ptr<X> &rhs);
+ ~ACE_Auto_Basic_Array_Ptr (void);
+
+ // = Accessor methods.
+ X &operator* () const;
+ X &operator[] (int i) const;
+ X *get (void) const;
+ X *release (void);
+ void reset (X *p = 0);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+protected:
+ X *p_;
+};
+
+/**
+ * @class ACE_Auto_Array_Ptr
+ *
+ * @brief Implements an extension to the draft C++ standard auto_ptr
+ * abstraction.
+ */
+template<class X>
+class ACE_Auto_Array_Ptr : public ACE_Auto_Basic_Array_Ptr<X>
+{
+public:
+ // = Initialization and termination methods.
+ ACE_EXPLICIT ACE_Auto_Array_Ptr (X *p = 0)
+ : ACE_Auto_Basic_Array_Ptr<X> (p) {}
+
+ X *operator-> () const;
+};
+
+// Some platforms have an older version of auto_ptr
+// support, which lacks reset, and cannot be disabled
+// easily. Portability to these platforms requires
+// use of the following ACE_AUTO_PTR_RESET macro.
+# if defined (ACE_AUTO_PTR_LACKS_RESET)
+# define ACE_AUTO_PTR_RESET(X,Y,Z) \
+ do { \
+ if (Y != X.get ()) \
+ { \
+ X.release (); \
+ X = auto_ptr<Z> (Y); \
+ } \
+ } while (0)
+# else /* ! ACE_AUTO_PTR_LACKS_RESET */
+# define ACE_AUTO_PTR_RESET(X,Y,Z) \
+ do { \
+ X.reset (Y); \
+ } while (0)
+# endif /* ACE_AUTO_PTR_LACKS_RESET */
+
+#if defined (__ACE_INLINE__)
+#include "ace/Auto_Ptr.i"
+#endif /* __ACE_INLINE__ */
+
+#if defined (ACE_TEMPLATES_REQUIRE_SOURCE)
+#include "ace/Auto_Ptr.cpp"
+#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */
+
+#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA)
+#pragma implementation ("Auto_Ptr.cpp")
+#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */
+
+#include "ace/post.h"
+#endif /* ACE_AUTO_PTR_H */
diff --git a/ace/Utils/Templates/Auto_Ptr.i b/ace/Utils/Templates/Auto_Ptr.i
new file mode 100644
index 00000000000..7fba5b4edfa
--- /dev/null
+++ b/ace/Utils/Templates/Auto_Ptr.i
@@ -0,0 +1,144 @@
+/* -*- C++ -*- */
+// $Id$
+
+// Auto_Ptr.i
+
+template<class X> ACE_INLINE
+ACE_Auto_Basic_Ptr<X>::ACE_Auto_Basic_Ptr (ACE_Auto_Basic_Ptr<X> &rhs)
+ : p_ (rhs.release ())
+{
+ ACE_TRACE ("ACE_Auto_Basic_Ptr<X>::ACE_Auto_Basic_Ptr");
+}
+
+template<class X> ACE_INLINE X *
+ACE_Auto_Basic_Ptr<X>::get (void) const
+{
+ ACE_TRACE ("ACE_Auto_Basic_Ptr<X>::get");
+ return this->p_;
+}
+
+template<class X> ACE_INLINE X *
+ACE_Auto_Basic_Ptr<X>::release (void)
+{
+ ACE_TRACE ("ACE_Auto_Basic_Ptr<X>::release");
+ X *old = this->p_;
+ this->p_ = 0;
+ return old;
+}
+
+template<class X> ACE_INLINE void
+ACE_Auto_Basic_Ptr<X>::reset (X *p)
+{
+ ACE_TRACE ("ACE_Auto_Basic_Ptr<X>::reset");
+ if (this->get () != p)
+ delete this->get ();
+ this->p_ = p;
+}
+
+template<class X> ACE_INLINE ACE_Auto_Basic_Ptr<X> &
+ACE_Auto_Basic_Ptr<X>::operator= (ACE_Auto_Basic_Ptr<X> &rhs)
+{
+ ACE_TRACE ("ACE_Auto_Basic_Ptr<X>::operator=");
+ if (this != &rhs)
+ {
+ this->reset (rhs.release ());
+ }
+ return *this;
+}
+
+template<class X> ACE_INLINE
+ACE_Auto_Basic_Ptr<X>::~ACE_Auto_Basic_Ptr (void)
+{
+ ACE_TRACE ("ACE_Auto_Basic_Ptr<X>::~ACE_Auto_Basic_Ptr");
+ delete this->get ();
+}
+
+template<class X> ACE_INLINE X &
+ACE_Auto_Basic_Ptr<X>::operator *() const
+{
+ ACE_TRACE ("ACE_Auto_Basic_Ptr<X>::operator *()");
+ return *this->get ();
+}
+
+#if defined (ACE_LACKS_AUTO_PTR) || \
+ !defined (ACE_HAS_STANDARD_CPP_LIBRARY) || \
+ (ACE_HAS_STANDARD_CPP_LIBRARY == 0)
+
+template<class X> ACE_INLINE X *
+auto_ptr<X>::operator-> () const
+{
+ ACE_TRACE ("auto_ptr<X>::operator->");
+ return this->get ();
+}
+
+#endif /* ACE_HAS_STANDARD_CPP_LIBRARY */
+
+template<class X> ACE_INLINE X *
+ACE_Auto_Basic_Array_Ptr<X>::get (void) const
+{
+ ACE_TRACE ("ACE_Auto_Basic_Array_Ptr<X>::get");
+ return this->p_;
+}
+
+template<class X> ACE_INLINE X *
+ACE_Auto_Basic_Array_Ptr<X>::release (void)
+{
+ ACE_TRACE ("ACE_Auto_Basic_Array_Ptr<X>::release");
+ X *old = this->p_;
+ this->p_ = 0;
+ return old;
+}
+
+template<class X> ACE_INLINE void
+ACE_Auto_Basic_Array_Ptr<X>::reset (X *p)
+{
+ ACE_TRACE ("ACE_Auto_Basic_Array_Ptr<X>::reset");
+ if (this->get () != p)
+ delete [] this->get ();
+ this->p_ = p;
+}
+
+template<class X> ACE_INLINE
+ACE_Auto_Basic_Array_Ptr<X>::ACE_Auto_Basic_Array_Ptr (ACE_Auto_Basic_Array_Ptr<X> &rhs)
+ : p_ (rhs.release ())
+{
+ ACE_TRACE ("ACE_Auto_Basic_Array_Ptr<X>::ACE_Auto_Basic_Array_Ptr");
+}
+
+template<class X> ACE_INLINE ACE_Auto_Basic_Array_Ptr<X> &
+ACE_Auto_Basic_Array_Ptr<X>::operator= (ACE_Auto_Basic_Array_Ptr<X> &rhs)
+{
+ ACE_TRACE ("ACE_Auto_Basic_Array_Ptr<X>::operator=");
+ if (this != &rhs)
+ {
+ this->reset (rhs.release ());
+ }
+ return *this;
+}
+
+template<class X> ACE_INLINE
+ACE_Auto_Basic_Array_Ptr<X>::~ACE_Auto_Basic_Array_Ptr (void)
+{
+ ACE_TRACE ("ACE_Auto_Basic_Array_Ptr<X>::~ACE_Auto_Basic_Array_Ptr");
+ delete [] this->get ();
+}
+
+template<class X> ACE_INLINE X &
+ACE_Auto_Basic_Array_Ptr<X>::operator *() const
+{
+ return *this->get ();
+}
+
+template<class X> ACE_INLINE X &
+ACE_Auto_Basic_Array_Ptr<X>::operator[](int i) const
+{
+ X *array = this->get ();
+ return array[i];
+}
+
+template<class X> ACE_INLINE X *
+ACE_Auto_Array_Ptr<X>::operator->() const
+{
+ return this->get ();
+}
+
diff --git a/ace/Utils/Templates/Cache_Map_Manager_T.cpp b/ace/Utils/Templates/Cache_Map_Manager_T.cpp
new file mode 100644
index 00000000000..9460c2df16d
--- /dev/null
+++ b/ace/Utils/Templates/Cache_Map_Manager_T.cpp
@@ -0,0 +1,420 @@
+// $Id$
+
+#ifndef ACE_CACHE_MAP_MANAGER_T_C
+#define ACE_CACHE_MAP_MANAGER_T_C
+
+#include "ace/Cache_Map_Manager_T.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+#define ACE_LACKS_PRAGMA_ONCE
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "ace/Malloc.h"
+
+#if !defined (__ACE_INLINE__)
+#include "ace/Cache_Map_Manager_T.i"
+#endif /* __ACE_INLINE__ */
+
+ACE_RCSID(ace, Cache_Map_Manager_T, "$Id$")
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Cache_Map_Manager)
+
+#if !defined (ACE_HAS_BROKEN_EXTENDED_TEMPLATES)
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Cache_Map_Iterator)
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Cache_Map_Reverse_Iterator)
+
+#define ACE_T1 class KEY, class VALUE, class MAP, class ITERATOR_IMPL, class REVERSE_ITERATOR_IMPL, class CACHING_STRATEGY, class ATTRIBUTES
+#define ACE_T2 KEY, VALUE, MAP, ITERATOR_IMPL, REVERSE_ITERATOR_IMPL, CACHING_STRATEGY, ATTRIBUTES
+
+#else
+
+#define ACE_T1 class KEY, class VALUE, class MAP, class CACHING_STRATEGY, class ATTRIBUTES
+#define ACE_T2 KEY, VALUE, MAP, CACHING_STRATEGY, ATTRIBUTES
+
+#endif /* ACE_HAS_BROKEN_EXTENDED_TEMPLATES */
+
+template <ACE_T1>
+ACE_Cache_Map_Manager<ACE_T2>::ACE_Cache_Map_Manager (CACHING_STRATEGY &caching_s,
+ size_t size,
+ ACE_Allocator *alloc)
+ : caching_strategy_ (caching_s)
+{
+ if (this->open (size, alloc) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("%p\n"),
+ ACE_LIB_TEXT ("ACE_Cache_Map_Manager::ACE_Cache_Map_Manager")));
+
+}
+
+template <ACE_T1>
+ACE_Cache_Map_Manager<ACE_T2>::~ACE_Cache_Map_Manager (void)
+{
+ this->close ();
+}
+
+template <ACE_T1> int
+ACE_Cache_Map_Manager<ACE_T2>::open (size_t length,
+ ACE_Allocator *alloc)
+{
+ return this->map_.open (length,
+ alloc);
+}
+
+template <ACE_T1> int
+ACE_Cache_Map_Manager<ACE_T2>::close (void)
+{
+ return this->map_.close ();
+}
+
+template <ACE_T1> int
+ACE_Cache_Map_Manager<ACE_T2>::bind (const KEY &key,
+ const VALUE &value)
+{
+ // Insert an entry which has the <key> and the <cache_value> which
+ // is the combination of the <value> and the attributes of the
+ // caching strategy.
+ CACHE_VALUE cache_value (value,
+ this->caching_strategy_.attributes ());
+
+ int bind_result = this->map_.bind (key,
+ cache_value);
+
+ if (bind_result != -1)
+ {
+
+ int result = this->caching_strategy_.notify_bind (bind_result,
+ cache_value.second ());
+
+ if (result == -1)
+ {
+
+ this->map_.unbind (key);
+
+ // Unless the notification goes thru the bind operation is
+ // not complete.
+ bind_result = -1;
+
+ }
+
+ }
+
+ return bind_result;
+}
+
+
+template <ACE_T1> int
+ACE_Cache_Map_Manager<ACE_T2>::rebind (const KEY &key,
+ const VALUE &value)
+{
+ CACHE_VALUE cache_value (value,
+ this->caching_strategy_.attributes ());
+
+ int rebind_result = this->map_.rebind (key,
+ cache_value);
+
+ if (rebind_result != -1)
+ {
+
+ int result = this->caching_strategy_.notify_rebind (rebind_result,
+ cache_value.second ());
+
+ if (result == -1)
+ {
+
+ // Make sure the unbind operation is done only when the
+ // notification fails after a bind which is denoted by
+ // rebind_result = 0
+ if (rebind_result == 0)
+ this->map_.unbind (key);
+
+ // Unless the notification goes thru the rebind operation is
+ // not complete.
+ rebind_result = -1;
+
+ }
+
+ }
+
+ return rebind_result;
+}
+
+
+template <ACE_T1> int
+ACE_Cache_Map_Manager<ACE_T2>::rebind (const KEY &key,
+ const VALUE &value,
+ VALUE &old_value)
+{
+ CACHE_VALUE cache_value (value,
+ this->caching_strategy_.attributes ());
+
+ CACHE_VALUE old_cache_value (old_value,
+ this->caching_strategy_.attributes ());
+
+ int rebind_result = this->map_.rebind (key,
+ cache_value,
+ old_cache_value);
+
+ if (rebind_result != -1)
+ {
+
+ int result = this->caching_strategy_.notify_rebind (rebind_result,
+ cache_value.second ());
+
+ if (result == -1)
+ {
+
+ // Make sure the unbind operation is done only when the
+ // notification fails after a bind which is denoted by
+ // rebind_result = 0
+ if (rebind_result == 0)
+ this->map_.unbind (key);
+
+ // Unless the notification goes thru the rebind operation is
+ // not complete.
+ rebind_result = -1;
+
+ }
+ else
+ {
+
+ old_value = old_cache_value.first ();
+
+ }
+
+ }
+
+ return rebind_result;
+}
+
+template <ACE_T1> int
+ACE_Cache_Map_Manager<ACE_T2>::rebind (const KEY &key,
+ const VALUE &value,
+ KEY &old_key,
+ VALUE &old_value)
+{
+ CACHE_VALUE cache_value (value,
+ this->caching_strategy_.attributes ());
+
+ CACHE_VALUE old_cache_value (old_value,
+ this->caching_strategy_.attributes ());
+
+ int rebind_result = this->map_.rebind (key,
+ cache_value,
+ old_key,
+ old_cache_value);
+
+ if (rebind_result != -1)
+ {
+
+ int result = this->caching_strategy_.notify_rebind (rebind_result,
+ cache_value.second ());
+
+ if (result == -1)
+ {
+
+ // Make sure the unbind operation is done only when the
+ // notification fails after a bind which is denoted by
+ // rebind_result = 0
+ if (rebind_result == 0)
+ this->map_.unbind (key);
+
+ // Unless the notification goes thru the rebind operation is
+ // not complete.
+ rebind_result = -1;
+
+ }
+ else
+ {
+
+ old_value = old_cache_value.first ();
+
+ }
+
+ }
+
+ return rebind_result;
+}
+
+template <ACE_T1> int
+ACE_Cache_Map_Manager<ACE_T2>::trybind (const KEY &key,
+ VALUE &value)
+{
+ CACHE_VALUE cache_value (value,
+ this->caching_strategy_.attributes ());
+
+ int trybind_result = this->map_.trybind (key,
+ cache_value);
+
+ if (trybind_result != -1)
+ {
+
+ int result = this->caching_strategy_.notify_trybind (trybind_result,
+ cache_value.second ());
+
+ if (result == -1)
+ {
+
+ // If the entry has got inserted into the map, it is removed
+ // due to failure.
+ if (trybind_result == 0)
+ this->map_.unbind (key);
+
+ trybind_result = -1;
+
+ }
+ else
+ {
+
+ // If an attempt is made to bind an existing entry the value
+ // is overwritten with the value from the map.
+ if (trybind_result == 1)
+ value = cache_value.first ();
+
+ }
+
+ }
+
+ return trybind_result;
+}
+
+template <ACE_T1> int
+ACE_Cache_Map_Manager<ACE_T2>::find (const KEY &key,
+ VALUE &value)
+{
+ // Lookup the key and populate the <value>.
+ CACHE_VALUE cache_value;
+
+ int find_result = this->map_.find (key,
+ cache_value);
+
+ if (find_result != -1)
+ {
+
+ int result = this->caching_strategy_.notify_find (find_result,
+ cache_value.second ());
+
+ // Unless the find and notification operations go thru, this
+ // method is not successful.
+ if (result == -1)
+ find_result = -1;
+ else
+ {
+
+ // Since the <cache_value> has now changed after the
+ // notification, we need to bind to the map again.
+ int rebind_result = this->map_.rebind (key,
+ cache_value);
+ if (rebind_result == -1)
+ find_result = -1;
+ else
+ value = cache_value.first ();
+
+ }
+
+ }
+
+ return find_result;
+}
+
+template <ACE_T1> int
+ACE_Cache_Map_Manager<ACE_T2>::find (const KEY &key)
+{
+ // Lookup the key and populate the <value>.
+ CACHE_VALUE cache_value;
+
+ int find_result = this->map_.find (key,
+ cache_value);
+
+ if (find_result != -1)
+ {
+
+ int result = this->caching_strategy_.notify_find (find_result,
+ cache_value.second ());
+
+ // Unless the find and notification operations go thru, this
+ // method is not successful.
+ if (result == -1)
+ find_result = -1;
+ else
+ {
+
+ // Since the <cache_value> has now changed after the
+ // notification, we need to bind to the map again.
+ int rebind_result = this->map_.rebind (key,
+ cache_value);
+
+ if (rebind_result == -1)
+ find_result = -1;
+
+ }
+
+ }
+
+ return find_result;
+}
+
+
+template <ACE_T1> int
+ACE_Cache_Map_Manager<ACE_T2>::unbind (const KEY &key)
+{
+ // Remove the entry from the cache.
+ CACHE_VALUE cache_value;
+
+ int unbind_result = this->map_.unbind (key,
+ cache_value);
+
+ if (unbind_result != -1)
+ {
+
+ int result = this->caching_strategy_.notify_unbind (unbind_result,
+ cache_value.second ());
+
+ if (result == -1)
+ unbind_result = -1;
+
+ }
+
+ return unbind_result;
+}
+
+template <ACE_T1> int
+ACE_Cache_Map_Manager<ACE_T2>::unbind (const KEY &key,
+ VALUE &value)
+{
+ // Remove the entry from the cache.
+ CACHE_VALUE cache_value;
+
+ int unbind_result = this->map_.unbind (key,
+ cache_value);
+
+ if (unbind_result != -1)
+ {
+
+ int result = this->caching_strategy_.notify_unbind (unbind_result,
+ cache_value.second ());
+
+ if (result == -1)
+ unbind_result = -1;
+ else
+ value = cache_value.first ();
+
+ }
+
+ return unbind_result;
+}
+
+
+template <ACE_T1> void
+ACE_Cache_Map_Manager<ACE_T2>::dump (void) const
+{
+ this->map_.dump ();
+
+ this->caching_strategy_.dump ();
+}
+
+#undef ACE_T1
+#undef ACE_T2
+
+#endif /* ACE_CACHE_MAP_MANAGER_T_C */
diff --git a/ace/Utils/Templates/Cache_Map_Manager_T.h b/ace/Utils/Templates/Cache_Map_Manager_T.h
new file mode 100644
index 00000000000..cef4f7ab99f
--- /dev/null
+++ b/ace/Utils/Templates/Cache_Map_Manager_T.h
@@ -0,0 +1,425 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Cache_Map_Manager_T.h
+ *
+ * $Id$
+ *
+ * @author Kirthika Parameswaran <kirthika@cs.wustl.edu>
+ */
+//=============================================================================
+
+
+#ifndef CACHE_MAP_MANAGER_T_H
+#define CACHE_MAP_MANAGER_T_H
+#include "ace/pre.h"
+
+#include "ace/OS.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+#define ACE_LACKS_PRAGMA_ONCE
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "ace/Pair_T.h"
+
+// Forward declaration.
+class ACE_Allocator;
+
+#if !defined (ACE_HAS_BROKEN_EXTENDED_TEMPLATES)
+
+#define ACE_Cache_Map_Iterator ACMI
+#define ACE_Cache_Map_Reverse_Iterator ACMRI
+
+template <class KEY, class VALUE, class IMPLEMENTATION, class CACHING_STRATEGY, class ATTRIBUTES>
+class ACE_Cache_Map_Iterator;
+
+template <class KEY, class VALUE, class REVERSE_IMPLEMENTATION, class CACHING_STRATEGY, class ATTRIBUTES>
+class ACE_Cache_Map_Reverse_Iterator;
+
+#define ACE_T1 class KEY, class VALUE, class MAP, class ITERATOR_IMPL, class REVERSE_ITERATOR_IMPL, class CACHING_STRATEGY, class ATTRIBUTES
+#define ACE_T2 KEY, VALUE, MAP, ITERATOR_IMPL, REVERSE_ITERATOR_IMPL, CACHING_STRATEGY, ATTRIBUTES
+
+#else
+
+#define ACE_T1 class KEY, class VALUE, class MAP, class CACHING_STRATEGY, class ATTRIBUTES
+#define ACE_T2 KEY, VALUE, MAP, CACHING_STRATEGY, ATTRIBUTES
+
+#endif /* ACE_HAS_BROKEN_EXTENDED_TEMPLATES */
+
+// For linkers that cant grok long names.
+#define ACE_Cache_Map_Manager ACMM
+
+/**
+ * @class ACE_Cache_Map_Manager
+ *
+ * @brief Defines a abstraction that will purge entries from a map.
+ *
+ * The <ACE_Cache_Map_Manager> will manage the map it contains
+ * and provide purging on demand from the map. The strategy for
+ * caching is decided by the user and provided to the Cache
+ * Manager. The Cache Manager acts as a agent and communicates
+ * between the Map and the Strategy for purging entries from the
+ * map.
+ * No locking mechanism provided since locking at this level
+ * isn't efficient. Locking has to be provided by the
+ * application.
+ */
+template <ACE_T1>
+class ACE_Cache_Map_Manager
+{
+public:
+
+ // = Traits.
+ typedef KEY key_type;
+ typedef VALUE mapped_type;
+ typedef MAP map_type;
+ typedef CACHING_STRATEGY caching_strategy_type;
+
+#if !defined (ACE_HAS_BROKEN_EXTENDED_TEMPLATES)
+
+ typedef ITERATOR_IMPL ITERATOR_IMPLEMENTATION;
+ typedef REVERSE_ITERATOR_IMPL REVERSE_ITERATOR_IMPLEMENTATION;
+
+ friend class ACE_Cache_Map_Iterator<KEY, VALUE, ITERATOR_IMPLEMENTATION, CACHING_STRATEGY, ATTRIBUTES>;
+ friend class ACE_Cache_Map_Reverse_Iterator<KEY, VALUE, REVERSE_ITERATOR_IMPLEMENTATION, CACHING_STRATEGY, ATTRIBUTES>;
+
+ // = ACE-style iterator typedefs.
+ typedef ACE_Cache_Map_Iterator<KEY, VALUE, ITERATOR_IMPLEMENTATION, CACHING_STRATEGY, ATTRIBUTES>
+ ITERATOR;
+ typedef ACE_Cache_Map_Reverse_Iterator<KEY, VALUE, REVERSE_ITERATOR_IMPLEMENTATION, CACHING_STRATEGY, ATTRIBUTES>
+ REVERSE_ITERATOR;
+
+ // = STL-style iterator typedefs.
+ typedef ITERATOR
+ iterator;
+ typedef REVERSE_ITERATOR
+ reverse_iterator;
+
+#endif /* ACE_HAS_BROKEN_EXTENDED_TEMPLATES */
+
+ /**
+ * The actual value mapped to the key in the map. The <attributes>
+ * are used by the strategy and is transparent to the user of this
+ * class.
+ */
+ typedef ACE_Pair<VALUE, ATTRIBUTES> CACHE_VALUE;
+
+ // = Initialization and termination methods.
+
+ /// Initialize a <Cache_Map_Manager> with <caching_strategy> and
+ /// <size> entries.
+ ACE_Cache_Map_Manager (CACHING_STRATEGY &caching_strategy,
+ size_t size = ACE_DEFAULT_MAP_SIZE,
+ ACE_Allocator *alloc = 0);
+
+ /// Close down a <Cache_Map_Manager> and release dynamically allocated
+ /// resources.
+ virtual ~ACE_Cache_Map_Manager (void);
+
+ /// Initialize a cache with size <length>.
+ int open (size_t length = ACE_DEFAULT_MAP_SIZE,
+ ACE_Allocator *alloc = 0);
+
+ /// Close down a cache and release dynamically allocated resources.
+ int close (void);
+
+ /**
+ * Associate <key> with <value>. If <key> is already in the MAP
+ * then the ENTRY is not changed. Returns 0 if a new entry is bound
+ * successfully, returns 1 if an attempt is made to bind an existing
+ * entry, and returns -1 if failures occur.
+ */
+ int bind (const KEY &key,
+ const VALUE &value);
+
+ /**
+ * Lookup entry<key,value> in the cache. If it is not found, returns -1.
+ * If the <key> is located in the MAP object, the CACHING_STRATEGY is
+ * notified of it via notify_find (int result, ATTRIBUTES &attribute).
+ * If notify_find also returns 0 (success), then this function returns
+ * 0 (success) and sets the cached value in <value>.
+ */
+ int find (const KEY &key,
+ VALUE &value);
+
+ /**
+ * Lookup entry<key,value> in the cache. If it is not found, returns -1.
+ * If the <key> is located in the MAP object, the CACHING_STRATEGY is
+ * notified of it via notify_find (int result, ATTRIBUTES &attribute).
+ * If notify_find also returns 0 (success), then this function returns
+ * 0 (success).
+ */
+ int find (const KEY &key);
+
+ /**
+ * Reassociate the <key> with <value>. If the <key> already exists
+ * in the cache then returns 1, on a new bind returns 0 and returns
+ * -1 in case of any failures.
+ */
+ int rebind (const KEY &key,
+ const VALUE &value);
+
+ /**
+ * Reassociate <key> with <value>, storing the old value into the
+ * "out" parameter <old_value>. The function fails if <key> is not
+ * in the cache for caches that do not allow user specified keys.
+ * However, for caches that allow user specified keys, if the key is
+ * not in the cache, a new <key>/<value> association is created.
+ */
+ int rebind (const KEY &key,
+ const VALUE &value,
+ VALUE &old_value);
+
+ /**
+ * Reassociate <key> with <value>, storing the old key and value
+ * into the "out" parameters <old_key> and <old_value>. The
+ * function fails if <key> is not in the cache for caches that do
+ * not allow user specified keys. However, for caches that allow
+ * user specified keys, if the key is not in the cache, a new
+ * <key>/<value> association is created.
+ */
+ int rebind (const KEY &key,
+ const VALUE &value,
+ KEY &old_key,
+ VALUE &old_value);
+
+ /**
+ * Associate <key> with <value> if and only if <key> is not in the
+ * cache. If <key> is already in the cache, then the <value>
+ * parameter is overwritten with the existing value in the
+ * cache. Returns 0 if a new <key>/<value> association is created.
+ * Returns 1 if an attempt is made to bind an existing entry. This
+ * function fails for maps that do not allow user specified keys.
+ */
+ int trybind (const KEY &key,
+ VALUE &value);
+
+ /// Remove <key> from the cache.
+ int unbind (const KEY &key);
+
+ /// Remove <key> from the cache, and return the <value> associated with
+ /// <key>.
+ int unbind (const KEY &key,
+ VALUE &value);
+
+ /// Remove entries from the cache depending upon the strategy.
+ int purge (void);
+
+ /// Return the current size of the cache.
+ size_t current_size (void) const;
+
+ /// Return the total size of the cache.
+ size_t total_size (void) const;
+
+ /// Dumps the state of the object.
+ void dump (void) const;
+
+#if !defined (ACE_HAS_BROKEN_EXTENDED_TEMPLATES)
+
+ // = STL styled iterator factory functions.
+
+ /// Return forward iterator.
+ ITERATOR begin (void);
+ ITERATOR end (void);
+
+ /// Return reverse iterator.
+ REVERSE_ITERATOR rbegin (void);
+ REVERSE_ITERATOR rend (void);
+
+#endif /* ACE_HAS_BROKEN_EXTENDED_TEMPLATES */
+
+ /// The map managed by the Cache_Map_Manager.
+ MAP &map (void);
+
+ /// The caching strategy used on the cache.
+ CACHING_STRATEGY &caching_strategy (void);
+
+protected:
+
+ /// The underlying map which needs to be cached.
+ MAP map_;
+
+ /// The strategy to be followed for caching entries in the map.
+ CACHING_STRATEGY &caching_strategy_;
+
+private:
+
+ // = Disallow these operations.
+ ACE_UNIMPLEMENTED_FUNC (void operator= (const ACE_Cache_Map_Manager<ACE_T2> &))
+ ACE_UNIMPLEMENTED_FUNC (ACE_Cache_Map_Manager (const ACE_Cache_Map_Manager<ACE_T2> &))
+
+};
+
+#if !defined (ACE_HAS_BROKEN_EXTENDED_TEMPLATES)
+
+/**
+ * @class ACE_Cache_Map_Iterator
+ *
+ * @brief Defines a iterator for the Cache_Map_Manager.
+ *
+ * Implementation to be provided by the iterator of the map
+ * managed by the ACE_Cache_Map_Manager.
+ */
+template <class KEY, class VALUE, class IMPLEMENTATION, class CACHING_STRATEGY, class ATTRIBUTES>
+class ACE_Cache_Map_Iterator
+{
+
+public:
+
+ // = Traits.
+ /// The actual value mapped to the key in the cache. The <attributes>
+ /// are used by the strategy and is transperant to the cache user.
+ typedef ACE_Reference_Pair<KEY, VALUE>
+ value_type;
+ typedef ACE_Pair <VALUE, ATTRIBUTES>
+ CACHE_VALUE;
+
+ // = Initialisation and termination methods.
+
+ ACE_Cache_Map_Iterator (const IMPLEMENTATION &iterator_impl);
+
+ /// Copy constructor.
+ ACE_Cache_Map_Iterator (const ACE_Cache_Map_Iterator<KEY, VALUE, IMPLEMENTATION, CACHING_STRATEGY, ATTRIBUTES> &rhs);
+
+ virtual ~ACE_Cache_Map_Iterator (void);
+
+ // = Iteration methods.
+
+ /// assignment operator.
+ ACE_Cache_Map_Iterator <KEY, VALUE, IMPLEMENTATION,
+ CACHING_STRATEGY, ATTRIBUTES> &operator=
+ (const ACE_Cache_Map_Iterator<KEY, VALUE, IMPLEMENTATION,
+ CACHING_STRATEGY, ATTRIBUTES> &rhs);
+
+ /// Comparision operators.
+ int operator== (const ACE_Cache_Map_Iterator<KEY, VALUE, IMPLEMENTATION, CACHING_STRATEGY, ATTRIBUTES> &rhs) const;
+ int operator!= (const ACE_Cache_Map_Iterator<KEY, VALUE, IMPLEMENTATION, CACHING_STRATEGY, ATTRIBUTES> &rhs) const;
+
+ /// Returns a reference to the internal element <this> is pointing
+ /// to.
+ ACE_Reference_Pair<KEY, VALUE> operator* (void) const;
+
+ // = STL styled iteration, compare, and reference functions.
+
+ /// Prefix advance
+ ACE_Cache_Map_Iterator<KEY, VALUE, IMPLEMENTATION, CACHING_STRATEGY, ATTRIBUTES> &operator++ (void);
+
+ /// Postfix advance.
+ ACE_Cache_Map_Iterator<KEY, VALUE, IMPLEMENTATION, CACHING_STRATEGY, ATTRIBUTES> operator++ (int);
+
+ /// Prefix reverse.
+ ACE_Cache_Map_Iterator<KEY, VALUE, IMPLEMENTATION, CACHING_STRATEGY, ATTRIBUTES> &operator-- (void);
+
+ /// Postfix reverse.
+ ACE_Cache_Map_Iterator<KEY, VALUE, IMPLEMENTATION, CACHING_STRATEGY, ATTRIBUTES> operator-- (int);
+
+ /// Returns the iterator of the internal map in the custody of the
+ /// Cache_Map_Manager.
+ IMPLEMENTATION &iterator_implementation (void);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+protected:
+ /// The actual iterator which iterates internally on the map
+ /// belonging to the Cache_Map_Manager.
+ IMPLEMENTATION iterator_implementation_;
+};
+
+/**
+ * @class ACE_Cache_Map_Reverse_Iterator
+ *
+ * @brief Defines a reverse iterator for the Cache_Map_Manager.
+ *
+ * Implementation to be provided by the reverse iterator of the map
+ * managed by thr Cache_Map_manager.
+ */
+template <class KEY, class VALUE, class REVERSE_IMPLEMENTATION, class CACHING_STRATEGY, class ATTRIBUTES>
+class ACE_Cache_Map_Reverse_Iterator
+{
+public:
+
+ // = Traits.
+ /// The actual value mapped to the key in the cache. The <attributes>
+ /// are used by the strategy and is transperant to the cache user.
+ typedef ACE_Reference_Pair<KEY, VALUE> value_type;
+ typedef ACE_Pair <VALUE, ATTRIBUTES> CACHE_VALUE;
+
+ // = Initialisation and termination methods.
+
+ ACE_Cache_Map_Reverse_Iterator (const REVERSE_IMPLEMENTATION &iterator_impl);
+
+ /// Copy constructor.
+ ACE_Cache_Map_Reverse_Iterator (const ACE_Cache_Map_Reverse_Iterator<KEY, VALUE, REVERSE_IMPLEMENTATION, CACHING_STRATEGY, ATTRIBUTES> &rhs);
+
+ ~ACE_Cache_Map_Reverse_Iterator (void);
+
+ // = Iteration methods.
+
+ /// Assignment operator.
+ ACE_Cache_Map_Reverse_Iterator <KEY, VALUE, REVERSE_IMPLEMENTATION,
+ CACHING_STRATEGY, ATTRIBUTES> &operator=
+ (const ACE_Cache_Map_Reverse_Iterator<KEY, VALUE, REVERSE_IMPLEMENTATION,
+ CACHING_STRATEGY, ATTRIBUTES> &rhs);
+
+ /// Comparision operators.
+ int operator== (const ACE_Cache_Map_Reverse_Iterator<KEY, VALUE, REVERSE_IMPLEMENTATION, CACHING_STRATEGY, ATTRIBUTES> &rhs) const;
+ int operator!= (const ACE_Cache_Map_Reverse_Iterator<KEY, VALUE, REVERSE_IMPLEMENTATION, CACHING_STRATEGY, ATTRIBUTES> &rhs) const;
+
+ /// Returns a reference to the internal element <this> is pointing
+ /// to.
+ ACE_Reference_Pair<KEY, VALUE> operator* (void) const;
+
+ // = STL styled iteration, compare, and reference functions.
+
+ /// Prefix advance
+ ACE_Cache_Map_Reverse_Iterator<KEY, VALUE, REVERSE_IMPLEMENTATION, CACHING_STRATEGY, ATTRIBUTES> &operator++ (void);
+
+ /// Postfix advance.
+ ACE_Cache_Map_Reverse_Iterator<KEY, VALUE, REVERSE_IMPLEMENTATION, CACHING_STRATEGY, ATTRIBUTES> operator++ (int);
+
+ /// Prefix reverse.
+ ACE_Cache_Map_Reverse_Iterator<KEY, VALUE, REVERSE_IMPLEMENTATION, CACHING_STRATEGY, ATTRIBUTES> &operator-- (void);
+
+ /// Postfix reverse.
+ ACE_Cache_Map_Reverse_Iterator<KEY, VALUE, REVERSE_IMPLEMENTATION, CACHING_STRATEGY, ATTRIBUTES> operator-- (int);
+
+ /// Returns the iterator of the internal map in the custody of the
+ /// Cache_Map_Manager.
+ REVERSE_IMPLEMENTATION &iterator_implementation (void);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+protected:
+ /// The actual iterator which iterates internally on the map
+ /// belonging to the Cache_Map_Manager.
+ REVERSE_IMPLEMENTATION reverse_iterator_implementation_;
+};
+
+#endif /* ACE_HAS_BROKEN_EXTENDED_TEMPLATES */
+
+#undef ACE_T1
+#undef ACE_T2
+
+#if defined (__ACE_INLINE__)
+#include "ace/Cache_Map_Manager_T.i"
+#endif /* __ACE_INLINE__ */
+
+#if defined (ACE_TEMPLATES_REQUIRE_SOURCE)
+#include "ace/Cache_Map_Manager_T.cpp"
+#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */
+
+#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA)
+#pragma implementation ("Cache_Map_Manager_T.cpp")
+#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */
+
+#include "ace/post.h"
+#endif /* CACHE_MAP_MANAGER_T_H */
diff --git a/ace/Utils/Templates/Cache_Map_Manager_T.i b/ace/Utils/Templates/Cache_Map_Manager_T.i
new file mode 100644
index 00000000000..ab90786fe1b
--- /dev/null
+++ b/ace/Utils/Templates/Cache_Map_Manager_T.i
@@ -0,0 +1,273 @@
+/* -*- C++ -*- */
+//$Id$
+
+#if !defined (ACE_HAS_BROKEN_EXTENDED_TEMPLATES)
+
+#define ACE_T1 class KEY, class VALUE, class MAP, class ITERATOR_IMPL, class REVERSE_ITERATOR_IMPL, class CACHING_STRATEGY, class ATTRIBUTES
+#define ACE_T2 KEY, VALUE, MAP, ITERATOR_IMPL, REVERSE_ITERATOR_IMPL, CACHING_STRATEGY, ATTRIBUTES
+
+#else
+
+#define ACE_T1 class KEY, class VALUE, class MAP, class CACHING_STRATEGY, class ATTRIBUTES
+#define ACE_T2 KEY, VALUE, MAP, CACHING_STRATEGY, ATTRIBUTES
+
+#endif /* ACE_HAS_BROKEN_EXTENDED_TEMPLATES */
+
+template <ACE_T1> ACE_INLINE int
+ACE_Cache_Map_Manager<ACE_T2>::purge (void)
+{
+ return this->caching_strategy ().caching_utility ().clear_cache (this->map_,
+ this->caching_strategy ().purge_percent ());
+}
+
+template <ACE_T1> ACE_INLINE size_t
+ACE_Cache_Map_Manager<ACE_T2>::current_size (void) const
+{
+ return this->map_.current_size ();
+}
+
+template <ACE_T1> ACE_INLINE size_t
+ACE_Cache_Map_Manager<ACE_T2>::total_size (void) const
+{
+ return this->map_.total_size ();
+}
+
+template <ACE_T1> ACE_INLINE MAP &
+ACE_Cache_Map_Manager<ACE_T2>::map (void)
+{
+ return this->map_;
+}
+
+template <ACE_T1> ACE_INLINE CACHING_STRATEGY &
+ACE_Cache_Map_Manager<ACE_T2>::caching_strategy (void)
+{
+ return this->caching_strategy_;
+}
+
+#if !defined (ACE_HAS_BROKEN_EXTENDED_TEMPLATES)
+
+template <ACE_T1> ACE_INLINE ACE_Cache_Map_Iterator<KEY, VALUE, ITERATOR_IMPL, CACHING_STRATEGY, ATTRIBUTES>
+ACE_Cache_Map_Manager<ACE_T2>::begin (void)
+{
+ return ITERATOR (this->map_.begin ());
+}
+
+template <ACE_T1> ACE_INLINE ACE_Cache_Map_Iterator<KEY, VALUE, ITERATOR_IMPL, CACHING_STRATEGY, ATTRIBUTES>
+ACE_Cache_Map_Manager<ACE_T2>::end (void)
+{
+ return ITERATOR (this->map_.end ());
+}
+
+template <ACE_T1> ACE_INLINE ACE_Cache_Map_Reverse_Iterator<KEY, VALUE, REVERSE_ITERATOR_IMPL, CACHING_STRATEGY, ATTRIBUTES>
+ACE_Cache_Map_Manager<ACE_T2>::rbegin (void)
+{
+ return REVERSE_ITERATOR (this->map_.rbegin ());
+}
+template <ACE_T1> ACE_INLINE ACE_Cache_Map_Reverse_Iterator<KEY, VALUE, REVERSE_ITERATOR_IMPL, CACHING_STRATEGY, ATTRIBUTES>
+ACE_Cache_Map_Manager<ACE_T2>::rend (void)
+{
+ return REVERSE_ITERATOR (this->map_.rend ());
+}
+
+#undef ACE_T1
+#undef ACE_T2
+
+////////////////////////////////////////////////////////////////////////////////
+
+#define ACE_T1 class KEY, class VALUE, class IMPLEMENTATION, class CACHING_STRATEGY, class ATTRIBUTES
+#define ACE_T2 KEY, VALUE, IMPLEMENTATION, CACHING_STRATEGY, ATTRIBUTES
+
+template <ACE_T1> ACE_INLINE
+ACE_Cache_Map_Iterator<ACE_T2>::ACE_Cache_Map_Iterator (const ACE_Cache_Map_Iterator <ACE_T2> &rhs)
+ : iterator_implementation_ (rhs.iterator_implementation_)
+{
+}
+
+template <ACE_T1> ACE_INLINE
+ACE_Cache_Map_Iterator<ACE_T2>::~ACE_Cache_Map_Iterator (void)
+{
+}
+
+template <ACE_T1> ACE_INLINE ACE_Cache_Map_Iterator<ACE_T2> &
+ACE_Cache_Map_Iterator<ACE_T2>::operator= (const ACE_Cache_Map_Iterator<ACE_T2> &rhs)
+{
+ this->iterator_implementation_ = rhs.iterator_implementation_;
+ return *this;
+}
+
+template <ACE_T1> ACE_INLINE int
+ACE_Cache_Map_Iterator<ACE_T2>::operator== (const ACE_Cache_Map_Iterator<ACE_T2> &rhs) const
+{
+ return this->iterator_implementation_ == rhs.iterator_implementation_;
+}
+
+template <ACE_T1> ACE_INLINE int
+ACE_Cache_Map_Iterator<ACE_T2>::operator!= (const ACE_Cache_Map_Iterator<ACE_T2> &rhs) const
+{
+ return this->iterator_implementation_ != rhs.iterator_implementation_;
+}
+
+template <ACE_T1> ACE_INLINE ACE_Reference_Pair<KEY, VALUE>
+ACE_Cache_Map_Iterator<ACE_T2>::operator* (void) const
+{
+ value_type retn ((*this->iterator_implementation_).ext_id_,
+ (*this->iterator_implementation_).int_id_.first ());
+ return retn;
+}
+
+template <ACE_T1> ACE_INLINE
+ACE_Cache_Map_Iterator<ACE_T2> &
+ACE_Cache_Map_Iterator<ACE_T2>::operator++ (void)
+{
+ ++this->iterator_implementation_;
+ return *this;
+}
+
+template <ACE_T1> ACE_INLINE
+ACE_Cache_Map_Iterator<ACE_T2>
+ACE_Cache_Map_Iterator<ACE_T2>::operator++ (int)
+{
+ ACE_Cache_Map_Iterator<ACE_T2> retn = *this;
+ ++this->iterator_implementation_;
+ return retn;
+}
+
+template <ACE_T1> ACE_INLINE
+ACE_Cache_Map_Iterator<ACE_T2> &
+ACE_Cache_Map_Iterator<ACE_T2>::operator-- (void)
+{
+ --this->iterator_implementation_;
+ return *this;
+}
+
+template <ACE_T1> ACE_INLINE
+ACE_Cache_Map_Iterator<ACE_T2>
+ACE_Cache_Map_Iterator<ACE_T2>::operator-- (int)
+{
+ ACE_Cache_Map_Iterator<ACE_T2> retn = *this;
+ --this->iterator_implementation_;
+ return retn;
+}
+
+
+template <ACE_T1> ACE_INLINE void
+ACE_Cache_Map_Iterator<ACE_T2>::dump (void) const
+{
+ this->iterator_implementation_.dump ();
+}
+
+template <ACE_T1> ACE_INLINE
+ACE_Cache_Map_Iterator<ACE_T2>::ACE_Cache_Map_Iterator (const IMPLEMENTATION &iterator_impl)
+ : iterator_implementation_ (iterator_impl)
+{
+}
+
+template <ACE_T1> ACE_INLINE IMPLEMENTATION &
+ACE_Cache_Map_Iterator<ACE_T2>::iterator_implementation (void)
+{
+ return this->iterator_implementation_;
+}
+
+#undef ACE_T1
+#undef ACE_T2
+
+////////////////////////////////////////////////////////////////////////////////
+
+#define ACE_T1 class KEY, class VALUE, class REVERSE_IMPLEMENTATION, class CACHING_STRATEGY, class ATTRIBUTES
+#define ACE_T2 KEY, VALUE, REVERSE_IMPLEMENTATION, CACHING_STRATEGY, ATTRIBUTES
+
+template <ACE_T1> ACE_INLINE
+ACE_Cache_Map_Reverse_Iterator<ACE_T2>::ACE_Cache_Map_Reverse_Iterator (const ACE_Cache_Map_Reverse_Iterator <ACE_T2> &rhs)
+ : reverse_iterator_implementation_ (rhs.reverse_iterator_implementation_)
+{
+}
+
+template <ACE_T1> ACE_INLINE
+ACE_Cache_Map_Reverse_Iterator<ACE_T2>::~ACE_Cache_Map_Reverse_Iterator (void)
+{
+}
+
+template <ACE_T1> ACE_INLINE ACE_Cache_Map_Reverse_Iterator<ACE_T2> &
+ACE_Cache_Map_Reverse_Iterator<ACE_T2>::operator= (const ACE_Cache_Map_Reverse_Iterator<ACE_T2> &rhs)
+{
+ this->reverse_iterator_implementation_ = rhs.reverse_iterator_implementation_;
+ return *this;
+}
+
+template <ACE_T1> ACE_INLINE int
+ACE_Cache_Map_Reverse_Iterator<ACE_T2>::operator== (const ACE_Cache_Map_Reverse_Iterator<ACE_T2> &rhs) const
+{
+ return this->reverse_iterator_implementation_ == rhs.reverse_iterator_implementation_;
+}
+
+template <ACE_T1> ACE_INLINE int
+ACE_Cache_Map_Reverse_Iterator<ACE_T2>::operator!= (const ACE_Cache_Map_Reverse_Iterator<ACE_T2> &rhs) const
+{
+ return this->reverse_iterator_implementation_ != rhs.reverse_iterator_implementation_;
+}
+
+template <ACE_T1> ACE_INLINE ACE_Reference_Pair<KEY, VALUE>
+ACE_Cache_Map_Reverse_Iterator<ACE_T2>::operator* (void) const
+{
+ value_type retv ((*this->reverse_iterator_implementation_).ext_id_,
+ (*this->reverse_iterator_implementation_).int_id_.first ());
+ return retv;
+}
+
+template <ACE_T1> ACE_INLINE
+ACE_Cache_Map_Reverse_Iterator<ACE_T2> &
+ACE_Cache_Map_Reverse_Iterator<ACE_T2>::operator++ (void)
+{
+ ++this->reverse_iterator_implementation_;
+ return *this;
+}
+
+template <ACE_T1> ACE_INLINE
+ACE_Cache_Map_Reverse_Iterator<ACE_T2>
+ACE_Cache_Map_Reverse_Iterator<ACE_T2>::operator++ (int)
+{
+ ACE_Cache_Map_Reverse_Iterator<ACE_T2> retn = *this;
+ ++this->reverse_iterator_implementation_;
+ return retn;
+}
+
+template <ACE_T1> ACE_INLINE
+ACE_Cache_Map_Reverse_Iterator<ACE_T2> &
+ACE_Cache_Map_Reverse_Iterator<ACE_T2>::operator-- (void)
+{
+ --this->reverse_iterator_implementation_;
+ return *this;
+}
+
+template <ACE_T1> ACE_INLINE
+ACE_Cache_Map_Reverse_Iterator<ACE_T2>
+ACE_Cache_Map_Reverse_Iterator<ACE_T2>::operator-- (int)
+{
+ ACE_Cache_Map_Reverse_Iterator<ACE_T2> retn = *this;
+ --this->reverse_iterator_implementation_;
+ return retn;
+}
+
+
+template <ACE_T1> ACE_INLINE void
+ACE_Cache_Map_Reverse_Iterator<ACE_T2>::dump (void) const
+{
+ this->reverse_iterator_implementation_.dump ();
+}
+
+template <ACE_T1> ACE_INLINE
+ACE_Cache_Map_Reverse_Iterator<ACE_T2>::ACE_Cache_Map_Reverse_Iterator (const REVERSE_IMPLEMENTATION &iterator_impl)
+ : reverse_iterator_implementation_(iterator_impl)
+{
+}
+
+template <ACE_T1> ACE_INLINE REVERSE_IMPLEMENTATION &
+ACE_Cache_Map_Reverse_Iterator<ACE_T2>::iterator_implementation (void)
+{
+ return this->reverse_iterator_implementation_;
+}
+
+#endif /* ACE_HAS_BROKEN_EXTENDED_TEMPLATES */
+
+#undef ACE_T1
+#undef ACE_T2
diff --git a/ace/Utils/Templates/Cached_Connect_Strategy_T.cpp b/ace/Utils/Templates/Cached_Connect_Strategy_T.cpp
new file mode 100644
index 00000000000..0086f9d001f
--- /dev/null
+++ b/ace/Utils/Templates/Cached_Connect_Strategy_T.cpp
@@ -0,0 +1,775 @@
+//$Id$
+
+#ifndef CACHED_CONNECT_STRATEGY_T_C
+#define CACHED_CONNECT_STRATEGY_T_C
+
+#include "ace/Cached_Connect_Strategy_T.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+#define ACE_LACKS_PRAGMA_ONCE
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "ace/ACE.h"
+#include "ace/Service_Repository.h"
+#include "ace/Synch.h"
+#include "ace/Service_Types.h"
+#include "ace/Thread_Manager.h"
+#include "ace/WFMO_Reactor.h"
+#include "ace/Pair_T.h"
+
+ACE_RCSID(ace, Cached_Connect_Strategy_T, "$Id$")
+
+#define ACE_T1 class SVC_HANDLER, ACE_PEER_CONNECTOR_1, class CACHING_STRATEGY, class ATTRIBUTES, class MUTEX
+#define ACE_T2 SVC_HANDLER, ACE_PEER_CONNECTOR_2, CACHING_STRATEGY, ATTRIBUTES, MUTEX
+
+template <ACE_T1>
+ACE_Cached_Connect_Strategy_Ex<ACE_T2>::ACE_Cached_Connect_Strategy_Ex
+(CACHING_STRATEGY &caching_s,
+ ACE_Creation_Strategy<SVC_HANDLER> *cre_s,
+ ACE_Concurrency_Strategy<SVC_HANDLER> *con_s,
+ ACE_Recycling_Strategy<SVC_HANDLER> *rec_s,
+ MUTEX *lock,
+ int delete_lock)
+ : CCSBASE (cre_s, con_s, rec_s, lock, delete_lock),
+ connection_cache_ (caching_s)
+{
+ if (this->open (cre_s, con_s, rec_s) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("%p\n"),
+ ACE_LIB_TEXT ("ACE_Cached_Connect_Strategy_Ex<ACE_T2>\n")));
+}
+
+template <ACE_T1>
+ACE_Cached_Connect_Strategy_Ex<ACE_T2>::~ACE_Cached_Connect_Strategy_Ex (void)
+{
+ cleanup ();
+}
+
+
+template <ACE_T1> int
+ACE_Cached_Connect_Strategy_Ex<ACE_T2>::check_hint_i
+(SVC_HANDLER *&sh,
+ const ACE_PEER_CONNECTOR_ADDR &remote_addr,
+ ACE_Time_Value *timeout,
+ const ACE_PEER_CONNECTOR_ADDR &local_addr,
+ int reuse_addr,
+ int flags,
+ int perms,
+ ACE_Hash_Map_Entry<ACE_Refcounted_Hash_Recyclable<ACE_PEER_CONNECTOR_ADDR>, ACE_Pair<SVC_HANDLER *, ATTRIBUTES> > *&entry,
+ int &found)
+{
+ ACE_UNUSED_ARG (remote_addr);
+ ACE_UNUSED_ARG (timeout);
+ ACE_UNUSED_ARG (local_addr);
+ ACE_UNUSED_ARG (reuse_addr);
+ ACE_UNUSED_ARG (flags);
+ ACE_UNUSED_ARG (perms);
+
+ found = 0;
+
+ // Get the recycling act for the svc_handler
+ CONNECTION_CACHE_ENTRY *possible_entry = (CONNECTION_CACHE_ENTRY *) sh->recycling_act ();
+
+ // Check to see if the hint svc_handler has been closed down
+ if (possible_entry->ext_id_.recycle_state () == ACE_RECYCLABLE_CLOSED)
+ {
+ // If close, decrement refcount
+ if (possible_entry->ext_id_.decrement () == 0)
+ {
+ // If refcount goes to zero, close down the svc_handler
+ possible_entry->int_id_.first ()->recycler (0, 0);
+ possible_entry->int_id_.first ()->close ();
+ this->purge_i (possible_entry);
+ }
+
+ // Hint not successful
+ found = 0;
+
+ // Reset hint
+ sh = 0;
+ }
+
+ // If hint is not closed, see if it is connected to the correct
+ // address and is recyclable
+ else if ((possible_entry->ext_id_.recycle_state () == ACE_RECYCLABLE_IDLE_AND_PURGABLE ||
+ possible_entry->ext_id_.recycle_state () == ACE_RECYCLABLE_IDLE_BUT_NOT_PURGABLE) &&
+ possible_entry->ext_id_.subject () == remote_addr)
+ {
+ // Hint successful
+ found = 1;
+
+ // Tell the <svc_handler> that it should prepare itself for
+ // being recycled.
+ this->prepare_for_recycling (sh);
+
+ //
+ // Update the caching attributes directly since we don't do a
+ // find() on the cache map.
+ //
+
+ // Indicates successful find.
+ int find_result = 0;
+
+ int result = this->caching_strategy ().notify_find (find_result,
+ possible_entry->int_id_.second ());
+
+ if (result == -1)
+ return result;
+ }
+ else
+ {
+ // This hint will not be used.
+ possible_entry->ext_id_.decrement ();
+
+ // Hint not successful
+ found = 0;
+
+ // If <sh> is not connected to the correct address or is busy,
+ // we will not use it.
+ sh = 0;
+ }
+
+ if (found)
+ entry = possible_entry;
+
+ return 0;
+}
+
+template <ACE_T1> int
+ACE_Cached_Connect_Strategy_Ex<ACE_T2>::find_or_create_svc_handler_i
+(SVC_HANDLER *&sh,
+ const ACE_PEER_CONNECTOR_ADDR &remote_addr,
+ ACE_Time_Value *timeout,
+ const ACE_PEER_CONNECTOR_ADDR &local_addr,
+ int reuse_addr,
+ int flags,
+ int perms,
+ ACE_Hash_Map_Entry<ACE_Refcounted_Hash_Recyclable<ACE_PEER_CONNECTOR_ADDR>, ACE_Pair<SVC_HANDLER *, ATTRIBUTES> > *&entry,
+ int &found)
+{
+ REFCOUNTED_HASH_RECYCLABLE_ADDRESS search_addr (remote_addr);
+
+ // Try to find the address in the cache. Only if we don't find it
+ // do we create a new <SVC_HANDLER> and connect it with the server.
+ while (this->find (search_addr, entry) != -1)
+ {
+ // We found a cached svc_handler.
+ // Get the cached <svc_handler>
+ sh = entry->int_id_.first ();
+
+ // Is the connection clean?
+ int state_result =
+ ACE::handle_ready (sh->peer ().get_handle (),
+ &ACE_Time_Value::zero,
+ 1, // read ready
+ 0, // write ready
+ 1);// exception ready
+
+ if (state_result == 1)
+ {
+
+ if (sh->close () == -1)
+ return -1;
+
+ sh = 0;
+
+ // Cycle it once again..
+ }
+ else if ((state_result == -1) && (errno == ETIME))
+ {
+ // Found!!!
+ // Set the flag
+ found = 1;
+
+ // Tell the <svc_handler> that it should prepare itself for
+ // being recycled.
+ if (this->prepare_for_recycling (sh) == -1)
+ return -1;
+
+ return 0;
+ }
+ else
+ {
+ return -1;
+ }
+ }
+
+ // Not found...
+
+ // Set the flag
+ found = 0;
+
+ // We need to use a temporary variable here since we are not
+ // allowed to change <sh> because other threads may use this
+ // when we let go of the lock during the OS level connect.
+ //
+ // Note that making a new svc_handler, connecting remotely,
+ // binding to the map, and assigning of the hint and recycler
+ // should be atomic to the outside world.
+ SVC_HANDLER *potential_handler = 0;
+
+ // Create a new svc_handler
+ if (this->make_svc_handler (potential_handler) == -1)
+ return -1;
+
+ // Connect using the svc_handler.
+ if (this->cached_connect (potential_handler,
+ remote_addr,
+ timeout,
+ local_addr,
+ reuse_addr,
+ flags,
+ perms) == -1)
+ {
+ // Close the svc handler.
+ potential_handler->close (0);
+
+ return -1;
+ }
+ else
+ {
+ // Insert the new SVC_HANDLER instance into the cache.
+ if (this->connection_cache_.bind (search_addr,
+ potential_handler,
+ entry) == -1)
+ {
+ // Close the svc handler and reset <sh>.
+ potential_handler->close (0);
+
+ return -1;
+ }
+
+ // Everything succeeded as planned. Assign <sh> to
+ // <potential_handler>.
+ sh = potential_handler;
+
+ // Set the recycler and the recycling act
+
+ this->assign_recycler (sh, this, entry);
+ }
+
+ return 0;
+}
+
+template <ACE_T1> int
+ACE_Cached_Connect_Strategy_Ex<ACE_T2>::cached_connect (SVC_HANDLER *&sh,
+ const ACE_PEER_CONNECTOR_ADDR &remote_addr,
+ ACE_Time_Value *timeout,
+ const ACE_PEER_CONNECTOR_ADDR &local_addr,
+ int reuse_addr,
+ int flags,
+ int perms)
+{
+ // Actively establish the connection. This is a timed blocking
+ // connect.
+ if (this->new_connection (sh,
+ remote_addr,
+ timeout,
+ local_addr,
+ reuse_addr,
+ flags,
+ perms) == -1)
+ {
+ // If connect() failed because of timeouts, we have to reject
+ // the connection entirely. This is necessary since currently
+ // there is no way for the non-blocking connects to complete and
+ // for the <Connector> to notify the cache of the completion of
+ // connect().
+
+ if (errno == EWOULDBLOCK)
+ errno = ENOTSUP;
+ else if (ACE::out_of_handles (errno))
+ {
+ // If the connect failed due to the process running out of
+ // file descriptors then, auto_purging of some connections
+ // are done from the CONNECTION_CACHE. This frees the
+ // descriptors which get used in the connect process and
+ // hence the same method is called again!
+ if (this->purge_connections () == -1)
+ return -1;
+
+ // Try connecting again.
+ if (this->new_connection (sh,
+ remote_addr,
+ timeout,
+ local_addr,
+ reuse_addr,
+ flags,
+ perms) == -1)
+ {
+ if (errno == EWOULDBLOCK)
+ errno = ENOTSUP;
+ return -1;
+ }
+ }
+ else
+ {
+ return -1;
+ }
+ }
+
+ return 0;
+
+}
+
+
+template <ACE_T1> int
+ACE_Cached_Connect_Strategy_Ex<ACE_T2>::connect_svc_handler_i
+(SVC_HANDLER *&sh,
+ const ACE_PEER_CONNECTOR_ADDR &remote_addr,
+ ACE_Time_Value *timeout,
+ const ACE_PEER_CONNECTOR_ADDR &local_addr,
+ int reuse_addr,
+ int flags,
+ int perms,
+ int& found)
+{
+ CONNECTION_CACHE_ENTRY *entry = 0;
+
+ // Check if the user passed a hint svc_handler
+ if (sh != 0)
+ {
+
+ int result = this->check_hint_i (sh,
+ remote_addr,
+ timeout,
+ local_addr,
+ reuse_addr,
+ flags,
+ perms,
+ entry,
+ found);
+ if (result != 0)
+ return result;
+ }
+
+ // If not found
+ if (!found)
+ {
+ int result = this->find_or_create_svc_handler_i (sh,
+ remote_addr,
+ timeout,
+ local_addr,
+ reuse_addr,
+ flags,
+ perms,
+ entry,
+ found);
+
+ if (result != 0)
+ return result;
+
+ }
+
+ // For all successful cases: mark the <svc_handler> in the cache
+ // as being <in_use>. Therefore recyclable is BUSY.
+ entry->ext_id_.recycle_state (ACE_RECYCLABLE_BUSY);
+
+ // And increment the refcount
+ entry->ext_id_.increment ();
+
+ return 0;
+}
+
+
+template <ACE_T1> int
+ACE_Cached_Connect_Strategy_Ex<ACE_T2>::cache_i (const void *recycling_act)
+{
+ // The wonders and perils of ACT
+ CONNECTION_CACHE_ENTRY *entry = (CONNECTION_CACHE_ENTRY *) recycling_act;
+
+ // Mark the <svc_handler> in the cache as not being <in_use>.
+ // Therefore recyclable is IDLE.
+ entry->ext_id_.recycle_state (ACE_RECYCLABLE_IDLE_AND_PURGABLE);
+
+ return 0;
+}
+
+template<ACE_T1> int
+ACE_Cached_Connect_Strategy_Ex<ACE_T2>::recycle_state_i (const void *recycling_act,
+ ACE_Recyclable_State new_state)
+{
+ // The wonders and perils of ACT
+ CONNECTION_CACHE_ENTRY *entry = (CONNECTION_CACHE_ENTRY *) recycling_act;
+
+ // Mark the <svc_handler> in the cache as not being <in_use>.
+ // Therefore recyclable is IDLE.
+ entry->ext_id_.recycle_state (new_state);
+
+ return 0;
+}
+
+template<ACE_T1> ACE_Recyclable_State
+ACE_Cached_Connect_Strategy_Ex<ACE_T2>::recycle_state_i (const void *recycling_act) const
+{
+ // The wonders and perils of ACT
+ CONNECTION_CACHE_ENTRY *entry = (CONNECTION_CACHE_ENTRY *) recycling_act;
+
+ // Mark the <svc_handler> in the cache as not being <in_use>.
+ // Therefore recyclable is IDLE.
+ return entry->ext_id_.recycle_state ();
+}
+
+template <ACE_T1> int
+ACE_Cached_Connect_Strategy_Ex<ACE_T2>::purge_i (const void *recycling_act)
+{
+ // The wonders and perils of ACT
+ CONNECTION_CACHE_ENTRY *entry = (CONNECTION_CACHE_ENTRY *) recycling_act;
+
+ return this->connection_cache_.unbind (entry);
+}
+
+
+template <ACE_T1> int
+ACE_Cached_Connect_Strategy_Ex<ACE_T2>::mark_as_closed_i (const void *recycling_act)
+{
+ // The wonders and perils of ACT
+ CONNECTION_CACHE_ENTRY *entry = (CONNECTION_CACHE_ENTRY *) recycling_act;
+
+ // Mark the <svc_handler> in the cache as CLOSED.
+ entry->ext_id_.recycle_state (ACE_RECYCLABLE_CLOSED);
+
+ return 0;
+}
+
+template <ACE_T1> int
+ACE_Cached_Connect_Strategy_Ex<ACE_T2>::cleanup_hint_i (const void *recycling_act,
+ void **act_holder)
+{
+ // Reset the <*act_holder> in the confines and protection of the
+ // lock.
+ if (act_holder)
+ *act_holder = 0;
+
+ // The wonders and perils of ACT
+ CONNECTION_CACHE_ENTRY *entry = (CONNECTION_CACHE_ENTRY *) recycling_act;
+
+ // Decrement the refcount on the <svc_handler>.
+ int refcount = entry->ext_id_.decrement ();
+
+ // If the svc_handler state is closed and the refcount == 0, call
+ // close() on svc_handler.
+ if (entry->ext_id_.recycle_state () == ACE_RECYCLABLE_CLOSED &&
+ refcount == 0)
+ {
+ entry->int_id_.first ()->recycler (0, 0);
+ entry->int_id_.first ()->close ();
+ this->purge_i (entry);
+ }
+
+ return 0;
+}
+
+template <ACE_T1> int
+ACE_Cached_Connect_Strategy_Ex<ACE_T2>::purge_connections (void)
+{
+ return this->connection_cache_.purge ();
+}
+
+template <ACE_T1> CACHING_STRATEGY &
+ACE_Cached_Connect_Strategy_Ex<ACE_T2>::caching_strategy (void)
+{
+ return this->connection_cache_.caching_strategy ();
+}
+
+template <ACE_T1> int
+ACE_Cached_Connect_Strategy_Ex<ACE_T2>::find (ACE_Refcounted_Hash_Recyclable<ACE_PEER_CONNECTOR_ADDR> &search_addr,
+ ACE_Hash_Map_Entry<ACE_Refcounted_Hash_Recyclable<ACE_PEER_CONNECTOR_ADDR>, ACE_Pair<SVC_HANDLER *, ATTRIBUTES> > *&entry)
+{
+ typedef ACE_Hash_Map_Bucket_Iterator<REFCOUNTED_HASH_RECYCLABLE_ADDRESS,
+ ACE_Pair<SVC_HANDLER *, ATTRIBUTES>,
+ ACE_Hash<REFCOUNTED_HASH_RECYCLABLE_ADDRESS>,
+ ACE_Equal_To<REFCOUNTED_HASH_RECYCLABLE_ADDRESS>,
+ ACE_Null_Mutex>
+ CONNECTION_CACHE_BUCKET_ITERATOR;
+
+ CONNECTION_CACHE_BUCKET_ITERATOR iterator (this->connection_cache_.map (),
+ search_addr);
+
+ CONNECTION_CACHE_BUCKET_ITERATOR end (this->connection_cache_.map (),
+ search_addr,
+ 1);
+
+ for (;
+ iterator != end;
+ ++iterator)
+ {
+ REFCOUNTED_HASH_RECYCLABLE_ADDRESS &addr = (*iterator).ext_id_;
+
+ if (addr.recycle_state () != ACE_RECYCLABLE_IDLE_AND_PURGABLE &&
+ addr.recycle_state () != ACE_RECYCLABLE_IDLE_BUT_NOT_PURGABLE)
+ continue;
+
+ if (addr.subject () != search_addr.subject ())
+ continue;
+
+ entry = &(*iterator);
+
+ //
+ // Update the caching attributes directly since we don't do a
+ // find() on the cache map.
+ //
+
+ // Indicates successful find.
+ int find_result = 0;
+
+ int result = this->caching_strategy ().notify_find (find_result,
+ entry->int_id_.second ());
+
+ if (result == -1)
+ return result;
+
+ return 0;
+ }
+
+ return -1;
+}
+
+template <ACE_T1> void
+ACE_Cached_Connect_Strategy_Ex<ACE_T2>::cleanup (void)
+{
+ // Excluded other threads from changing the cache while we cleanup
+ ACE_GUARD (MUTEX, ace_mon, *this->lock_);
+ // Close down all cached service handlers.
+#if defined (ACE_HAS_BROKEN_EXTENDED_TEMPLATES)
+
+ typedef ACE_Hash_Map_Iterator_Ex<REFCOUNTED_HASH_RECYCLABLE_ADDRESS,
+ ACE_Pair<SVC_HANDLER *, ATTRIBUTES>,
+ ACE_Hash<REFCOUNTED_HASH_RECYCLABLE_ADDRESS>,
+ ACE_Equal_To<REFCOUNTED_HASH_RECYCLABLE_ADDRESS>,
+ ACE_Null_Mutex>
+ CONNECTION_MAP_ITERATOR;
+
+ // CONNECTION_MAP_ITERATOR end = this->connection_cache_.map ().end ();
+ CONNECTION_MAP_ITERATOR iter = this->connection_cache_.map ().begin ();
+
+
+ while (iter != this->connection_cache_.map ().end ())
+ {
+ if ((*iter).int_id_.first () != 0)
+ {
+ // save entry for future use
+ CONNECTION_CACHE_ENTRY *entry = (CONNECTION_CACHE_ENTRY *)
+ (*iter).int_id_.first ()->recycling_act ();
+
+ // close handler
+ (*iter).int_id_.first ()->recycler (0, 0);
+ (*iter).int_id_.first ()->close ();
+
+ // remember next iter
+ CONNECTION_MAP_ITERATOR next_iter = iter;
+ ++next_iter;
+
+ // purge the item from the hash
+ this->purge_i (entry);
+
+ // assign next iter
+ iter = next_iter;
+ }
+ else
+ ++iter;
+ }
+#else /* ACE_HAS_BROKEN_EXTENDED_TEMPLATES */
+ ACE_TYPENAME CONNECTION_CACHE::ITERATOR iter =
+ this->connection_cache_.begin ();
+ while (iter != this->connection_cache_.end ())
+ {
+ if ((*iter).second () != 0)
+ {
+ // save entry for future use
+ CONNECTION_CACHE_ENTRY *entry = (CONNECTION_CACHE_ENTRY *)
+ (*iter).second ()->recycling_act ();
+
+ // close handler
+ (*iter).second ()->recycler (0, 0);
+ (*iter).second ()->close ();
+
+ // remember next iter
+ ACE_TYPENAME CONNECTION_CACHE::ITERATOR next_iter = iter;
+ ++next_iter;
+
+ // purge the item from the hash
+ this->purge_i (entry);
+
+ // assign next iter
+ iter = next_iter;
+ }
+ else
+ ++iter;
+ }
+#endif /* ACE_HAS_BROKEN_EXTENDED_TEMPLATES */
+
+}
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Cached_Connect_Strategy_Ex)
+/////////////////////////////////////////////////////////////////////////
+
+template <ACE_T1>
+ACE_Bounded_Cached_Connect_Strategy<ACE_T2>::ACE_Bounded_Cached_Connect_Strategy
+(size_t max_size,
+ CACHING_STRATEGY &caching_s,
+ ACE_Creation_Strategy<SVC_HANDLER> *cre_s,
+ ACE_Concurrency_Strategy<SVC_HANDLER> *con_s,
+ ACE_Recycling_Strategy<SVC_HANDLER> *rec_s,
+ MUTEX *lock,
+ int delete_lock)
+ : CCSEBASE (caching_s, cre_s, con_s, rec_s, lock, delete_lock),
+ max_size_ (max_size)
+{
+}
+
+template <ACE_T1>
+ACE_Bounded_Cached_Connect_Strategy<ACE_T2>::~ACE_Bounded_Cached_Connect_Strategy(void)
+{
+}
+
+template <ACE_T1>
+int
+ACE_Bounded_Cached_Connect_Strategy<ACE_T2>::find_or_create_svc_handler_i
+(SVC_HANDLER *&sh,
+ const ACE_PEER_CONNECTOR_ADDR &remote_addr,
+ ACE_Time_Value *timeout,
+ const ACE_PEER_CONNECTOR_ADDR &local_addr,
+ int reuse_addr,
+ int flags,
+ int perms,
+ ACE_Hash_Map_Entry<ACE_Refcounted_Hash_Recyclable<ACE_PEER_CONNECTOR_ADDR>,
+ ACE_Pair<SVC_HANDLER *, ATTRIBUTES> > *&entry,
+ int &found)
+{
+
+ REFCOUNTED_HASH_RECYCLABLE_ADDRESS search_addr (remote_addr);
+
+ // Try to find the address in the cache. Only if we don't find it
+ // do we create a new <SVC_HANDLER> and connect it with the server.
+ while (this->find (search_addr, entry) != -1)
+ {
+ // We found a cached svc_handler.
+ // Get the cached <svc_handler>
+ sh = entry->int_id_.first ();
+
+ // Is the connection clean?
+ int state_result= ACE::handle_ready (sh->peer ().get_handle (),
+ &ACE_Time_Value::zero,
+ 1, // read ready
+ 0, // write ready
+ 1);// exception ready
+
+ if (state_result == 1)
+ {
+ // The connection was disconnected during idle.
+ // close the svc_handler down.
+ if (sh->close () == -1)
+ {
+ ACE_ASSERT (0);
+ return -1;
+ }
+ sh = 0;
+ // and rotate once more...
+ }
+ else if ((state_result == -1) && (errno == ETIME))
+ {
+ // Found!!!
+ // Set the flag
+ found = 1;
+
+ // Tell the <svc_handler> that it should prepare itself for
+ // being recycled.
+ if (this->prepare_for_recycling (sh) == -1)
+ {
+ ACE_ASSERT (0);
+ return -1;
+ }
+
+ return 0;
+ }
+ else // some other return value or error...
+ {
+ ACE_ASSERT (0); // just to see it coming
+
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("(%t)ACE_Bounded_Cached_Connect_Strategy<>::")
+ ACE_LIB_TEXT ("find_or_create_svc_handler_i - ")
+ ACE_LIB_TEXT ("error polling server socket state.\n")));
+
+ return -1;
+ }
+ }
+
+ // Not found...
+
+ // Set the flag
+ found = 0;
+
+ // Check the limit of handlers...
+ if ((this->max_size_ > 0) &&
+ (this->connection_cache_.current_size () >= this->max_size_))
+ {
+ // Try to purge idle connections
+ if (this->purge_connections () == -1)
+ return -1;
+
+ // Check limit again.
+ if (this->connection_cache_.current_size () >= this->max_size_)
+ // still too much!
+ return -1;
+
+ // OK, we have room now...
+ }
+
+ // We need to use a temporary variable here since we are not
+ // allowed to change <sh> because other threads may use this
+ // when we let go of the lock during the OS level connect.
+ //
+ // Note that making a new svc_handler, connecting remotely,
+ // binding to the map, and assigning of the hint and recycler
+ // should be atomic to the outside world.
+ SVC_HANDLER *potential_handler = 0;
+
+ // Create a new svc_handler
+ if (this->make_svc_handler (potential_handler) == -1)
+ return -1;
+
+ // Connect using the svc_handler.
+ if (this->cached_connect (potential_handler,
+ remote_addr,
+ timeout,
+ local_addr,
+ reuse_addr,
+ flags,
+ perms) == -1)
+ {
+ // Close the svc handler.
+ potential_handler->close (0);
+ return -1;
+ }
+ else
+ {
+ // Insert the new SVC_HANDLER instance into the cache.
+ if (this->connection_cache_.bind (search_addr,
+ potential_handler,
+ entry) == -1)
+ {
+ // Close the svc handler and reset <sh>.
+ potential_handler->close (0);
+
+ return -1;
+ }
+
+ // Everything succeeded as planned. Assign <sh> to
+ // <potential_handler>.
+ sh = potential_handler;
+
+ // Set the recycler and the recycling act
+ this->assign_recycler (sh, this, entry);
+ }
+
+ return 0;
+}
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Bounded_Cached_Connect_Strategy)
+
+#undef ACE_T1
+#undef ACE_T2
+
+#endif /* CACHED_CONNECT_STRATEGY_T_C */
diff --git a/ace/Utils/Templates/Cached_Connect_Strategy_T.h b/ace/Utils/Templates/Cached_Connect_Strategy_T.h
new file mode 100644
index 00000000000..56ec72b1606
--- /dev/null
+++ b/ace/Utils/Templates/Cached_Connect_Strategy_T.h
@@ -0,0 +1,259 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Cached_Connect_Strategy_T.h
+ *
+ * $Id$
+ *
+ * @author Kirthika Parameswaran <kirthika@cs.wustl.edu>
+ */
+//=============================================================================
+
+#ifndef CACHED_CONNECT_STRATEGY_T_H
+#define CACHED_CONNECT_STRATEGY_T_H
+#include "ace/pre.h"
+
+#include "ace/OS.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+#define ACE_LACKS_PRAGMA_ONCE
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "ace/Strategies_T.h"
+#include "ace/Hash_Cache_Map_Manager_T.h"
+#include "ace/Caching_Strategies_T.h"
+#include "ace/Functor_T.h"
+#include "ace/Pair_T.h"
+#include "ace/Synch.h"
+
+// For linkers which cant grok long names...
+#define ACE_Cached_Connect_Strategy_Ex ACCSE
+
+/**
+ * @class ACE_Cached_Connect_Strategy_Ex
+ *
+ * @brief A connection strategy which caches connections to peers
+ * (represented by <SVC_HANDLER> instances), thereby allowing
+ * subsequent re-use of unused, but available, connections.
+ *
+ * <Cached_Connect_Strategy> is intended to be used as a
+ * plug-in connection strategy for <ACE_Strategy_Connector>.
+ * It's added value is re-use of established connections and
+ * tweaking the role of the cache as per the caching strategy.
+ */
+template <class SVC_HANDLER, ACE_PEER_CONNECTOR_1, class CACHING_STRATEGY, class ATTRIBUTES, class MUTEX>
+class ACE_Cached_Connect_Strategy_Ex : public ACE_Cached_Connect_Strategy<SVC_HANDLER, ACE_PEER_CONNECTOR_2, MUTEX>
+{
+public:
+ /// Constructor
+ ACE_Cached_Connect_Strategy_Ex (CACHING_STRATEGY &caching_s,
+ ACE_Creation_Strategy<SVC_HANDLER> *cre_s = 0,
+ ACE_Concurrency_Strategy<SVC_HANDLER> *con_s = 0,
+ ACE_Recycling_Strategy<SVC_HANDLER> *rec_s = 0,
+ MUTEX *lock = 0,
+ int delete_lock = 0);
+
+ /// Destructor
+ virtual ~ACE_Cached_Connect_Strategy_Ex (void);
+
+ /// Explicit purging of connection entries from the connection cache.
+ virtual int purge_connections (void);
+
+ /// Mark as closed (non-locking version). This is used during the cleanup of the
+ /// connections purged.
+ virtual int mark_as_closed_i (const void *recycling_act);
+
+ /**
+ * Since g++ version < 2.8 arent happy with templates, this special
+ * method had to be devised to avoid memory leaks and perform
+ * cleanup of the <connection_cache_>.
+ */
+ void cleanup (void);
+
+ // = Typedefs for managing the map
+ typedef ACE_Refcounted_Hash_Recyclable<ACE_PEER_CONNECTOR_ADDR>
+ REFCOUNTED_HASH_RECYCLABLE_ADDRESS;
+ typedef ACE_Hash_Cache_Map_Manager<REFCOUNTED_HASH_RECYCLABLE_ADDRESS,
+ SVC_HANDLER *,
+ ACE_Hash<REFCOUNTED_HASH_RECYCLABLE_ADDRESS>,
+ ACE_Equal_To<REFCOUNTED_HASH_RECYCLABLE_ADDRESS>,
+ CACHING_STRATEGY,
+ ATTRIBUTES>
+ CONNECTION_CACHE;
+ typedef ACE_TYPENAME CONNECTION_CACHE::CACHE_ENTRY
+ CONNECTION_CACHE_ENTRY;
+ typedef ACE_TYPENAME CONNECTION_CACHE::key_type
+ KEY;
+ typedef ACE_TYPENAME CONNECTION_CACHE::mapped_type
+ VALUE;
+
+ // = Cleanup of the svc_handler.
+ typedef ACE_Recyclable_Handler_Cleanup_Strategy<REFCOUNTED_HASH_RECYCLABLE_ADDRESS,
+ ACE_Pair<SVC_HANDLER *, ATTRIBUTES>,
+ ACE_Hash_Map_Manager_Ex<REFCOUNTED_HASH_RECYCLABLE_ADDRESS,
+ ACE_Pair<SVC_HANDLER *, ATTRIBUTES>,
+ ACE_Hash<REFCOUNTED_HASH_RECYCLABLE_ADDRESS>,
+ ACE_Equal_To<REFCOUNTED_HASH_RECYCLABLE_ADDRESS>,
+ MUTEX> >
+ CLEANUP_STRATEGY;
+
+ typedef ACE_Cached_Connect_Strategy<SVC_HANDLER, ACE_PEER_CONNECTOR_2, MUTEX>
+ CCSBASE;
+
+ // = Accessor.
+ CACHING_STRATEGY &caching_strategy (void);
+
+protected:
+
+ /// Find an idle handle.
+ int find (ACE_Refcounted_Hash_Recyclable<ACE_PEER_CONNECTOR_ADDR> &search_addr,
+ ACE_Hash_Map_Entry<ACE_Refcounted_Hash_Recyclable<ACE_PEER_CONNECTOR_ADDR>, ACE_Pair<SVC_HANDLER *, ATTRIBUTES> > *&entry);
+
+ /// Remove from cache (non-locking version).
+ virtual int purge_i (const void *recycling_act);
+
+ /// Add to cache (non-locking version).
+ virtual int cache_i (const void *recycling_act);
+
+ /// Get/Set <recycle_state> (non-locking version).
+ virtual int recycle_state_i (const void *recycling_act,
+ ACE_Recyclable_State new_state);
+ virtual ACE_Recyclable_State recycle_state_i (const void *recycling_act) const;
+
+ /// Cleanup hint and reset <*act_holder> to zero if <act_holder != 0>.
+ virtual int cleanup_hint_i (const void *recycling_act,
+ void **act_holder);
+
+ // = Helpers
+ int check_hint_i (SVC_HANDLER *&sh,
+ const ACE_PEER_CONNECTOR_ADDR &remote_addr,
+ ACE_Time_Value *timeout,
+ const ACE_PEER_CONNECTOR_ADDR &local_addr,
+ int reuse_addr,
+ int flags,
+ int perms,
+ ACE_Hash_Map_Entry<ACE_Refcounted_Hash_Recyclable<ACE_PEER_CONNECTOR_ADDR>, ACE_Pair<SVC_HANDLER *, ATTRIBUTES> > *&entry,
+ int &found);
+
+ virtual int find_or_create_svc_handler_i (SVC_HANDLER *&sh,
+ const ACE_PEER_CONNECTOR_ADDR &remote_addr,
+ ACE_Time_Value *timeout,
+ const ACE_PEER_CONNECTOR_ADDR &local_addr,
+ int reuse_addr,
+ int flags,
+ int perms,
+ ACE_Hash_Map_Entry<ACE_Refcounted_Hash_Recyclable<ACE_PEER_CONNECTOR_ADDR>, ACE_Pair<SVC_HANDLER *, ATTRIBUTES> > *&entry,
+ int &found);
+
+ virtual int connect_svc_handler_i (SVC_HANDLER *&sh,
+ const ACE_PEER_CONNECTOR_ADDR &remote_addr,
+ ACE_Time_Value *timeout,
+ const ACE_PEER_CONNECTOR_ADDR &local_addr,
+ int reuse_addr,
+ int flags,
+ int perms,
+ int &found);
+
+ /**
+ * Connection of the svc_handler with the remote host. This method
+ * also encapsulates the connection done with auto_purging under the
+ * hood. If the connect failed due to the process running out of
+ * file descriptors then, auto_purging of some connections are done
+ * from the CONNECTION_CACHE. This frees the descriptors which get
+ * used in the connect process and hence the connect operation can
+ * succeed.
+ */
+ virtual int cached_connect (SVC_HANDLER *&sh,
+ const ACE_PEER_CONNECTOR_ADDR &remote_addr,
+ ACE_Time_Value *timeout,
+ const ACE_PEER_CONNECTOR_ADDR &local_addr,
+ int reuse_addr,
+ int flags,
+ int perms);
+
+ /// Table that maintains the cache of connected <SVC_HANDLER>s.
+ CONNECTION_CACHE connection_cache_;
+};
+
+/////////////////////////////////////////////////////////////////////////////
+
+// For linkers which cant grok long names...
+#define ACE_Bounded_Cached_Connect_Strategy ABCCS
+
+/**
+ * @class ACE_Bounded_Cached_Connect_Strategy
+ *
+ * @brief A connection strategy which caches connections to peers
+ * (represented by <SVC_HANDLER> instances), thereby allowing
+ * subsequent re-use of unused, but available, connections.
+ * This strategy should be used when the cache is bounded by
+ * maximum size.
+ *
+ * <Bounded_Cached_Connect_Strategy> is intended to be used as a
+ * plug-in connection strategy for <ACE_Strategy_Connector>.
+ * It's added value is re-use of established connections and
+ * tweaking the role of the cache as per the caching strategy.
+ * Thanks to Edan Ayal <edana@bandwiz.com> for contributing this
+ * class and Susan Liebeskind <shl@janis.gtri.gatech.edu> for
+ * brainstorming about it.
+ */
+template <class SVC_HANDLER, ACE_PEER_CONNECTOR_1,
+ class CACHING_STRATEGY, class ATTRIBUTES,
+ class MUTEX>
+ class ACE_Bounded_Cached_Connect_Strategy
+ : public ACE_Cached_Connect_Strategy_Ex<SVC_HANDLER, ACE_PEER_CONNECTOR_2, CACHING_STRATEGY, ATTRIBUTES, MUTEX>
+{
+
+ typedef ACE_Cached_Connect_Strategy_Ex<SVC_HANDLER, ACE_PEER_CONNECTOR_2, CACHING_STRATEGY, ATTRIBUTES, MUTEX>
+ CCSEBASE;
+
+ // = Typedefs for managing the map
+ typedef ACE_Refcounted_Hash_Recyclable<ACE_PEER_CONNECTOR_ADDR>
+ REFCOUNTED_HASH_RECYCLABLE_ADDRESS;
+
+ public:
+
+ /// Constructor
+ ACE_Bounded_Cached_Connect_Strategy (size_t max_size,
+ CACHING_STRATEGY &caching_s,
+ ACE_Creation_Strategy<SVC_HANDLER> *cre_s = 0,
+ ACE_Concurrency_Strategy<SVC_HANDLER> *con_s = 0,
+ ACE_Recycling_Strategy<SVC_HANDLER> *rec_s = 0,
+ MUTEX *lock = 0,
+ int delete_lock = 0);
+
+ /// Destructor
+ virtual ~ACE_Bounded_Cached_Connect_Strategy (void);
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+ protected:
+
+ virtual int find_or_create_svc_handler_i (SVC_HANDLER *&sh,
+ const ACE_PEER_CONNECTOR_ADDR &remote_addr,
+ ACE_Time_Value *timeout,
+ const ACE_PEER_CONNECTOR_ADDR &local_addr,
+ int reuse_addr,
+ int flags,
+ int perms,
+ ACE_Hash_Map_Entry<ACE_Refcounted_Hash_Recyclable<ACE_PEER_CONNECTOR_ADDR>,
+ ACE_Pair<SVC_HANDLER *, ATTRIBUTES> > *&entry,
+ int &found);
+
+ /// max items in the cache, used as a bound for the creation of svc_handlers.
+ size_t max_size_;
+};
+
+
+#if defined (ACE_TEMPLATES_REQUIRE_SOURCE)
+#include "ace/Cached_Connect_Strategy_T.cpp"
+#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */
+
+#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA)
+#pragma implementation ("Cached_Connect_Strategy_T.cpp")
+#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */
+
+#include "ace/post.h"
+#endif /* CACHED_CONNECT_STRATEGY_T_H */
diff --git a/ace/Utils/Templates/Caching_Utility_T.cpp b/ace/Utils/Templates/Caching_Utility_T.cpp
new file mode 100644
index 00000000000..75ce2aeda72
--- /dev/null
+++ b/ace/Utils/Templates/Caching_Utility_T.cpp
@@ -0,0 +1,500 @@
+// $Id$
+
+#ifndef CACHING_UTILITY_T_C
+#define CACHING_UTILITY_T_C
+
+#include "ace/Caching_Utility_T.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+#define ACE_LACKS_PRAGMA_ONCE
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+// #include "ace/Strategies.h"
+#include "ace/Recyclable.h"
+
+ACE_RCSID(ace, Caching_Utility_T, "$Id$")
+
+//////////////////////////////////////////////////////////////////////////////
+
+template <class KEY, class VALUE, class CONTAINER, class ITERATOR, class ATTRIBUTES>
+ACE_Pair_Caching_Utility<KEY, VALUE, CONTAINER, ITERATOR, ATTRIBUTES>::ACE_Pair_Caching_Utility (ACE_Cleanup_Strategy<KEY, VALUE, CONTAINER> *cleanup_strategy,
+ int delete_cleanup_strategy)
+ : cleanup_strategy_ (cleanup_strategy),
+ delete_cleanup_strategy_ (delete_cleanup_strategy)
+{
+ if (cleanup_strategy == 0)
+ {
+ ACE_NEW (this->cleanup_strategy_,
+ CLEANUP_STRATEGY);
+ this->delete_cleanup_strategy_ = 1;
+ }
+}
+
+template <class KEY, class VALUE, class CONTAINER, class ITERATOR, class ATTRIBUTES>
+ACE_Pair_Caching_Utility<KEY, VALUE, CONTAINER, ITERATOR, ATTRIBUTES>::~ACE_Pair_Caching_Utility (void)
+{
+ if (this->delete_cleanup_strategy_)
+ delete this->cleanup_strategy_;
+}
+
+template <class KEY, class VALUE, class CONTAINER, class ITERATOR, class ATTRIBUTES> int
+ACE_Pair_Caching_Utility<KEY, VALUE, CONTAINER, ITERATOR, ATTRIBUTES>::clear_cache (CONTAINER &container,
+ double purge_percent)
+{
+ // Check that the purge_percent is non-zero.
+ if (purge_percent == 0)
+ return 0;
+
+ // Get the number of entries in the container.
+ size_t current_map_size = container.current_size ();
+
+ // Also whether the number of entries in the cache!
+ // Oops! then there is no way out but exiting. So return an error.
+ if (current_map_size == 0)
+ return 0;
+
+ // Calculate the no of entries to remove from the cache depending
+ // upon the <purge_percent>.
+ size_t entries_to_remove
+ = ACE_MAX (ACE_static_cast (size_t, 1),
+ ACE_static_cast(size_t,
+ ACE_static_cast(double, purge_percent)
+ / 100 * current_map_size));
+ KEY *key_to_remove = 0;
+ VALUE *value_to_remove = 0;
+
+ for (size_t i = 0; i < entries_to_remove ; ++i)
+ {
+ this->minimum (container,
+ key_to_remove,
+ value_to_remove);
+
+ // Simply verifying that the key is non-zero.
+ // This is important for strategies where the minimum
+ // entry cant be found due to constraints on the type of entry
+ // to remove.
+ if (key_to_remove == 0)
+ return 0;
+
+ if (this->cleanup_strategy_->cleanup (container,
+ key_to_remove,
+ value_to_remove) == -1)
+ return -1;
+
+ }
+
+ return 0;
+}
+
+template <class KEY, class VALUE, class CONTAINER, class ITERATOR, class ATTRIBUTES> void
+ACE_Pair_Caching_Utility<KEY, VALUE, CONTAINER, ITERATOR, ATTRIBUTES>::minimum (CONTAINER &container,
+ KEY *&key_to_remove,
+ VALUE *&value_to_remove)
+{
+ // Starting values.
+ ITERATOR iter = container.begin ();
+ ITERATOR end = container.end ();
+ ATTRIBUTES min = (*iter).int_id_.second ();
+ key_to_remove = &(*iter).ext_id_;
+ value_to_remove = &(*iter).int_id_;
+
+ // The iterator moves thru the container searching for the entry
+ // with the lowest ATTRIBUTES.
+ for (++iter;
+ iter != end;
+ ++iter)
+ {
+ if (min > (*iter).int_id_.second ())
+ {
+ // Ah! an item with lower ATTTRIBUTES...
+ min = (*iter).int_id_.second ();
+ key_to_remove = &(*iter).ext_id_;
+ value_to_remove = &(*iter).int_id_;
+ }
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+template <class KEY, class VALUE, class CONTAINER, class ITERATOR, class ATTRIBUTES>
+ACE_Recyclable_Handler_Caching_Utility<KEY, VALUE, CONTAINER, ITERATOR, ATTRIBUTES>::ACE_Recyclable_Handler_Caching_Utility (ACE_Cleanup_Strategy<KEY, VALUE, CONTAINER> *cleanup_strategy,
+ int delete_cleanup_strategy)
+ : cleanup_strategy_ (cleanup_strategy),
+ delete_cleanup_strategy_ (delete_cleanup_strategy)
+{
+ if (cleanup_strategy == 0)
+ {
+ ACE_NEW (this->cleanup_strategy_,
+ CLEANUP_STRATEGY);
+ this->delete_cleanup_strategy_ = 1;
+ }
+}
+
+template <class KEY, class VALUE, class CONTAINER, class ITERATOR, class ATTRIBUTES>
+ACE_Recyclable_Handler_Caching_Utility<KEY, VALUE, CONTAINER, ITERATOR, ATTRIBUTES>::~ACE_Recyclable_Handler_Caching_Utility (void)
+{
+ if (this->delete_cleanup_strategy_)
+ delete this->cleanup_strategy_;
+}
+
+template <class KEY, class VALUE, class CONTAINER, class ITERATOR, class ATTRIBUTES> int
+ACE_Recyclable_Handler_Caching_Utility<KEY, VALUE, CONTAINER, ITERATOR, ATTRIBUTES>::clear_cache (CONTAINER &container,
+ double purge_percent)
+{
+ // Check that the purge_percent is non-zero.
+ if (purge_percent == 0)
+ return 0;
+
+ // Get the number of entries in the container.
+ size_t current_map_size = container.current_size ();
+
+ // Also whether the number of entries in the cache is just one!
+ // Oops! then there is no way out but exiting. So return an error.
+ // if (current_map_size <= 1)
+ if (current_map_size == 0)
+ return 0;
+
+ // Calculate the no of entries to remove from the cache depending
+ // upon the <purge_percent>.
+ size_t entries_to_remove
+ = ACE_MAX (ACE_static_cast (size_t, 1),
+ ACE_static_cast(size_t,
+ ACE_static_cast(double, purge_percent)
+ / 100 * current_map_size));
+
+ KEY *key_to_remove = 0;
+ VALUE *value_to_remove = 0;
+
+ for (size_t i = 0; i < entries_to_remove ; ++i)
+ {
+ this->minimum (container,
+ key_to_remove,
+ value_to_remove);
+
+ // Simply verifying that the key is non-zero.
+ // This is important for strategies where the minimum
+ // entry cant be found due to constraints on the type of entry
+ // to remove.
+ if (key_to_remove == 0)
+ return 0;
+
+ if (this->cleanup_strategy_->cleanup (container,
+ key_to_remove,
+ value_to_remove) == -1)
+ return -1;
+ }
+
+ return 0;
+}
+
+template <class KEY, class VALUE, class CONTAINER, class ITERATOR, class ATTRIBUTES> void
+ACE_Recyclable_Handler_Caching_Utility<KEY, VALUE, CONTAINER, ITERATOR, ATTRIBUTES>::minimum (CONTAINER &container,
+ KEY *&key_to_remove,
+ VALUE *&value_to_remove)
+{
+ // Starting values.
+ ITERATOR end = container.end ();
+ ITERATOR iter = container.begin ();
+ ATTRIBUTES min = (*iter).int_id_.second ();
+ key_to_remove = 0;
+ value_to_remove = 0;
+ // Found the minimum entry to be purged?
+ int found = 0;
+
+ // The iterator moves thru the container searching for the entry
+ // with the lowest ATTRIBUTES.
+ for (;
+ iter != end;
+ ++iter)
+ {
+ // If the <min> entry isnt IDLE_AND_PURGABLE continue until you reach
+ // the first entry which can be purged. This is the minimum with
+ // which you will compare the rest of the purgable entries.
+ if ((*iter).ext_id_.recycle_state () == ACE_RECYCLABLE_IDLE_AND_PURGABLE ||
+ (*iter).ext_id_.recycle_state () == ACE_RECYCLABLE_PURGABLE_BUT_NOT_IDLE)
+ {
+ if (found == 0)
+ {
+ min = (*iter).int_id_.second ();
+ key_to_remove = &(*iter).ext_id_;
+ value_to_remove = &(*iter).int_id_;
+ found = 1;
+ }
+ else
+ {
+ // Ah! an entry with lower ATTTRIBUTES...
+ if (min > (*iter).int_id_.second ())
+ {
+ min = (*iter).int_id_.second ();
+ key_to_remove = &(*iter).ext_id_;
+ value_to_remove = &(*iter).int_id_;
+ }
+ }
+ }
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+template <class KEY, class VALUE, class CONTAINER, class ITERATOR, class ATTRIBUTES>
+ACE_Refcounted_Recyclable_Handler_Caching_Utility<KEY, VALUE, CONTAINER, ITERATOR, ATTRIBUTES>::ACE_Refcounted_Recyclable_Handler_Caching_Utility (ACE_Cleanup_Strategy<KEY, VALUE, CONTAINER> *cleanup_strategy,
+ int delete_cleanup_strategy)
+ : cleanup_strategy_ (cleanup_strategy),
+ delete_cleanup_strategy_ (delete_cleanup_strategy),
+ marked_as_closed_entries_ (0)
+{
+ if (cleanup_strategy == 0)
+ {
+ ACE_NEW (this->cleanup_strategy_,
+ CLEANUP_STRATEGY);
+ this->delete_cleanup_strategy_ = 1;
+ }
+}
+
+template <class KEY, class VALUE, class CONTAINER, class ITERATOR, class ATTRIBUTES>
+ACE_Refcounted_Recyclable_Handler_Caching_Utility<KEY, VALUE, CONTAINER, ITERATOR, ATTRIBUTES>::~ACE_Refcounted_Recyclable_Handler_Caching_Utility (void)
+{
+ if (this->delete_cleanup_strategy_)
+ delete this->cleanup_strategy_;
+}
+
+template <class KEY, class VALUE, class CONTAINER, class ITERATOR, class ATTRIBUTES> int
+ACE_Refcounted_Recyclable_Handler_Caching_Utility<KEY, VALUE, CONTAINER, ITERATOR, ATTRIBUTES>::clear_cache (CONTAINER &container,
+ double purge_percent)
+{
+ // Check that the purge_percent is non-zero.
+ if (purge_percent == 0)
+ return 0;
+
+ // Get the number of entries in the container which can be considered for purging.
+ size_t available_entries = container.current_size () - this->marked_as_closed_entries_;
+
+ // Also whether the number of entries in the cache zero.
+ // Oops! then there is no way out but exiting.
+ if (available_entries <= 0)
+ return 0;
+
+ // Calculate the no of entries to remove from the cache depending
+ // upon the <purge_percent>.
+ size_t entries_to_remove
+ = ACE_MAX (ACE_static_cast (size_t, 1),
+ ACE_static_cast(size_t,
+ ACE_static_cast(double, purge_percent)
+ / 100 * available_entries));
+
+ if (entries_to_remove >= available_entries ||
+ entries_to_remove == 0)
+ entries_to_remove = available_entries - 1;
+
+ KEY *key_to_remove = 0;
+ VALUE *value_to_remove = 0;
+
+ for (size_t i = 0; i < entries_to_remove ; ++i)
+ {
+ this->minimum (container,
+ key_to_remove,
+ value_to_remove);
+
+ // Simply verifying that the key is non-zero.
+ // This is important for strategies where the minimum
+ // entry cant be found due to constraints on the type of entry
+ // to remove.
+ if (key_to_remove == 0)
+ return 0;
+
+ if (this->cleanup_strategy_->cleanup (container,
+ key_to_remove,
+ value_to_remove) == -1)
+ return -1;
+
+ ++this->marked_as_closed_entries_;
+ }
+
+ return 0;
+}
+
+template <class KEY, class VALUE, class CONTAINER, class ITERATOR, class ATTRIBUTES> void
+ACE_Refcounted_Recyclable_Handler_Caching_Utility<KEY, VALUE, CONTAINER, ITERATOR, ATTRIBUTES>::minimum (CONTAINER &container,
+ KEY *&key_to_remove,
+ VALUE *&value_to_remove)
+{
+ // Starting values.
+ ITERATOR end = container.end ();
+ ITERATOR iter = container.begin ();
+ ATTRIBUTES min = (*iter).int_id_.second ();
+ key_to_remove = 0;
+ value_to_remove = 0;
+ // Found the minimum entry to be purged?
+ int found = 0;
+
+ // The iterator moves thru the container searching for the entry
+ // with the lowest ATTRIBUTES.
+ for (;
+ iter != end;
+ ++iter)
+ {
+ // If the <min> entry isnt IDLE_AND_PURGABLE continue until you reach
+ // the first entry which can be purged. This is the minimum with
+ // which you will compare the rest of the purgable entries.
+ if ((*iter).ext_id_.recycle_state () == ACE_RECYCLABLE_IDLE_AND_PURGABLE ||
+ (*iter).ext_id_.recycle_state () == ACE_RECYCLABLE_PURGABLE_BUT_NOT_IDLE)
+ {
+ if (found == 0)
+ {
+ min = (*iter).int_id_.second ();
+ key_to_remove = &(*iter).ext_id_;
+ value_to_remove = &(*iter).int_id_;
+ found = 1;
+ }
+ else
+ {
+ // Ah! an entry with lower ATTTRIBUTES...
+ if (min > (*iter).int_id_.second ())
+ {
+ min = (*iter).int_id_.second ();
+ key_to_remove = &(*iter).ext_id_;
+ value_to_remove = &(*iter).int_id_;
+ }
+ }
+ }
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+template <class KEY, class VALUE, class CONTAINER, class ITERATOR, class ATTRIBUTES>
+ACE_Handler_Caching_Utility<KEY, VALUE, CONTAINER, ITERATOR, ATTRIBUTES>::ACE_Handler_Caching_Utility (ACE_Cleanup_Strategy<KEY, VALUE, CONTAINER> *cleanup_strategy,
+ int delete_cleanup_strategy)
+ : cleanup_strategy_ (cleanup_strategy),
+ delete_cleanup_strategy_ (delete_cleanup_strategy)
+{
+ if (cleanup_strategy == 0)
+ {
+ ACE_NEW (this->cleanup_strategy_,
+ CLEANUP_STRATEGY);
+ this->delete_cleanup_strategy_ = 1;
+ }
+}
+
+template <class KEY, class VALUE, class CONTAINER, class ITERATOR, class ATTRIBUTES>
+ACE_Handler_Caching_Utility<KEY, VALUE, CONTAINER, ITERATOR, ATTRIBUTES>::~ACE_Handler_Caching_Utility (void)
+{
+ if (this->delete_cleanup_strategy_)
+ delete this->cleanup_strategy_;
+}
+
+template <class KEY, class VALUE, class CONTAINER, class ITERATOR, class ATTRIBUTES> int
+ACE_Handler_Caching_Utility<KEY, VALUE, CONTAINER, ITERATOR, ATTRIBUTES>::clear_cache (CONTAINER &container,
+ double purge_percent)
+{
+ // Check that the purge_percent is non-zero.
+ if (purge_percent == 0)
+ return 0;
+
+ // Get the number of entries in the container.
+ size_t current_map_size = container.current_size ();
+
+ // Also whether the number of entries in the cache is just one!
+ // Oops! then there is no way out but exiting. So return an error.
+ if (current_map_size == 0)
+ return 0;
+
+ // Calculate the no of entries to remove from the cache depending
+ // upon the <purge_percent>.
+ size_t entries_to_remove
+ = ACE_MAX (ACE_static_cast (size_t, 1),
+ ACE_static_cast(size_t,
+ ACE_static_cast(double, purge_percent)
+ / 100 * current_map_size));
+
+ KEY *key_to_remove = 0;
+ VALUE *value_to_remove = 0;
+
+ for (size_t i = 0; i < entries_to_remove ; ++i)
+ {
+ this->minimum (container,
+ key_to_remove,
+ value_to_remove);
+
+ if (this->cleanup_strategy_->cleanup (container,
+ key_to_remove,
+ value_to_remove) == -1)
+ return -1;
+ }
+
+ return 0;
+}
+
+template <class KEY, class VALUE, class CONTAINER, class ITERATOR, class ATTRIBUTES> void
+ACE_Handler_Caching_Utility<KEY, VALUE, CONTAINER, ITERATOR, ATTRIBUTES>::minimum (CONTAINER &container,
+ KEY *&key_to_remove,
+ VALUE *&value_to_remove)
+{
+ // Starting values.
+ ITERATOR iter = container.begin ();
+ ITERATOR end = container.end ();
+ ATTRIBUTES min = (*iter).int_id_->caching_attributes ();
+ key_to_remove = &(*iter).ext_id_;
+ value_to_remove = &(*iter).int_id_;
+
+ // The iterator moves thru the container searching for the entry
+ // with the lowest ATTRIBUTES.
+ for (++iter;
+ iter != end;
+ ++iter)
+ {
+ if (min > (*iter).int_id_->caching_attributes () &&
+ (*iter).int_id_->active () != 1)
+ {
+ // Ah! an item with lower ATTTRIBUTES...
+ min = (*iter).int_id_->caching_attributes ();
+ key_to_remove = &(*iter).ext_id_;
+ value_to_remove = &(*iter).int_id_;
+ }
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+template <class KEY, class VALUE, class CONTAINER, class ITERATOR, class ATTRIBUTES>
+ACE_Null_Caching_Utility<KEY, VALUE, CONTAINER, ITERATOR, ATTRIBUTES>::ACE_Null_Caching_Utility (ACE_Cleanup_Strategy<KEY, VALUE, CONTAINER> *cleanup_strategy,
+ int delete_cleanup_strategy)
+ : cleanup_strategy_ (cleanup_strategy),
+ delete_cleanup_strategy_ (delete_cleanup_strategy)
+{
+ if (cleanup_strategy == 0)
+ {
+ ACE_NEW (this->cleanup_strategy_,
+ CLEANUP_STRATEGY);
+ this->delete_cleanup_strategy_ = 1;
+ }
+}
+
+template <class KEY, class VALUE, class CONTAINER, class ITERATOR, class ATTRIBUTES>
+ACE_Null_Caching_Utility<KEY, VALUE, CONTAINER, ITERATOR, ATTRIBUTES>::~ACE_Null_Caching_Utility (void)
+{
+ if (this->delete_cleanup_strategy_)
+ delete this->cleanup_strategy_;
+}
+
+template <class KEY, class VALUE, class CONTAINER, class ITERATOR, class ATTRIBUTES> int
+ACE_Null_Caching_Utility<KEY, VALUE, CONTAINER, ITERATOR, ATTRIBUTES>::clear_cache (CONTAINER &container,
+ double purge_percent)
+{
+ ACE_UNUSED_ARG (container);
+ ACE_UNUSED_ARG (purge_percent);
+
+ return 0;
+}
+
+template <class KEY, class VALUE, class CONTAINER, class ITERATOR, class ATTRIBUTES> void
+ACE_Null_Caching_Utility<KEY, VALUE, CONTAINER, ITERATOR, ATTRIBUTES>::minimum (CONTAINER &container,
+ KEY *&key_to_remove,
+ VALUE *&value_to_remove)
+{
+ ACE_UNUSED_ARG (container);
+ ACE_UNUSED_ARG (key_to_remove);
+ ACE_UNUSED_ARG (value_to_remove);
+}
+
+#endif /* CACHING_UTILITY_T_C */
diff --git a/ace/Utils/Templates/Caching_Utility_T.h b/ace/Utils/Templates/Caching_Utility_T.h
new file mode 100644
index 00000000000..4a529627f20
--- /dev/null
+++ b/ace/Utils/Templates/Caching_Utility_T.h
@@ -0,0 +1,343 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Caching_Utility_T.h
+ *
+ * $Id$
+ *
+ * @author Kirthika Parameswaran <kirthika@cs.wustl.edu>
+ */
+//=============================================================================
+
+#ifndef CACHING_UTILITY_H
+#define CACHING_UTILITY_H
+#include "ace/pre.h"
+
+#include "ace/OS.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+#define ACE_LACKS_PRAGMA_ONCE
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "ace/Cleanup_Strategies_T.h"
+
+// For linkers that cant grok long names.
+#define ACE_Pair_Caching_Utility APUTIL
+
+/**
+ * @class ACE_Pair_Caching_Utility
+ *
+ * @brief Defines a helper class for the Caching Strategies.
+ *
+ * This class defines the methods commonly used by the different
+ * caching strategies. For instance: <clear_cache> method which
+ * decides and purges the entry from the container. Note: This
+ * class helps in the caching_strategies using a container
+ * containing entries of <KEY, ACE_Pair<VALUE, attributes>>
+ * kind. The attributes helps in deciding the entries to be
+ * purged. The Cleanup_Strategy is the callback class to which the
+ * entries to be cleaned up will be delegated.
+ */
+template <class KEY, class VALUE, class CONTAINER, class ITERATOR, class ATTRIBUTES>
+class ACE_Pair_Caching_Utility
+{
+public:
+
+ typedef ACE_Cleanup_Strategy<KEY, VALUE, CONTAINER> CLEANUP_STRATEGY;
+
+ ACE_Pair_Caching_Utility (ACE_Cleanup_Strategy<KEY, VALUE, CONTAINER> *cleanup_strategy = 0,
+ int delete_cleanup_strategy = 0);
+
+ // Constructor.
+
+ /// Destructor.
+ ~ACE_Pair_Caching_Utility (void);
+
+ int clear_cache (CONTAINER &container,
+ double purge_percent);
+
+ // Purge entries from the <container>. The Cleanup_Strategy will do
+ // the actual job of cleanup once the entries to be cleaned up are
+ // decided.
+
+protected:
+
+ /// Find the entry with minimum caching attributes.
+ void minimum (CONTAINER &container,
+ KEY *&key_to_remove,
+ VALUE *&value_to_remove);
+
+ /// The cleanup strategy which can be used to destroy the entries of
+ /// the container.
+ CLEANUP_STRATEGY *cleanup_strategy_;
+
+ /// Whether the cleanup_strategy should be destroyed or not.
+ int delete_cleanup_strategy_;
+
+ ACE_UNIMPLEMENTED_FUNC (void operator= (const ACE_Pair_Caching_Utility<KEY,VALUE,CONTAINER,ITERATOR,ATTRIBUTES> &))
+ ACE_UNIMPLEMENTED_FUNC (ACE_Pair_Caching_Utility (const ACE_Pair_Caching_Utility<KEY,VALUE,CONTAINER,ITERATOR,ATTRIBUTES> &))
+};
+
+////////////////////////////////////////////////////////////////////////////////
+#define ACE_Recyclable_Handler_Caching_Utility ARHUTIL
+
+/**
+ * @class ACE_Recyclable_Handler_Caching_Utility
+ *
+ * @brief Defines a helper class for the Caching Strategies.
+ *
+ * This class defines the methods commonly used by the different
+ * caching strategies. For instance: <clear_cache> method which
+ * decides and purges the entry from the container. Note: This
+ * class helps in the caching_strategies using a container
+ * containing entries of <KEY, Svc_Handler> kind. The attributes
+ * helps in deciding the entries to be purged. The
+ * Cleanup_Strategy is the callback class to which the entries to
+ * be cleaned up will be delegated.
+ */
+template <class KEY, class VALUE, class CONTAINER, class ITERATOR, class ATTRIBUTES>
+class ACE_Recyclable_Handler_Caching_Utility
+{
+
+public:
+
+ typedef ACE_Recyclable_Handler_Cleanup_Strategy<KEY, VALUE, CONTAINER> CLEANUP_STRATEGY;
+ typedef ACE_Cleanup_Strategy<KEY, VALUE, CONTAINER> CLEANUP_STRATEGY_BASE;
+
+ ACE_Recyclable_Handler_Caching_Utility (ACE_Cleanup_Strategy<KEY, VALUE, CONTAINER> *cleanup_strategy = 0,
+ int delete_cleanup_strategy = 0);
+
+ // Constructor.
+
+ /// Destructor.
+ ~ACE_Recyclable_Handler_Caching_Utility (void);
+
+ /**
+ * Purge entries from the <container>. The Cleanup_Strategy will do
+ * the actual job of cleanup once the entries to be cleaned up are
+ * decided.
+ */
+ int clear_cache (CONTAINER &container,
+ double purge_percent);
+
+protected:
+
+ /// Find the entry with minimum caching attributes.
+ void minimum (CONTAINER &container,
+ KEY *&key_to_remove,
+ VALUE *&value_to_remove);
+
+ /// This is the default Cleanup Strategy for this utility.
+ CLEANUP_STRATEGY_BASE *cleanup_strategy_;
+
+ /// Whether the cleanup_strategy should be destroyed or not.
+ int delete_cleanup_strategy_;
+
+private:
+ ACE_UNIMPLEMENTED_FUNC (void operator= (const ACE_Recyclable_Handler_Caching_Utility<KEY,VALUE,CONTAINER,ITERATOR,ATTRIBUTES> &))
+ ACE_UNIMPLEMENTED_FUNC (ACE_Recyclable_Handler_Caching_Utility (const ACE_Recyclable_Handler_Caching_Utility<KEY,VALUE,CONTAINER,ITERATOR,ATTRIBUTES> &))
+};
+
+///////////////////////////////////////////////////////////////////////////
+#define ACE_Refcounted_Recyclable_Handler_Caching_Utility ARRHUTIL
+
+/**
+ * @class ACE_Refcounted_Recyclable_Handler_Caching_Utility
+ *
+ * @brief Defines a helper class for the Caching Strategies.
+ *
+ * This class defines the methods commonly used by the different
+ * caching strategies. For instance: clear_cache () method which
+ * decides and purges the entry from the container. Note: This
+ * class helps in the caching_strategies using a container
+ * containing entries of <Refcounted_KEY,
+ * Recyclable_Connection_Handler> kind. The attributes helps in
+ * deciding the entries to be purged. The Cleanup_Strategy is the
+ * callback class to which the entries to be cleaned up will be
+ * delegated.
+ */
+template <class KEY, class VALUE, class CONTAINER, class ITERATOR, class ATTRIBUTES>
+class ACE_Refcounted_Recyclable_Handler_Caching_Utility
+{
+
+public:
+
+ typedef ACE_Refcounted_Recyclable_Handler_Cleanup_Strategy<KEY, VALUE, CONTAINER> CLEANUP_STRATEGY;
+ typedef ACE_Cleanup_Strategy<KEY, VALUE, CONTAINER> CLEANUP_STRATEGY_BASE;
+
+ ACE_Refcounted_Recyclable_Handler_Caching_Utility (ACE_Cleanup_Strategy<KEY, VALUE, CONTAINER> *cleanup_strategy = 0,
+ int delete_cleanup_strategy = 0);
+
+ // Constructor.
+
+ /// Destructor.
+ ~ACE_Refcounted_Recyclable_Handler_Caching_Utility (void);
+
+ /**
+ * Purge entries from the <container>. The Cleanup_Strategy will do
+ * the actual job of cleanup once the entries to be cleaned up are
+ * decided.
+ */
+ int clear_cache (CONTAINER &container,
+ double purge_percent);
+
+protected:
+
+ /// Find the entry with minimum caching attributes.
+ void minimum (CONTAINER &container,
+ KEY *&key_to_remove,
+ VALUE *&value_to_remove);
+
+ /// This is the default Cleanup Strategy for this utility.
+ CLEANUP_STRATEGY_BASE *cleanup_strategy_;
+
+ /// Whether the cleanup_strategy should be destroyed or not.
+ int delete_cleanup_strategy_;
+
+ /**
+ * This figure denotes the number of entries are there in the
+ * container which have been marked as closed already but might
+ * not have been unbound from the container.
+ */
+ size_t marked_as_closed_entries_;
+
+private:
+ ACE_UNIMPLEMENTED_FUNC (void operator= (const ACE_Refcounted_Recyclable_Handler_Caching_Utility<KEY,VALUE,CONTAINER,ITERATOR,ATTRIBUTES> &))
+ ACE_UNIMPLEMENTED_FUNC (ACE_Refcounted_Recyclable_Handler_Caching_Utility (const ACE_Refcounted_Recyclable_Handler_Caching_Utility<KEY,VALUE,CONTAINER,ITERATOR,ATTRIBUTES> &))
+};
+
+////////////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * @class ACE_Handler_Caching_Utility
+ *
+ * @brief Defines a helper class for the Caching Strategies.
+ *
+ * This class defines the methods commonly used by the different
+ * caching strategies. For instance: <clear_cache> method which
+ * decides and purges the entry from the container. Note: This
+ * class helps in the caching_strategies using a container
+ * containing entries of <KEY, HANDLER> kind where the HANDLER
+ * contains the caching attributes which help in deciding the
+ * entries to be purged. The Cleanup_Strategy is the callback
+ * class to which the entries to be cleaned up will be delegated.
+ */
+template <class KEY, class VALUE, class CONTAINER, class ITERATOR, class ATTRIBUTES>
+class ACE_Handler_Caching_Utility
+{
+public:
+
+ typedef ACE_Handler_Cleanup_Strategy<KEY, VALUE, CONTAINER> CLEANUP_STRATEGY;
+ typedef ACE_Cleanup_Strategy<KEY, VALUE, CONTAINER> CLEANUP_STRATEGY_BASE;
+
+ /// Constructor.
+ ACE_Handler_Caching_Utility (ACE_Cleanup_Strategy<KEY, VALUE, CONTAINER> *cleanup_strategy = 0,
+ int delete_cleanup_strategy = 0);
+
+ /// Destructor.
+ ~ACE_Handler_Caching_Utility (void);
+
+ /**
+ * Purge entries from the <container>. The Cleanup_Strategy will do
+ * the actual job of cleanup once the entries to be cleaned up are
+ * decided.
+ */
+ int clear_cache (CONTAINER &container,
+ double purge_percent);
+
+protected:
+
+ /**
+ * Find the entry with minimum caching attributes. This is handler
+ * specific since this utility is to be used very specifically for
+ * handler who have caching_attributes for server side acched
+ * connection management.
+ */
+ void minimum (CONTAINER &container,
+ KEY *&key_to_remove,
+ VALUE *&value_to_remove);
+
+ /// The cleanup strategy which can be used to destroy the entries of
+ /// the container.
+ CLEANUP_STRATEGY_BASE *cleanup_strategy_;
+
+ /// Whether the cleanup_strategy should be destroyed or not.
+ int delete_cleanup_strategy_;
+
+private:
+ ACE_UNIMPLEMENTED_FUNC (void operator= (const ACE_Handler_Caching_Utility<KEY,VALUE,CONTAINER,ITERATOR,ATTRIBUTES> &))
+ ACE_UNIMPLEMENTED_FUNC (ACE_Handler_Caching_Utility (const ACE_Handler_Caching_Utility<KEY,VALUE,CONTAINER,ITERATOR,ATTRIBUTES> &))
+};
+
+///////////////////////////////////////////////////////////////////////////
+#define ACE_Null_Caching_Utility ANUTIL
+/**
+ * @class ACE_Null_Caching_Utility
+ *
+ * @brief Defines a dummy helper class for the Caching Strategies.
+ *
+ * This class defines the methods commonly used by the different
+ * caching strategies. For instance: <clear_cache> method which
+ * decides and purges the entry from the container. Note: This
+ * class is be used with the Null_Caching_Strategy. The
+ * Cleanup_Strategy is the callback class to which the entries to
+ * be cleaned up will be delegated.
+ */
+template <class KEY, class VALUE, class CONTAINER, class ITERATOR, class ATTRIBUTES>
+class ACE_Null_Caching_Utility
+{
+public:
+
+ typedef ACE_Null_Cleanup_Strategy<KEY, VALUE, CONTAINER> CLEANUP_STRATEGY;
+ typedef ACE_Cleanup_Strategy<KEY, VALUE, CONTAINER> CLEANUP_STRATEGY_BASE;
+
+ /// Constructor.
+ ACE_Null_Caching_Utility (ACE_Cleanup_Strategy<KEY, VALUE, CONTAINER> *cleanup_strategy = 0,
+ int delete_cleanup_strategy = 0);
+
+ /// Destructor.
+ ~ACE_Null_Caching_Utility (void);
+
+ /**
+ * Purge entries from the <container>. The Cleanup_Strategy will do
+ * the actual job of cleanup once the entries to be cleaned up are
+ * decided. NOte: Here it is a no-op.
+ */
+ int clear_cache (CONTAINER &container,
+ double purge_percent);
+
+protected:
+
+ /**
+ * Find the entry with minimum caching attributes. This is handler
+ * specific since this utility is to be used very specifically for
+ * handler who have caching_attributes for server side acched
+ * connection management.Note: Here it is a no-op.
+ */
+ void minimum (CONTAINER &container,
+ KEY *&key_to_remove,
+ VALUE *&value_to_remove);
+
+ /// The cleanup strategy which can be used to destroy the entries of
+ /// the container.
+ CLEANUP_STRATEGY_BASE *cleanup_strategy_;
+
+ /// Whether the cleanup_strategy should be destroyed or not.
+ int delete_cleanup_strategy_;
+
+private:
+ ACE_UNIMPLEMENTED_FUNC (void operator= (const ACE_Null_Caching_Utility<KEY,VALUE,CONTAINER,ITERATOR,ATTRIBUTES> &))
+ ACE_UNIMPLEMENTED_FUNC (ACE_Null_Caching_Utility (const ACE_Null_Caching_Utility<KEY,VALUE,CONTAINER,ITERATOR,ATTRIBUTES> &))
+};
+
+#if defined (ACE_TEMPLATES_REQUIRE_SOURCE)
+#include "ace/Caching_Utility_T.cpp"
+#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */
+
+#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA)
+#pragma implementation ("Caching_Utility_T.cpp")
+#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */
+
+#include "ace/post.h"
+#endif /* CACHING_UTILITY_H */
diff --git a/ace/Utils/Templates/Cleanup_Strategies_T.cpp b/ace/Utils/Templates/Cleanup_Strategies_T.cpp
new file mode 100644
index 00000000000..84b20f9035a
--- /dev/null
+++ b/ace/Utils/Templates/Cleanup_Strategies_T.cpp
@@ -0,0 +1,89 @@
+//$Id$
+
+#ifndef CLEANUP_STRATEGIES_T_C
+#define CLEANUP_STRATEGIES_T_C
+
+#include "ace/Cleanup_Strategies_T.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+#define ACE_LACKS_PRAGMA_ONCE
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+ACE_RCSID(ace, Cleanup_Strategies_T, "$Id$")
+
+////////////////////////////////////////////////////////////////////////////
+
+template <class KEY, class VALUE, class CONTAINER> int
+ACE_Cleanup_Strategy<KEY, VALUE, CONTAINER>::cleanup (CONTAINER &container,
+ KEY *key,
+ VALUE *value)
+{
+ ACE_UNUSED_ARG (value);
+
+ return container.unbind (*key);
+}
+
+////////////////////////////////////////////////////////////////////////////
+
+template <class KEY, class VALUE, class CONTAINER> int
+ACE_Recyclable_Handler_Cleanup_Strategy<KEY, VALUE, CONTAINER>::cleanup (CONTAINER &container,
+ KEY *key,
+ VALUE *)
+{
+ VALUE value;
+
+ if (container.unbind (*key, value) == -1)
+ return -1;
+
+ value.first ()->recycler (0, 0);
+
+ value.first ()->close ();
+
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+template <class KEY, class VALUE, class CONTAINER> int
+ACE_Refcounted_Recyclable_Handler_Cleanup_Strategy<KEY, VALUE, CONTAINER>::cleanup (CONTAINER &,
+ KEY *,
+ VALUE *value)
+{
+ return value->first ()->handle_close_i ();
+}
+
+////////////////////////////////////////////////////////////////////////////
+
+template <class KEY, class VALUE, class CONTAINER> int
+ACE_Handler_Cleanup_Strategy<KEY, VALUE, CONTAINER>::cleanup (CONTAINER &container,
+ KEY *key,
+ VALUE *value)
+{
+ // Remove the item from cache only if the handler isnt in use.
+ if ((*value)->active () == 0)
+ {
+ (*value)->close ();
+
+ if (container.unbind (*key) == -1)
+ return -1;
+
+ }
+
+ return 0;
+}
+
+////////////////////////////////////////////////////////////////////////////
+
+template <class KEY, class VALUE, class CONTAINER> int
+ACE_Null_Cleanup_Strategy<KEY, VALUE, CONTAINER>::cleanup (CONTAINER &container,
+ KEY *key,
+ VALUE *value)
+{
+ ACE_UNUSED_ARG (container);
+ ACE_UNUSED_ARG (key);
+ ACE_UNUSED_ARG (value);
+
+ return 0;
+}
+
+#endif /* CLEANUP_STRATEGIES_T_C */
diff --git a/ace/Utils/Templates/Cleanup_Strategies_T.h b/ace/Utils/Templates/Cleanup_Strategies_T.h
new file mode 100644
index 00000000000..337e30bd9fe
--- /dev/null
+++ b/ace/Utils/Templates/Cleanup_Strategies_T.h
@@ -0,0 +1,148 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Cleanup_Strategies_T.h
+ *
+ * $Id$
+ *
+ * @author Kirthika Parameswaran <kirthika@cs.wustl.edu>
+ */
+//=============================================================================
+
+
+#ifndef CLEANUP_STRATEGIES_H
+#define CLEANUP_STRATEGIES_H
+#include "ace/pre.h"
+
+#include "ace/OS.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+#define ACE_LACKS_PRAGMA_ONCE
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+// For linkers that cant grok long names.
+#define ACE_Cleanup_Strategy ACLE
+
+/**
+ * @class ACE_Cleanup_Strategy
+ *
+ * @brief Defines a default strategy to be followed for cleaning up
+ * entries from a map which is the container.
+ *
+ * By default the entry to be cleaned up is removed from the
+ * container.
+ */
+template <class KEY, class VALUE, class CONTAINER>
+class ACE_Cleanup_Strategy
+{
+
+public:
+
+ /// The method which will do the cleanup of the entry in the container.
+ virtual int cleanup (CONTAINER &container, KEY *key, VALUE *value);
+};
+
+//////////////////////////////////////////////////////////////////////
+#define ACE_Recyclable_Handler_Cleanup_Strategy ARHCLE
+
+/**
+ * @class ACE_Recyclable_Handler_Cleanup_Strategy
+ *
+ * @brief Defines a strategy to be followed for cleaning up
+ * entries which are svc_handlers from a container.
+ *
+ * The entry to be cleaned up is removed from the container.
+ * Here, since we are dealing with svc_handlers specifically, we
+ * perform a couple of extra operations. Note: To be used when
+ * the handler is recyclable.
+ */
+template <class KEY, class VALUE, class CONTAINER>
+class ACE_Recyclable_Handler_Cleanup_Strategy : public ACE_Cleanup_Strategy<KEY, VALUE, CONTAINER>
+{
+
+public:
+
+ /// The method which will do the cleanup of the entry in the container.
+ virtual int cleanup (CONTAINER &container, KEY *key, VALUE *value);
+};
+
+//////////////////////////////////////////////////////////////////////
+#define ACE_Refcounted_Recyclable_Handler_Cleanup_Strategy ARRHCLE
+
+/**
+ * @class ACE_Refcounted_Recyclable_Handler_Cleanup_Strategy
+ *
+ * @brief Defines a strategy to be followed for cleaning up
+ * entries which are svc_handlers from a container.
+ *
+ * The entry to be cleaned up is removed from the container.
+ * Here, since we are dealing with recyclable svc_handlers with
+ * addresses which are refcountable specifically, we perform a
+ * couple of extra operations and do so without any locking.
+ */
+template <class KEY, class VALUE, class CONTAINER>
+class ACE_Refcounted_Recyclable_Handler_Cleanup_Strategy : public ACE_Cleanup_Strategy<KEY, VALUE, CONTAINER>
+{
+
+public:
+
+ /// The method which will do the cleanup of the entry in the container.
+ virtual int cleanup (CONTAINER &container, KEY *key, VALUE *value);
+};
+
+//////////////////////////////////////////////////////////////////////
+
+/**
+ * @class ACE_Handler_Cleanup_Strategy
+ *
+ * @brief Defines a strategy to be followed for cleaning up
+ * entries which are svc_handlers from a container.
+ *
+ * The entry to be cleaned up is removed from the container.
+ * Here, since we are dealing with svc_handlers specifically, we
+ * perform a couple of extra operations. Note: This cleanup strategy
+ * should be used in the case when the handler has the caching
+ * attributes.
+ */
+template <class KEY, class VALUE, class CONTAINER>
+class ACE_Handler_Cleanup_Strategy : public ACE_Cleanup_Strategy<KEY, VALUE, CONTAINER>
+{
+
+public:
+
+ /// The method which will do the cleanup of the entry in the container.
+ virtual int cleanup (CONTAINER &container, KEY *key, VALUE *value);
+};
+
+//////////////////////////////////////////////////////////////////////
+#define ACE_Null_Cleanup_Strategy ANCLE
+
+/**
+ * @class ACE_Null_Cleanup_Strategy
+ *
+ * @brief Defines a do-nothing implementation of the cleanup strategy.
+ *
+ * This class simply does nothing at all! Can be used to nullify
+ * the effect of the Cleanup Strategy.
+ */
+template <class KEY, class VALUE, class CONTAINER>
+class ACE_Null_Cleanup_Strategy : public ACE_Cleanup_Strategy<KEY, VALUE, CONTAINER>
+{
+
+public:
+
+ /// The dummy cleanup method.
+ virtual int cleanup (CONTAINER &container, KEY *key, VALUE *value);
+};
+
+#if defined (ACE_TEMPLATES_REQUIRE_SOURCE)
+#include "ace/Cleanup_Strategies_T.cpp"
+#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */
+
+#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA)
+#pragma implementation ("Cleanup_Strategies_T.cpp")
+#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */
+
+#include "ace/post.h"
+#endif /* CLEANUP_STRATEGIES_H */
diff --git a/ace/Utils/Templates/Containers_T.cpp b/ace/Utils/Templates/Containers_T.cpp
new file mode 100644
index 00000000000..7f6d0683368
--- /dev/null
+++ b/ace/Utils/Templates/Containers_T.cpp
@@ -0,0 +1,1813 @@
+// $Id$
+
+#ifndef ACE_CONTAINERS_T_C
+#define ACE_CONTAINERS_T_C
+
+#include "ace/Log_Msg.h"
+#include "ace/Malloc_Base.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "ace/Containers.h"
+
+#if !defined (__ACE_INLINE__)
+#include "ace/Containers_T.i"
+#endif /* __ACE_INLINE__ */
+
+ACE_RCSID(ace, Containers_T, "$Id$")
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Bounded_Stack)
+
+template <class T> void
+ACE_Bounded_Stack<T>::dump (void) const
+{
+ ACE_TRACE ("ACE_Bounded_Stack<T>::dump");
+}
+
+template<class T>
+ACE_Bounded_Stack<T>::ACE_Bounded_Stack (size_t size)
+ : top_ (0),
+ size_ (size)
+{
+ ACE_NEW (this->stack_,
+ T[size]);
+ ACE_TRACE ("ACE_Bounded_Stack<T>::ACE_Bounded_Stack");
+}
+
+template<class T>
+ACE_Bounded_Stack<T>::ACE_Bounded_Stack (const ACE_Bounded_Stack<T> &s)
+ : top_ (s.top_),
+ size_ (s.size_)
+{
+ ACE_NEW (this->stack_,
+ T[s.size_]);
+
+ ACE_TRACE ("ACE_Bounded_Stack<T>::ACE_Bounded_Stack");
+
+ for (size_t i = 0; i < this->top_; i++)
+ this->stack_[i] = s.stack_[i];
+}
+
+template<class T> void
+ACE_Bounded_Stack<T>::operator= (const ACE_Bounded_Stack<T> &s)
+{
+ ACE_TRACE ("ACE_Bounded_Stack<T>::operator=");
+
+ if (&s != this)
+ {
+ if (this->size_ < s.size_)
+ {
+ delete [] this->stack_;
+ ACE_NEW (this->stack_,
+ T[s.size_]);
+ this->size_ = s.size_;
+ }
+ this->top_ = s.top_;
+
+ for (size_t i = 0; i < this->top_; i++)
+ this->stack_[i] = s.stack_[i];
+ }
+}
+
+template<class T>
+ACE_Bounded_Stack<T>::~ACE_Bounded_Stack (void)
+{
+ ACE_TRACE ("ACE_Bounded_Stack<T>::~ACE_Bounded_Stack");
+ delete [] this->stack_;
+}
+
+// ----------------------------------------
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Fixed_Stack)
+
+template <class T, size_t ACE_SIZE> void
+ACE_Fixed_Stack<T, ACE_SIZE>::dump (void) const
+{
+ ACE_TRACE ("ACE_Fixed_Stack<T, ACE_SIZE>::dump");
+}
+
+template<class T, size_t ACE_SIZE>
+ACE_Fixed_Stack<T, ACE_SIZE>::ACE_Fixed_Stack (void)
+ : top_ (0),
+ size_ (ACE_SIZE)
+{
+ ACE_TRACE ("ACE_Fixed_Stack<T, ACE_SIZE>::ACE_Fixed_Stack");
+}
+
+template<class T, size_t ACE_SIZE>
+ACE_Fixed_Stack<T, ACE_SIZE>::ACE_Fixed_Stack (const ACE_Fixed_Stack<T, ACE_SIZE> &s)
+ : top_ (s.top_),
+ size_ (s.size_)
+{
+ ACE_TRACE ("ACE_Fixed_Stack<T, ACE_SIZE>::ACE_Fixed_Stack");
+ for (size_t i = 0; i < this->top_; i++)
+ this->stack_[i] = s.stack_[i];
+}
+
+template<class T, size_t ACE_SIZE> void
+ACE_Fixed_Stack<T, ACE_SIZE>::operator= (const ACE_Fixed_Stack<T, ACE_SIZE> &s)
+{
+ ACE_TRACE ("ACE_Fixed_Stack<T, ACE_SIZE>::operator=");
+
+ if (&s != this)
+ {
+ this->top_ = s.top_;
+
+ for (size_t i = 0; i < this->top_; i++)
+ this->stack_[i] = s.stack_[i];
+ }
+}
+
+template<class T, size_t ACE_SIZE>
+ACE_Fixed_Stack<T, ACE_SIZE>::~ACE_Fixed_Stack (void)
+{
+ ACE_TRACE ("ACE_Fixed_Stack<T, ACE_SIZE>::~ACE_Fixed_Stack");
+}
+
+//----------------------------------------
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Unbounded_Stack)
+
+template <class T> void
+ACE_Unbounded_Stack<T>::dump (void) const
+{
+ // ACE_TRACE ("ACE_Unbounded_Stack<T>::dump");
+}
+
+template<class T>
+ACE_Unbounded_Stack<T>::ACE_Unbounded_Stack (ACE_Allocator *alloc)
+ : head_ (0),
+ cur_size_ (0),
+ allocator_ (alloc)
+{
+ // ACE_TRACE ("ACE_Unbounded_Stack<T>::ACE_Unbounded_Stack");
+ if (this->allocator_ == 0)
+ this->allocator_ = ACE_Allocator::instance ();
+
+ ACE_NEW_MALLOC (this->head_,
+ (ACE_Node<T> *) this->allocator_->malloc (sizeof (ACE_Node<T>)),
+ ACE_Node<T>);
+ this->head_->next_ = this->head_;
+}
+
+template<class T> void
+ACE_Unbounded_Stack<T>::delete_all_nodes (void)
+{
+ // ACE_TRACE ("ACE_Unbounded_Stack<T>::delete_all_nodes");
+
+ while (this->is_empty () == 0)
+ {
+ ACE_Node<T> *temp = this->head_->next_;
+ this->head_->next_ = temp->next_;
+ ACE_DES_FREE_TEMPLATE (temp, this->allocator_->free,
+ ACE_Node, <T>);
+ }
+
+ this->cur_size_ = 0;
+
+ ACE_ASSERT (this->head_ == this->head_->next_
+ && this->is_empty ());
+}
+
+template<class T> void
+ACE_Unbounded_Stack<T>::copy_all_nodes (const ACE_Unbounded_Stack<T> &s)
+{
+ // ACE_TRACE ("ACE_Unbounded_Stack<T>::copy_all_nodes");
+
+ ACE_ASSERT (this->head_ == this->head_->next_);
+
+ ACE_Node<T> *temp = this->head_;
+
+ for (ACE_Node<T> *s_temp = s.head_->next_;
+ s_temp != s.head_;
+ s_temp = s_temp->next_)
+ {
+ ACE_Node<T> *nptr = temp->next_;
+ ACE_NEW_MALLOC (temp->next_,
+ (ACE_Node<T> *) this->allocator_->malloc (sizeof (ACE_Node<T>)),
+ ACE_Node<T> (s_temp->item_, nptr));
+ temp = temp->next_;
+ }
+ this->cur_size_ = s.cur_size_;
+}
+
+template<class T>
+ACE_Unbounded_Stack<T>::ACE_Unbounded_Stack (const ACE_Unbounded_Stack<T> &s)
+ : head_ (0),
+ cur_size_ (0),
+ allocator_ (s.allocator_)
+{
+ if (this->allocator_ == 0)
+ this->allocator_ = ACE_Allocator::instance ();
+
+ ACE_NEW_MALLOC (this->head_,
+ (ACE_Node<T> *) this->allocator_->malloc (sizeof (ACE_Node<T>)),
+ ACE_Node<T>);
+ this->head_->next_ = this->head_;
+
+ // ACE_TRACE ("ACE_Unbounded_Stack<T>::ACE_Unbounded_Stack");
+ this->copy_all_nodes (s);
+}
+
+template<class T> void
+ACE_Unbounded_Stack<T>::operator= (const ACE_Unbounded_Stack<T> &s)
+{
+ // ACE_TRACE ("ACE_Unbounded_Stack<T>::operator=");
+
+ if (this != &s)
+ {
+ this->delete_all_nodes ();
+ this->copy_all_nodes (s);
+ }
+}
+
+template<class T>
+ACE_Unbounded_Stack<T>::~ACE_Unbounded_Stack (void)
+{
+ // ACE_TRACE ("ACE_Unbounded_Stack<T>::~ACE_Unbounded_Stack");
+
+ this->delete_all_nodes ();
+ ACE_DES_FREE_TEMPLATE (head_,
+ this->allocator_->free,
+ ACE_Node,
+ <T>);
+}
+
+template<class T> int
+ACE_Unbounded_Stack<T>::push (const T &new_item)
+{
+ // ACE_TRACE ("ACE_Unbounded_Stack<T>::push");
+
+ ACE_Node<T> *temp;
+
+ ACE_NEW_MALLOC_RETURN (temp,
+ ACE_static_cast(ACE_Node<T> *,
+ this->allocator_->malloc (sizeof (ACE_Node<T>))),
+ ACE_Node<T> (new_item, this->head_->next_),
+ -1);
+ this->head_->next_ = temp;
+ this->cur_size_++;
+ return 0;
+}
+
+template<class T> int
+ACE_Unbounded_Stack<T>::pop (T &item)
+{
+ // ACE_TRACE ("ACE_Unbounded_Stack<T>::pop");
+
+ if (this->is_empty ())
+ return -1;
+ else
+ {
+ ACE_Node<T> *temp = this->head_->next_;
+ item = temp->item_;
+ this->head_->next_ = temp->next_;
+
+ ACE_DES_FREE_TEMPLATE (temp,
+ this->allocator_->free,
+ ACE_Node,
+ <T>);
+ this->cur_size_--;
+ return 0;
+ }
+}
+
+template <class T> int
+ACE_Unbounded_Stack<T>::find (const T &item) const
+{
+ // ACE_TRACE ("ACE_Unbounded_Stack<T>::find");
+ // Set <item> into the dummy node.
+ this->head_->item_ = item;
+
+ ACE_Node<T> *temp = this->head_->next_;
+
+ // Keep looping until we find the item.
+ while (!(temp->item_ == item))
+ temp = temp->next_;
+
+ // If we found the dummy node then it's not really there, otherwise,
+ // it is there.
+ return temp == this->head_ ? -1 : 0;
+}
+
+template <class T> int
+ACE_Unbounded_Stack<T>::insert (const T &item)
+{
+ // ACE_TRACE ("ACE_Unbounded_Stack<T>::insert");
+
+ if (this->find (item) == 0)
+ return 1;
+ else
+ return this->push (item);
+}
+
+template <class T> int
+ACE_Unbounded_Stack<T>::remove (const T &item)
+{
+ // ACE_TRACE ("ACE_Unbounded_Stack<T>::remove");
+
+ // Insert the item to be founded into the dummy node.
+ this->head_->item_ = item;
+
+ ACE_Node<T> *curr = this->head_;
+
+ while (!(curr->next_->item_ == item))
+ curr = curr->next_;
+
+ if (curr->next_ == this->head_)
+ return -1; // Item was not found.
+ else
+ {
+ ACE_Node<T> *temp = curr->next_;
+ // Skip over the node that we're deleting.
+ curr->next_ = temp->next_;
+ this->cur_size_--;
+ ACE_DES_FREE_TEMPLATE (temp,
+ this->allocator_->free,
+ ACE_Node,
+ <T>);
+ return 0;
+ }
+}
+
+//--------------------------------------------------
+ACE_ALLOC_HOOK_DEFINE(ACE_Double_Linked_List_Iterator_Base)
+
+template <class T>
+ACE_Double_Linked_List_Iterator_Base<T>::ACE_Double_Linked_List_Iterator_Base (const ACE_Double_Linked_List<T> &dll)
+ : current_ (0), dllist_ (&dll)
+{
+ // Do nothing
+}
+
+template <class T>
+ACE_Double_Linked_List_Iterator_Base<T>::ACE_Double_Linked_List_Iterator_Base (const ACE_Double_Linked_List_Iterator_Base<T> &iter)
+ : current_ (iter.current_),
+ dllist_ (iter.dllist_)
+{
+ // Do nothing
+}
+
+
+template <class T> T *
+ACE_Double_Linked_List_Iterator_Base<T>::next (void) const
+{
+ return this->not_done ();
+}
+
+template <class T> int
+ACE_Double_Linked_List_Iterator_Base<T>::next (T *&ptr) const
+{
+ ptr = this->not_done ();
+ return ptr ? 1 : 0;
+}
+
+
+template <class T> int
+ACE_Double_Linked_List_Iterator_Base<T>::done (void) const
+{
+ return this->not_done () ? 0 : 1;
+}
+
+template <class T> T &
+ACE_Double_Linked_List_Iterator_Base<T>::operator* (void) const
+{
+ return *(this->not_done ());
+}
+
+// @@ Is this a valid retasking? Make sure to check with Purify and
+// whatnot that we're not leaking memory or doing any other screwing things.
+template <class T> void
+ACE_Double_Linked_List_Iterator_Base<T>::reset (ACE_Double_Linked_List<T> &dll)
+{
+ current_ = 0;
+ dllist_ = &dll;
+}
+
+ template <class T> int
+ACE_Double_Linked_List_Iterator_Base<T>::go_head (void)
+{
+ this->current_ = ACE_static_cast (T*, dllist_->head_->next_);
+ return this->current_ ? 1 : 0;
+}
+
+template <class T> int
+ACE_Double_Linked_List_Iterator_Base<T>::go_tail (void)
+{
+ this->current_ = ACE_static_cast (T*, dllist_->head_->prev_);
+ return this->current_ ? 1 : 0;
+}
+
+template <class T> T *
+ACE_Double_Linked_List_Iterator_Base<T>::not_done (void) const
+{
+ if (this->current_ != this->dllist_->head_)
+ return this->current_;
+ else
+ return 0;
+}
+
+template <class T> T *
+ACE_Double_Linked_List_Iterator_Base<T>::do_advance (void)
+{
+ if (this->not_done ())
+ {
+ this->current_ = ACE_static_cast (T*, this->current_->next_);
+ return this->not_done ();
+ }
+ else
+ return 0;
+}
+
+template <class T> T *
+ACE_Double_Linked_List_Iterator_Base<T>::do_retreat (void)
+{
+ if (this->not_done ())
+ {
+ this->current_ = ACE_static_cast (T*, this->current_->prev_);
+ return this->not_done ();
+ }
+ else
+ return 0;
+}
+
+template <class T> void
+ACE_Double_Linked_List_Iterator_Base<T>::dump_i (void) const
+{
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("current_ = %x"), this->current_));
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+//--------------------------------------------------
+ACE_ALLOC_HOOK_DEFINE(ACE_Double_Linked_List_Iterator)
+
+template <class T>
+ACE_Double_Linked_List_Iterator<T>::ACE_Double_Linked_List_Iterator (const ACE_Double_Linked_List<T> &dll)
+ : ACE_Double_Linked_List_Iterator_Base <T> (dll)
+{
+ this->current_ = ACE_static_cast (T*, dll.head_->next_);
+ // Advance current_ out of the null area and onto the first item in
+ // the list
+}
+
+template <class T> void
+ACE_Double_Linked_List_Iterator<T>::reset (ACE_Double_Linked_List<T> &dll)
+{
+ this->ACE_Double_Linked_List_Iterator_Base <T>::reset (dll);
+ this->current_ = ACE_static_cast (T*, dll.head_->next_);
+ // Advance current_ out of the null area and onto the first item in
+ // the list
+}
+
+template <class T> int
+ACE_Double_Linked_List_Iterator<T>::first (void)
+{
+ return this->go_head ();
+}
+
+template <class T> int
+ACE_Double_Linked_List_Iterator<T>::advance (void)
+{
+ return this->do_advance () ? 1 : 0;
+}
+
+template <class T> T*
+ACE_Double_Linked_List_Iterator<T>::advance_and_remove (int dont_remove)
+{
+ T* item = 0;
+ if (dont_remove)
+ this->do_advance ();
+ else
+ {
+ item = this->next ();
+ this->do_advance ();
+ // It seems dangerous to remove nodes in an iterator, but so it goes...
+ ACE_Double_Linked_List<T> *dllist = ACE_const_cast (ACE_Double_Linked_List<T> *, this->dllist_);
+ dllist->remove (item);
+ }
+ return item;
+}
+
+template <class T> void
+ACE_Double_Linked_List_Iterator<T>::dump (void) const
+{
+ this->dump_i ();
+}
+
+// Prefix advance.
+
+template <class T>
+ACE_Double_Linked_List_Iterator<T> &
+ACE_Double_Linked_List_Iterator<T>::operator++ (void)
+{
+ this->do_advance ();
+ return *this;
+}
+
+
+// Postfix advance.
+
+template <class T>
+ACE_Double_Linked_List_Iterator<T>
+ACE_Double_Linked_List_Iterator<T>::operator++ (int)
+{
+ ACE_Double_Linked_List_Iterator<T> retv (*this);
+ this->do_advance ();
+ return retv;
+}
+
+
+// Prefix reverse.
+
+template <class T>
+ACE_Double_Linked_List_Iterator<T> &
+ACE_Double_Linked_List_Iterator<T>::operator-- (void)
+{
+ this->do_retreat ();
+ return *this;
+}
+
+
+// Postfix reverse.
+
+template <class T>
+ACE_Double_Linked_List_Iterator<T>
+ACE_Double_Linked_List_Iterator<T>::operator-- (int)
+{
+ ACE_Double_Linked_List_Iterator<T> retv (*this);
+ this->do_retreat ();
+ return retv;
+}
+
+
+//--------------------------------------------------
+ACE_ALLOC_HOOK_DEFINE(ACE_Double_Linked_List_Reverse_Iterator)
+
+ template <class T>
+ACE_Double_Linked_List_Reverse_Iterator<T>::ACE_Double_Linked_List_Reverse_Iterator (ACE_Double_Linked_List<T> &dll)
+ : ACE_Double_Linked_List_Iterator_Base <T> (dll)
+{
+ this->current_ = ACE_static_cast (T*, dll.head_->prev_);
+ // Advance current_ out of the null area and onto the last item in
+ // the list
+}
+
+template <class T> void
+ACE_Double_Linked_List_Reverse_Iterator<T>::reset (ACE_Double_Linked_List<T> &dll)
+{
+ this->ACE_Double_Linked_List_Iterator_Base <T>::reset (dll);
+ this->current_ = ACE_static_cast (T*, dll.head_->prev_);
+ // Advance current_ out of the null area and onto the last item in
+ // the list
+}
+
+template <class T> int
+ACE_Double_Linked_List_Reverse_Iterator<T>::first (void)
+{
+ return this->go_tail ();
+}
+
+template <class T> int
+ACE_Double_Linked_List_Reverse_Iterator<T>::advance (void)
+{
+ return this->do_retreat () ? 1 : 0;
+}
+
+template <class T> T*
+ACE_Double_Linked_List_Reverse_Iterator<T>::advance_and_remove (int dont_remove)
+{
+ T* item = 0;
+ if (dont_remove)
+ this->do_retreat ();
+ else
+ {
+ item = this->next ();
+ this->do_retreat ();
+ // It seems dangerous to remove nodes in an iterator, but so it goes...
+ ACE_Double_Linked_List<T> *dllist = ACE_const_cast (ACE_Double_Linked_List<T> *, this->dllist_);
+ dllist->remove (item);
+ }
+ return item;
+}
+
+template <class T> void
+ACE_Double_Linked_List_Reverse_Iterator<T>::dump (void) const
+{
+ this->dump_i ();
+}
+
+// Prefix advance.
+
+template <class T>
+ACE_Double_Linked_List_Reverse_Iterator<T> &
+ACE_Double_Linked_List_Reverse_Iterator<T>::operator++ (void)
+{
+ this->do_retreat ();
+ return *this;
+}
+
+
+// Postfix advance.
+
+template <class T>
+ACE_Double_Linked_List_Reverse_Iterator<T>
+ACE_Double_Linked_List_Reverse_Iterator<T>::operator++ (int)
+{
+ ACE_Double_Linked_List_Reverse_Iterator<T> retv (*this);
+ this->do_retreat ();
+ return retv;
+}
+
+
+// Prefix reverse.
+
+template <class T>
+ACE_Double_Linked_List_Reverse_Iterator<T> &
+ACE_Double_Linked_List_Reverse_Iterator<T>::operator-- (void)
+{
+ this->do_advance ();
+ return *this;
+}
+
+
+// Postfix reverse.
+
+template <class T>
+ACE_Double_Linked_List_Reverse_Iterator<T>
+ACE_Double_Linked_List_Reverse_Iterator<T>::operator-- (int)
+{
+ ACE_Double_Linked_List_Reverse_Iterator<T> retv (*this);
+ this->do_advance ();
+ return retv;
+}
+
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Double_Linked_List)
+
+ template <class T>
+ACE_Double_Linked_List<T>:: ACE_Double_Linked_List (ACE_Allocator *alloc)
+ : size_ (0), allocator_ (alloc)
+{
+ if (this->allocator_ == 0)
+ this->allocator_ = ACE_Allocator::instance ();
+
+ ACE_NEW_MALLOC (this->head_,
+ (T *) this->allocator_->malloc (sizeof (T)),
+ T);
+ this->init_head ();
+}
+
+template <class T>
+ACE_Double_Linked_List<T>::ACE_Double_Linked_List (const ACE_Double_Linked_List<T> &cx)
+ : allocator_ (cx.allocator_)
+{
+ if (this->allocator_ == 0)
+ this->allocator_ = ACE_Allocator::instance ();
+
+ ACE_NEW_MALLOC (this->head_,
+ (T *) this->allocator_->malloc (sizeof (T)),
+ T);
+ this->init_head ();
+ this->copy_nodes (cx);
+ this->size_ = cx.size_;
+}
+
+template <class T> void
+ACE_Double_Linked_List<T>::operator= (const ACE_Double_Linked_List<T> &cx)
+{
+ if (this != &cx)
+ {
+ this->delete_nodes ();
+ this->copy_nodes (cx);
+ }
+}
+
+template <class T>
+ACE_Double_Linked_List<T>::~ACE_Double_Linked_List (void)
+{
+ this->delete_nodes ();
+
+ ACE_DES_FREE (head_,
+ this->allocator_->free,
+ T);
+
+ this->head_ = 0;
+}
+
+template <class T> int
+ACE_Double_Linked_List<T>::is_empty (void) const
+{
+ return this->size () ? 0 : 1;
+}
+
+template <class T> int
+ACE_Double_Linked_List<T>::is_full (void) const
+{
+ return 0; // We have no bound.
+}
+
+template <class T> T *
+ACE_Double_Linked_List<T>::insert_tail (T *new_item)
+{
+ // Insert it before <head_>, i.e., at tail.
+ this->insert_element (new_item, 1);
+ return new_item;
+}
+
+template <class T> T *
+ACE_Double_Linked_List<T>::insert_head (T *new_item)
+{
+ this->insert_element (new_item); // Insert it after <head_>, i.e., at head.
+ return new_item;
+}
+
+template <class T> T *
+ACE_Double_Linked_List<T>::delete_head (void)
+{
+ T *temp;
+
+ if (this->is_empty ())
+ return 0;
+
+ temp = ACE_static_cast (T *,
+ this->head_->next_);
+ // Detach it from the list.
+ this->remove_element (temp);
+ return temp;
+}
+
+template <class T> T *
+ACE_Double_Linked_List<T>::delete_tail (void)
+{
+ T *temp;
+
+ if (this->is_empty ())
+ return 0;
+
+ temp = ACE_static_cast (T *,
+ this->head_->prev_);
+ // Detach it from the list.
+ this->remove_element (temp);
+ return temp;
+}
+
+template <class T> void
+ACE_Double_Linked_List<T>::reset (void)
+{
+ this->delete_nodes ();
+}
+
+template <class T> int
+ACE_Double_Linked_List<T>::get (T *&item, size_t slot)
+{
+ ACE_Double_Linked_List_Iterator<T> iter (*this);
+
+ for (size_t i = 0;
+ i < slot && !iter.done ();
+ i++)
+ iter.advance ();
+
+ item = iter.next ();
+ return item ? 0 : -1;
+}
+
+template <class T> size_t
+ACE_Double_Linked_List<T>::size (void) const
+{
+ return this->size_;
+}
+
+template <class T> void
+ACE_Double_Linked_List<T>::dump (void) const
+{
+ // Dump the state of an object.
+}
+
+#if 0
+template <class T> T *
+ACE_Double_Linked_List<T>::find (const T &item)
+{
+ for (ACE_Double_Linked_List_Iterator<T> iter (*this);
+ !iter.done ();
+ iter.advance ())
+ {
+ T *temp = iter.next ();
+
+ if (*temp == item)
+ return temp;
+ }
+
+ return 0;
+}
+
+template <class T> int
+ACE_Double_Linked_List<T>::remove (const T &item)
+{
+ T *temp = this->find (item);
+
+ if (temp != 0)
+ return this->remove (temp);
+ else
+ return -1;
+}
+#endif /* 0 */
+
+template <class T> int
+ACE_Double_Linked_List<T>::remove (T *n)
+{
+ return this->remove_element (n);
+}
+
+template <class T> void
+ACE_Double_Linked_List<T>::delete_nodes (void)
+{
+ while (! this->is_empty ())
+ {
+ T * temp = ACE_static_cast (T*, this->head_->next_);
+ this->remove_element (temp);
+ delete temp;
+ }
+}
+
+template <class T> void
+ACE_Double_Linked_List<T>::copy_nodes (const ACE_Double_Linked_List<T> &c)
+{
+ for (ACE_Double_Linked_List_Iterator<T> iter (c);
+ !iter.done ();
+ iter.advance ())
+ {
+ T* temp = 0;
+ ACE_NEW_MALLOC (temp,
+ (T *)this->allocator_->malloc (sizeof (T)),
+ T (*iter.next ()));
+ this->insert_tail (temp);
+ }
+}
+
+template <class T> void
+ACE_Double_Linked_List<T>::init_head (void)
+{
+ this->head_->next_ = this->head_->prev_ = this->head_;
+}
+
+template <class T> int
+ACE_Double_Linked_List<T>::insert_element (T *new_item,
+ int before,
+ T *old_item)
+{
+ if (old_item == 0)
+ old_item = this->head_;
+
+ if (before)
+ old_item = ACE_static_cast (T *,
+ old_item->prev_);
+
+ new_item->next_ = old_item->next_;
+ new_item->next_->prev_ = new_item;
+ new_item->prev_ = old_item;
+ old_item->next_ = new_item;
+ this->size_++;
+ return 0; // Well, what will cause errors here?
+}
+
+template <class T> int
+ACE_Double_Linked_List<T>::remove_element (T *item)
+{
+ // Notice that you have to ensure that item is an element of this
+ // list. We can't do much checking here.
+
+ if (item == this->head_ || item->next_ == 0
+ || item->prev_ == 0 || this->size () == 0) // Can't remove head
+ return -1;
+
+ item->prev_->next_ = item->next_;
+ item->next_->prev_ = item->prev_;
+ item->next_ = item->prev_ = 0; // reset pointers to prevent double removal.
+ this->size_--;
+ return 0;
+}
+
+//--------------------------------------------------
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Fixed_Set)
+
+ template <class T, size_t ACE_SIZE> size_t
+ACE_Fixed_Set<T, ACE_SIZE>::size (void) const
+{
+ return this->cur_size_;
+}
+
+template <class T> size_t
+ACE_Bounded_Set<T>::size (void) const
+{
+ ACE_TRACE ("ACE_Bounded_Set<T>::size");
+ return this->cur_size_;
+}
+
+template <class T, size_t ACE_SIZE> void
+ACE_Fixed_Set<T, ACE_SIZE>::dump (void) const
+{
+ ACE_TRACE ("ACE_Fixed_Set<T, ACE_SIZE>::dump");
+}
+
+template <class T, size_t ACE_SIZE>
+ACE_Fixed_Set<T, ACE_SIZE>::~ACE_Fixed_Set (void)
+{
+ ACE_TRACE ("ACE_Fixed_Set<T, ACE_SIZE>::~ACE_Fixed_Set");
+ this->cur_size_ = 0;
+}
+
+template <class T, size_t ACE_SIZE>
+ACE_Fixed_Set<T, ACE_SIZE>::ACE_Fixed_Set (const ACE_Fixed_Set<T, ACE_SIZE> &fs)
+ : cur_size_ (fs.cur_size_)
+{
+ ACE_TRACE ("ACE_Fixed_Set<T>::ACE_Fixed_Set");
+
+ for (size_t i = 0; i < this->cur_size_; i++)
+ this->search_structure_[i] = fs.search_structure_[i];
+}
+
+template <class T, size_t ACE_SIZE> void
+ACE_Fixed_Set<T, ACE_SIZE>::operator= (const ACE_Fixed_Set<T, ACE_SIZE> &fs)
+{
+ ACE_TRACE ("ACE_Fixed_Set<T>::operator=");
+
+ if (this != &fs)
+ {
+ this->cur_size_ = fs.cur_size_;
+
+ for (size_t i = 0; i < this->cur_size_; i++)
+ this->search_structure_[i] = fs.search_structure_[i];
+ }
+}
+
+template <class T, size_t ACE_SIZE>
+ACE_Fixed_Set<T, ACE_SIZE>::ACE_Fixed_Set (void)
+ : cur_size_ (0),
+ max_size_ (ACE_SIZE)
+{
+ ACE_TRACE ("ACE_Fixed_Set<T, ACE_SIZE>::ACE_Fixed_Set");
+ for (size_t i = 0; i < this->max_size_; i++)
+ this->search_structure_[i].is_free_ = 1;
+}
+
+template <class T, size_t ACE_SIZE> int
+ACE_Fixed_Set<T, ACE_SIZE>::find (const T &item) const
+{
+ ACE_TRACE ("ACE_Fixed_Set<T, ACE_SIZE>::find");
+
+ for (size_t i = 0; i < this->cur_size_; i++)
+ if (this->search_structure_[i].item_ == item
+ && this->search_structure_[i].is_free_ == 0)
+ return 0;
+
+ return -1;
+}
+
+template <class T, size_t ACE_SIZE> int
+ACE_Fixed_Set<T, ACE_SIZE>::insert (const T &item)
+{
+ ACE_TRACE ("ACE_Fixed_Set<T, ACE_SIZE>::insert");
+ int first_free = -1; // Keep track of first free slot.
+ size_t i;
+
+ for (i = 0; i < this->cur_size_; i++)
+ // First, make sure we don't allow duplicates.
+
+ if (this->search_structure_[i].item_ == item
+ && this->search_structure_[i].is_free_ == 0)
+ return 1;
+ else if (this->search_structure_[i].is_free_
+ && first_free == -1)
+ first_free = i;
+
+ // If we found a free spot let's reuse it.
+ if (first_free > -1)
+ {
+ this->search_structure_[first_free].item_ = item;
+ this->search_structure_[first_free].is_free_ = 0;
+ return 0;
+ }
+ // Insert at the end of the active portion.
+ else if (i < this->max_size_)
+ {
+ this->search_structure_[i].item_ = item;
+ this->search_structure_[i].is_free_ = 0;
+ this->cur_size_++;
+ return 0;
+ }
+ else /* No more room! */
+ {
+ errno = ENOMEM;
+ return -1;
+ }
+}
+
+template <class T, size_t ACE_SIZE> int
+ACE_Fixed_Set<T, ACE_SIZE>::remove (const T &item)
+{
+ ACE_TRACE ("ACE_Fixed_Set<T, ACE_SIZE>::remove");
+
+ for (size_t i = 0; i < this->cur_size_; i++)
+ if (this->search_structure_[i].item_ == item)
+ {
+ // Mark this entry as being free.
+ this->search_structure_[i].is_free_ = 1;
+
+ // If we just unbound the highest entry, then we need to
+ // figure out where the next highest active entry is.
+ if (i + 1 == this->cur_size_)
+ {
+ while (i > 0
+ && this->search_structure_[--i].is_free_)
+ continue;
+
+ if (i == 0
+ && this->search_structure_[i].is_free_)
+ this->cur_size_ = 0;
+ else
+ this->cur_size_ = i + 1;
+ }
+ return 0;
+ }
+
+ return -1;
+}
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Fixed_Set_Iterator)
+
+ template <class T, size_t ACE_SIZE> void
+ACE_Fixed_Set_Iterator<T, ACE_SIZE>::dump (void) const
+{
+ ACE_TRACE ("ACE_Fixed_Set_Iterator<T, ACE_SIZE>::dump");
+}
+
+template <class T, size_t ACE_SIZE>
+ACE_Fixed_Set_Iterator<T, ACE_SIZE>::ACE_Fixed_Set_Iterator (ACE_Fixed_Set<T, ACE_SIZE> &s)
+ : s_ (s),
+ next_ (-1)
+{
+ ACE_TRACE ("ACE_Fixed_Set_Iterator<T, ACE_SIZE>::ACE_Fixed_Set_Iterator");
+ this->advance ();
+}
+
+template <class T, size_t ACE_SIZE> int
+ACE_Fixed_Set_Iterator<T, ACE_SIZE>::advance (void)
+{
+ ACE_TRACE ("ACE_Fixed_Set_Iterator<T, ACE_SIZE>::advance");
+
+ for (++this->next_;
+ ACE_static_cast(size_t, this->next_) < this->s_.cur_size_
+ && this->s_.search_structure_[this->next_].is_free_;
+ ++this->next_)
+ continue;
+
+ return ACE_static_cast(size_t, this->next_) < this->s_.cur_size_;
+}
+
+template <class T, size_t ACE_SIZE> int
+ACE_Fixed_Set_Iterator<T, ACE_SIZE>::first (void)
+{
+ ACE_TRACE ("ACE_Fixed_Set_Iterator<T, ACE_SIZE>::first");
+
+ next_ = -1;
+ return this->advance ();
+}
+
+template <class T, size_t ACE_SIZE> int
+ACE_Fixed_Set_Iterator<T, ACE_SIZE>::done (void) const
+{
+ ACE_TRACE ("ACE_Fixed_Set_Iterator<T, ACE_SIZE>::done");
+
+ return ACE_static_cast (ACE_CAST_CONST size_t, this->next_) >=
+ this->s_.cur_size_;
+}
+
+template <class T, size_t ACE_SIZE> int
+ACE_Fixed_Set_Iterator<T, ACE_SIZE>::next (T *&item)
+{
+ ACE_TRACE ("ACE_Fixed_Set_Iterator<T, ACE_SIZE>::next");
+ if (ACE_static_cast (size_t, this->next_) < this->s_.cur_size_)
+ {
+ item = &this->s_.search_structure_[this->next_].item_;
+ return 1;
+ }
+ else
+ return 0;
+}
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Bounded_Set)
+
+ template <class T> void
+ACE_Bounded_Set<T>::dump (void) const
+{
+ ACE_TRACE ("ACE_Bounded_Set<T>::dump");
+}
+
+template <class T>
+ACE_Bounded_Set<T>::~ACE_Bounded_Set (void)
+{
+ ACE_TRACE ("ACE_Bounded_Set<T>::~ACE_Bounded_Set");
+ delete [] this->search_structure_;
+}
+
+template <class T>
+ACE_Bounded_Set<T>::ACE_Bounded_Set (void)
+ : cur_size_ (0),
+ max_size_ (ACE_static_cast(size_t, ACE_Bounded_Set<T>::DEFAULT_SIZE))
+{
+ ACE_TRACE ("ACE_Bounded_Set<T>::ACE_Bounded_Set");
+
+ ACE_NEW (this->search_structure_,
+ ACE_TYPENAME ACE_Bounded_Set<T>::Search_Structure[this->max_size_]);
+
+ for (size_t i = 0; i < this->max_size_; i++)
+ this->search_structure_[i].is_free_ = 1;
+}
+
+template <class T>
+ACE_Bounded_Set<T>::ACE_Bounded_Set (const ACE_Bounded_Set<T> &bs)
+ : cur_size_ (bs.cur_size_),
+ max_size_ (bs.max_size_)
+{
+ ACE_TRACE ("ACE_Bounded_Set<T>::ACE_Bounded_Set");
+
+ ACE_NEW (this->search_structure_,
+ ACE_TYPENAME ACE_Bounded_Set<T>::Search_Structure[this->max_size_]);
+
+ for (size_t i = 0; i < this->cur_size_; i++)
+ this->search_structure_[i] = bs.search_structure_[i];
+}
+
+template <class T> void
+ACE_Bounded_Set<T>::operator= (const ACE_Bounded_Set<T> &bs)
+{
+ ACE_TRACE ("ACE_Bounded_Set<T>::operator=");
+
+ if (this != &bs)
+ {
+ if (this->max_size_ < bs.cur_size_)
+ {
+ delete [] this->search_structure_;
+ ACE_NEW (this->search_structure_,
+ ACE_TYPENAME ACE_Bounded_Set<T>::Search_Structure[bs.cur_size_]);
+ this->max_size_ = bs.cur_size_;
+ }
+
+ this->cur_size_ = bs.cur_size_;
+
+ for (size_t i = 0; i < this->cur_size_; i++)
+ this->search_structure_[i] = bs.search_structure_[i];
+ }
+}
+
+template <class T>
+ACE_Bounded_Set<T>::ACE_Bounded_Set (size_t size)
+ : cur_size_ (0),
+ max_size_ (size)
+{
+ ACE_TRACE ("ACE_Bounded_Set<T>::ACE_Bounded_Set");
+ ACE_NEW (this->search_structure_,
+ ACE_TYPENAME ACE_Bounded_Set<T>::Search_Structure[size]);
+
+ for (size_t i = 0; i < this->max_size_; i++)
+ this->search_structure_[i].is_free_ = 1;
+}
+
+template <class T> int
+ACE_Bounded_Set<T>::find (const T &item) const
+{
+ ACE_TRACE ("ACE_Bounded_Set<T>::find");
+
+ for (size_t i = 0; i < this->cur_size_; i++)
+ if (this->search_structure_[i].item_ == item
+ && this->search_structure_[i].is_free_ == 0)
+ return 0;
+
+ return -1;
+}
+
+template <class T> int
+ACE_Bounded_Set<T>::insert (const T &item)
+{
+ ACE_TRACE ("ACE_Bounded_Set<T>::insert");
+ int first_free = -1; // Keep track of first free slot.
+ size_t i;
+
+ for (i = 0; i < this->cur_size_; i++)
+ // First, make sure we don't allow duplicates.
+
+ if (this->search_structure_[i].item_ == item
+ && this->search_structure_[i].is_free_ == 0)
+ return 1;
+ else if (this->search_structure_[i].is_free_ && first_free == -1)
+ first_free = i;
+
+ if (first_free > -1) // If we found a free spot let's reuse it.
+ {
+ this->search_structure_[first_free].item_ = item;
+ this->search_structure_[first_free].is_free_ = 0;
+ return 0;
+ }
+ else if (i < this->max_size_) // Insert at the end of the active portion.
+ {
+ this->search_structure_[i].item_ = item;
+ this->search_structure_[i].is_free_ = 0;
+ this->cur_size_++;
+ return 0;
+ }
+ else /* No more room! */
+ {
+ errno = ENOMEM;
+ return -1;
+ }
+}
+
+template <class T> int
+ACE_Bounded_Set<T>::remove (const T &item)
+{
+ ACE_TRACE ("ACE_Bounded_Set<T>::remove");
+ for (size_t i = 0; i < this->cur_size_; i++)
+ if (this->search_structure_[i].item_ == item)
+ {
+ // Mark this entry as being free.
+ this->search_structure_[i].is_free_ = 1;
+
+ // If we just unbound the highest entry, then we need to
+ // figure out where the next highest active entry is.
+ if (i + 1 == this->cur_size_)
+ {
+ while (i > 0 && this->search_structure_[--i].is_free_)
+ continue;
+
+ if (i == 0 && this->search_structure_[i].is_free_)
+ this->cur_size_ = 0;
+ else
+ this->cur_size_ = i + 1;
+ }
+ return 0;
+ }
+
+ return -1;
+}
+
+#if defined (__Lynx__)
+// LynxOS 3.0.0 native g++ compiler raises internal error with this inline.
+template <class T> int
+ACE_Bounded_Set<T>::is_full (void) const
+{
+ ACE_TRACE ("ACE_Bounded_Set<T>::is_full");
+ return this->cur_size_ == this->max_size_;
+}
+#endif /* __Lynx__ */
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Bounded_Set_Iterator)
+
+ template <class T> void
+ACE_Bounded_Set_Iterator<T>::dump (void) const
+{
+ ACE_TRACE ("ACE_Bounded_Set_Iterator<T>::dump");
+}
+
+template <class T>
+ACE_Bounded_Set_Iterator<T>::ACE_Bounded_Set_Iterator (ACE_Bounded_Set<T> &s)
+ : s_ (s),
+ next_ (-1)
+{
+ ACE_TRACE ("ACE_Bounded_Set_Iterator<T>::ACE_Bounded_Set_Iterator");
+ this->advance ();
+}
+
+template <class T> int
+ACE_Bounded_Set_Iterator<T>::advance (void)
+{
+ ACE_TRACE ("ACE_Bounded_Set_Iterator<T>::advance");
+
+ for (++this->next_;
+ ACE_static_cast(size_t, this->next_) < this->s_.cur_size_
+ && this->s_.search_structure_[this->next_].is_free_;
+ ++this->next_)
+ continue;
+
+ return ACE_static_cast(size_t, this->next_) < this->s_.cur_size_;
+}
+
+template <class T> int
+ACE_Bounded_Set_Iterator<T>::first (void)
+{
+ ACE_TRACE ("ACE_Bounded_Set_Iterator<T>::first");
+
+ next_ = -1;
+ return this->advance ();
+}
+
+template <class T> int
+ACE_Bounded_Set_Iterator<T>::done (void) const
+{
+ ACE_TRACE ("ACE_Bounded_Set_Iterator<T>::done");
+
+ return ACE_static_cast (ACE_CAST_CONST size_t, this->next_) >=
+ this->s_.cur_size_;
+}
+
+template <class T> int
+ACE_Bounded_Set_Iterator<T>::next (T *&item)
+{
+ ACE_TRACE ("ACE_Bounded_Set_Iterator<T>::next");
+ if (ACE_static_cast(size_t, this->next_) < this->s_.cur_size_)
+ {
+ item = &this->s_.search_structure_[this->next_].item_;
+ return 1;
+ }
+ else
+ return 0;
+}
+
+ACE_ALLOC_HOOK_DEFINE(ACE_DNode)
+
+ template <class T>
+ACE_DNode<T>::ACE_DNode (const T &i, ACE_DNode<T> *n, ACE_DNode<T> *p)
+ : next_ (n), prev_ (p), item_ (i)
+{
+}
+
+# if ! defined (ACE_HAS_BROKEN_NOOP_DTORS)
+template <class T>
+ACE_DNode<T>::~ACE_DNode (void)
+{
+}
+# endif /* ! defined (ACE_HAS_BROKEN_NOOP_DTORS) */
+
+// ****************************************************************
+
+template <class T> void
+ACE_Unbounded_Stack_Iterator<T>::dump (void) const
+{
+ // ACE_TRACE ("ACE_Unbounded_Stack_Iterator<T>::dump");
+}
+
+template <class T>
+ACE_Unbounded_Stack_Iterator<T>::ACE_Unbounded_Stack_Iterator (ACE_Unbounded_Stack<T> &q)
+ : current_ (q.head_->next_),
+ stack_ (q)
+{
+ // ACE_TRACE ("ACE_Unbounded_Stack_Iterator<T>::ACE_Unbounded_Stack_Iterator");
+}
+
+template <class T> int
+ACE_Unbounded_Stack_Iterator<T>::advance (void)
+{
+ // ACE_TRACE ("ACE_Unbounded_Stack_Iterator<T>::advance");
+ this->current_ = this->current_->next_;
+ return this->current_ != this->stack_.head_;
+}
+
+template <class T> int
+ACE_Unbounded_Stack_Iterator<T>::first (void)
+{
+ // ACE_TRACE ("ACE_Unbounded_Stack_Iterator<T>::first");
+ this->current_ = this->stack_.head_->next_;
+ return this->current_ != this->stack_.head_;
+}
+
+template <class T> int
+ACE_Unbounded_Stack_Iterator<T>::done (void) const
+{
+ ACE_TRACE ("ACE_Unbounded_Stack_Iterator<T>::done");
+
+ return this->current_ == this->stack_.head_;
+}
+
+template <class T> int
+ACE_Unbounded_Stack_Iterator<T>::next (T *&item)
+{
+ // ACE_TRACE ("ACE_Unbounded_Stack_Iterator<T>::next");
+ if (this->current_ == this->stack_.head_)
+ return 0;
+ else
+ {
+ item = &this->current_->item_;
+ return 1;
+ }
+}
+
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Ordered_MultiSet)
+
+
+ template <class T>
+ACE_Ordered_MultiSet<T>::ACE_Ordered_MultiSet (ACE_Allocator *alloc)
+ : head_ (0)
+ , tail_ (0)
+ , cur_size_ (0)
+ , allocator_ (alloc)
+{
+ // ACE_TRACE ("ACE_Ordered_MultiSet<T>::ACE_Ordered_MultiSet");
+
+ if (this->allocator_ == 0)
+ this->allocator_ = ACE_Allocator::instance ();
+}
+
+template <class T>
+ACE_Ordered_MultiSet<T>::ACE_Ordered_MultiSet (const ACE_Ordered_MultiSet<T> &us)
+ : head_ (0)
+ , tail_ (0)
+ , cur_size_ (0)
+ , allocator_ (us.allocator_)
+{
+ ACE_TRACE ("ACE_Ordered_MultiSet<T>::ACE_Ordered_MultiSet");
+
+ if (this->allocator_ == 0)
+ this->allocator_ = ACE_Allocator::instance ();
+
+ this->copy_nodes (us);
+}
+
+template <class T>
+ACE_Ordered_MultiSet<T>::~ACE_Ordered_MultiSet (void)
+{
+ // ACE_TRACE ("ACE_Ordered_MultiSet<T>::~ACE_Ordered_MultiSet");
+
+ this->delete_nodes ();
+}
+
+
+template <class T> void
+ACE_Ordered_MultiSet<T>::operator= (const ACE_Ordered_MultiSet<T> &us)
+{
+ ACE_TRACE ("ACE_Ordered_MultiSet<T>::operator=");
+
+ if (this != &us)
+ {
+ this->delete_nodes ();
+ this->copy_nodes (us);
+ }
+}
+
+
+template <class T> int
+ACE_Ordered_MultiSet<T>::insert (const T &item)
+{
+ // ACE_TRACE ("ACE_Ordered_MultiSet<T>::insert");
+
+ return this->insert_from (item, this->head_, 0);
+}
+
+template <class T> int
+ACE_Ordered_MultiSet<T>::insert (const T &item,
+ ACE_Ordered_MultiSet_Iterator<T> &iter)
+{
+ // ACE_TRACE ("ACE_Ordered_MultiSet<T>::insert using iterator");
+
+ return this->insert_from (item, iter.current_, &iter.current_);
+}
+
+template <class T> int
+ACE_Ordered_MultiSet<T>::remove (const T &item)
+{
+ // ACE_TRACE ("ACE_Ordered_MultiSet<T>::remove");
+
+ ACE_DNode<T> *node = 0;
+
+ int result = locate (item, 0, node);
+
+ // if we found the node, remove from list and free it
+ if (node && (result == 0))
+ {
+ if (node->prev_)
+ node->prev_->next_ = node->next_;
+ else
+ head_ = node->next_;
+
+ if (node->next_)
+ node->next_->prev_ = node->prev_;
+ else
+ tail_ = node->prev_;
+
+ this->cur_size_--;
+
+ ACE_DES_FREE_TEMPLATE (node,
+ this->allocator_->free,
+ ACE_DNode,
+ <T>);
+ return 0;
+ }
+
+ return -1;
+}
+
+template <class T> int
+ACE_Ordered_MultiSet<T>::find (const T &item,
+ ACE_Ordered_MultiSet_Iterator<T> &iter) const
+{
+ // search an occurance of item, using iterator's current position as a hint
+ ACE_DNode<T> *node = iter.current_;
+ int result = locate (item, node, node);
+
+ // if we found the node, update the iterator and indicate success
+ if (node && (result == 0))
+ {
+ iter.current_ = node;
+ return 0;
+ }
+
+ return -1;
+}
+
+
+
+template <class T> void
+ACE_Ordered_MultiSet<T>::reset (void)
+{
+ ACE_TRACE ("reset");
+
+ this->delete_nodes ();
+}
+
+template <class T> void
+ACE_Ordered_MultiSet<T>::dump (void) const
+{
+ // ACE_TRACE ("ACE_Ordered_MultiSet<T>::dump");
+ //
+ // ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+ // ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\nhead_ = %u"), this->head_));
+ // ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\nhead_->next_ = %u"), this->head_->next_));
+ // ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\ncur_size_ = %d\n"), this->cur_size_));
+ //
+ // T *item = 0;
+ // size_t count = 1;
+ //
+ // for (ACE_Ordered_MultiSet_Iterator<T> iter (*(ACE_Ordered_MultiSet<T> *) this);
+ // iter.next (item) != 0;
+ // iter.advance ())
+ // ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("count = %d\n"), count++));
+ //
+ // ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+template <class T> int
+ACE_Ordered_MultiSet<T>::insert_from (const T &item, ACE_DNode<T> *position,
+ ACE_DNode<T> **new_position)
+{
+ // ACE_TRACE ("ACE_Ordered_MultiSet<T>::insert_from");
+
+ // create a new node
+ ACE_DNode<T> *temp;
+ ACE_NEW_MALLOC_RETURN (temp,
+ ACE_static_cast(ACE_DNode<T>*,
+ this->allocator_->malloc (sizeof (ACE_DNode<T>))),
+ ACE_DNode<T> (item),
+ -1);
+ // obtain approximate location of the node
+ int result = locate (item, position, position);
+
+ // if there are nodes in the multiset
+ if (position)
+ {
+ switch (result)
+ {
+ // insert after the approximate position
+ case -1:
+
+ // if there is a following node
+ if (position->next_)
+ {
+ // link up with the following node
+ position->next_->prev_ = temp;
+ temp->next_ = position->next_;
+ }
+ else
+ // appending to the end of the set
+ tail_ = temp;
+
+ // link up with the preceeding node
+ temp->prev_ = position;
+ position->next_ = temp;
+
+ break;
+
+ // insert before the position
+ case 0:
+ case 1:
+
+ // if there is a preceeding node
+ if (position->prev_)
+ {
+ // link up with the preceeding node
+ position->prev_->next_ = temp;
+ temp->prev_ = position->prev_;
+ }
+ else
+ // prepending to the start of the set
+ head_ = temp;
+
+ // link up with the preceeding node
+ temp->next_ = position;
+ position->prev_ = temp;
+
+ break;
+
+ default:
+ return -1;
+ }
+ }
+ else
+ {
+ // point the head and tail to the new node.
+ this->head_ = temp;
+ this->tail_ = temp;
+ }
+
+ this->cur_size_++;
+ if (new_position)
+ *new_position = temp;
+
+ return 0;
+}
+
+template <class T> int
+ACE_Ordered_MultiSet<T>::locate (const T &item, ACE_DNode<T> *start_position,
+ ACE_DNode<T> *&new_position) const
+{
+ if (! start_position)
+ start_position = this->head_;
+
+ // If starting before the item, move forward until at or just before
+ // item.
+ while (start_position && start_position->item_ < item &&
+ start_position->next_)
+ start_position = start_position->next_;
+
+ // If starting after the item, move back until at or just after item
+ while (start_position && item < start_position->item_ &&
+ start_position->prev_)
+ start_position = start_position->prev_;
+
+ // Save the (approximate) location in the passed pointer.
+ new_position = start_position;
+
+ // Show the location is after (1), before (-1) , or at (0) the item
+ if (!new_position)
+ return 1;
+ else if (item < new_position->item_)
+ return 1;
+ else if (new_position->item_ < item)
+ return -1;
+ else
+ return 0;
+}
+
+// Looks for first occurance of <item> in the ordered set, using the
+// passed starting position as a hint: if there is such an instance,
+// it updates the new_position pointer to point to one such node and
+// returns 0; if there is no such node, then if there is a node before
+// where the item would have been, it updates the new_position pointer
+// to point to this node and returns -1; if there is no such node,
+// then if there is a node after where the item would have been, it
+// updates the new_position pointer to point to this node (or 0 if
+// there is no such node) and returns 1;
+
+template <class T> void
+ACE_Ordered_MultiSet<T>::copy_nodes (const ACE_Ordered_MultiSet<T> &us)
+{
+ ACE_DNode<T> *insertion_point = this->head_;
+
+ for (ACE_DNode<T> *curr = us.head_;
+ curr != 0;
+ curr = curr->next_)
+ this->insert_from (curr->item_, insertion_point, &insertion_point);
+}
+
+template <class T> void
+ACE_Ordered_MultiSet<T>::delete_nodes (void)
+{
+ // iterate through list, deleting nodes
+ for (ACE_DNode<T> *curr = this->head_;
+ curr != 0;
+ )
+ {
+ ACE_DNode<T> *temp = curr;
+ curr = curr->next_;
+ ACE_DES_FREE_TEMPLATE (temp,
+ this->allocator_->free,
+ ACE_DNode,
+ <T>);
+ }
+
+ this->head_ = 0;
+ this->tail_ = 0;
+ this->cur_size_ = 0;
+}
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Ordered_MultiSet_Iterator)
+
+template <class T>
+ACE_Ordered_MultiSet_Iterator<T>::ACE_Ordered_MultiSet_Iterator (ACE_Ordered_MultiSet<T> &s)
+ : current_ (s.head_),
+ set_ (s)
+{
+ // ACE_TRACE ("ACE_Ordered_MultiSet_Iterator<T>::ACE_Ordered_MultiSet_Iterator");
+}
+
+template <class T> int
+ACE_Ordered_MultiSet_Iterator<T>::next (T *&item) const
+{
+ // ACE_TRACE ("ACE_Ordered_MultiSet_Iterator<T>::next");
+ if (this->current_)
+ {
+ item = &this->current_->item_;
+ return 1;
+ }
+
+ return 0;
+}
+
+template <class T> T&
+ACE_Ordered_MultiSet_Iterator<T>::operator* (void)
+{
+ //ACE_TRACE ("ACE_Ordered_MultiSet_Iterator<T>::operator*");
+ T *retv = 0;
+
+ int result = this->next (retv);
+ ACE_ASSERT (result != 0);
+ ACE_UNUSED_ARG (result);
+
+ return *retv;
+}
+
+ACE_ALLOC_HOOK_DEFINE (ACE_DLList_Node)
+
+template <class T> T *
+ACE_DLList<T>::insert_tail (T *new_item)
+{
+ ACE_DLList_Node *temp1, *temp2;
+ ACE_NEW_MALLOC_RETURN (temp1,
+ ACE_static_cast(ACE_DLList_Node *,
+ this->allocator_->malloc (sizeof (ACE_DLList_Node))),
+ ACE_DLList_Node ((void *&)new_item),
+ 0);
+ temp2 = ACE_DLList_Base::insert_tail (temp1);
+ return (T *) (temp2 ? temp2->item_ : 0);
+}
+
+template <class T> T *
+ACE_DLList<T>::insert_head (T *new_item)
+{
+ ACE_DLList_Node *temp1;
+ ACE_NEW_MALLOC_RETURN (temp1,
+ (ACE_DLList_Node *) this->allocator_->malloc (sizeof (ACE_DLList_Node)),
+ ACE_DLList_Node ((void *&)new_item), 0);
+ ACE_DLList_Node *temp2 =
+ ACE_DLList_Base::insert_head (temp1);
+ return (T *) (temp2 ? temp2->item_ : 0);
+}
+
+template <class T> T *
+ACE_DLList<T>::delete_head (void)
+{
+ ACE_DLList_Node *temp1 = ACE_DLList_Base::delete_head ();
+ T *temp2 = (T *) (temp1 ? temp1->item_ : 0);
+ ACE_DES_FREE (temp1,
+ this->allocator_->free,
+ ACE_DLList_Node);
+
+ return temp2;
+}
+
+template <class T> T *
+ACE_DLList<T>::delete_tail (void)
+{
+ ACE_DLList_Node *temp1 = ACE_DLList_Base::delete_tail ();
+ T *temp2 = (T *) (temp1 ? temp1->item_ : 0);
+ ACE_DES_FREE (temp1,
+ this->allocator_->free,
+ ACE_DLList_Node);
+ return temp2;
+}
+
+// ****************************************************************
+
+// Compare this array with <s> for equality.
+
+template <class T> int
+ACE_Array<T>::operator== (const ACE_Array<T> &s) const
+{
+ if (this == &s)
+ return 1;
+ else if (this->size () != s.size ())
+ return 0;
+
+ for (size_t slot = 0; slot < s.size (); slot++)
+ if ((*this)[slot] != s[slot])
+ return 0;
+
+ return 1;
+}
+
+// ****************************************************************
+
+
+#endif /* ACE_CONTAINERS_T_C */
diff --git a/ace/Utils/Templates/Containers_T.h b/ace/Utils/Templates/Containers_T.h
new file mode 100644
index 00000000000..9751c6ca132
--- /dev/null
+++ b/ace/Utils/Templates/Containers_T.h
@@ -0,0 +1,1495 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Containers_T.h
+ *
+ * $Id$
+ *
+ * @author Douglas C. Schmidt <schmidt@cs.wustl.edu>
+ */
+//=============================================================================
+
+#ifndef ACE_CONTAINERS_T_H
+#define ACE_CONTAINERS_T_H
+#include "ace/pre.h"
+
+#include "ace/ACE.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+// Need by ACE_DLList_Node.
+#include "ace/Containers.h"
+
+// Shared with "ace/Unbounded_Set.h"
+#include "ace/Node.h"
+
+// Backwards compatibility, please include "ace/Array_Base.h" directly.
+#include "ace/Array_Base.h"
+
+// Backwards compatibility, please include "ace/Unbounded_Set.h" directly.
+#include "ace/Unbounded_Set.h"
+
+// Backwards compatibility, please include "ace/Unbounded_Queue.h" directly.
+#include "ace/Unbounded_Queue.h"
+
+class ACE_Allocator;
+
+/**
+ * @class ACE_Bounded_Stack
+ *
+ * @brief Implement a generic LIFO abstract data type.
+ *
+ * This implementation of a Stack uses a bounded array
+ * that is allocated dynamically.
+ */
+template <class T>
+class ACE_Bounded_Stack
+{
+public:
+ // = Initialization, assignment, and termination methods.
+
+ /// Initialize a new stack so that it is empty.
+ /// The copy constructor (performs initialization).
+ ACE_Bounded_Stack (size_t size);
+ ACE_Bounded_Stack (const ACE_Bounded_Stack<T> &s);
+
+ /// Assignment operator (performs assignment).
+ void operator= (const ACE_Bounded_Stack<T> &s);
+
+ /// Perform actions needed when stack goes out of scope.
+ ~ACE_Bounded_Stack (void);
+
+ // = Classic Stack operations.
+
+ /**
+ * Place a new item on top of the stack. Returns -1 if the stack
+ * is already full, 0 if the stack is not already full, and -1 if
+ * failure occurs.
+ */
+ int push (const T &new_item);
+
+ /**
+ * Remove and return the top stack item. Returns -1 if the stack is
+ * already empty, 0 if the stack is not already empty, and -1 if
+ * failure occurs.
+ */
+ int pop (T &item);
+
+ /**
+ * Return top stack item without removing it. Returns -1 if the
+ * stack is already empty, 0 if the stack is not already empty, and
+ * -1 if failure occurs.
+ */
+ int top (T &item) const;
+
+ // = Check boundary conditions.
+
+ /// Returns 1 if the container is empty, otherwise returns 0.
+ int is_empty (void) const;
+
+ /// Returns 1 if the container is full, otherwise returns 0.
+ int is_full (void) const;
+
+ /// The number of items in the stack.
+ size_t size (void) const;
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+private:
+ /// Size of the dynamically allocated data.
+ size_t size_;
+
+ /// Keeps track of the current top of stack.
+ size_t top_;
+
+ /// Holds the stack's contents.
+ T *stack_;
+};
+
+//----------------------------------------
+
+/**
+ * @class ACE_Fixed_Stack
+ *
+ * @brief Implement a generic LIFO abstract data type.
+ *
+ * This implementation of a Stack uses a fixed array
+ * with the size fixed at instantiation time.
+ */
+template <class T, size_t ACE_SIZE>
+class ACE_Fixed_Stack
+{
+public:
+ // = Initialization, assignment, and termination methods.
+ /// Initialize a new stack so that it is empty.
+ ACE_Fixed_Stack (void);
+
+ /// The copy constructor (performs initialization).
+ ACE_Fixed_Stack (const ACE_Fixed_Stack<T, ACE_SIZE> &s);
+
+ /// Assignment operator (performs assignment).
+ void operator= (const ACE_Fixed_Stack<T, ACE_SIZE> &s);
+
+ /// Perform actions needed when stack goes out of scope.
+ ~ACE_Fixed_Stack (void);
+
+ // = Classic Stack operations.
+
+ /**
+ * Place a new item on top of the stack. Returns -1 if the stack
+ * is already full, 0 if the stack is not already full, and -1 if
+ * failure occurs.
+ */
+ int push (const T &new_item);
+
+ /**
+ * Remove and return the top stack item. Returns -1 if the stack is
+ * already empty, 0 if the stack is not already empty, and -1 if
+ * failure occurs.
+ */
+ int pop (T &item);
+
+ /**
+ * Return top stack item without removing it. Returns -1 if the
+ * stack is already empty, 0 if the stack is not already empty, and
+ * -1 if failure occurs.
+ */
+ int top (T &item) const;
+
+ // = Check boundary conditions.
+
+ /// Returns 1 if the container is empty, otherwise returns 0.
+ int is_empty (void) const;
+
+ /// Returns 1 if the container is full, otherwise returns 0.
+ int is_full (void) const;
+
+ /// The number of items in the stack.
+ size_t size (void) const;
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+private:
+ /// Size of the allocated data.
+ size_t size_;
+
+ /// Keeps track of the current top of stack.
+ size_t top_;
+
+ /// Holds the stack's contents.
+ T stack_[ACE_SIZE];
+};
+
+//----------------------------------------
+
+template<class T> class ACE_Ordered_MultiSet;
+template<class T> class ACE_Ordered_MultiSet_Iterator;
+
+/**
+ * @class ACE_DNode
+ *
+ * @brief Implementation element in a bilinked list.
+ */
+template<class T>
+class ACE_DNode
+{
+ friend class ACE_Ordered_MultiSet<T>;
+ friend class ACE_Ordered_MultiSet_Iterator<T>;
+
+public:
+
+# if ! defined (ACE_HAS_BROKEN_NOOP_DTORS)
+ /// This isn't necessary, but it keeps some compilers happy.
+ ~ACE_DNode (void);
+# endif /* ! defined (ACE_HAS_BROKEN_NOOP_DTORS) */
+
+private:
+
+ // = Initialization methods
+ ACE_DNode (const T &i, ACE_DNode<T> *n = 0, ACE_DNode<T> *p = 0);
+
+ /// Pointer to next element in the list of <ACE_DNode>s.
+ ACE_DNode<T> *next_;
+
+ /// Pointer to previous element in the list of <ACE_DNode>s.
+ ACE_DNode<T> *prev_;
+
+ /// Current value of the item in this node.
+ T item_;
+};
+
+
+/**
+ * @class ACE_Unbounded_Stack
+ *
+ * @brief Implement a generic LIFO abstract data type.
+ *
+ * This implementation of an unbounded Stack uses a linked list.
+ * If you use the <insert> or <remove> methods you should keep
+ * in mind that duplicate entries aren't allowed. In general,
+ * therefore, you should avoid the use of these methods since
+ * they aren't really part of the ADT stack.
+ */
+template <class T>
+class ACE_Unbounded_Stack
+{
+public:
+ friend class ACE_Unbounded_Stack_Iterator<T>;
+
+ // Trait definition.
+ typedef ACE_Unbounded_Stack_Iterator<T> ITERATOR;
+
+ // = Initialization, assignment, and termination methods.
+ /// Initialize a new stack so that it is empty. Use user defined
+ /// allocation strategy if specified.
+ ACE_Unbounded_Stack (ACE_Allocator *alloc = 0);
+
+ /// The copy constructor (performs initialization).
+ ACE_Unbounded_Stack (const ACE_Unbounded_Stack<T> &s);
+
+ /// Assignment operator (performs assignment).
+ void operator= (const ACE_Unbounded_Stack<T> &s);
+
+ /// Perform actions needed when stack goes out of scope.
+ ~ACE_Unbounded_Stack (void);
+
+ // = Classic Stack operations.
+
+ /**
+ * Place a new item on top of the stack. Returns -1 if the stack
+ * is already full, 0 if the stack is not already full, and -1 if
+ * failure occurs.
+ */
+ int push (const T &new_item);
+
+ /**
+ * Remove and return the top stack item. Returns -1 if the stack is
+ * already empty, 0 if the stack is not already empty, and -1 if
+ * failure occurs.
+ */
+ int pop (T &item);
+
+ /**
+ * Return top stack item without removing it. Returns -1 if the
+ * stack is already empty, 0 if the stack is not already empty, and
+ * -1 if failure occurs.
+ */
+ int top (T &item) const;
+
+ // = Check boundary conditions.
+
+ /// Returns 1 if the container is empty, otherwise returns 0.
+ int is_empty (void) const;
+
+ /// Returns 1 if the container is full, otherwise returns 0.
+ int is_full (void) const;
+
+ // = Auxiliary methods (not strictly part of the Stack ADT).
+
+ /**
+ * Insert <new_item> into the Stack at the head (but doesn't allow
+ * duplicates). Returns -1 if failures occur, 1 if item is already
+ * present (i.e., no duplicates are allowed), else 0.
+ */
+ int insert (const T &new_item);
+
+ /// Remove <item> from the Stack. Returns 0 if it removes the item,
+ /// -1 if it can't find the item, and -1 if a failure occurs.
+ int remove (const T &item);
+
+ /// Finds if <item> occurs the set. Returns 0 if finds, else -1.
+ int find (const T &item) const;
+
+ /// The number of items in the stack.
+ size_t size (void) const;
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+private:
+ /// Delete all the nodes in the stack.
+ void delete_all_nodes (void);
+
+ /// Copy all nodes from <s> to <this>.
+ void copy_all_nodes (const ACE_Unbounded_Stack<T> &s);
+
+ /// Head of the linked list of Nodes.
+ ACE_Node<T> *head_;
+
+ /// Current size of the stack.
+ size_t cur_size_;
+
+ /// Allocation strategy of the stack.
+ ACE_Allocator *allocator_;
+};
+
+/**
+ * @class ACE_Unbounded_Stack_Iterator
+ *
+ * @brief Implement an iterator over an unbounded Stack.
+ */
+template <class T>
+class ACE_Unbounded_Stack_Iterator
+{
+public:
+ // = Initialization method.
+ /// Move to the first element in the <stack>.
+ ACE_Unbounded_Stack_Iterator (ACE_Unbounded_Stack<T> &stack);
+
+ // = Iteration methods.
+
+ /// Pass back the <next_item> that hasn't been seen in the Stack.
+ /// Returns 0 when all items have been seen, else 1.
+ int next (T *&next_item);
+
+ /// Move forward by one element in the Stack. Returns 0 when all the
+ /// items in the Stack have been seen, else 1.
+ int advance (void);
+
+ /// Move to the first element in the Stack. Returns 0 if the
+ /// Stack is empty, else 1.
+ int first (void);
+
+ /// Returns 1 when all items have been seen, else 0.
+ int done (void) const;
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+private:
+ /// Pointer to the current node in the iteration.
+ ACE_Node<T> *current_;
+
+ /// Pointer to the Stack we're iterating over.
+ ACE_Unbounded_Stack<T> &stack_;
+};
+
+template <class T>
+class ACE_Double_Linked_List;
+
+/**
+ * @class ACE_Double_Linked_List_Iterator_Base
+ *
+ * @brief Implements a common base class for iterators for a double
+ * linked list ADT
+ */
+template <class T>
+class ACE_Double_Linked_List_Iterator_Base
+{
+public:
+ // = Iteration methods.
+
+ /// Passes back the <entry> under the iterator. Returns 0 if the
+ /// iteration has completed, otherwise 1
+ int next (T *&) const;
+
+ /**
+ * Return the address of next (current) unvisited item in the list.
+ * 0 if there is no more element available.
+ * DEPRECATED
+ */
+ T *next (void) const;
+
+ /// Returns 1 when all items have been seen, else 0.
+ int done (void) const;
+
+ /// STL-like iterator dereference operator: returns a reference
+ /// to the node underneath the iterator.
+ T & operator* (void) const ;
+
+ /**
+ * Retasks the iterator to iterate over a new
+ * Double_Linked_List. This allows clients to reuse an iterator
+ * without incurring the constructor overhead. If you do use this,
+ * be aware that if there are more than one reference to this
+ * iterator, the other "clients" may be very bothered when their
+ * iterator changes. @@ Here be dragons. Comments?
+ */
+ void reset (ACE_Double_Linked_List<T> &);
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+protected:
+ // = Initialization methods.
+
+ /// Constructor
+ ACE_Double_Linked_List_Iterator_Base (const ACE_Double_Linked_List<T> &);
+
+ /// Copy constructor.
+ ACE_Double_Linked_List_Iterator_Base (const
+ ACE_Double_Linked_List_Iterator_Base<T>
+ &iter);
+
+ // = Iteration methods.
+ /**
+ * Move to the first element of the list. Returns 0 if the list is
+ * empty, else 1. Note: the head of the ACE_DLList is actually a
+ * null entry, so the first element is actually the 2n'd entry
+ */
+ int go_head (void);
+
+ /// Move to the last element of the list. Returns 0 if the list is
+ /// empty, else 1.
+ int go_tail (void);
+
+ /**
+ * Check if we reach the end of the list. Can also be used to get
+ * the *current* element in the list. Return the address of the
+ * current item if there are still elements left , 0 if we run out
+ * of element.
+ */
+ T *not_done (void) const ;
+
+ /// Advance to the next element in the list. Return the address of the
+ /// next element if there are more, 0 otherwise.
+ T *do_advance (void);
+
+ /// Retreat to the previous element in the list. Return the address
+ /// of the previous element if there are more, 0 otherwise.
+ T *do_retreat (void);
+
+ /// Dump the state of an object.
+ void dump_i (void) const;
+
+ /// Remember where we are.
+ T *current_;
+
+ const ACE_Double_Linked_List<T> *dllist_;
+};
+
+/**
+ * @class ACE_Double_Linked_List_Iterator
+ *
+ * @brief Implements an iterator for a double linked list ADT
+ *
+ * Iterate thru the double-linked list. This class provides
+ * an interface that let users access the internal element
+ * addresses directly. Notice <class T> must delcare
+ * ACE_Double_Linked_List<T>,
+ * ACE_Double_Linked_List_Iterator_Base <T> and
+ * ACE_Double_Linked_List_Iterator as friend classes and class T
+ * should also have data members T* next_ and T* prev_.
+ */
+template <class T>
+class ACE_Double_Linked_List_Iterator : public ACE_Double_Linked_List_Iterator_Base <T>
+{
+public:
+ // = Initialization method.
+ ACE_Double_Linked_List_Iterator (const ACE_Double_Linked_List<T> &);
+
+ /**
+ * Retasks the iterator to iterate over a new
+ * Double_Linked_List. This allows clients to reuse an iterator
+ * without incurring the constructor overhead. If you do use this,
+ * be aware that if there are more than one reference to this
+ * iterator, the other "clients" may be very bothered when their
+ * iterator changes.
+ * @@ Here be dragons. Comments?
+ */
+ void reset (ACE_Double_Linked_List<T> &);
+
+ /// Move to the first element in the list. Returns 0 if the
+ /// list is empty, else 1.
+ int first (void);
+
+ /// Move forward by one element in the list. Returns 0 when all the
+ /// items in the list have been seen, else 1.
+ int advance (void);
+
+ /**
+ * Advance the iterator while removing the original item from the
+ * list. Return a pointer points to the original (removed) item.
+ * If <dont_remove> equals 0, this function behaves like <advance>
+ * but return 0 (NULL) instead.
+ */
+ T* advance_and_remove (int dont_remove);
+
+ // = STL-style iteration methods
+
+ /// Prefix advance.
+ ACE_Double_Linked_List_Iterator<T> & operator++ (void);
+
+ /// Postfix advance.
+ ACE_Double_Linked_List_Iterator<T> operator++ (int);
+
+ /// Prefix reverse.
+ ACE_Double_Linked_List_Iterator<T> & operator-- (void);
+
+ /// Postfix reverse.
+ ACE_Double_Linked_List_Iterator<T> operator-- (int);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+};
+
+/**
+ * @class ACE_Double_Linked_List_Reverse_Iterator
+ *
+ * @brief Implements a reverse iterator for a double linked list ADT
+ *
+ * Iterate backwards over the double-linked list. This class
+ * provide an interface that let users access the internal
+ * element addresses directly, which seems to break the
+ * encapsulation. Notice <class T> must delcare
+ * ACE_Double_Linked_List<T>,
+ * ACE_Double_Linked_List_Iterator_Base <T> and
+ * ACE_Double_Linked_List_Iterator as friend classes and class T
+ * should also have data members T* next_ and T* prev_.
+ */
+template <class T>
+class ACE_Double_Linked_List_Reverse_Iterator : public ACE_Double_Linked_List_Iterator_Base <T>
+{
+public:
+ // = Initialization method.
+ ACE_Double_Linked_List_Reverse_Iterator (ACE_Double_Linked_List<T> &);
+
+ /**
+ * Retasks the iterator to iterate over a new
+ * Double_Linked_List. This allows clients to reuse an iterator
+ * without incurring the constructor overhead. If you do use this,
+ * be aware that if there are more than one reference to this
+ * iterator, the other "clients" may be very bothered when their
+ * iterator changes.
+ * @@ Here be dragons. Comments?
+ */
+ void reset (ACE_Double_Linked_List<T> &);
+
+ /// Move to the first element in the list. Returns 0 if the
+ /// list is empty, else 1.
+ int first (void);
+
+ /// Move forward by one element in the list. Returns 0 when all the
+ /// items in the list have been seen, else 1.
+ int advance (void);
+
+ /**
+ * Advance the iterator while removing the original item from the
+ * list. Return a pointer points to the original (removed) item.
+ * If <dont_remove> equals 0, this function behaves like <advance>
+ * but return 0 (NULL) instead.
+ */
+ T* advance_and_remove (int dont_remove);
+
+ // = STL-style iteration methods
+
+ /// Prefix advance.
+ ACE_Double_Linked_List_Reverse_Iterator<T> & operator++ (void);
+
+ /// Postfix advance.
+ ACE_Double_Linked_List_Reverse_Iterator<T> operator++ (int);
+
+ /// Prefix reverse.
+ ACE_Double_Linked_List_Reverse_Iterator<T> & operator-- (void);
+
+ /// Postfix reverse.
+ ACE_Double_Linked_List_Reverse_Iterator<T> operator-- (int);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+};
+
+/**
+ * @class ACE_Double_Linked_List
+ *
+ * @brief A double-linked list implementation.
+ *
+ * This implementation of an unbounded double-linked list uses a
+ * circular linked list with a dummy node. It is pretty much
+ * like the <ACE_Unbounded_Queue> except that it allows removing
+ * of a specific element from a specific location.
+ * Notice that this class is an implementation of a very simply
+ * data structure.is *NOT* a container class. You can use the
+ * class to implement other contains classes but it is *NOT* a
+ * general purpose container class.
+ * The parameter class *MUST* has members T* prev and T* next
+ * and users of this class are responsible to follow the general
+ * rules of using double-linked lists to maintaining the list
+ * integrities.
+ * If you need a double linked container class, check out the
+ * DLList class in this file.
+ */
+template <class T>
+class ACE_Double_Linked_List
+{
+public:
+ friend class ACE_Double_Linked_List_Iterator_Base<T>;
+ friend class ACE_Double_Linked_List_Iterator<T>;
+ friend class ACE_Double_Linked_List_Reverse_Iterator<T>;
+
+ // Trait definition.
+ typedef ACE_Double_Linked_List_Iterator<T> ITERATOR;
+ typedef ACE_Double_Linked_List_Reverse_Iterator<T> REVERSE_ITERATOR;
+
+ // = Initialization and termination methods.
+ /// construction. Use user specified allocation strategy
+ /// if specified.
+ ACE_Double_Linked_List (ACE_Allocator *alloc = 0);
+
+ /// Copy constructor.
+ ACE_Double_Linked_List (const ACE_Double_Linked_List<T> &);
+
+ /// Assignment operator.
+ void operator= (const ACE_Double_Linked_List<T> &);
+
+ /// Destructor.
+ ~ACE_Double_Linked_List (void);
+
+ // = Check boundary conditions.
+
+ /// Returns 1 if the container is empty, otherwise returns 0.
+ int is_empty (void) const;
+
+ /// Returns 1 if the container is full, otherwise returns 0.
+ int is_full (void) const;
+
+ // = Classic queue operations.
+
+ /// Adds <new_item> to the tail of the list. Returns the new item
+ /// that was inserted.
+ T *insert_tail (T *new_item);
+
+ /// Adds <new_item> to the head of the list.Returns the new item that
+ /// was inserted.
+ T *insert_head (T *new_item);
+
+ /**
+ * Removes and returns the first <item> in the list. Returns
+ * internal node's address on success, 0 if the queue was empty.
+ * This method will *not* free the internal node.
+ */
+ T* delete_head (void);
+
+ /**
+ * Removes and returns the last <item> in the list. Returns
+ * internal nodes's address on success, 0 if the queue was
+ * empty. This method will *not* free the internal node.
+ */
+ T *delete_tail (void);
+
+ // = Additional utility methods.
+
+ /**
+ * Reset the <ACE_Double_Linked_List> to be empty.
+ * Notice that since no one is interested in the items within,
+ * This operation will delete all items.
+ */
+ void reset (void);
+
+ /// Get the <slot>th element in the set. Returns -1 if the element
+ /// isn't in the range {0..<size> - 1}, else 0.
+ int get (T *&item, size_t slot = 0);
+
+ /// The number of items in the queue.
+ size_t size (void) const;
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Use DNode address directly.
+ int remove (T *n);
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+protected:
+ /// Delete all the nodes in the list.
+ void delete_nodes (void);
+
+ /// Copy nodes from <rhs> into this list.
+ void copy_nodes (const ACE_Double_Linked_List<T> &rhs);
+
+ /// Setup header pointer. Called after we create the head node in ctor.
+ void init_head (void);
+
+ /**
+ * Insert a <new_element> into the list. It will be added before
+ * or after <old_item>. Default is to insert the new item *after*
+ * <head_>. Return 0 if succeed, -1 if error occured.
+ */
+ int insert_element (T *new_item,
+ int before = 0,
+ T *old_item = 0);
+
+ /**
+ * Remove an <item> from the list. Return 0 if succeed, -1 otherwise.
+ * Notice that this function checks if item is <head_> and either its
+ * <next_> or <prev_> is NULL. The function resets item's <next_> and
+ * <prev_> to 0 to prevent clobbering the double-linked list if a user
+ * tries to remove the same node again.
+ */
+ int remove_element (T *item);
+
+ /// Head of the circular double-linked list.
+ T *head_;
+
+ /// Size of this list.
+ size_t size_;
+
+ /// Allocation Strategy of the queue.
+ ACE_Allocator *allocator_;
+};
+
+
+template <class T> class ACE_DLList;
+template <class T> class ACE_DLList_Iterator;
+template <class T> class ACE_DLList_Reverse_Iterator;
+
+typedef ACE_Double_Linked_List<ACE_DLList_Node> ACE_DLList_Base;
+
+//typedef ACE_Double_Linked_List_Iterator <ACE_DLList_Node>
+// ACE_DLList_Iterator_Base;
+//typedef ACE_Double_Linked_List_Reverse_Iterator <ACE_DLList_Node>
+// ACE_DLList_Reverse_Iterator_Base;
+//@@ These two typedefs (inherited from James Hu's original design)
+// have been removed because Sun CC 4.2 had problems with it. I guess
+// having the DLList_Iterators inheriting from a class which is
+// actually a typedef leads to problems. #define'ing rather than
+// typedef'ing worked, but as per Carlos's reccomendation, I'm just
+// replacing all references to the base classes with their actual
+// type. Matt Braun (6/15/99)
+
+/**
+ * @class ACE_DLList
+ *
+ * @brief A double-linked list container class.
+ *
+ * This implementation uses ACE_Double_Linked_List to perform
+ * the logic behind this container class. It delegates all of its
+ * calls to ACE_Double_Linked_List.
+ */
+template <class T>
+class ACE_DLList : public ACE_DLList_Base
+{
+ friend class ACE_DLList_Node;
+ friend class ACE_Double_Linked_List_Iterator<T>;
+ friend class ACE_DLList_Iterator<T>;
+ friend class ACE_DLList_Reverse_Iterator<T>;
+
+public:
+
+ /// Delegates to ACE_Double_Linked_List.
+ void operator= (const ACE_DLList<T> &l);
+
+ // = Classic queue operations.
+
+ /// Delegates to ACE_Double_Linked_List.
+ T *insert_tail (T *new_item);
+
+ /// Delegates to ACE_Double_Linked_List.
+ T *insert_head (T *new_item);
+
+ /// Delegates to ACE_Double_Linked_List.
+ T *delete_head (void);
+
+ /// Delegates to ACE_Double_Linked_List.
+ T *delete_tail (void);
+
+ // = Additional utility methods.
+
+ /**
+ * Delegates to <ACE_Double_Linked_List>, but where
+ * <ACE_Double_Linked_List> returns the node as the item, this get
+ * returns the contents of the node in item.
+ */
+ int get (T *&item, size_t slot = 0);
+
+ /// Delegates to ACE_Double_Linked_List.
+ void dump (void) const;
+
+ /// Delegates to ACE_Double_Linked_List.
+ int remove (ACE_DLList_Node *n);
+
+
+ // = Initialization and termination methods.
+
+ /// Delegates to ACE_Double_Linked_List.
+ ACE_DLList (ACE_Allocator *alloc = 0);
+
+ /// Delegates to ACE_Double_Linked_List.
+ ACE_DLList (const ACE_DLList<T> &l);
+
+ /// Deletes the list starting from the head.
+ ~ACE_DLList (void);
+};
+
+/**
+ * @class ACE_DLList_Iterator
+ *
+ * @brief A double-linked list container class iterator.
+ *
+ * This implementation uses ACE_Double_Linked_List_Iterator to
+ * perform the logic behind this container class. It delegates
+ * all of its calls to ACE_Double_Linked_List_Iterator.
+ */
+template <class T>
+class ACE_DLList_Iterator : public ACE_Double_Linked_List_Iterator <ACE_DLList_Node>
+{
+
+ friend class ACE_DLList<T>;
+ friend class ACE_DLList_Node;
+
+public:
+
+ // = Initialization method.
+ ACE_DLList_Iterator (ACE_DLList<T> &l);
+
+ /**
+ * Retasks the iterator to iterate over a new
+ * Double_Linked_List. This allows clients to reuse an iterator
+ * without incurring the constructor overhead. If you do use this,
+ * be aware that if there are more than one reference to this
+ * iterator, the other "clients" may be very bothered when their
+ * iterator changes.
+ * @@ Here be dragons. Comments?
+ */
+ void reset (ACE_DLList<T> &l);
+
+ // = Iteration methods.
+ /// Move forward by one element in the set. Returns 0 when all the
+ /// items in the set have been seen, else 1.
+ int advance (void);
+
+ /// Pass back the <next_item> that hasn't been seen in the Stack.
+ /// Returns 0 when all items have been seen, else 1.
+ int next (T *&);
+
+ /**
+ * Delegates to ACE_Double_Linked_List_Iterator, except that whereas
+ * the Double_Linked_List version of next returns the node, this next
+ * returns the contents of the node
+ * DEPRECATED
+ */
+ T *next (void) const;
+
+ /// Removes the current item (i.e., <next>) from the list.
+ /// Note that DLList iterators do not support <advance_and_remove>
+ /// directly (defined in its base class) and you will need to
+ /// release the element returned by it.
+ int remove (void);
+
+ /// Delegates to ACE_Double_Linked_List_Iterator.
+ void dump (void) const;
+
+private:
+ ACE_DLList<T> *list_;
+};
+
+/**
+ * @class ACE_DLList_Reverse_Iterator
+ *
+ * @brief A double-linked list container class iterator.
+ *
+ * This implementation uses ACE_Double_Linked_List_Iterator to
+ * perform the logic behind this container class. It delegates
+ * all of its calls to ACE_Double_Linked_List_Iterator.
+ */
+template <class T>
+class ACE_DLList_Reverse_Iterator : public ACE_Double_Linked_List_Reverse_Iterator <ACE_DLList_Node>
+{
+
+ friend class ACE_DLList<T>;
+ friend class ACE_DLList_Node;
+
+public:
+
+ // = Initialization method.
+ ACE_DLList_Reverse_Iterator (ACE_DLList<T> &l);
+
+ /**
+ * Retasks the iterator to iterate over a new
+ * Double_Linked_List. This allows clients to reuse an iterator
+ * without incurring the constructor overhead. If you do use this,
+ * be aware that if there are more than one reference to this
+ * iterator, the other "clients" may be very bothered when their
+ * iterator changes.
+ * @@ Here be dragons. Comments?
+ */
+ void reset (ACE_DLList<T> &l);
+
+ // = Iteration methods.
+ /// Move forward by one element in the set. Returns 0 when all the
+ /// items in the set have been seen, else 1.
+ int advance (void);
+
+ /// Pass back the <next_item> that hasn't been seen in the Stack.
+ /// Returns 0 when all items have been seen, else 1.
+ int next (T *&);
+
+ /// Delegates to ACE_Double_Linked_List_Iterator.
+ /// DEPRECATED
+ T *next (void) const;
+
+ /// Removes the current item (i.e., <next>) from the list.
+ /// Note that DLList iterators do not support <advance_and_remove>
+ /// directly (defined in its base class) and you will need to
+ /// release the element returned by it.
+ int remove (void);
+
+ /// Delegates to ACE_Double_Linked_List_Iterator.
+ void dump (void) const;
+
+private:
+ ACE_DLList<T> *list_;
+};
+
+// Forward declaration.
+template <class T, size_t ACE_SIZE>
+class ACE_Fixed_Set;
+
+/**
+ * @class ACE_Fixed_Set_Iterator
+ *
+ * @brief Interates through an unordered set.
+ *
+ * This implementation of an unordered set uses a fixed array.
+ * Allows deletions while iteration is occurring.
+ */
+template <class T, size_t ACE_SIZE>
+class ACE_Fixed_Set_Iterator
+{
+public:
+ // = Initialization method.
+ ACE_Fixed_Set_Iterator (ACE_Fixed_Set<T, ACE_SIZE> &s);
+
+ // = Iteration methods.
+
+ /// Pass back the <next_item> that hasn't been seen in the Set.
+ /// Returns 0 when all items have been seen, else 1.
+ int next (T *&next_item);
+
+ /// Move forward by one element in the set. Returns 0 when all the
+ /// items in the set have been seen, else 1.
+ int advance (void);
+
+ /// Move to the first element in the set. Returns 0 if the
+ /// set is empty, else 1.
+ int first (void);
+
+ /// Returns 1 when all items have been seen, else 0.
+ int done (void) const;
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+private:
+ /// Set we are iterating over.
+ ACE_Fixed_Set<T, ACE_SIZE> &s_;
+
+ /// How far we've advanced over the set.
+ ssize_t next_;
+};
+
+/**
+ * @class ACE_Fixed_Set
+ *
+ * @brief Implement a simple unordered set of <T> with maximum <ACE_SIZE>.
+ *
+ * This implementation of an unordered set uses a fixed array.
+ * This implementation does not allow duplicates...
+ */
+template <class T, size_t ACE_SIZE>
+class ACE_Fixed_Set
+{
+public:
+ friend class ACE_Fixed_Set_Iterator<T, ACE_SIZE>;
+
+ // Trait definition.
+ typedef ACE_Fixed_Set_Iterator<T, ACE_SIZE> ITERATOR;
+
+ // = Initialization and termination methods.
+ /// Constructor.
+ ACE_Fixed_Set (void);
+
+ /// Copy constructor.
+ ACE_Fixed_Set (const ACE_Fixed_Set<T, ACE_SIZE> &);
+
+ /// Assignment operator.
+ void operator= (const ACE_Fixed_Set<T, ACE_SIZE> &);
+
+ /// Destructor.
+ ~ACE_Fixed_Set (void);
+
+ // = Check boundary conditions.
+
+ /// Returns 1 if the container is empty, otherwise returns 0.
+ int is_empty (void) const;
+
+ /// Returns 1 if the container is full, otherwise returns 0.
+ int is_full (void) const;
+
+ // = Classic unordered set operations.
+
+ /**
+ * Insert <new_item> into the set (doesn't allow duplicates).
+ * Returns -1 if failures occur, 1 if item is already present, else
+ * 0.
+ */
+ int insert (const T &new_item);
+
+ /**
+ * Remove first occurrence of <item> from the set. Returns 0 if
+ * it removes the item, -1 if it can't find the item, and -1 if a
+ * failure occurs.
+ */
+ int remove (const T &item);
+
+ /// Finds if <item> occurs in the set. Returns 0 if finds, else -1.
+ int find (const T &item) const;
+
+ /// Size of the set.
+ size_t size (void) const;
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+private:
+ struct
+ {
+ T item_;
+ // Item in the set.
+
+ int is_free_;
+ // Keeps track of whether this item is in use or not.
+ } search_structure_[ACE_SIZE];
+ // Holds the contents of the set.
+
+ /// Current size of the set.
+ size_t cur_size_;
+
+ /// Maximum size of the set.
+ size_t max_size_;
+};
+
+// Forward declaration.
+template <class T>
+class ACE_Bounded_Set;
+
+/**
+ * @class ACE_Bounded_Set_Iterator
+ *
+ * @brief Interates through an unordered set.
+ *
+ * This implementation of an unordered set uses a Bounded array.
+ * Allows deletions while iteration is occurring.
+ */
+template <class T>
+class ACE_Bounded_Set_Iterator
+{
+public:
+ // = Initialization method.
+ ACE_Bounded_Set_Iterator (ACE_Bounded_Set<T> &s);
+
+ // = Iteration methods.
+
+ /// Pass back the <next_item> that hasn't been seen in the Set.
+ /// Returns 0 when all items have been seen, else 1.
+ int next (T *&next_item);
+
+ /// Move forward by one element in the set. Returns 0 when all the
+ /// items in the set have been seen, else 1.
+ int advance (void);
+
+ /// Move to the first element in the set. Returns 0 if the
+ /// set is empty, else 1.
+ int first (void);
+
+ /// Returns 1 when all items have been seen, else 0.
+ int done (void) const;
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+private:
+ /// Set we are iterating over.
+ ACE_Bounded_Set<T> &s_;
+
+ /// How far we've advanced over the set.
+ ssize_t next_;
+};
+
+/**
+ * @class ACE_Bounded_Set
+ *
+ * @brief Implement a simple unordered set of <T> with maximum
+ * set at creation time.
+ *
+ * This implementation of an unordered set uses a Bounded array.
+ * This implementation does not allow duplicates...
+ */
+template <class T>
+class ACE_Bounded_Set
+{
+public:
+ friend class ACE_Bounded_Set_Iterator<T>;
+
+ // Trait definition.
+ typedef ACE_Bounded_Set_Iterator<T> ITERATOR;
+
+ enum
+ {
+ DEFAULT_SIZE = 10
+ };
+
+ // = Initialization and termination methods.
+ /// Constructor.
+ ACE_Bounded_Set (void);
+
+ /// Constructor.
+ ACE_Bounded_Set (size_t size);
+
+ /// Copy constructor.
+ ACE_Bounded_Set (const ACE_Bounded_Set<T> &);
+
+ /// Assignment operator.
+ void operator= (const ACE_Bounded_Set<T> &);
+
+ /// Destructor
+ ~ACE_Bounded_Set (void);
+
+ // = Check boundary conditions.
+
+ /// Returns 1 if the container is empty, otherwise returns 0.
+ int is_empty (void) const;
+
+ /// Returns 1 if the container is full, otherwise returns 0.
+ int is_full (void) const;
+
+ // = Classic unordered set operations.
+
+ /**
+ * Insert <new_item> into the set (doesn't allow duplicates).
+ * Returns -1 if failures occur, 1 if item is already present, else
+ * 0.
+ */
+ int insert (const T &new_item);
+
+ /**
+ * Remove first occurrence of <item> from the set. Returns 0 if it
+ * removes the item, -1 if it can't find the item, and -1 if a
+ * failure occurs.
+ */
+ int remove (const T &item);
+
+ /// Finds if <item> occurs in the set. Returns 0 if finds, else -1.
+ int find (const T &item) const;
+
+ /// Size of the set.
+ size_t size (void) const;
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+private:
+ struct Search_Structure
+ {
+ T item_;
+ // Item in the set.
+
+ int is_free_;
+ // Keeps track of whether this item is in use or not.
+ };
+
+ /// Holds the contents of the set.
+ Search_Structure *search_structure_;
+
+ /// Current size of the set.
+ size_t cur_size_;
+
+ /// Maximum size of the set.
+ size_t max_size_;
+};
+
+/**
+ * @class ACE_Ordered_MultiSet_Iterator
+ *
+ * @brief Implement a bidirectional iterator over an ordered multiset.
+ * This class template requires that < operator semantics be
+ * defined for the parameterized type <T>, but does not impose
+ * any restriction on how that ordering operator is implemented.
+ */
+template <class T>
+class ACE_Ordered_MultiSet_Iterator
+{
+public:
+ friend class ACE_Ordered_MultiSet<T>;
+
+ // = Initialization method.
+ ACE_Ordered_MultiSet_Iterator (ACE_Ordered_MultiSet<T> &s);
+
+ // = Iteration methods.
+
+ /// Pass back the <next_item> that hasn't been seen in the ordered multiset.
+ /// Returns 0 when all items have been seen, else 1.
+ int next (T *&next_item) const;
+
+ /// Repositions the iterator at the first item in the ordered multiset
+ /// Returns 0 if the list is empty else 1.
+ int first (void);
+
+ /// Repositions the iterator at the last item in the ordered multiset
+ /// Returns 0 if the list is empty else 1.
+ int last (void);
+
+ /// Move forward by one element in the set. Returns 0 when all the
+ /// items in the set have been seen, else 1.
+ int advance (void);
+
+ /// Move backward by one element in the set. Returns 0 when all the
+ /// items in the set have been seen, else 1.
+ int retreat (void);
+
+ /// Returns 1 when all items have been seen, else 0.
+ int done (void) const;
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Returns a reference to the internal element <this> is pointing to.
+ T& operator* (void);
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+private:
+
+ /// Pointer to the current node in the iteration.
+ ACE_DNode<T> *current_;
+
+ /// Pointer to the set we're iterating over.
+ ACE_Ordered_MultiSet<T> &set_;
+};
+
+/**
+ * @class ACE_Ordered_MultiSet
+ *
+ * @brief Implement a simple ordered multiset of <T> of unbounded size
+ * that allows duplicates. This class template requires that <
+ * operator semantics be defined for the parameterized type <T>, but
+ * does not impose any restriction on how that ordering operator is
+ * implemented.
+ */
+template <class T>
+class ACE_Ordered_MultiSet
+{
+public:
+ friend class ACE_Ordered_MultiSet_Iterator<T>;
+
+ // Trait definition.
+ typedef ACE_Ordered_MultiSet_Iterator<T> ITERATOR;
+
+ // = Initialization and termination methods.
+ /// Constructor. Use user specified allocation strategy
+ /// if specified.
+ ACE_Ordered_MultiSet (ACE_Allocator *alloc = 0);
+
+ /// Copy constructor.
+ ACE_Ordered_MultiSet (const ACE_Ordered_MultiSet<T> &);
+
+ /// Destructor.
+ ~ACE_Ordered_MultiSet (void);
+
+ /// Assignment operator.
+ void operator= (const ACE_Ordered_MultiSet<T> &);
+
+ // = Check boundary conditions.
+
+ /// Returns 1 if the container is empty, otherwise returns 0.
+ int is_empty (void) const;
+
+ /// Size of the set.
+ size_t size (void) const;
+
+ // = Classic unordered set operations.
+
+ /// Insert <new_item> into the ordered multiset.
+ /// Returns -1 if failures occur, else 0.
+ int insert (const T &new_item);
+
+ /**
+ * Insert <new_item> into the ordered multiset, starting its search at
+ * the node pointed to by the iterator, and if insertion was successful,
+ * updates the iterator to point to the newly inserted node.
+ * Returns -1 if failures occur, else 0.
+ */
+ int insert (const T &new_item, ITERATOR &iter);
+
+ /// Remove first occurrence of <item> from the set. Returns 0 if
+ /// it removes the item, -1 if it can't find the item.
+ int remove (const T &item);
+
+ /**
+ * Finds first occurrance of <item> in the multiset, using the iterator's
+ * current position as a hint to improve performance. If find succeeds,
+ * it positions the iterator at that node and returns 0, or if it cannot
+ * locate the node, it leaves the iterator alone and just returns -1.
+ */
+ int find (const T &item, ITERATOR &iter) const;
+
+ /// Reset the <ACE_Ordered_MultiSet> to be empty.
+ void reset (void);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+private:
+
+ /**
+ * Insert <item>, starting its search at the position given,
+ * and if successful updates the passed pointer to point to
+ * the newly inserted item's node.
+ */
+ int insert_from (const T &item, ACE_DNode<T> *start_position,
+ ACE_DNode<T> **new_position);
+
+ /**
+ * looks for first occurance of <item> in the ordered set, using the
+ * passed starting position as a hint: if there is such an instance, it
+ * updates the new_position pointer to point to this node and returns 0;
+ * if there is no such node, then if there is a node before where the
+ * item would have been, it updates the new_position pointer to point
+ * to this node and returns -1; if there is no such node, then if there
+ * is a node after where the item would have been, it updates the
+ * new_position pointer to point to this node (or 0 if there is no such
+ * node) and returns 1;
+ */
+ int locate (const T &item, ACE_DNode<T> *start_position,
+ ACE_DNode<T> *&new_position) const;
+
+ /// Delete all the nodes in the Set.
+ void delete_nodes (void);
+
+ /// Copy nodes into this set.
+ void copy_nodes (const ACE_Ordered_MultiSet<T> &);
+
+ /// Head of the bilinked list of Nodes.
+ ACE_DNode<T> *head_;
+
+ /// Head of the bilinked list of Nodes.
+ ACE_DNode<T> *tail_;
+
+ /// Current size of the set.
+ size_t cur_size_;
+
+ /// Allocation strategy of the set.
+ ACE_Allocator *allocator_;
+};
+
+// ****************************************************************
+
+/**
+ * @class ACE_Array
+ *
+ * @brief Implement a dynamic array class.
+ *
+ * This class extends ACE_Array_Base, it provides comparison
+ * operators.
+ */
+template <class T>
+class ACE_Array : public ACE_Array_Base<T>
+{
+public:
+ // Define a "trait"
+ typedef T TYPE;
+
+ typedef ACE_Array_Iterator<T> ITERATOR;
+
+ // = Exceptions.
+
+ // = Initialization and termination methods.
+
+ /// Dynamically create an uninitialized array.
+ ACE_Array (size_t size = 0,
+ ACE_Allocator* alloc = 0);
+
+ /// Dynamically initialize the entire array to the <default_value>.
+ ACE_Array (size_t size,
+ const T &default_value,
+ ACE_Allocator* alloc = 0);
+
+ /**
+ * The copy constructor performs initialization by making an exact
+ * copy of the contents of parameter <s>, i.e., *this == s will
+ * return true.
+ */
+ ACE_Array (const ACE_Array<T> &s);
+
+ /**
+ * Assignment operator performs an assignment by making an exact
+ * copy of the contents of parameter <s>, i.e., *this == s will
+ * return true. Note that if the <max_size_> of <array_> is >= than
+ * <s.max_size_> we can copy it without reallocating. However, if
+ * <max_size_> is < <s.max_size_> we must delete the <array_>,
+ * reallocate a new <array_>, and then copy the contents of <s>.
+ */
+ void operator= (const ACE_Array<T> &s);
+
+ // = Compare operators
+
+ /**
+ * Compare this array with <s> for equality. Two arrays are equal
+ * if their <size>'s are equal and all the elements from 0 .. <size>
+ * are equal.
+ */
+ int operator== (const ACE_Array<T> &s) const;
+
+ /**
+ * Compare this array with <s> for inequality such that <*this> !=
+ * <s> is always the complement of the boolean return value of
+ * <*this> == <s>.
+ */
+ int operator!= (const ACE_Array<T> &s) const;
+};
+
+#if defined (__ACE_INLINE__)
+#include "ace/Containers_T.i"
+#endif /* __ACE_INLINE__ */
+
+#if defined (ACE_TEMPLATES_REQUIRE_SOURCE)
+#include "ace/Containers_T.cpp"
+#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */
+
+#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA)
+#pragma implementation ("Containers_T.cpp")
+#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */
+
+#include "ace/post.h"
+#endif /* ACE_CONTAINERS_T_H */
diff --git a/ace/Utils/Templates/Containers_T.i b/ace/Utils/Templates/Containers_T.i
new file mode 100644
index 00000000000..6ec7895fce2
--- /dev/null
+++ b/ace/Utils/Templates/Containers_T.i
@@ -0,0 +1,469 @@
+/* -*- C++ -*- */
+// $Id$
+
+// Containers.i
+
+template <class T> ACE_INLINE int
+ACE_Bounded_Stack<T>::is_empty (void) const
+{
+ ACE_TRACE ("ACE_Bounded_Stack<T>::is_empty");
+ return this->top_ == 0;
+}
+
+template <class T> ACE_INLINE int
+ACE_Bounded_Stack<T>::is_full (void) const
+{
+ ACE_TRACE ("ACE_Bounded_Stack<T>::is_full");
+ return this->top_ >= this->size_;
+}
+
+template <class T> ACE_INLINE int
+ACE_Bounded_Stack<T>::push (const T &new_item)
+{
+ ACE_TRACE ("ACE_Bounded_Stack<T>::push");
+ if (this->is_full () == 0)
+ {
+ this->stack_[this->top_++] = new_item;
+ return 0;
+ }
+ else
+ return -1;
+}
+
+template <class T> ACE_INLINE int
+ACE_Bounded_Stack<T>::pop (T &item)
+{
+ ACE_TRACE ("ACE_Bounded_Stack<T>::pop");
+ if (this->is_empty () == 0)
+ {
+ item = this->stack_[--this->top_];
+ return 0;
+ }
+ else
+ return -1;
+}
+
+template <class T> ACE_INLINE int
+ACE_Bounded_Stack<T>::top (T &item) const
+{
+ ACE_TRACE ("ACE_Bounded_Stack<T>::top");
+ if (this->is_empty () == 0)
+ {
+ item = this->stack_[this->top_ - 1];
+ return 0;
+ }
+ else
+ return -1;
+}
+
+template <class T> ACE_INLINE size_t
+ACE_Bounded_Stack<T>::size (void) const
+{
+ return this->size_;
+}
+
+//----------------------------------------
+
+template <class T, size_t ACE_SIZE> ACE_INLINE int
+ACE_Fixed_Stack<T, ACE_SIZE>::is_empty (void) const
+{
+ ACE_TRACE ("ACE_Fixed_Stack<T, ACE_SIZE>::is_empty");
+ return this->top_ == 0;
+}
+
+template <class T, size_t ACE_SIZE> ACE_INLINE int
+ACE_Fixed_Stack<T, ACE_SIZE>::is_full (void) const
+{
+ ACE_TRACE ("ACE_Fixed_Stack<T, ACE_SIZE>::is_full");
+ return this->top_ >= this->size_;
+}
+
+template <class T, size_t ACE_SIZE> ACE_INLINE int
+ACE_Fixed_Stack<T, ACE_SIZE>::push (const T &new_item)
+{
+ ACE_TRACE ("ACE_Fixed_Stack<T, ACE_SIZE>::push");
+ if (this->is_full () == 0)
+ {
+ this->stack_[this->top_++] = new_item;
+ return 0;
+ }
+ else
+ return -1;
+}
+
+template <class T, size_t ACE_SIZE> ACE_INLINE int
+ACE_Fixed_Stack<T, ACE_SIZE>::pop (T &item)
+{
+ ACE_TRACE ("ACE_Fixed_Stack<T, ACE_SIZE>::pop");
+ if (this->is_empty () == 0)
+ {
+ item = this->stack_[--this->top_];
+ return 0;
+ }
+ else
+ return -1;
+}
+
+template <class T, size_t ACE_SIZE> ACE_INLINE int
+ACE_Fixed_Stack<T, ACE_SIZE>::top (T &item) const
+{
+ ACE_TRACE ("ACE_Fixed_Stack<T, ACE_SIZE>::top");
+ if (this->is_empty () == 0)
+ {
+ item = this->stack_[this->top_ - 1];
+ return 0;
+ }
+ else
+ return -1;
+}
+
+template <class T, size_t ACE_SIZE> ACE_INLINE size_t
+ACE_Fixed_Stack<T, ACE_SIZE>::size (void) const
+{
+ return this->size_;
+}
+
+template <class T> ACE_INLINE int
+ACE_Unbounded_Stack<T>::is_empty (void) const
+{
+ // ACE_TRACE ("ACE_Unbounded_Stack<T>::is_empty");
+ return this->head_ == this->head_->next_;
+}
+
+template <class T> ACE_INLINE int
+ACE_Unbounded_Stack<T>::top (T &item) const
+{
+ ACE_TRACE ("ACE_Unbounded_Stack<T>::top");
+ if (this->is_empty () == 0)
+ {
+ item = this->head_->next_->item_;
+ return 0;
+ }
+ else
+ return -1;
+}
+
+template <class T> ACE_INLINE int
+ACE_Unbounded_Stack<T>::is_full (void) const
+{
+ ACE_TRACE ("ACE_Unbounded_Stack<T>::is_full");
+ return 0; // ???
+}
+
+template <class T> ACE_INLINE size_t
+ACE_Unbounded_Stack<T>::size (void) const
+{
+ return this->cur_size_;
+}
+
+// ---
+
+
+// ---
+
+template <class T, size_t ACE_SIZE> ACE_INLINE int
+ACE_Fixed_Set<T, ACE_SIZE>::is_empty (void) const
+{
+ ACE_TRACE ("ACE_Fixed_Set<T>::is_empty");
+ return this->cur_size_ == 0;
+}
+
+template <class T, size_t ACE_SIZE> ACE_INLINE int
+ACE_Fixed_Set<T, ACE_SIZE>::is_full (void) const
+{
+ ACE_TRACE ("ACE_Fixed_Set<T, ACE_SIZE>::is_full");
+ return this->cur_size_ == this->max_size_;
+}
+
+// ---
+
+template <class T> ACE_INLINE int
+ACE_Bounded_Set<T>::is_empty (void) const
+{
+ ACE_TRACE ("ACE_Bounded_Set<T>::is_empty");
+ return this->cur_size_ == 0;
+}
+
+#if !defined (__Lynx__)
+ // LynxOS 3.0.0 native g++ compiler raises internal error with this inline.
+template <class T> ACE_INLINE int
+ACE_Bounded_Set<T>::is_full (void) const
+{
+ ACE_TRACE ("ACE_Bounded_Set<T>::is_full");
+ return this->cur_size_ == this->max_size_;
+}
+#endif /* ! __Lynx__ */
+
+// --
+
+template <class T> ACE_INLINE int
+ACE_Ordered_MultiSet_Iterator<T>::first (void)
+{
+ ACE_TRACE ("ACE_Ordered_MultiSet_Iterator<T>::first");
+ current_ = set_.head_;
+
+ return (current_ ? 1 : 0);
+}
+
+template <class T> ACE_INLINE int
+ACE_Ordered_MultiSet_Iterator<T>::last (void)
+{
+ ACE_TRACE ("ACE_Ordered_MultiSet_Iterator<T>::last");
+ current_ = set_.tail_;
+
+ return (current_ ? 1 : 0);
+}
+
+template <class T> ACE_INLINE int
+ACE_Ordered_MultiSet_Iterator<T>::advance (void)
+{
+ ACE_TRACE ("ACE_Ordered_MultiSet_Iterator<T>::advance");
+
+ current_ = current_ ? current_->next_ : 0;
+
+ return (current_ ? 1 : 0);
+}
+
+template <class T> ACE_INLINE int
+ACE_Ordered_MultiSet_Iterator<T>::retreat (void)
+{
+ ACE_TRACE ("ACE_Ordered_MultiSet_Iterator<T>::retreat");
+
+ current_ = current_ ? current_->prev_ : 0;
+
+ return (current_ ? 1 : 0);
+}
+
+template <class T> ACE_INLINE int
+ACE_Ordered_MultiSet_Iterator<T>::done (void) const
+{
+ ACE_TRACE ("ACE_Ordered_MultiSet_Iterator<T>::done");
+
+ return (current_ ? 0 : 1);
+}
+
+template <class T> ACE_INLINE void
+ACE_Ordered_MultiSet_Iterator<T>::dump (void) const
+{
+// ACE_TRACE ("ACE_Ordered_MultiSet_Iterator<T>::dump");
+}
+
+
+
+// --
+
+template <class T> ACE_INLINE int
+ACE_Ordered_MultiSet<T>::is_empty (void) const
+{
+ ACE_TRACE ("ACE_Ordered_MultiSet<T>::is_empty");
+ return this->cur_size_ > 0 ? 0 : 1;
+}
+
+template <class T> ACE_INLINE size_t
+ACE_Ordered_MultiSet<T>::size (void) const
+{
+// ACE_TRACE ("ACE_Ordered_MultiSet<T>::size");
+ return this->cur_size_;
+}
+
+// ****************************************************************
+
+template <class T> ACE_INLINE
+ACE_Array<T>::ACE_Array (size_t size,
+ ACE_Allocator *alloc)
+ : ACE_Array_Base<T> (size, alloc)
+{
+}
+
+template <class T> ACE_INLINE
+ACE_Array<T>::ACE_Array (size_t size,
+ const T &default_value,
+ ACE_Allocator *alloc)
+ : ACE_Array_Base<T> (size, default_value, alloc)
+{
+}
+
+// The copy constructor (performs initialization).
+
+template <class T> ACE_INLINE
+ACE_Array<T>::ACE_Array (const ACE_Array<T> &s)
+ : ACE_Array_Base<T> (s)
+{
+}
+
+// Assignment operator (performs assignment).
+
+template <class T> ACE_INLINE void
+ACE_Array<T>::operator= (const ACE_Array<T> &s)
+{
+ // Check for "self-assignment".
+
+ if (this != &s)
+ this->ACE_Array_Base<T>::operator= (s);
+}
+
+// Compare this array with <s> for inequality.
+
+template <class T> ACE_INLINE int
+ACE_Array<T>::operator!= (const ACE_Array<T> &s) const
+{
+ return !(*this == s);
+}
+
+// ****************************************************************
+
+
+// ****************************************************************
+
+template <class T> ACE_INLINE void
+ACE_DLList<T>::operator= (const ACE_DLList<T> &l)
+{
+ *(ACE_DLList_Base *) this = l;
+}
+
+template <class T> ACE_INLINE int
+ACE_DLList<T>::get (T *&item, size_t index)
+{
+ ACE_DLList_Node *node;
+ int result = ACE_DLList_Base::get (node, index);
+ if (result != -1)
+ item = (T *) node->item_;
+ return result;
+}
+
+template <class T> ACE_INLINE void
+ACE_DLList<T>::dump (void) const
+{
+ ACE_DLList_Base::dump ();
+}
+
+template <class T> ACE_INLINE int
+ACE_DLList<T>::remove (ACE_DLList_Node *n)
+{
+ int result = ACE_DLList_Base::remove (n);
+ ACE_DES_FREE (n,
+ this->allocator_->free,
+ ACE_DLList_Node);
+ return result;
+}
+
+template <class T> ACE_INLINE
+ACE_DLList<T>::ACE_DLList (ACE_Allocator *alloc )
+ : ACE_DLList_Base (alloc)
+{
+}
+
+template <class T> ACE_INLINE
+ACE_DLList<T>::ACE_DLList (const ACE_DLList<T> &l)
+ : ACE_DLList_Base ((ACE_DLList<T> &) l)
+{
+}
+
+template <class T> ACE_INLINE
+ACE_DLList<T>::~ACE_DLList (void)
+{
+ while (this->delete_head ()) ;
+}
+
+template <class T> ACE_INLINE int
+ACE_DLList_Iterator<T>::remove (void)
+{
+ ACE_DLList_Node *temp = this->ACE_Double_Linked_List_Iterator <ACE_DLList_Node>::next ();
+ this->ACE_Double_Linked_List_Iterator <ACE_DLList_Node>::advance ();
+ return list_->remove (temp);
+}
+
+template <class T> ACE_INLINE
+ACE_DLList_Iterator<T>::ACE_DLList_Iterator (ACE_DLList<T> &l)
+ : ACE_Double_Linked_List_Iterator <ACE_DLList_Node> ((ACE_DLList_Base &)l),
+ list_ (&l)
+{
+}
+
+template <class T> ACE_INLINE void
+ACE_DLList_Iterator<T>::reset (ACE_DLList<T> &l)
+{
+ list_ = &l;
+ this->ACE_Double_Linked_List_Iterator <ACE_DLList_Node>::reset ((ACE_DLList_Base &)l);
+}
+
+template <class T> ACE_INLINE int
+ACE_DLList_Iterator<T>::next (T *&ptr)
+{
+ ACE_DLList_Node *temp =
+ ACE_Double_Linked_List_Iterator <ACE_DLList_Node>::next ();
+ if (temp)
+ ptr = (T *) temp->item_;
+ return temp ? 1 : 0;
+}
+
+template <class T> ACE_INLINE T *
+ACE_DLList_Iterator<T>::next (void) const
+{
+ ACE_DLList_Node *temp = ACE_Double_Linked_List_Iterator <ACE_DLList_Node>::next ();
+ return (T *) (temp ? temp->item_ : 0);
+}
+
+template <class T> ACE_INLINE int
+ACE_DLList_Iterator<T>::advance (void)
+{
+ return this->ACE_Double_Linked_List_Iterator <ACE_DLList_Node>::advance ();
+}
+
+template <class T> ACE_INLINE void
+ACE_DLList_Iterator<T>::dump (void) const
+{
+ ACE_Double_Linked_List_Iterator <ACE_DLList_Node>::dump ();
+}
+
+
+template <class T> ACE_INLINE int
+ACE_DLList_Reverse_Iterator<T>::remove (void)
+{
+ ACE_DLList_Node *temp = ACE_Double_Linked_List_Reverse_Iterator <ACE_DLList_Node>::next ();
+ this->ACE_Double_Linked_List_Reverse_Iterator <ACE_DLList_Node>::advance ();
+ return list_->remove (temp);
+}
+
+template <class T> ACE_INLINE
+ACE_DLList_Reverse_Iterator<T>::ACE_DLList_Reverse_Iterator (ACE_DLList<T> &l)
+ : ACE_Double_Linked_List_Reverse_Iterator <ACE_DLList_Node> ((ACE_DLList_Base &)l),
+ list_ (&l)
+{
+}
+
+template <class T> ACE_INLINE void
+ACE_DLList_Reverse_Iterator<T>::reset (ACE_DLList<T> &l)
+{
+ list_ = &l;
+ this->ACE_Double_Linked_List_Reverse_Iterator <ACE_DLList_Node>::reset ((ACE_DLList_Base &)l);
+}
+
+template <class T> ACE_INLINE int
+ACE_DLList_Reverse_Iterator<T>::advance (void)
+{
+ return ACE_Double_Linked_List_Reverse_Iterator <ACE_DLList_Node>::advance ();
+}
+
+template <class T> ACE_INLINE int
+ACE_DLList_Reverse_Iterator<T>::next (T *&ptr)
+{
+ ACE_DLList_Node *temp =
+ ACE_Double_Linked_List_Reverse_Iterator <ACE_DLList_Node>::next ();
+ ptr = (T *) temp->item_;
+ return ptr ? 1 : 0;
+}
+
+template <class T> ACE_INLINE T *
+ACE_DLList_Reverse_Iterator<T>::next (void) const
+{
+ ACE_DLList_Node *temp = ACE_Double_Linked_List_Reverse_Iterator <ACE_DLList_Node>::next ();
+ return (T *) (temp ? temp->item_ : 0);
+}
+
+
+template <class T> ACE_INLINE void
+ACE_DLList_Reverse_Iterator<T>::dump (void) const
+{
+ ACE_Double_Linked_List_Reverse_Iterator <ACE_DLList_Node>::dump ();
+}
diff --git a/ace/Utils/Templates/Env_Value_T.cpp b/ace/Utils/Templates/Env_Value_T.cpp
new file mode 100644
index 00000000000..d99819ec6b9
--- /dev/null
+++ b/ace/Utils/Templates/Env_Value_T.cpp
@@ -0,0 +1,14 @@
+// $Id$
+
+#if !defined (ACE_ENV_VALUE_T_C)
+#define ACE_ENV_VALUE_T_C
+
+#include "ace/Env_Value_T.h"
+
+#if ! defined (__ACE_INLINE__)
+#include "ace/Env_Value_T.i"
+#endif /* __ACE_INLINE__ */
+
+ACE_RCSID(ace, Env_Value_T, "$Id$")
+
+#endif /* ACE_ENV_VALUE_T_C */
diff --git a/ace/Utils/Templates/Env_Value_T.h b/ace/Utils/Templates/Env_Value_T.h
new file mode 100644
index 00000000000..c38e5deac86
--- /dev/null
+++ b/ace/Utils/Templates/Env_Value_T.h
@@ -0,0 +1,161 @@
+/* This may look like C, but it's really -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Env_Value_T.h
+ *
+ * $Id$
+ *
+ * Template to encapsulate getting a value from an environment variable
+ * and using a supplied default value if not in the environment.
+ *
+ *
+ * @author Chris Cleeland (derived from work by Carlos O'Ryan)
+ */
+//=============================================================================
+
+
+#ifndef ACE_ENV_VALUE_T_H
+#define ACE_ENV_VALUE_T_H
+#include "ace/pre.h"
+
+#include "ace/OS.h" // Need to get ACE_static_cast definition
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+/**
+ * @class ACE_Env_Value
+ *
+ * @brief Enviroment Variable Value
+ *
+ * Reads a variable from the user enviroment, providing a default
+ * value.
+ * = AUTHOR
+ * Chris Cleeland, Carlos O'Ryan
+ */
+template <class T>
+class ACE_Env_Value
+{
+public:
+ /**
+ * Default constructor which isn't bound to a specific environment
+ * variable name or a default value. Before being useful it must
+ * <open>'d.
+ */
+ ACE_Env_Value (void);
+
+ /// Constructor that calls <open>.
+ ACE_Env_Value (const ACE_TCHAR *varname,
+ const T &vardefault);
+
+ /// Destroy the value.
+ ~ACE_Env_Value (void);
+
+ /// Returns the value as type T.
+ operator T (void);
+
+ /// The constructor, read <varname> from the enviroment, using
+ /// <vardefault> as its value if it is not defined.
+ void open (const ACE_TCHAR *varname, const T &defval);
+
+ /// Returns the name of the variable being tracked.
+ const ACE_TCHAR *varname (void) const;
+
+private:
+ /// Disallow copying and assignment.
+ ACE_UNIMPLEMENTED_FUNC (ACE_Env_Value(const ACE_Env_Value<T> &))
+ ACE_UNIMPLEMENTED_FUNC (ACE_Env_Value<T> operator=(const ACE_Env_Value<T> &))
+
+ void fetch_value (void);
+
+ const ACE_TCHAR *varname_;
+ T value_;
+};
+
+template <class T> void ACE_Convert (const ACE_TCHAR *s, T &t);
+// Function to convert a string <s> into type <T>.
+
+#if defined (__ACE_INLINE__)
+#include "ace/Env_Value_T.i"
+#endif /* __ACE_INLINE__ */
+
+#if defined (ACE_TEMPLATES_REQUIRE_SOURCE)
+#include "ace/Env_Value_T.cpp"
+#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */
+
+
+// Default calls a CTOR on type T of the form 'T::T(const char*)', but
+// users can feel free to create their own specialized conversion
+// functions if necessary, as shown below. Note that for 'char*' the
+// default is used because a simple cast will be performed and no
+// conversion will be necessary.
+
+template <class T> inline void
+ACE_Convert (const ACE_TCHAR *s, T &t)
+{
+ t = T (s);
+}
+
+inline void
+ACE_Convert (const ACE_TCHAR *s, ACE_TCHAR *&v)
+{
+ v = (ACE_TCHAR *) s;
+}
+
+inline void
+ACE_Convert (const ACE_TCHAR *s, const ACE_TCHAR *&v)
+{
+ v = (const ACE_TCHAR *) s;
+}
+
+inline void
+ACE_Convert (const ACE_TCHAR *s, short &si)
+{
+ si = ACE_static_cast (short, ACE_OS::strtol (s, 0, 10));
+}
+
+inline void
+ACE_Convert (const ACE_TCHAR *s, u_short &us)
+{
+ us = ACE_static_cast (u_short, ACE_OS::strtol (s, 0, 10));
+}
+
+inline void
+ACE_Convert (const ACE_TCHAR *s, u_int &i)
+{
+ i = ACE_static_cast (u_int,
+ ACE_OS::strtol (s, 0, 10));
+}
+
+inline void
+ACE_Convert (const ACE_TCHAR *s, long &l)
+{
+ l = ACE_OS::strtol (s, 0, 10);
+}
+
+inline void
+ACE_Convert (const ACE_TCHAR *s, int &i)
+{
+ i = ACE_static_cast (int, ACE_OS::strtol (s, 0, 10));
+}
+
+inline void
+ACE_Convert (const ACE_TCHAR *s, u_long &ul)
+{
+ ul = ACE_OS::strtoul (s, 0, 10);
+}
+
+inline void
+ACE_Convert (const ACE_TCHAR *s, double &d)
+{
+ d = ACE_OS::strtod (s, 0);
+}
+
+#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA)
+#pragma implementation ("Env_Value_T.cpp")
+#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */
+
+#include "ace/post.h"
+#endif /* ACE_ENV_VALUE_T_H */
diff --git a/ace/Utils/Templates/Env_Value_T.i b/ace/Utils/Templates/Env_Value_T.i
new file mode 100644
index 00000000000..9f98f0fdb45
--- /dev/null
+++ b/ace/Utils/Templates/Env_Value_T.i
@@ -0,0 +1,51 @@
+// $Id$
+
+template <class T> ACE_INLINE
+ACE_Env_Value<T>::operator T (void)
+{
+ return value_;
+}
+
+template <class T> ACE_INLINE
+ACE_Env_Value<T>::ACE_Env_Value (void)
+ : varname_ (0)
+{
+}
+
+template <class T> ACE_INLINE
+ACE_Env_Value<T>::ACE_Env_Value (const ACE_TCHAR *varname,
+ const T &defval)
+ : varname_ (varname),
+ value_(defval)
+{
+ this->fetch_value ();
+}
+
+template <class T> ACE_INLINE void
+ACE_Env_Value<T>::open (const ACE_TCHAR *varname,
+ const T &defval)
+{
+ varname_ = varname;
+ value_ = defval;
+ this->fetch_value ();
+}
+
+template <class T> ACE_INLINE void
+ACE_Env_Value<T>::fetch_value (void)
+{
+ const ACE_TCHAR *env = ACE_OS::getenv (varname_);
+
+ if (env != 0)
+ ACE_Convert (env, value_);
+}
+
+template <class T> ACE_INLINE const ACE_TCHAR*
+ACE_Env_Value<T>::varname (void) const
+{
+ return varname_;
+}
+
+template <class T> ACE_INLINE
+ACE_Env_Value<T>::~ACE_Env_Value (void)
+{
+}
diff --git a/ace/Utils/Templates/Free_List.cpp b/ace/Utils/Templates/Free_List.cpp
new file mode 100644
index 00000000000..703e2f7f572
--- /dev/null
+++ b/ace/Utils/Templates/Free_List.cpp
@@ -0,0 +1,90 @@
+// $Id$
+
+#ifndef ACE_FREE_LIST_C
+#define ACE_FREE_LIST_C
+
+#include "ace/Free_List.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#if !defined (__ACE_INLINE__)
+#include "ace/Free_List.i"
+#endif /* __ACE_INLINE__ */
+
+ACE_RCSID(ace, Free_List, "$Id$")
+
+// Empty constructor
+
+template <class T>
+ACE_Free_List<T>::~ACE_Free_List (void)
+{
+ // Nothing
+}
+
+// Default constructor that takes in a preallocation number
+// (<prealloc>), a low and high water mark (<lwm> and <hwm>) and an
+// increment value (<inc>)
+
+template <class T, class ACE_LOCK>
+ACE_Locked_Free_List<T, ACE_LOCK>::ACE_Locked_Free_List (int mode,
+ size_t prealloc,
+ size_t lwm,
+ size_t hwm,
+ size_t inc)
+ : mode_ (mode),
+ free_list_ (0),
+ lwm_ (lwm),
+ hwm_ (hwm),
+ inc_ (inc),
+ size_ (0)
+{
+ this->alloc (prealloc);
+}
+
+// Destructor - removes all the elements from the free_list
+
+template <class T, class ACE_LOCK>
+ACE_Locked_Free_List<T, ACE_LOCK>::~ACE_Locked_Free_List (void)
+{
+ if (this->mode_ != ACE_PURE_FREE_LIST)
+ while (this->free_list_ != 0)
+ {
+ T *temp = this->free_list_;
+ this->free_list_ = this->free_list_->get_next ();
+ delete temp;
+ }
+}
+
+// Allocates <n> extra nodes for the freelist
+
+template <class T, class ACE_LOCK> void
+ACE_Locked_Free_List<T, ACE_LOCK>::alloc (size_t n)
+{
+ for (; n > 0; n--)
+ {
+ T *temp = 0;
+ ACE_NEW (temp, T);
+ temp->set_next (this->free_list_);
+ this->free_list_ = temp;
+ this->size_++;
+ }
+}
+
+// Removes and frees <n> nodes from the freelist.
+
+template <class T, class ACE_LOCK> void
+ACE_Locked_Free_List<T, ACE_LOCK>::dealloc (size_t n)
+{
+ for (; this->free_list_ != 0 && n > 0;
+ n--)
+ {
+ T *temp = this->free_list_;
+ this->free_list_ = this->free_list_->get_next ();
+ delete temp;
+ this->size_--;
+ }
+}
+
+#endif /* ACE_FREE_LIST_C */
diff --git a/ace/Utils/Templates/Free_List.h b/ace/Utils/Templates/Free_List.h
new file mode 100644
index 00000000000..339cc9b9200
--- /dev/null
+++ b/ace/Utils/Templates/Free_List.h
@@ -0,0 +1,148 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Free_List.h
+ *
+ * $Id$
+ *
+ * @author Darrell Brunsch (brunsch@cs.wustl.edu)
+ */
+//=============================================================================
+
+#ifndef ACE_FREE_LIST_H
+#define ACE_FREE_LIST_H
+#include "ace/pre.h"
+
+#include "ace/OS.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "ace/Synch_T.h"
+
+/**
+ * @class ACE_Free_List
+ *
+ * @brief Implements a free list.
+ *
+ * This class maintains a free list of nodes of type T.
+ */
+template <class T>
+class ACE_Free_List
+{
+public:
+ /// Destructor - removes all the elements from the free_list.
+ virtual ~ACE_Free_List (void);
+
+ /// Inserts an element onto the free list (if it isn't past the high
+ /// water mark).
+ virtual void add (T *element) = 0;
+
+ /// Takes a element off the freelist and returns it. It creates
+ /// <inc> new elements if the size is at or below the low water mark.
+ virtual T *remove (void) = 0;
+
+ /// Returns the current size of the free list.
+ virtual size_t size (void) = 0;
+
+ /// Resizes the free list to <newsize>.
+ virtual void resize (size_t newsize) = 0;
+};
+
+/**
+ * @class ACE_Locked_Free_List
+ *
+ * @brief Implements a free list.
+ *
+ * This class maintains a free list of nodes of type T. It
+ * depends on the type T having a <get_next> and <set_next>
+ * method. It maintains a mutex so the freelist can be used in
+ * a multithreaded program .
+ */
+template <class T, class ACE_LOCK>
+class ACE_Locked_Free_List : public ACE_Free_List<T>
+{
+public:
+ // = Initialization and termination.
+ /**
+ * Constructor takes a <mode> (i.e., ACE_FREE_LIST_WITH_POOL or
+ * ACE_PURE_FREE_LIST), a count of the number of nodes to
+ * <prealloc>, a low and high water mark (<lwm> and <hwm>) that
+ * indicate when to allocate more nodes, an increment value (<inc>)
+ * that indicates how many nodes to allocate when the list must
+ * grow.
+ */
+ ACE_Locked_Free_List (int mode = ACE_FREE_LIST_WITH_POOL,
+ size_t prealloc = ACE_DEFAULT_FREE_LIST_PREALLOC,
+ size_t lwm = ACE_DEFAULT_FREE_LIST_LWM,
+ size_t hwm = ACE_DEFAULT_FREE_LIST_HWM,
+ size_t inc = ACE_DEFAULT_FREE_LIST_INC);
+
+ /// Destructor - removes all the elements from the free_list.
+ virtual ~ACE_Locked_Free_List (void);
+
+ /// Inserts an element onto the free list (if it isn't past the high
+ /// water mark).
+ virtual void add (T *element);
+
+ /// Takes a element off the freelist and returns it. It creates
+ /// <inc> new elements if the size is at or below the low water mark.
+ virtual T *remove (void);
+
+ /// Returns the current size of the free list.
+ virtual size_t size (void);
+
+ /// Resizes the free list to <newsize>.
+ virtual void resize (size_t newsize);
+
+protected:
+ /// Allocates <n> extra nodes for the freelist.
+ virtual void alloc (size_t n);
+
+ /// Removes and frees <n> nodes from the freelist.
+ virtual void dealloc (size_t n);
+
+ /// Free list operation mode, either ACE_FREE_LIST_WITH_POOL or
+ /// ACE_PURE_FREE_LIST.
+ int mode_;
+
+ /// Pointer to the first node in the freelist.
+ T *free_list_;
+
+ /// Low water mark.
+ size_t lwm_;
+
+ /// High water mark.
+ size_t hwm_;
+
+ /// Increment value.
+ size_t inc_;
+
+ /// Keeps track of the size of the list.
+ size_t size_;
+
+ /// Synchronization variable for <ACE_Timer_Queue>.
+ ACE_LOCK mutex_;
+
+private:
+ // = Don't allow these operations for now.
+ ACE_UNIMPLEMENTED_FUNC (ACE_Locked_Free_List (const ACE_Locked_Free_List<T, ACE_LOCK> &))
+ ACE_UNIMPLEMENTED_FUNC (void operator= (const ACE_Locked_Free_List<T, ACE_LOCK> &))
+};
+
+#if defined (__ACE_INLINE__)
+#include "ace/Free_List.i"
+#endif /* __ACE_INLINE__ */
+
+#if defined (ACE_TEMPLATES_REQUIRE_SOURCE)
+#include "ace/Free_List.cpp"
+#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */
+
+#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA)
+#pragma implementation ("Free_List.cpp")
+#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */
+
+#include "ace/post.h"
+#endif /* ACE_FREE_LIST_H */
diff --git a/ace/Utils/Templates/Free_List.i b/ace/Utils/Templates/Free_List.i
new file mode 100644
index 00000000000..7875592c8a9
--- /dev/null
+++ b/ace/Utils/Templates/Free_List.i
@@ -0,0 +1,76 @@
+/* -*- C++ -*- */
+// $Id$
+
+
+// Inserts an element onto the free list (if we are allowed to manage
+// elements withing and it pasts the high water mark, delete the
+// element)
+
+template <class T, class ACE_LOCK> ACE_INLINE void
+ACE_Locked_Free_List<T, ACE_LOCK>::add (T *element)
+{
+ ACE_MT (ACE_GUARD (ACE_LOCK, ace_mon, this->mutex_));
+
+ // Check to see that we not at the high water mark.
+ if (this->mode_ == ACE_PURE_FREE_LIST
+ || this->size_ < this->hwm_)
+ {
+ element->set_next (this->free_list_);
+ this->free_list_ = element;
+ this->size_++;
+ }
+ else
+ delete element;
+}
+
+// Takes a element off the freelist and returns it. It creates <inc>
+// new elements if we are allowed to do it and the size is at the low
+// water mark.
+
+template <class T, class ACE_LOCK> ACE_INLINE T *
+ACE_Locked_Free_List<T, ACE_LOCK>::remove (void)
+{
+ ACE_MT (ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, 0));
+
+ // If we are at the low water mark, add some nodes
+ if (this->mode_ != ACE_PURE_FREE_LIST && this->size_ <= this->lwm_)
+ this->alloc (this->inc_);
+
+ // Remove a node
+ T *temp = this->free_list_;
+
+ if (temp != 0)
+ {
+ this->free_list_ = this->free_list_->get_next ();
+ this->size_--;
+ }
+
+ return temp;
+}
+
+
+// Returns the current size of the free list
+
+template <class T, class ACE_LOCK> ACE_INLINE size_t
+ACE_Locked_Free_List<T, ACE_LOCK>::size (void)
+{
+ return this->size_;
+}
+
+// Resizes the free list to <newsize>
+
+template <class T, class ACE_LOCK> ACE_INLINE void
+ACE_Locked_Free_List<T, ACE_LOCK>::resize (size_t newsize)
+{
+ ACE_MT (ACE_GUARD (ACE_LOCK, ace_mon, this->mutex_));
+
+ // Check if we are allowed to resize
+ if (this->mode_ != ACE_PURE_FREE_LIST)
+ // Check to see if we grow or shrink
+ if (newsize < this->size_)
+ this->dealloc (this->size_ - newsize);
+ else
+ this->alloc (newsize - this->size_);
+}
+
+
diff --git a/ace/Utils/Templates/Hash_Cache_Map_Manager_T.cpp b/ace/Utils/Templates/Hash_Cache_Map_Manager_T.cpp
new file mode 100644
index 00000000000..e632924334e
--- /dev/null
+++ b/ace/Utils/Templates/Hash_Cache_Map_Manager_T.cpp
@@ -0,0 +1,230 @@
+// $Id$
+
+#ifndef ACE_HASH_CACHE_MAP_MANAGER_T_C
+#define ACE_HASH_CACHE_MAP_MANAGER_T_C
+
+#include "ace/Hash_Cache_Map_Manager_T.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+#define ACE_LACKS_PRAGMA_ONCE
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#if !defined (__ACE_INLINE__)
+#include "ace/Hash_Cache_Map_Manager_T.i"
+#endif /* __ACE_INLINE__ */
+
+ACE_RCSID(ace, Hash_Cache_Map_Manager_T, "$Id$")
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Hash_Cache_Map_Manager)
+
+#define T_1 class KEY, class VALUE, class HASH_KEY, class COMPARE_KEYS, class CACHING_STRATEGY, class ATTRIBUTES
+#define T_2 KEY, VALUE, HASH_KEY, COMPARE_KEYS, CACHING_STRATEGY, ATTRIBUTES
+
+template <T_1>
+ACE_Hash_Cache_Map_Manager<T_2>::ACE_Hash_Cache_Map_Manager (CACHING_STRATEGY &caching_s,
+ size_t size,
+ ACE_Allocator *alloc)
+ : ACE_HCMM_BASE (caching_s,
+ size,
+ alloc)
+{
+}
+
+template <T_1>
+ACE_Hash_Cache_Map_Manager<T_2>::~ACE_Hash_Cache_Map_Manager (void)
+{
+}
+
+template <T_1> int
+ACE_Hash_Cache_Map_Manager<T_2>:: bind (const KEY &key,
+ const VALUE &value,
+ ACE_Hash_Map_Entry<KEY, ACE_Pair<VALUE, ATTRIBUTES> > *&entry)
+{
+ // Insert a entry which has the <key> and the <cache_value> which is
+ // the combination of the <value> and the attributes of the caching
+ // strategy.
+ CACHE_VALUE cache_value (value,
+ this->caching_strategy_.attributes ());
+
+ int bind_result = this->map_.bind (key,
+ cache_value,
+ entry);
+
+ if (bind_result != -1)
+ {
+
+ int result = this->caching_strategy_.notify_bind (bind_result,
+ cache_value.second ());
+
+ if (result == -1)
+ {
+
+ this->map_.unbind (key);
+
+ // Unless the notification goes thru the bind operation is
+ // not complete.
+ bind_result = -1;
+
+ }
+ }
+
+ return bind_result;
+}
+
+template <T_1> int
+ACE_Hash_Cache_Map_Manager<T_2>::rebind (const KEY &key,
+ const VALUE &value,
+ ACE_Hash_Map_Entry<KEY, ACE_Pair<VALUE, ATTRIBUTES> > *&entry)
+{
+ CACHE_VALUE cache_value (value,
+ this->caching_strategy_.attributes ());
+
+ int rebind_result = this->map_.rebind (key,
+ cache_value,
+ entry);
+
+ if (rebind_result != -1)
+ {
+
+ int result = this->caching_strategy_.notify_rebind (rebind_result,
+ cache_value.second ());
+
+ if (result == -1)
+ {
+
+ // Make sure the unbind operation is done only when the
+ // notification fails after a bind which is denoted by
+ // rebind_result = 0
+ if (rebind_result == 0)
+ this->map_.unbind (key);
+
+ // Unless the notification goes thru the rebind operation is
+ // not complete.
+ rebind_result = -1;
+
+ }
+
+ }
+
+ return rebind_result;
+}
+
+template <T_1> int
+ACE_Hash_Cache_Map_Manager<T_2>::trybind (const KEY &key,
+ VALUE &value,
+ ACE_Hash_Map_Entry<KEY, ACE_Pair<VALUE, ATTRIBUTES> > *&entry)
+{
+ CACHE_VALUE cache_value (value,
+ this->caching_strategy_.attributes ());
+
+ int trybind_result = this->map_.trybind (key,
+ cache_value,
+ entry);
+
+ if (trybind_result != -1)
+ {
+ int result = this->caching_strategy_.notify_trybind (trybind_result,
+ cache_value.second ());
+
+ if (result == -1)
+ {
+
+ // If the entry has got inserted into the map, it is removed
+ // due to failure.
+ if (trybind_result == 0)
+ this->map_.unbind (key);
+
+ trybind_result = -1;
+
+ }
+ else
+ {
+
+ // If an attempt is made to bind an existing entry the value
+ // is overwritten with the value from the map.
+ if (trybind_result == 1)
+ value = cache_value.first ();
+
+ }
+
+ }
+
+ return trybind_result;
+}
+
+template <T_1> int
+ACE_Hash_Cache_Map_Manager<T_2>::find (const KEY &key,
+ ACE_Hash_Map_Entry<KEY, ACE_Pair<VALUE, ATTRIBUTES> > *&entry)
+{
+ // Lookup the key and populate the <value>.
+ int find_result = this->map_.find (key,
+ entry);
+
+ if (find_result != -1)
+ {
+
+ int result = this->caching_strategy_.notify_find (find_result,
+ entry->int_id_.second ());
+
+ // Unless the find and notification operations go thru, this
+ // method is not successful.
+ if (result == -1)
+ find_result = -1;
+ else
+ find_result = 0;
+
+ }
+
+ return find_result;
+}
+
+template <T_1> int
+ACE_Hash_Cache_Map_Manager<T_2>::find (const KEY &key,
+ VALUE &value)
+{
+ CACHE_ENTRY *entry = 0;
+
+ int result = this->find (key,
+ entry);
+
+ if (result != -1)
+ {
+ value = entry->int_id_.first ();
+ }
+
+ return result;
+}
+
+template <T_1> int
+ACE_Hash_Cache_Map_Manager<T_2>::find (const KEY &key)
+{
+ CACHE_ENTRY *entry = 0;
+
+ return this->find (key,
+ entry);
+}
+
+template <T_1> int
+ACE_Hash_Cache_Map_Manager<T_2>::unbind (ACE_Hash_Map_Entry<KEY, ACE_Pair<VALUE, ATTRIBUTES> > *entry)
+{
+ // Remove the entry from the cache.
+ int unbind_result = this->map_.unbind (entry);
+
+ if (unbind_result != -1)
+ {
+
+ int result = this->caching_strategy_.notify_unbind (unbind_result,
+ entry->int_id_.second ());
+
+ if (result == -1)
+ unbind_result = -1;
+
+ }
+
+ return unbind_result;
+}
+
+#undef T_1
+#undef T_2
+
+#endif /* ACE_HASH_CACHE_MAP_MANAGER_T_C */
diff --git a/ace/Utils/Templates/Hash_Cache_Map_Manager_T.h b/ace/Utils/Templates/Hash_Cache_Map_Manager_T.h
new file mode 100644
index 00000000000..d2eb1e37c7c
--- /dev/null
+++ b/ace/Utils/Templates/Hash_Cache_Map_Manager_T.h
@@ -0,0 +1,215 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Hash_Cache_Map_Manager_T.h
+ *
+ * $Id$
+ *
+ * @author Kirthika Parameswaran <kirthika@cs.wustl.edu>
+ */
+//=============================================================================
+
+
+#ifndef HASH_CACHE_MAP_MANAGER_T_H
+#define HASH_CACHE_MAP_MANAGER_T_H
+#include "ace/pre.h"
+
+#include "ace/Hash_Map_Manager_T.h"
+#include "ace/Cache_Map_Manager_T.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+#define ACE_LACKS_PRAGMA_ONCE
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+// Forward declaration.
+class ACE_Allocator;
+
+#if !defined (ACE_HAS_BROKEN_EXTENDED_TEMPLATES)
+#define ACE_CACHE_MAP_MANAGER \
+ ACE_Cache_Map_Manager<KEY, \
+ VALUE, \
+ ACE_Hash_Map_Manager_Ex<KEY, ACE_Pair<VALUE, ATTRIBUTES>, HASH_KEY, COMPARE_KEYS, ACE_Null_Mutex>, \
+ ACE_Hash_Map_Iterator_Ex<KEY, ACE_Pair<VALUE, ATTRIBUTES>, HASH_KEY, COMPARE_KEYS, ACE_Null_Mutex>, \
+ ACE_Hash_Map_Reverse_Iterator_Ex<KEY, ACE_Pair<VALUE, ATTRIBUTES>, HASH_KEY, COMPARE_KEYS, ACE_Null_Mutex>, \
+ CACHING_STRATEGY, \
+ ATTRIBUTES>
+#else
+#define ACE_CACHE_MAP_MANAGER \
+ ACE_Cache_Map_Manager<KEY, \
+ VALUE, \
+ ACE_Hash_Map_Manager_Ex<KEY, ACE_Pair<VALUE, ATTRIBUTES>, HASH_KEY, COMPARE_KEYS, ACE_Null_Mutex>, \
+ CACHING_STRATEGY, \
+ ATTRIBUTES>
+#endif /* ACE_HAS_BROKEN_EXTENDED_TEMPLATES */
+
+// For linkers that cant grok long names.
+#define ACE_Hash_Cache_Map_Manager AHCMM
+
+ /**
+ * @class ACE_Hash_Cache_Map_Manager
+ *
+ * @brief Defines a abstraction which will purge entries from a map.
+ * The map considered is the ACE_Hash_Map_Manager_Ex.
+ *
+ * The Hash_Cache_Map_Manager will manage the map it contains
+ * and provide purging on demand from the map. The strategy for
+ * caching is decided by the user and provided to the Cache
+ * Manager. The Cache Manager acts as a agent and communicates
+ * between the Map and the Strategy for purging entries from the
+ * map. To tap the optimal methods like find(key,value,entry)
+ * present in the ACE_Hash_Map_Manager,
+ * Hash_Cache_Map_Manager provides extra functionality on top
+ * of the Cache_Map_Manager.
+ * No locking mechanism provided since locking at this level
+ * isnt efficient. Locking has to be provided by the
+ * application.
+ */
+template <class KEY, class VALUE, class HASH_KEY, class COMPARE_KEYS, class CACHING_STRATEGY, class ATTRIBUTES>
+class ACE_Hash_Cache_Map_Manager : public ACE_CACHE_MAP_MANAGER
+{
+ public:
+
+ /**
+ * The actual value mapped to the key in the map. The <attributes>
+ * are used by the strategy and is transparent to the user of this
+ * class.
+ */
+ typedef ACE_Pair<VALUE, ATTRIBUTES> CACHE_VALUE;
+ typedef ACE_Hash_Map_Manager_Ex<KEY, CACHE_VALUE, HASH_KEY, COMPARE_KEYS, ACE_Null_Mutex> HASH_MAP;
+ typedef ACE_Hash_Map_Entry<KEY, CACHE_VALUE> CACHE_ENTRY;
+ typedef KEY key_type;
+ typedef VALUE mapped_type;
+
+ // = Initialization and termination methods.
+ /// Initialize a <Hash_Cache_Map_Manager> with <size> entries.
+ ACE_Hash_Cache_Map_Manager (CACHING_STRATEGY &caching_s,
+ size_t size = ACE_DEFAULT_MAP_SIZE,
+ ACE_Allocator *alloc = 0);
+
+ /// Close down a <Cache_Map_Manager> and release dynamically allocated
+ /// resources.
+ ~ACE_Hash_Cache_Map_Manager (void);
+
+ /**
+ * Associate <key> with <value>. If <key> is already in the
+ * MAP then the ENTRY is not changed. Returns 0 if a new entry is
+ * bound successfully, returns 1 if an attempt is made to bind an
+ * existing entry, and returns -1 if failures occur.
+ */
+ int bind (const KEY &key,
+ const VALUE &value);
+
+ /**
+ * Same as a normal bind, except the cache entry is also passed back
+ * to the caller. The entry in this case will either be the newly
+ * created entry, or the existing one.
+ */
+ int bind (const KEY &key,
+ const VALUE &value,
+ CACHE_ENTRY *&entry);
+
+ /// Loopkup entry<key,value> in the cache.
+ int find (const KEY &key,
+ VALUE &value);
+
+ /// Is <key> in the cache?
+ int find (const KEY &key);
+
+ /// Obtain the entry when the find succeeds.
+ int find (const KEY &key,
+ CACHE_ENTRY *&entry);
+
+ /**
+ * Reassociate the <key> with <value>. If the <key> already exists
+ * in the cache then returns 1, on a new bind returns 0 and returns
+ * -1 in case of any failures.
+ */
+ int rebind (const KEY &key,
+ const VALUE &value);
+
+ /**
+ * Reassociate <key> with <value>, storing the old value into the
+ * "out" parameter <old_value>. The function fails if <key> is not
+ * in the cache for caches that do not allow user specified keys.
+ * However, for caches that allow user specified keys, if the key is
+ * not in the cache, a new <key>/<value> association is created.
+ */
+ int rebind (const KEY &key,
+ const VALUE &value,
+ VALUE &old_value);
+
+ /**
+ * Reassociate <key> with <value>, storing the old key and value
+ * into the "out" parameters <old_key> and <old_value>. The
+ * function fails if <key> is not in the cache for caches that do not
+ * allow user specified keys. However, for caches that allow user
+ * specified keys, if the key is not in the cache, a new <key>/<value>
+ * association is created.
+ */
+ int rebind (const KEY &key,
+ const VALUE &value,
+ KEY &old_key,
+ VALUE &old_value);
+
+ /**
+ * Same as a normal rebind, except the cache entry is also passed back
+ * to the caller. The entry in this case will either be the newly
+ * created entry, or the existing one.
+ */
+ int rebind (const KEY &key,
+ const VALUE &value,
+ CACHE_ENTRY *&entry);
+
+ /**
+ * Associate <key> with <value> if and only if <key> is not in the
+ * cache. If <key> is already in the cache, then the <value> parameter
+ * is overwritten with the existing value in the cache. Returns 0 if a
+ * new <key>/<value> association is created. Returns 1 if an
+ * attempt is made to bind an existing entry. This function fails
+ * for maps that do not allow user specified keys.
+ */
+ int trybind (const KEY &key,
+ VALUE &value);
+
+ /**
+ * Same as a normal trybind, except the cache entry is also passed
+ * back to the caller. The entry in this case will either be the
+ * newly created entry, or the existing one.
+ */
+ int trybind (const KEY &key,
+ VALUE &value,
+ CACHE_ENTRY *&entry);
+
+ /// Remove <key> from the cache.
+ int unbind (const KEY &key);
+
+ /// Remove <key> from the cache, and return the <value> associated with
+ /// <key>.
+ int unbind (const KEY &key,
+ VALUE &value);
+
+ /// Remove entry from map.
+ int unbind (CACHE_ENTRY *entry);
+
+protected:
+
+ /// Base class.
+ typedef ACE_CACHE_MAP_MANAGER ACE_HCMM_BASE;
+};
+
+
+#if defined (__ACE_INLINE__)
+#include "ace/Hash_Cache_Map_Manager_T.i"
+#endif /* __ACE_INLINE__ */
+
+#if defined (ACE_TEMPLATES_REQUIRE_SOURCE)
+#include "ace/Hash_Cache_Map_Manager_T.cpp"
+#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */
+
+#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA)
+#pragma implementation ("Hash_Cache_Map_Manager_T.cpp")
+#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */
+
+#include "ace/post.h"
+#endif /* HASH_CACHE_MAP_MANAGER_T_H */
diff --git a/ace/Utils/Templates/Hash_Cache_Map_Manager_T.i b/ace/Utils/Templates/Hash_Cache_Map_Manager_T.i
new file mode 100644
index 00000000000..f73e2d2aa7d
--- /dev/null
+++ b/ace/Utils/Templates/Hash_Cache_Map_Manager_T.i
@@ -0,0 +1,68 @@
+/* -*- C++ -*- */
+// $Id$
+
+#define T_1 class KEY, class VALUE, class HASH_KEY, class COMPARE_KEYS, class CACHING_STRATEGY, class ATTRIBUTES
+#define T_2 KEY, VALUE, HASH_KEY, COMPARE_KEYS, CACHING_STRATEGY, ATTRIBUTES
+
+template <T_1> ACE_INLINE int
+ACE_Hash_Cache_Map_Manager<T_2>::bind (const KEY &key,
+ const VALUE &value)
+{
+ return ACE_HCMM_BASE::bind (key,
+ value);
+}
+
+template <T_1> ACE_INLINE int
+ACE_Hash_Cache_Map_Manager<T_2>::rebind (const KEY &key,
+ const VALUE &value)
+{
+ return ACE_HCMM_BASE::rebind (key,
+ value);
+}
+
+template <T_1> ACE_INLINE int
+ACE_Hash_Cache_Map_Manager<T_2>::rebind (const KEY &key,
+ const VALUE &value,
+ VALUE &old_value)
+{
+ return ACE_HCMM_BASE::rebind (key,
+ value,
+ old_value);
+}
+
+template <T_1> ACE_INLINE int
+ACE_Hash_Cache_Map_Manager<T_2>::rebind (const KEY &key,
+ const VALUE &value,
+ KEY &old_key,
+ VALUE &old_value)
+{
+ return ACE_HCMM_BASE::rebind (key,
+ value,
+ old_key,
+ old_value);
+}
+
+template <T_1> ACE_INLINE int
+ACE_Hash_Cache_Map_Manager<T_2>::trybind (const KEY &key,
+ VALUE &value)
+{
+ return ACE_HCMM_BASE::trybind (key,
+ value);
+}
+
+template <T_1> ACE_INLINE int
+ACE_Hash_Cache_Map_Manager<T_2>::unbind (const KEY &key)
+{
+ return ACE_HCMM_BASE::unbind (key);
+}
+
+template <T_1> ACE_INLINE int
+ACE_Hash_Cache_Map_Manager<T_2>::unbind (const KEY &key,
+ VALUE &value)
+{
+ return ACE_HCMM_BASE::unbind (key,
+ value);
+}
+
+#undef T_1
+#undef T_2
diff --git a/ace/Utils/Templates/Hash_Map_Manager_T.cpp b/ace/Utils/Templates/Hash_Map_Manager_T.cpp
new file mode 100644
index 00000000000..669ca4bc756
--- /dev/null
+++ b/ace/Utils/Templates/Hash_Map_Manager_T.cpp
@@ -0,0 +1,520 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// ace
+//
+// = FILENAME
+// Hash_Map_Manager_T.cpp
+//
+// = AUTHOR
+// Doug Schmidt
+//
+// ============================================================================
+
+#ifndef ACE_HASH_MAP_MANAGER_T_CPP
+#define ACE_HASH_MAP_MANAGER_T_CPP
+
+#include "ace/Hash_Map_Manager_T.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#if !defined (__ACE_INLINE__)
+# include "ace/Hash_Map_Manager_T.i"
+#elif defined (__SUNPRO_CC) && (__SUNPRO_CC == 0x420)
+// If ACE_INLINE is on and we are on SunCC, undefine ACE_INLINE,
+// include ace/Hash_Map_Manager_T.i, and then redefine ACE_INLINE.
+// This nonsense is necessary since SunCC (version 4.2) cannot inline
+// the code in ace/Hash_Map_Manager_T.i (with the fast option).
+# undef ACE_INLINE
+# define ACE_INLINE
+# include "ace/Hash_Map_Manager_T.i"
+# undef ACE_INLINE
+# define ACE_INLINE inline
+#endif /* __ACE_INLINE__ */
+
+#include "ace/Synch.h"
+#include "ace/Service_Config.h"
+#include "ace/Malloc.h"
+
+ACE_RCSID(ace, Hash_Map_Manager_T, "$Id$")
+
+template <class EXT_ID, class INT_ID>
+ACE_Hash_Map_Entry<EXT_ID, INT_ID>::ACE_Hash_Map_Entry (ACE_Hash_Map_Entry<EXT_ID, INT_ID> *next,
+ ACE_Hash_Map_Entry<EXT_ID, INT_ID> *prev)
+ : next_ (next),
+ prev_ (prev)
+{
+}
+
+template <class EXT_ID, class INT_ID>
+ACE_Hash_Map_Entry<EXT_ID, INT_ID>::ACE_Hash_Map_Entry (const EXT_ID &ext_id,
+ const INT_ID &int_id,
+ ACE_Hash_Map_Entry<EXT_ID, INT_ID> *next,
+ ACE_Hash_Map_Entry<EXT_ID, INT_ID> *prev)
+ : ext_id_ (ext_id),
+ int_id_ (int_id),
+ next_ (next),
+ prev_ (prev)
+{
+}
+
+# if ! defined (ACE_HAS_BROKEN_NOOP_DTORS)
+template <class EXT_ID, class INT_ID>
+ACE_Hash_Map_Entry<EXT_ID, INT_ID>::~ACE_Hash_Map_Entry (void)
+{
+}
+# endif /* ! defined (ACE_HAS_BROKEN_NOOP_DTORS) */
+
+template <class EXT_ID, class INT_ID> void
+ACE_Hash_Map_Entry<EXT_ID, INT_ID>::dump (void) const
+{
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("next_ = %d"), this->next_));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("prev_ = %d"), this->prev_));
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> void
+ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::dump (void) const
+{
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("total_size_ = %d"), this->total_size_));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\ncur_size_ = %d"), this->cur_size_));
+ this->allocator_->dump ();
+ this->lock_.dump ();
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> int
+ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::create_buckets (size_t size)
+{
+ size_t bytes = size * sizeof (ACE_Hash_Map_Entry<EXT_ID, INT_ID>);
+ void *ptr;
+
+ ACE_ALLOCATOR_RETURN (ptr,
+ this->allocator_->malloc (bytes),
+ -1);
+
+ this->table_ = (ACE_Hash_Map_Entry<EXT_ID, INT_ID> *) ptr;
+
+ this->total_size_ = size;
+
+ // Initialize each entry in the hash table to be a circular linked
+ // list with the dummy node in the front serving as the anchor of
+ // the list.
+ for (size_t i = 0; i < size; i++)
+ new (&this->table_[i]) ACE_Hash_Map_Entry<EXT_ID, INT_ID> (&this->table_[i],
+ &this->table_[i]);
+ return 0;
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> int
+ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::open (size_t size,
+ ACE_Allocator *alloc)
+{
+ ACE_WRITE_GUARD_RETURN (ACE_LOCK, ace_mon, this->lock_, -1);
+
+ // Calling this->close_i () to ensure we release previous allocated
+ // memory before allocating new one.
+ this->close_i ();
+
+ if (alloc == 0)
+ alloc = ACE_Allocator::instance ();
+
+ this->allocator_ = alloc;
+
+ // This assertion is here to help track a situation that shouldn't
+ // happen, but did with Sun C++ 4.1 (before a change to this class
+ // was made: it used to have an enum that was supposed to be defined
+ // to be ACE_DEFAULT_MAP_SIZE, but instead was defined to be 0).
+ ACE_ASSERT (size != 0);
+
+ return this->create_buckets (size);
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> int
+ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::close_i (void)
+{
+ // Protect against "double-deletion" in case the destructor also
+ // gets called.
+ if (this->table_ != 0)
+ {
+ // Remove all the entries.
+ this->unbind_all_i ();
+
+ // Iterate through the buckets cleaning up the sentinels.
+ for (size_t i = 0; i < this->total_size_; i++)
+ {
+ // Destroy the dummy entry.
+ ACE_Hash_Map_Entry<EXT_ID, INT_ID> *entry = &this->table_[i];
+ // The "if" second argument results in a no-op instead of
+ // deallocation.
+ ACE_DES_FREE_TEMPLATE2 (entry, ACE_NOOP,
+ ACE_Hash_Map_Entry, EXT_ID, INT_ID);
+ }
+
+ // Reset size.
+ this->total_size_ = 0;
+
+ // Free table memory.
+ this->allocator_->free (this->table_);
+
+ // Should be done last...
+ this->table_ = 0;
+ }
+
+ return 0;
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> int
+ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::unbind_all_i (void)
+{
+ // Iterate through the entire map calling the destuctor of each
+ // <ACE_Hash_Map_Entry>.
+ for (size_t i = 0; i < this->total_size_; i++)
+ {
+ for (ACE_Hash_Map_Entry<EXT_ID, INT_ID> *temp_ptr = this->table_[i].next_;
+ temp_ptr != &this->table_[i];
+ )
+ {
+ ACE_Hash_Map_Entry<EXT_ID, INT_ID> *hold_ptr = temp_ptr;
+ temp_ptr = temp_ptr->next_;
+
+ // Explicitly call the destructor.
+ ACE_DES_FREE_TEMPLATE2 (hold_ptr, this->allocator_->free,
+ ACE_Hash_Map_Entry, EXT_ID, INT_ID);
+ }
+
+ // Restore the sentinel.
+ this->table_[i].next_ = &this->table_[i];
+ this->table_[i].prev_ = &this->table_[i];
+ }
+
+ this->cur_size_ = 0;
+
+ return 0;
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> int
+ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::bind_i (const EXT_ID &ext_id,
+ const INT_ID &int_id,
+ ACE_Hash_Map_Entry<EXT_ID, INT_ID> *&entry)
+{
+ u_long loc;
+ int result = this->shared_find (ext_id, entry, loc);
+
+ if (result == -1)
+ {
+ void *ptr;
+ // Not found.
+ ACE_ALLOCATOR_RETURN (ptr,
+ this->allocator_->malloc (sizeof (ACE_Hash_Map_Entry<EXT_ID, INT_ID>)),
+ -1);
+
+ entry = new (ptr) ACE_Hash_Map_Entry<EXT_ID, INT_ID> (ext_id,
+ int_id,
+ this->table_[loc].next_,
+ &this->table_[loc]);
+ this->table_[loc].next_ = entry;
+ entry->next_->prev_ = entry;
+ this->cur_size_++;
+ return 0;
+ }
+ else
+ return 1;
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> int
+ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::trybind_i (const EXT_ID &ext_id,
+ INT_ID &int_id,
+ ACE_Hash_Map_Entry<EXT_ID, INT_ID> *&entry)
+{
+ u_long loc;
+ int result = this->shared_find (ext_id, entry, loc);
+
+ if (result == -1)
+ {
+ // Not found.
+ void *ptr;
+ ACE_ALLOCATOR_RETURN (ptr,
+ this->allocator_->malloc (sizeof (ACE_Hash_Map_Entry<EXT_ID, INT_ID>)),
+ -1);
+
+ entry = new (ptr) ACE_Hash_Map_Entry<EXT_ID, INT_ID> (ext_id,
+ int_id,
+ this->table_[loc].next_,
+ &this->table_[loc]);
+ this->table_[loc].next_ = entry;
+ entry->next_->prev_ = entry;
+ this->cur_size_++;
+ return 0;
+ }
+ else
+ return 1;
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> int
+ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::unbind_i (const EXT_ID &ext_id,
+ INT_ID &int_id)
+{
+ ACE_Hash_Map_Entry<EXT_ID, INT_ID> *temp;
+
+ u_long loc;
+ int result = this->shared_find (ext_id, temp, loc);
+
+ if (result == -1)
+ {
+ errno = ENOENT;
+ return -1;
+ }
+
+ int_id = temp->int_id_;
+
+ return this->unbind_i (temp);
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> int
+ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::unbind_i (ACE_Hash_Map_Entry<EXT_ID, INT_ID> *entry)
+{
+ entry->next_->prev_ = entry->prev_;
+ entry->prev_->next_ = entry->next_;
+
+ // Explicitly call the destructor.
+ ACE_DES_FREE_TEMPLATE2 (entry, this->allocator_->free,
+ ACE_Hash_Map_Entry, EXT_ID, INT_ID);
+ this->cur_size_--;
+ return 0;
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> int
+ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::shared_find (const EXT_ID &ext_id,
+ ACE_Hash_Map_Entry<EXT_ID, INT_ID> *&entry,
+ u_long &loc)
+{
+ loc = this->hash (ext_id) % this->total_size_;
+
+ ACE_Hash_Map_Entry<EXT_ID, INT_ID> *temp = this->table_[loc].next_;
+
+ while (temp != &this->table_[loc] && this->equal (temp->ext_id_, ext_id) == 0)
+ temp = temp->next_;
+
+ if (temp == &this->table_[loc])
+ {
+ errno = ENOENT;
+ return -1;
+ }
+ else
+ {
+ entry = temp;
+ return 0;
+ }
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> int
+ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::rebind_i (const EXT_ID &ext_id,
+ const INT_ID &int_id,
+ ACE_Hash_Map_Entry<EXT_ID, INT_ID> *&entry)
+{
+ u_long dummy;
+ if (this->shared_find (ext_id, entry, dummy) == -1)
+ return this->bind_i (ext_id, int_id);
+ else
+ {
+ entry->ext_id_ = ext_id;
+ entry->int_id_ = int_id;
+ return 1;
+ }
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> int
+ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::rebind_i (const EXT_ID &ext_id,
+ const INT_ID &int_id,
+ INT_ID &old_int_id,
+ ACE_Hash_Map_Entry<EXT_ID, INT_ID> *&entry)
+{
+ u_long dummy;
+ if (this->shared_find (ext_id, entry, dummy) == -1)
+ return this->bind_i (ext_id, int_id);
+ else
+ {
+ old_int_id = entry->int_id_;
+ entry->ext_id_ = ext_id;
+ entry->int_id_ = int_id;
+ return 1;
+ }
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> int
+ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::rebind_i (const EXT_ID &ext_id,
+ const INT_ID &int_id,
+ EXT_ID &old_ext_id,
+ INT_ID &old_int_id,
+ ACE_Hash_Map_Entry<EXT_ID, INT_ID> *&entry)
+{
+ u_long dummy;
+ if (this->shared_find (ext_id, entry, dummy) == -1)
+ return this->bind_i (ext_id, int_id);
+ else
+ {
+ old_ext_id = entry->ext_id_;
+ old_int_id = entry->int_id_;
+ entry->ext_id_ = ext_id;
+ entry->int_id_ = int_id;
+ return 1;
+ }
+}
+
+// ------------------------------------------------------------
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Hash_Map_Iterator_Base_Ex)
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> void
+ACE_Hash_Map_Iterator_Base_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::dump_i (void) const
+{
+ ACE_TRACE ("ACE_Hash_Map_Iterator_Base_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::dump_i");
+
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("index_ = %d "), this->index_));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("next_ = %x"), this->next_));
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> int
+ACE_Hash_Map_Iterator_Base_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::forward_i (void)
+{
+ ACE_TRACE ("ACE_Hash_Map_Iterator_Base_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::forward_i");
+
+ if (this->map_man_->table_ == 0)
+ return -1;
+ // Handle initial case specially.
+ else if (this->index_ == -1)
+ {
+ this->index_++;
+ return this->forward_i ();
+ }
+ else if (this->index_ >= ACE_static_cast (ssize_t, this->map_man_->total_size_))
+ return 0;
+
+ this->next_ = this->next_->next_;
+ if (this->next_ == &this->map_man_->table_[this->index_])
+ {
+ while (++this->index_ < ACE_static_cast (ssize_t,
+ this->map_man_->total_size_))
+ {
+ this->next_ = this->map_man_->table_[this->index_].next_;
+ if (this->next_ != &this->map_man_->table_[this->index_])
+ break;
+ }
+ }
+
+ return this->index_ < ACE_static_cast (ssize_t, this->map_man_->total_size_);
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> int
+ACE_Hash_Map_Iterator_Base_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::reverse_i (void)
+{
+ ACE_TRACE ("ACE_Hash_Map_Iterator_Base_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::reverse_i");
+
+ if (this->map_man_->table_ == 0)
+ return -1;
+ else if (this->index_ == ACE_static_cast (ssize_t, this->map_man_->total_size_))
+ {
+ this->index_--;
+ return this->reverse_i ();
+ }
+ else if (this->index_ < 0)
+ return 0;
+
+ this->next_ = this->next_->prev_;
+ if (this->next_ == &this->map_man_->table_[this->index_])
+ {
+ while (--this->index_ >= 0)
+ {
+ this->next_ = this->map_man_->table_[this->index_].prev_;
+ if (this->next_ != &this->map_man_->table_[this->index_])
+ break;
+ }
+ }
+
+ return this->index_ >= 0;
+}
+
+// ------------------------------------------------------------
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Hash_Map_Const_Iterator_Base_Ex)
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> void
+ACE_Hash_Map_Const_Iterator_Base_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::dump_i (void) const
+{
+ ACE_TRACE ("ACE_Hash_Map_Const_Iterator_Base_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::dump_i");
+
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("index_ = %d "), this->index_));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("next_ = %x"), this->next_));
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> int
+ACE_Hash_Map_Const_Iterator_Base_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::forward_i (void)
+{
+ ACE_TRACE ("ACE_Hash_Map_Const_Iterator_Base_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::forward_i");
+
+ if (this->map_man_->table_ == 0)
+ return -1;
+ // Handle initial case specially.
+ else if (this->index_ == -1)
+ {
+ this->index_++;
+ return this->forward_i ();
+ }
+ else if (this->index_ >= (ssize_t) this->map_man_->total_size_)
+ return 0;
+
+ this->next_ = this->next_->next_;
+ if (this->next_ == &this->map_man_->table_[this->index_])
+ {
+ while (++this->index_ < (ssize_t) this->map_man_->total_size_)
+ {
+ this->next_ = this->map_man_->table_[this->index_].next_;
+ if (this->next_ != &this->map_man_->table_[this->index_])
+ break;
+ }
+ }
+
+ return this->index_ < (ssize_t) this->map_man_->total_size_;
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> int
+ACE_Hash_Map_Const_Iterator_Base_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::reverse_i (void)
+{
+ ACE_TRACE ("ACE_Hash_Map_Const_Iterator_Base_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::reverse_i");
+
+ if (this->map_man_->table_ == 0)
+ return -1;
+ else if (this->index_ == (ssize_t) this->map_man_->total_size_)
+ {
+ this->index_--;
+ return this->reverse_i ();
+ }
+ else if (this->index_ < 0)
+ return 0;
+
+ this->next_ = this->next_->prev_;
+ if (this->next_ == &this->map_man_->table_[this->index_])
+ {
+ while (--this->index_ >= 0)
+ {
+ this->next_ = this->map_man_->table_[this->index_].prev_;
+ if (this->next_ != &this->map_man_->table_[this->index_])
+ break;
+ }
+ }
+
+ return this->index_ >= 0;
+}
+
+#endif /* ACE_HASH_MAP_MANAGER_T_CPP */
diff --git a/ace/Utils/Templates/Hash_Map_Manager_T.h b/ace/Utils/Templates/Hash_Map_Manager_T.h
new file mode 100644
index 00000000000..71bf90c10d1
--- /dev/null
+++ b/ace/Utils/Templates/Hash_Map_Manager_T.h
@@ -0,0 +1,914 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Hash_Map_Manager_T.h
+ *
+ * $Id$
+ *
+ * @author Douglas C. Schmidt <schmidt@cs.wustl.edu>
+ */
+//=============================================================================
+
+#ifndef ACE_HASH_MAP_MANAGER_T_H
+#define ACE_HASH_MAP_MANAGER_T_H
+#include "ace/pre.h"
+
+#include "ace/OS.h"
+#include "ace/Functor.h"
+#include "ace/Log_Msg.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+/**
+ * @class ACE_Hash_Map_Entry
+ *
+ * @brief Define an entry in the hash table.
+ */
+template <class EXT_ID, class INT_ID>
+class ACE_Hash_Map_Entry
+{
+public:
+ // = Initialization and termination methods.
+ /// Constructor.
+ ACE_Hash_Map_Entry (const EXT_ID &ext_id,
+ const INT_ID &int_id,
+ ACE_Hash_Map_Entry<EXT_ID, INT_ID> *next = 0,
+ ACE_Hash_Map_Entry<EXT_ID, INT_ID> *prev = 0);
+
+ /// Constructor.
+ ACE_Hash_Map_Entry (ACE_Hash_Map_Entry<EXT_ID, INT_ID> *next,
+ ACE_Hash_Map_Entry<EXT_ID, INT_ID> *prev);
+
+# if ! defined (ACE_HAS_BROKEN_NOOP_DTORS)
+ /// Destructor.
+ ~ACE_Hash_Map_Entry (void);
+#endif /* ! defined (ACE_HAS_BROKEN_NOOP_DTORS) */
+
+ /// Key used to look up an entry.
+ EXT_ID ext_id_;
+
+ /// The contents of the entry itself.
+ INT_ID int_id_;
+
+ /// Pointer to the next item in the bucket of overflow nodes.
+ ACE_Hash_Map_Entry<EXT_ID, INT_ID> *next_;
+
+ /// Pointer to the prev item in the bucket of overflow nodes.
+ ACE_Hash_Map_Entry<EXT_ID, INT_ID> *prev_;
+
+ /// Dump the state of an object.
+ void dump (void) const;
+};
+
+// Forward decl.
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK>
+class ACE_Hash_Map_Iterator_Base_Ex;
+
+// Forward decl.
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK>
+class ACE_Hash_Map_Const_Iterator_Base_Ex;
+
+// Forward decl.
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK>
+class ACE_Hash_Map_Iterator_Ex;
+
+// Forward decl.
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK>
+class ACE_Hash_Map_Const_Iterator_Ex;
+
+// Forward decl.
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK>
+class ACE_Hash_Map_Reverse_Iterator_Ex;
+
+// Forward decl.
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK>
+class ACE_Hash_Map_Bucket_Iterator;
+
+// Forward decl.
+class ACE_Allocator;
+
+/**
+ * @class ACE_Hash_Map_Manager_Ex
+ *
+ * @brief Define a map abstraction that efficiently associates
+ * <EXT_ID>s with <INT_ID>s.
+ *
+ * This implementation of a map uses a hash table. Key hashing
+ * is achieved through the HASH_KEY object and key comparison is
+ * achieved through the COMPARE_KEYS object.
+ * This class uses an <ACE_Allocator> to allocate memory. The
+ * user can make this a persistent class by providing an
+ * <ACE_Allocator> with a persistable memory pool.
+ */
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK>
+class ACE_Hash_Map_Manager_Ex
+{
+public:
+ friend class ACE_Hash_Map_Iterator_Base_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>;
+ friend class ACE_Hash_Map_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>;
+ friend class ACE_Hash_Map_Const_Iterator_Base_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>;
+ friend class ACE_Hash_Map_Const_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>;
+ friend class ACE_Hash_Map_Reverse_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>;
+ friend class ACE_Hash_Map_Bucket_Iterator<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>;
+
+ typedef EXT_ID
+ KEY;
+ typedef INT_ID
+ VALUE;
+ typedef ACE_Hash_Map_Entry<EXT_ID, INT_ID>
+ ENTRY;
+
+ // = ACE-style iterator typedefs.
+ typedef ACE_Hash_Map_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>
+ ITERATOR;
+ typedef ACE_Hash_Map_Const_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>
+ CONST_ITERATOR;
+ typedef ACE_Hash_Map_Reverse_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>
+ REVERSE_ITERATOR;
+
+ // = STL-style iterator typedefs.
+ typedef ACE_Hash_Map_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>
+ iterator;
+ typedef ACE_Hash_Map_Const_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>
+ const_iterator;
+ typedef ACE_Hash_Map_Reverse_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>
+ reverse_iterator;
+
+ // = Initialization and termination methods.
+
+ /// Initialize a <Hash_Map_Manager_Ex> with default size.
+ ACE_Hash_Map_Manager_Ex (ACE_Allocator *alloc = 0);
+
+ /// Initialize a <Hash_Map_Manager_Ex> with size <length>.
+ ACE_Hash_Map_Manager_Ex (size_t size,
+ ACE_Allocator *alloc = 0);
+
+ /// Initialize a <Hash_Map_Manager_Ex> with <size> elements.
+ int open (size_t size = ACE_DEFAULT_MAP_SIZE,
+ ACE_Allocator *alloc = 0);
+
+ /// Close down a <Hash_Map_Manager_Ex> and release dynamically allocated
+ /// resources.
+ int close (void);
+
+ /// Removes all the entries in <Map_Manager_Ex>.
+ int unbind_all (void);
+
+ /// Cleanup the <Hash_Map_Manager_Ex>.
+ ~ACE_Hash_Map_Manager_Ex (void);
+
+ /**
+ * Associate <ext_id> with <int_id>. If <ext_id> is already in the
+ * map then the <ACE_Hash_Map_Entry> is not changed. Returns 0 if a
+ * new entry is bound successfully, returns 1 if an attempt is made
+ * to bind an existing entry, and returns -1 if failures occur.
+ */
+ int bind (const EXT_ID &item,
+ const INT_ID &int_id);
+
+ /**
+ * Same as a normal bind, except the map entry is also passed back
+ * to the caller. The entry in this case will either be the newly
+ * created entry, or the existing one.
+ */
+ int bind (const EXT_ID &ext_id,
+ const INT_ID &int_id,
+ ACE_Hash_Map_Entry<EXT_ID, INT_ID> *&entry);
+
+ /**
+ * Associate <ext_id> with <int_id> if and only if <ext_id> is not
+ * in the map. If <ext_id> is already in the map then the <int_id>
+ * parameter is assigned the existing value in the map. Returns 0
+ * if a new entry is bound successfully, returns 1 if an attempt is
+ * made to bind an existing entry, and returns -1 if failures occur.
+ */
+ int trybind (const EXT_ID &ext_id,
+ INT_ID &int_id);
+
+ /**
+ * Same as a normal trybind, except the map entry is also passed
+ * back to the caller. The entry in this case will either be the
+ * newly created entry, or the existing one.
+ */
+ int trybind (const EXT_ID &ext_id,
+ INT_ID &int_id,
+ ACE_Hash_Map_Entry<EXT_ID, INT_ID> *&entry);
+
+ /**
+ * Reassociate <ext_id> with <int_id>. If <ext_id> is not in the
+ * map then behaves just like <bind>. Returns 0 if a new entry is
+ * bound successfully, returns 1 if an existing entry was rebound,
+ * and returns -1 if failures occur.
+ */
+ int rebind (const EXT_ID &ext_id,
+ const INT_ID &int_id);
+
+ /**
+ * Same as a normal rebind, except the map entry is also passed back
+ * to the caller. The entry in this case will either be the newly
+ * created entry, or the existing one.
+ */
+ int rebind (const EXT_ID &ext_id,
+ const INT_ID &int_id,
+ ACE_Hash_Map_Entry<EXT_ID, INT_ID> *&entry);
+
+ /**
+ * Associate <ext_id> with <int_id>. If <ext_id> is not in the map
+ * then behaves just like <bind>. Otherwise, store the old value of
+ * <int_id> into the "out" parameter and rebind the new parameters.
+ * Returns 0 if a new entry is bound successfully, returns 1 if an
+ * existing entry was rebound, and returns -1 if failures occur.
+ */
+ int rebind (const EXT_ID &ext_id,
+ const INT_ID &int_id,
+ INT_ID &old_int_id);
+
+ /**
+ * Same as a normal rebind, except the map entry is also passed back
+ * to the caller. The entry in this case will either be the newly
+ * created entry, or the existing one.
+ */
+ int rebind (const EXT_ID &ext_id,
+ const INT_ID &int_id,
+ INT_ID &old_int_id,
+ ACE_Hash_Map_Entry<EXT_ID, INT_ID> *&entry);
+
+ /**
+ * Associate <ext_id> with <int_id>. If <ext_id> is not in the map
+ * then behaves just like <bind>. Otherwise, store the old values
+ * of <ext_id> and <int_id> into the "out" parameters and rebind the
+ * new parameters. This is very useful if you need to have an
+ * atomic way of updating <ACE_Hash_Map_Entrys> and you also need
+ * full control over memory allocation. Returns 0 if a new entry is
+ * bound successfully, returns 1 if an existing entry was rebound,
+ * and returns -1 if failures occur.
+ */
+ int rebind (const EXT_ID &ext_id,
+ const INT_ID &int_id,
+ EXT_ID &old_ext_id,
+ INT_ID &old_int_id);
+
+ /**
+ * Same as a normal rebind, except the map entry is also passed back
+ * to the caller. The entry in this case will either be the newly
+ * created entry, or the existing one.
+ */
+ int rebind (const EXT_ID &ext_id,
+ const INT_ID &int_id,
+ EXT_ID &old_ext_id,
+ INT_ID &old_int_id,
+ ACE_Hash_Map_Entry<EXT_ID, INT_ID> *&entry);
+
+ /// Locate <ext_id> and pass out parameter via <int_id>.
+ /// Return 0 if found, returns -1 if not found.
+ int find (const EXT_ID &ext_id,
+ INT_ID &int_id) const;
+
+ /// Returns 0 if the <ext_id> is in the mapping, otherwise -1.
+ int find (const EXT_ID &ext_id) const;
+
+ /// Locate <ext_id> and pass out parameter via <entry>. If found,
+ /// return 0, returns -1 if not found.
+ int find (const EXT_ID &ext_id,
+ ACE_Hash_Map_Entry<EXT_ID, INT_ID> *&entry) const;
+
+ /**
+ * Unbind (remove) the <ext_id> from the map. Don't return the
+ * <int_id> to the caller (this is useful for collections where the
+ * <int_id>s are *not* dynamically allocated...)
+ */
+ int unbind (const EXT_ID &ext_id);
+
+ /// Break any association of <ext_id>. Returns the value of <int_id>
+ /// in case the caller needs to deallocate memory. Return 0 if the
+ /// unbind was successfully, and returns -1 if failures occur.
+ int unbind (const EXT_ID &ext_id,
+ INT_ID &int_id);
+
+ /// Remove entry from map. Return 0 if the unbind was successfully,
+ /// and returns -1 if failures occur.
+ int unbind (ACE_Hash_Map_Entry<EXT_ID, INT_ID> *entry);
+
+ /// Return the current size of the map.
+ size_t current_size (void) const;
+
+ /// Return the total size of the map.
+ size_t total_size (void) const;
+
+ /**
+ * Returns a reference to the underlying <ACE_LOCK>. This makes it
+ * possible to acquire the lock explicitly, which can be useful in
+ * some cases if you instantiate the <ACE_Atomic_Op> with an
+ * <ACE_Recursive_Mutex> or <ACE_Process_Mutex>, or if you need to
+ * guard the state of an iterator. NOTE: the right name would be
+ * <lock>, but HP/C++ will choke on that!
+ */
+ ACE_LOCK &mutex (void);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ // = STL styled iterator factory functions.
+
+ /// Return forward iterator.
+ ACE_Hash_Map_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK> begin (void);
+ ACE_Hash_Map_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK> end (void);
+
+ /// Return reverse iterator.
+ ACE_Hash_Map_Reverse_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK> rbegin (void);
+ ACE_Hash_Map_Reverse_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK> rend (void);
+
+protected:
+ // = The following methods do the actual work.
+
+ /// Returns 1 if <id1> == <id2>, else 0. This is defined as a
+ /// separate method to facilitate template specialization.
+ int equal (const EXT_ID &id1, const EXT_ID &id2);
+
+ /// Compute the hash value of the <ext_id>. This is defined as a
+ /// separate method to facilitate template specialization.
+ u_long hash (const EXT_ID &ext_id);
+
+ // = These methods assume locks are held by private methods.
+
+ /// Performs bind. Must be called with locks held.
+ int bind_i (const EXT_ID &ext_id,
+ const INT_ID &int_id);
+
+ /// Performs bind. Must be called with locks held.
+ int bind_i (const EXT_ID &ext_id,
+ const INT_ID &int_id,
+ ACE_Hash_Map_Entry<EXT_ID, INT_ID> *&entry);
+
+ /// Performs trybind. Must be called with locks held.
+ int trybind_i (const EXT_ID &ext_id,
+ INT_ID &int_id);
+
+ /// Performs trybind. Must be called with locks held.
+ int trybind_i (const EXT_ID &ext_id,
+ INT_ID &int_id,
+ ACE_Hash_Map_Entry<EXT_ID, INT_ID> *&entry);
+
+ /// Performs rebind. Must be called with locks held.
+ int rebind_i (const EXT_ID &ext_id,
+ const INT_ID &int_id);
+
+ /// Performs rebind. Must be called with locks held.
+ int rebind_i (const EXT_ID &ext_id,
+ const INT_ID &int_id,
+ ACE_Hash_Map_Entry<EXT_ID, INT_ID> *&entry);
+
+ /// Performs rebind. Must be called with locks held.
+ int rebind_i (const EXT_ID &ext_id,
+ const INT_ID &int_id,
+ INT_ID &old_int_id);
+
+ /// Performs rebind. Must be called with locks held.
+ int rebind_i (const EXT_ID &ext_id,
+ const INT_ID &int_id,
+ INT_ID &old_int_id,
+ ACE_Hash_Map_Entry<EXT_ID, INT_ID> *&entry);
+
+ /// Performs rebind. Must be called with locks held.
+ int rebind_i (const EXT_ID &ext_id,
+ const INT_ID &int_id,
+ EXT_ID &old_ext_id,
+ INT_ID &old_int_id);
+
+ /// Performs rebind. Must be called with locks held.
+ int rebind_i (const EXT_ID &ext_id,
+ const INT_ID &int_id,
+ EXT_ID &old_ext_id,
+ INT_ID &old_int_id,
+ ACE_Hash_Map_Entry<EXT_ID, INT_ID> *&entry);
+
+ /// Performs a find of <int_id> using <ext_id> as the key. Must be
+ /// called with locks held.
+ int find_i (const EXT_ID &ext_id,
+ INT_ID &int_id);
+
+ /// Performs a find using <ext_id> as the key. Must be called with
+ /// locks held.
+ int find_i (const EXT_ID &ext_id);
+
+ /// Performs a find using <ext_id> as the key. Must be called with
+ /// locks held.
+ int find_i (const EXT_ID &ext_id,
+ ACE_Hash_Map_Entry<EXT_ID, INT_ID> *&entry);
+
+ /// Performs unbind. Must be called with locks held.
+ int unbind_i (const EXT_ID &ext_id,
+ INT_ID &int_id);
+
+ /// Performs unbind. Must be called with locks held.
+ int unbind_i (const EXT_ID &ext_id);
+
+ /// Performs unbind. Must be called with locks held.
+ int unbind_i (ACE_Hash_Map_Entry<EXT_ID, INT_ID> *entry);
+
+ /**
+ * Resize the map. Must be called with locks held. Note, that this
+ * method should never be called more than once or else all the
+ * hashing will get screwed up as the size will change.
+ */
+ int create_buckets (size_t size);
+
+ /// Close down a <Map_Manager_Ex>. Must be called with
+ /// locks held.
+ int close_i (void);
+
+ /// Removes all the entries in <Map_Manager_Ex>. Must be called with
+ /// locks held.
+ int unbind_all_i (void);
+
+ /// Pointer to a memory allocator.
+ ACE_Allocator *allocator_;
+
+ /// Synchronization variable for the MT_SAFE <ACE_Hash_Map_Manager_Ex>.
+ ACE_LOCK lock_;
+
+ /// Function object used for hashing keys.
+ HASH_KEY hash_key_;
+
+ /// Function object used for comparing keys.
+ COMPARE_KEYS compare_keys_;
+
+private:
+ /// Returns the <ACE_Hash_Map_Entry> that corresponds to <ext_id>.
+ int shared_find (const EXT_ID &ext_id,
+ ACE_Hash_Map_Entry<EXT_ID, INT_ID> *&entry,
+ u_long &loc);
+
+ /**
+ * Array of <ACE_Hash_Map_Entry> *s, each of which points to an
+ * <ACE_Hash_Map_Entry> that serves as the beginning of a linked
+ * list of <EXT_ID>s that hash to that bucket.
+ */
+ ACE_Hash_Map_Entry<EXT_ID, INT_ID> *table_;
+
+ /// Total size of the hash table.
+ size_t total_size_;
+
+ /// Current number of entries in the table (note that this can be
+ /// larger than <total_size_> due to the bucket chaining).
+ size_t cur_size_;
+
+ // = Disallow these operations.
+ ACE_UNIMPLEMENTED_FUNC (void operator= (const ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK> &))
+ ACE_UNIMPLEMENTED_FUNC (ACE_Hash_Map_Manager_Ex (const ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK> &))
+};
+
+/**
+ * @class ACE_Hash_Map_Iterator_Base_Ex
+ *
+ * @brief Base iterator for the <ACE_Hash_Map_Manager_Ex>
+ *
+ * This class factors out common code from its templatized
+ * subclasses.
+ */
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK>
+class ACE_Hash_Map_Iterator_Base_Ex
+{
+public:
+ // = Initialization method.
+ /// Contructor. If head != 0, the iterator constructed is positioned
+ /// at the head of the map, it is positioned at the end otherwise.
+ ACE_Hash_Map_Iterator_Base_Ex (ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK> &mm,
+ int head);
+
+ // = ITERATION methods.
+
+ /// Pass back the next <entry> that hasn't been seen in the Set.
+ /// Returns 0 when all items have been seen, else 1.
+ int next (ACE_Hash_Map_Entry<EXT_ID, INT_ID> *&next_entry) const;
+
+ /// Returns 1 when all items have been seen, else 0.
+ int done (void) const;
+
+ /// Returns a reference to the interal element <this> is pointing to.
+ ACE_Hash_Map_Entry<EXT_ID, INT_ID>& operator* (void) const;
+
+ /// Returns reference the Hash_Map_Manager_Ex that is being iterated
+ /// over.
+ ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>& map (void);
+
+ /// Check if two iterators point to the same position
+ int operator== (const ACE_Hash_Map_Iterator_Base_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK> &) const;
+ int operator!= (const ACE_Hash_Map_Iterator_Base_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK> &) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+protected:
+ /// Move forward by one element in the set. Returns 0 when there's
+ /// no more item in the set after the current items, else 1.
+ int forward_i (void);
+
+ /// Move backward by one element in the set. Returns 0 when there's
+ /// no more item in the set before the current item, else 1.
+ int reverse_i (void);
+
+ /// Dump the state of an object.
+ void dump_i (void) const;
+
+ /// Map we are iterating over.
+ ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK> *map_man_;
+
+ /// Keeps track of how far we've advanced in the table.
+ ssize_t index_;
+
+ /// Keeps track of how far we've advanced in a linked list in each
+ /// table slot.
+ ACE_Hash_Map_Entry<EXT_ID, INT_ID> *next_;
+};
+
+/**
+ * @class ACE_Hash_Map_Const_Iterator_Base_Ex
+ *
+ * @brief Base const iterator for the <ACE_Hash_Map_Manager_Ex>
+ *
+ * This class factors out common code from its templatized
+ * subclasses.
+ */
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK>
+class ACE_Hash_Map_Const_Iterator_Base_Ex
+{
+public:
+ // = Initialization method.
+ /// Contructor. If head != 0, the iterator constructed is positioned
+ /// at the head of the map, it is positioned at the end otherwise.
+ ACE_Hash_Map_Const_Iterator_Base_Ex (const ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK> &mm,
+ int head);
+
+ // = ITERATION methods.
+
+ /// Pass back the next <entry> that hasn't been seen in the Set.
+ /// Returns 0 when all items have been seen, else 1.
+ int next (ACE_Hash_Map_Entry<EXT_ID, INT_ID> *&next_entry) const;
+
+ /// Returns 1 when all items have been seen, else 0.
+ int done (void) const;
+
+ /// Returns a reference to the interal element <this> is pointing to.
+ ACE_Hash_Map_Entry<EXT_ID, INT_ID>& operator* (void) const;
+
+ /// Returns reference the Hash_Map_Manager_Ex that is being iterated
+ /// over.
+ const ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>& map (void);
+
+ /// Check if two iterators point to the same position
+ int operator== (const ACE_Hash_Map_Const_Iterator_Base_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK> &) const;
+ int operator!= (const ACE_Hash_Map_Const_Iterator_Base_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK> &) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+protected:
+ /// Move forward by one element in the set. Returns 0 when there's
+ /// no more item in the set after the current items, else 1.
+ int forward_i (void);
+
+ /// Move backward by one element in the set. Returns 0 when there's
+ /// no more item in the set before the current item, else 1.
+ int reverse_i (void);
+
+ /// Dump the state of an object.
+ void dump_i (void) const;
+
+ /// Map we are iterating over.
+ const ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK> *map_man_;
+
+ /// Keeps track of how far we've advanced in the table.
+ ssize_t index_;
+
+ /// Keeps track of how far we've advanced in a linked list in each
+ /// table slot.
+ ACE_Hash_Map_Entry<EXT_ID, INT_ID> *next_;
+};
+
+/**
+ * @class ACE_Hash_Map_Iterator_Ex
+ *
+ * @brief Forward iterator for the <ACE_Hash_Map_Manager_Ex>.
+ *
+ * This class does not perform any internal locking of the
+ * <ACE_Hash_Map_Manager_Ex> it is iterating upon since locking is
+ * inherently inefficient and/or error-prone within an STL-style
+ * iterator. If you require locking, you can explicitly use an
+ * <ACE_Guard> or <ACE_Read_Guard> on the <ACE_Hash_Map_Manager_Ex>'s
+ * internal lock, which is accessible via its <mutex> method.
+ */
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK>
+class ACE_Hash_Map_Iterator_Ex : public ACE_Hash_Map_Iterator_Base_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>
+{
+public:
+ // = Initialization method.
+ ACE_Hash_Map_Iterator_Ex (ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK> &mm,
+ int tail = 0);
+
+ // = Iteration methods.
+ /// Move forward by one element in the set. Returns 0 when all the
+ /// items in the set have been seen, else 1.
+ int advance (void);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ // = STL styled iteration, compare, and reference functions.
+
+ /// Prefix advance.
+ ACE_Hash_Map_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK> &operator++ (void);
+
+ /// Postfix advance.
+ ACE_Hash_Map_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK> operator++ (int);
+
+ /// Prefix reverse.
+ ACE_Hash_Map_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK> &operator-- (void);
+
+ /// Postfix reverse.
+ ACE_Hash_Map_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK> operator-- (int);
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+};
+
+/**
+ * @class ACE_Hash_Map_Const_Iterator_Ex
+ *
+ * @brief Const forward iterator for the <ACE_Hash_Map_Manager_Ex>.
+ *
+ * This class does not perform any internal locking of the
+ * <ACE_Hash_Map_Manager_Ex> it is iterating upon since locking is
+ * inherently inefficient and/or error-prone within an STL-style
+ * iterator. If you require locking, you can explicitly use an
+ * <ACE_Guard> or <ACE_Read_Guard> on the <ACE_Hash_Map_Manager_Ex>'s
+ * internal lock, which is accessible via its <mutex> method.
+ */
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK>
+class ACE_Hash_Map_Const_Iterator_Ex : public ACE_Hash_Map_Const_Iterator_Base_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>
+{
+public:
+ // = Initialization method.
+ ACE_Hash_Map_Const_Iterator_Ex (const ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK> &mm,
+ int tail = 0);
+
+ // = Iteration methods.
+ /// Move forward by one element in the set. Returns 0 when all the
+ /// items in the set have been seen, else 1.
+ int advance (void);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ // = STL styled iteration, compare, and reference functions.
+
+ /// Prefix advance.
+ ACE_Hash_Map_Const_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK> &operator++ (void);
+
+ /// Postfix advance.
+ ACE_Hash_Map_Const_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK> operator++ (int);
+
+ /// Prefix reverse.
+ ACE_Hash_Map_Const_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK> &operator-- (void);
+
+ /// Postfix reverse.
+ ACE_Hash_Map_Const_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK> operator-- (int);
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+};
+
+/**
+ * @class ACE_Hash_Map_Bucket_Iterator
+ *
+ * @brief Forward iterator for the <ACE_Hash_Map_Manager_Ex> which only
+ * traverses a particular bucket. The particular bucket is
+ * specified by the <EXT_ID> parameter specified in the
+ * constructor.
+ *
+ * This class does not perform any internal locking of the
+ * <ACE_Hash_Map_Manager_Ex> it is iterating upon since locking
+ * is inherently inefficient and/or error-prone within an
+ * STL-style iterator. If you require locking, you can
+ * explicitly use an <ACE_Guard> or <ACE_Read_Guard> on the
+ * <ACE_Hash_Map_Manager_Ex>'s internal lock, which is
+ * accessible via its <mutex> method.
+ * Note that this iterator cannot be created by calling a method
+ * on the map, since this would require
+ */
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK>
+class ACE_Hash_Map_Bucket_Iterator
+{
+public:
+ // = Initialization method.
+ ACE_Hash_Map_Bucket_Iterator (ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK> &mm,
+ const EXT_ID &ext_id,
+ int tail = 0);
+
+ // = STL styled iteration, compare, and reference functions.
+
+ /// Prefix advance.
+ ACE_Hash_Map_Bucket_Iterator<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK> &operator++ (void);
+
+ /// Postfix advance.
+ ACE_Hash_Map_Bucket_Iterator<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK> operator++ (int);
+
+ /// Prefix reverse.
+ ACE_Hash_Map_Bucket_Iterator<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK> &operator-- (void);
+
+ /// Postfix reverse.
+ ACE_Hash_Map_Bucket_Iterator<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK> operator-- (int);
+
+ /// Returns a reference to the interal element <this> is pointing to.
+ ACE_Hash_Map_Entry<EXT_ID, INT_ID>& operator* (void) const;
+
+ /// Returns reference the Hash_Map_Manager_Ex that is being iterated
+ /// over.
+ ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>& map (void);
+
+ /// Check if two iterators point to the same position
+ int operator== (const ACE_Hash_Map_Bucket_Iterator<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK> &) const;
+ int operator!= (const ACE_Hash_Map_Bucket_Iterator<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK> &) const;
+
+protected:
+ /// Move forward by one element in the set. Returns 0 when there's
+ /// no more item in the set after the current items, else 1.
+ int forward_i (void);
+
+ /// Move backward by one element in the set. Returns 0 when there's
+ /// no more item in the set before the current item, else 1.
+ int reverse_i (void);
+
+ /// Map we are iterating over.
+ ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK> *map_man_;
+
+ /// Keeps track of how far we've advanced in the table.
+ ssize_t index_;
+
+ /// Keeps track of how far we've advanced in a linked list in each
+ /// table slot.
+ ACE_Hash_Map_Entry<EXT_ID, INT_ID> *next_;
+};
+
+/**
+ * @class ACE_Hash_Map_Reverse_Iterator_Ex
+ *
+ * @brief Reverse iterator for the <ACE_Hash_Map_Manager_Ex>.
+ *
+ * This class does not perform any internal locking of the
+ * <ACE_Hash_Map_Manager_Ex> it is iterating upon since locking is
+ * inherently inefficient and/or error-prone within an STL-style
+ * iterator. If you require locking, you can explicitly use an
+ * <ACE_Guard> or <ACE_Read_Guard> on the <ACE_Hash_Map_Manager_Ex>'s
+ * internal lock, which is accessible via its <mutex> method.
+ */
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK>
+class ACE_Hash_Map_Reverse_Iterator_Ex : public ACE_Hash_Map_Iterator_Base_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>
+{
+public:
+ // = Initialization method.
+ ACE_Hash_Map_Reverse_Iterator_Ex (ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK> &mm,
+ int head = 0);
+
+ // = Iteration methods.
+ /// Move forward by one element in the set. Returns 0 when all the
+ /// items in the set have been seen, else 1.
+ int advance (void);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ // = STL styled iteration, compare, and reference functions.
+
+ /// Prefix reverse.
+ ACE_Hash_Map_Reverse_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK> &operator++ (void);
+
+ /// Postfix reverse.
+ ACE_Hash_Map_Reverse_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK> operator++ (int);
+
+ /// Prefix advance.
+ ACE_Hash_Map_Reverse_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK> &operator-- (void);
+
+ /// Postfix advance.
+ ACE_Hash_Map_Reverse_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK> operator-- (int);
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+};
+
+/**
+ * @class ACE_Hash_Map_Manager
+ *
+ * @brief Wrapper for backward compatibility.
+ *
+ * This implementation of a map uses a hash table. This class
+ * expects that the <EXT_ID> contains a method called <hash>.
+ * In addition, the <EXT_ID> must support <operator==>. Both of
+ * these constraints can be alleviated via template
+ * specialization, as shown in the $ACE_ROOT/tests/Conn_Test.cpp
+ * test.
+ */
+template <class EXT_ID, class INT_ID, class ACE_LOCK>
+class ACE_Hash_Map_Manager : public ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, ACE_Hash<EXT_ID>, ACE_Equal_To<EXT_ID>, ACE_LOCK>
+{
+public:
+ /// Initialize a <Hash_Map_Manager> with default size.
+ ACE_Hash_Map_Manager (ACE_Allocator *alloc = 0);
+
+ /// Initialize a <Hash_Map_Manager> with size <length>.
+ ACE_Hash_Map_Manager (size_t size,
+ ACE_Allocator *alloc = 0);
+
+ // = The following two are necessary for template specialization of
+ // ACE_Hash_Map_Manager to work.
+ int equal (const EXT_ID &id1, const EXT_ID &id2);
+ u_long hash (const EXT_ID &ext_id);
+};
+
+/**
+ * @class ACE_Hash_Map_Iterator
+ *
+ * @brief Wrapper for backward compatibility.
+ */
+template <class EXT_ID, class INT_ID, class ACE_LOCK>
+class ACE_Hash_Map_Iterator : public ACE_Hash_Map_Iterator_Ex<EXT_ID, INT_ID, ACE_Hash<EXT_ID>, ACE_Equal_To<EXT_ID>, ACE_LOCK>
+{
+public:
+ // = Initialization method.
+ /// Construct from map
+ ACE_Hash_Map_Iterator (ACE_Hash_Map_Manager<EXT_ID, INT_ID, ACE_LOCK> &mm,
+ int tail = 0);
+
+ /// Construct from base
+ ACE_Hash_Map_Iterator (const ACE_Hash_Map_Iterator_Ex<EXT_ID, INT_ID, ACE_Hash<EXT_ID>, ACE_Equal_To<EXT_ID>, ACE_LOCK> &base);
+
+ /// Assignment from base
+ ACE_Hash_Map_Iterator<EXT_ID, INT_ID, ACE_LOCK> &
+ operator= (const ACE_Hash_Map_Iterator_Ex<EXT_ID, INT_ID, ACE_Hash<EXT_ID>, ACE_Equal_To<EXT_ID>, ACE_LOCK> &base);
+};
+
+/**
+ * @class ACE_Hash_Map_Const_Iterator
+ *
+ * @brief Wrapper for backward compatibility.
+ */
+template <class EXT_ID, class INT_ID, class ACE_LOCK>
+class ACE_Hash_Map_Const_Iterator : public ACE_Hash_Map_Const_Iterator_Ex<EXT_ID, INT_ID, ACE_Hash<EXT_ID>, ACE_Equal_To<EXT_ID>, ACE_LOCK>
+{
+public:
+ // = Initialization method.
+ /// Construct from map
+ ACE_Hash_Map_Const_Iterator (const ACE_Hash_Map_Manager<EXT_ID, INT_ID, ACE_LOCK> &mm,
+ int tail = 0);
+
+ /// Construct from base
+ ACE_Hash_Map_Const_Iterator (const ACE_Hash_Map_Const_Iterator_Ex<EXT_ID, INT_ID, ACE_Hash<EXT_ID>, ACE_Equal_To<EXT_ID>, ACE_LOCK> &base);
+
+ /// Assignment from base
+ ACE_Hash_Map_Const_Iterator<EXT_ID, INT_ID, ACE_LOCK> &
+ operator= (const ACE_Hash_Map_Const_Iterator_Ex<EXT_ID, INT_ID, ACE_Hash<EXT_ID>, ACE_Equal_To<EXT_ID>, ACE_LOCK> &base);
+};
+
+/**
+ * @class ACE_Hash_Map_Reverse_Iterator
+ *
+ * @brief Wrapper for backward compatibility.
+ */
+template <class EXT_ID, class INT_ID, class ACE_LOCK>
+class ACE_Hash_Map_Reverse_Iterator : public ACE_Hash_Map_Reverse_Iterator_Ex<EXT_ID, INT_ID, ACE_Hash<EXT_ID>, ACE_Equal_To<EXT_ID>, ACE_LOCK>
+{
+public:
+ // = Initialization method.
+ ACE_Hash_Map_Reverse_Iterator (ACE_Hash_Map_Manager<EXT_ID, INT_ID, ACE_LOCK> &mm,
+ int head = 0);
+
+ /// Construct from base
+ ACE_Hash_Map_Reverse_Iterator (const ACE_Hash_Map_Reverse_Iterator_Ex<EXT_ID, INT_ID, ACE_Hash<EXT_ID>, ACE_Equal_To<EXT_ID>, ACE_LOCK> &base);
+
+ /// Assignment from base
+ ACE_Hash_Map_Reverse_Iterator<EXT_ID, INT_ID, ACE_LOCK> &
+ operator= (const ACE_Hash_Map_Reverse_Iterator_Ex<EXT_ID, INT_ID, ACE_Hash<EXT_ID>, ACE_Equal_To<EXT_ID>, ACE_LOCK> &base);
+};
+
+#if defined (__ACE_INLINE__)
+// Include ace/Hash_Map_Manager_T.i on all platforms excluding SunCC.
+// This nonsense is necessary since SunCC (version 4.2) cannot inline
+// the code in ace/Hash_Map_Manager_T.i (with the fast option).
+# if !(defined (__SUNPRO_CC) && (__SUNPRO_CC == 0x420))
+# include "ace/Hash_Map_Manager_T.i"
+# endif /* ! __SUNPRO_CC */
+#endif /* __ACE_INLINE__ */
+
+#if defined (ACE_TEMPLATES_REQUIRE_SOURCE)
+#include "ace/Hash_Map_Manager_T.cpp"
+#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */
+
+#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA)
+#pragma implementation ("Hash_Map_Manager_T.cpp")
+#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */
+
+#include "ace/post.h"
+#endif /* ACE_HASH_MAP_MANAGER_T_H */
diff --git a/ace/Utils/Templates/Hash_Map_Manager_T.i b/ace/Utils/Templates/Hash_Map_Manager_T.i
new file mode 100644
index 00000000000..d57997a72bf
--- /dev/null
+++ b/ace/Utils/Templates/Hash_Map_Manager_T.i
@@ -0,0 +1,960 @@
+// $Id$
+
+#include "ace/Synch.h"
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> ACE_INLINE
+ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::ACE_Hash_Map_Manager_Ex (size_t size,
+ ACE_Allocator *alloc)
+ : allocator_ (alloc),
+ table_ (0),
+ total_size_ (0),
+ cur_size_ (0)
+{
+ if (this->open (size, alloc) == -1)
+ ACE_ERROR ((LM_ERROR, ACE_LIB_TEXT ("ACE_Hash_Map_Manager_Ex\n")));
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> ACE_INLINE
+ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::ACE_Hash_Map_Manager_Ex (ACE_Allocator *alloc)
+ : allocator_ (alloc),
+ table_ (0),
+ total_size_ (0),
+ cur_size_ (0)
+{
+ if (this->open (ACE_DEFAULT_MAP_SIZE, alloc) == -1)
+ ACE_ERROR ((LM_ERROR, ACE_LIB_TEXT ("ACE_Hash_Map_Manager_Ex\n")));
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> ACE_INLINE int
+ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::close (void)
+{
+ ACE_WRITE_GUARD_RETURN (ACE_LOCK, ace_mon, this->lock_, -1);
+
+ return this->close_i ();
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> ACE_INLINE int
+ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::unbind_all (void)
+{
+ ACE_WRITE_GUARD_RETURN (ACE_LOCK, ace_mon, this->lock_, -1);
+
+ return this->unbind_all_i ();
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> ACE_INLINE
+ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::~ACE_Hash_Map_Manager_Ex (void)
+{
+ this->close ();
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> ACE_INLINE size_t
+ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::current_size (void) const
+{
+ return this->cur_size_;
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> ACE_INLINE size_t
+ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::total_size (void) const
+{
+ return this->total_size_;
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> ACE_INLINE ACE_LOCK &
+ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::mutex (void)
+{
+ ACE_TRACE ("ACE_Hash_Map_Manager_Ex::mutex");
+ return this->lock_;
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> ACE_INLINE u_long
+ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::hash (const EXT_ID &ext_id)
+{
+ return this->hash_key_ (ext_id);
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> ACE_INLINE int
+ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::equal (const EXT_ID &id1,
+ const EXT_ID &id2)
+{
+ return this->compare_keys_ (id1, id2);
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> ACE_INLINE int
+ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::bind_i (const EXT_ID &ext_id,
+ const INT_ID &int_id)
+{
+ ACE_Hash_Map_Entry<EXT_ID, INT_ID> *temp;
+
+ return this->bind_i (ext_id, int_id, temp);
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> ACE_INLINE int
+ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::bind (const EXT_ID &ext_id,
+ const INT_ID &int_id)
+{
+ ACE_WRITE_GUARD_RETURN (ACE_LOCK, ace_mon, this->lock_, -1);
+
+ return this->bind_i (ext_id, int_id);
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> ACE_INLINE int
+ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::bind (const EXT_ID &ext_id,
+ const INT_ID &int_id,
+ ACE_Hash_Map_Entry<EXT_ID, INT_ID> *&entry)
+{
+ ACE_WRITE_GUARD_RETURN (ACE_LOCK, ace_mon, this->lock_, -1);
+
+ return this->bind_i (ext_id, int_id, entry);
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> ACE_INLINE int
+ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::trybind_i (const EXT_ID &ext_id,
+ INT_ID &int_id)
+{
+ ACE_Hash_Map_Entry<EXT_ID, INT_ID> *temp;
+
+ int result = this->trybind_i (ext_id, int_id, temp);
+ if (result == 1)
+ int_id = temp->int_id_;
+ return result;
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> ACE_INLINE int
+ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::trybind (const EXT_ID &ext_id,
+ INT_ID &int_id)
+{
+ ACE_WRITE_GUARD_RETURN (ACE_LOCK, ace_mon, this->lock_, -1);
+
+ return this->trybind_i (ext_id, int_id);
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> ACE_INLINE int
+ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::trybind (const EXT_ID &ext_id,
+ INT_ID &int_id,
+ ACE_Hash_Map_Entry<EXT_ID, INT_ID> *&entry)
+{
+ ACE_WRITE_GUARD_RETURN (ACE_LOCK, ace_mon, this->lock_, -1);
+
+ return this->trybind_i (ext_id, int_id, entry);
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> ACE_INLINE int
+ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::unbind_i (const EXT_ID &ext_id)
+{
+ INT_ID int_id;
+
+ return this->unbind_i (ext_id, int_id);
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> ACE_INLINE int
+ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::unbind (const EXT_ID &ext_id,
+ INT_ID &int_id)
+{
+ ACE_WRITE_GUARD_RETURN (ACE_LOCK, ace_mon, this->lock_, -1);
+
+ return this->unbind_i (ext_id, int_id);
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> ACE_INLINE int
+ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::unbind (const EXT_ID &ext_id)
+{
+ ACE_WRITE_GUARD_RETURN (ACE_LOCK, ace_mon, this->lock_, -1);
+
+ return this->unbind_i (ext_id) == -1 ? -1 : 0;
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> ACE_INLINE int
+ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::unbind (ACE_Hash_Map_Entry<EXT_ID, INT_ID> *entry)
+{
+ ACE_WRITE_GUARD_RETURN (ACE_LOCK, ace_mon, this->lock_, -1);
+
+ return this->unbind_i (entry) == -1 ? -1 : 0;
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> ACE_INLINE int
+ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::find_i (const EXT_ID &ext_id,
+ INT_ID &int_id)
+{
+ ACE_Hash_Map_Entry<EXT_ID, INT_ID> *entry;
+
+ u_long dummy;
+ if (this->shared_find (ext_id, entry, dummy) == -1)
+ return -1;
+ else
+ {
+ int_id = entry->int_id_;
+ return 0;
+ }
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> ACE_INLINE int
+ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::find_i (const EXT_ID &ext_id)
+{
+ ACE_Hash_Map_Entry<EXT_ID, INT_ID> *entry;
+
+ u_long dummy;
+ return this->shared_find (ext_id, entry, dummy);
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> ACE_INLINE int
+ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::find (const EXT_ID &ext_id,
+ INT_ID &int_id) const
+{
+ ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK> *nc_this =
+ (ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK> *)
+ this;
+
+ ACE_READ_GUARD_RETURN (ACE_LOCK, ace_mon, nc_this->lock_, -1);
+
+ return nc_this->find_i (ext_id, int_id);
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> ACE_INLINE int
+ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::find (const EXT_ID &ext_id) const
+{
+ ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK> *nc_this =
+ (ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK> *)
+ this;
+ ACE_READ_GUARD_RETURN (ACE_LOCK, ace_mon, nc_this->lock_, -1);
+
+ return nc_this->find_i (ext_id);
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> ACE_INLINE int
+ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::find_i (const EXT_ID &ext_id,
+ ACE_Hash_Map_Entry<EXT_ID, INT_ID> *&entry)
+{
+ u_long dummy;
+ return this->shared_find (ext_id, entry, dummy);
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> ACE_INLINE int
+ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::find (const EXT_ID &ext_id,
+ ACE_Hash_Map_Entry<EXT_ID, INT_ID> *&entry) const
+{
+ ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK> *nc_this =
+ (ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK> *)
+ this;
+
+ ACE_READ_GUARD_RETURN (ACE_LOCK, ace_mon, nc_this->lock_, -1);
+
+ return nc_this->find_i (ext_id, entry);
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> ACE_INLINE int
+ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::rebind_i (const EXT_ID &ext_id,
+ const INT_ID &int_id)
+{
+ ACE_Hash_Map_Entry<EXT_ID, INT_ID> *node;
+
+ return this->rebind_i (ext_id,
+ int_id,
+ node);
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> ACE_INLINE int
+ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::rebind_i (const EXT_ID &ext_id,
+ const INT_ID &int_id,
+ INT_ID &old_int_id)
+{
+ ACE_Hash_Map_Entry<EXT_ID, INT_ID> *node;
+
+ return this->rebind_i (ext_id,
+ int_id,
+ old_int_id,
+ node);
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> ACE_INLINE int
+ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::rebind_i (const EXT_ID &ext_id,
+ const INT_ID &int_id,
+ EXT_ID &old_ext_id,
+ INT_ID &old_int_id)
+{
+ ACE_Hash_Map_Entry<EXT_ID, INT_ID> *node;
+
+ return this->rebind_i (ext_id,
+ int_id,
+ old_ext_id,
+ old_int_id,
+ node);
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> ACE_INLINE int
+ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::rebind (const EXT_ID &ext_id,
+ const INT_ID &int_id)
+{
+ ACE_WRITE_GUARD_RETURN (ACE_LOCK, ace_mon, this->lock_, -1);
+
+ return this->rebind_i (ext_id, int_id);
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> ACE_INLINE int
+ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::rebind (const EXT_ID &ext_id,
+ const INT_ID &int_id,
+ ACE_Hash_Map_Entry<EXT_ID, INT_ID> *&entry)
+{
+ ACE_WRITE_GUARD_RETURN (ACE_LOCK, ace_mon, this->lock_, -1);
+
+ return this->rebind_i (ext_id, int_id, entry);
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> ACE_INLINE int
+ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::rebind (const EXT_ID &ext_id,
+ const INT_ID &int_id,
+ INT_ID &old_int_id)
+{
+ ACE_WRITE_GUARD_RETURN (ACE_LOCK, ace_mon, this->lock_, -1);
+
+ return this->rebind_i (ext_id, int_id, old_int_id);
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> ACE_INLINE int
+ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::rebind (const EXT_ID &ext_id,
+ const INT_ID &int_id,
+ INT_ID &old_int_id,
+ ACE_Hash_Map_Entry<EXT_ID, INT_ID> *&entry)
+{
+ ACE_WRITE_GUARD_RETURN (ACE_LOCK, ace_mon, this->lock_, -1);
+
+ return this->rebind_i (ext_id, int_id, old_int_id, entry);
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> ACE_INLINE int
+ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::rebind (const EXT_ID &ext_id,
+ const INT_ID &int_id,
+ EXT_ID &old_ext_id,
+ INT_ID &old_int_id)
+{
+ ACE_WRITE_GUARD_RETURN (ACE_LOCK, ace_mon, this->lock_, -1);
+
+ return this->rebind_i (ext_id, int_id, old_ext_id, old_int_id);
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> ACE_INLINE int
+ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::rebind (const EXT_ID &ext_id,
+ const INT_ID &int_id,
+ EXT_ID &old_ext_id,
+ INT_ID &old_int_id,
+ ACE_Hash_Map_Entry<EXT_ID, INT_ID> *&entry)
+{
+ ACE_WRITE_GUARD_RETURN (ACE_LOCK, ace_mon, this->lock_, -1);
+
+ return this->rebind_i (ext_id, int_id, old_ext_id, old_int_id, entry);
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> ACE_INLINE
+ACE_Hash_Map_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>
+ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::begin (void)
+{
+ return ACE_Hash_Map_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK> (*this);
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> ACE_INLINE
+ACE_Hash_Map_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>
+ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::end (void)
+{
+ return ACE_Hash_Map_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK> (*this, 1);
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> ACE_INLINE
+ACE_Hash_Map_Reverse_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>
+ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::rbegin (void)
+{
+ return ACE_Hash_Map_Reverse_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK> (*this);
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> ACE_INLINE
+ACE_Hash_Map_Reverse_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>
+ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::rend (void)
+{
+ return ACE_Hash_Map_Reverse_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK> (*this, 1);
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> ACE_INLINE
+ACE_Hash_Map_Iterator_Base_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::ACE_Hash_Map_Iterator_Base_Ex (ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK> &mm,
+ int head)
+ : map_man_ (&mm),
+ index_ (head != 0 ? -1 : (ssize_t) mm.total_size_),
+ next_ (0)
+{
+ ACE_TRACE ("ACE_Hash_Map_Iterator_Base_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::ACE_Hash_Map_Iterator_Base_Ex");
+
+ if (mm.table_ != 0)
+ this->next_ = &mm.table_[head != 0 ? 0 : mm.total_size_ - 1];
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> ACE_INLINE int
+ACE_Hash_Map_Iterator_Base_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::next (ACE_Hash_Map_Entry<EXT_ID, INT_ID> *&entry) const
+{
+ ACE_TRACE ("ACE_Hash_Map_Iterator_Base_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::next");
+
+ if (this->map_man_->table_ != 0
+ && this->index_ < ACE_static_cast (ssize_t, this->map_man_->total_size_)
+ && this->index_ >= 0
+ && this->next_ != &this->map_man_->table_[this->index_])
+ {
+ entry = this->next_;
+ return 1;
+ }
+ else
+ return 0;
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> ACE_INLINE int
+ACE_Hash_Map_Iterator_Base_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::done (void) const
+{
+ ACE_TRACE ("ACE_Hash_Map_Iterator_Base_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::done");
+
+ return this->map_man_->table_ == 0
+ || this->index_ >= ACE_static_cast (ssize_t, this->map_man_->total_size_)
+ || this->index_ < 0;
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> ACE_INLINE
+ACE_Hash_Map_Entry<EXT_ID, INT_ID> &
+ACE_Hash_Map_Iterator_Base_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::operator* (void) const
+{
+ ACE_TRACE ("ACE_Hash_Map_Iterator_Base_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::operator*");
+ ACE_Hash_Map_Entry<EXT_ID, INT_ID> *retv = 0;
+
+ int result = this->next (retv);
+
+ ACE_UNUSED_ARG (result);
+ ACE_ASSERT (result != 0);
+
+ return *retv;
+}
+
+// Returns the reference to the hash_map_manager_ex that is being
+// iterated over.
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> ACE_INLINE
+ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>&
+ACE_Hash_Map_Iterator_Base_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::map (void)
+{
+ ACE_TRACE ("ACE_Hash_Map_Iterator_Base_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::map");
+ return *this->map_man_;
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> ACE_INLINE int
+ACE_Hash_Map_Iterator_Base_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::operator== (const ACE_Hash_Map_Iterator_Base_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK> &rhs) const
+{
+ ACE_TRACE ("ACE_Hash_Map_Iterator_Base_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::operator==");
+ return this->map_man_ == rhs.map_man_
+ && this->index_ == rhs.index_
+ && this->next_ == rhs.next_;
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> ACE_INLINE int
+ACE_Hash_Map_Iterator_Base_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::operator!= (const ACE_Hash_Map_Iterator_Base_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK> &rhs) const
+{
+ ACE_TRACE ("ACE_Hash_Map_Iterator_Base_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::operator!=");
+ return this->next_ != rhs.next_
+ || this->index_ != rhs.index_
+ || this->map_man_ != rhs.map_man_;
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> ACE_INLINE
+ACE_Hash_Map_Const_Iterator_Base_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::ACE_Hash_Map_Const_Iterator_Base_Ex (const ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK> &mm,
+ int head)
+ : map_man_ (&mm),
+ index_ (head != 0 ? -1 : (ssize_t) mm.total_size_),
+ next_ (0)
+{
+ ACE_TRACE ("ACE_Hash_Map_Const_Iterator_Base_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::ACE_Hash_Map_Const_Iterator_Base_Ex");
+
+ if (mm.table_ != 0)
+ this->next_ = &mm.table_[head != 0 ? 0 : mm.total_size_ - 1];
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> ACE_INLINE int
+ACE_Hash_Map_Const_Iterator_Base_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::next (ACE_Hash_Map_Entry<EXT_ID, INT_ID> *&entry) const
+{
+ ACE_TRACE ("ACE_Hash_Map_Const_Iterator_Base_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::next");
+
+ if (this->map_man_->table_ != 0
+ && this->index_ < (ssize_t) this->map_man_->total_size_
+ && this->index_ >= 0
+ && this->next_ != &this->map_man_->table_[this->index_])
+ {
+ entry = this->next_;
+ return 1;
+ }
+ else
+ return 0;
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> ACE_INLINE int
+ACE_Hash_Map_Const_Iterator_Base_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::done (void) const
+{
+ ACE_TRACE ("ACE_Hash_Map_Const_Iterator_Base_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::done");
+
+ return this->map_man_->table_ == 0
+ || this->index_ >= (ssize_t) this->map_man_->total_size_
+ || this->index_ < 0;
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> ACE_INLINE
+ACE_Hash_Map_Entry<EXT_ID, INT_ID> &
+ACE_Hash_Map_Const_Iterator_Base_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::operator* (void) const
+{
+ ACE_TRACE ("ACE_Hash_Map_Const_Iterator_Base_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::operator*");
+ ACE_Hash_Map_Entry<EXT_ID, INT_ID> *retv = 0;
+
+ int result = this->next (retv);
+
+ ACE_UNUSED_ARG (result);
+ ACE_ASSERT (result != 0);
+
+ return *retv;
+}
+
+// Returns the reference to the hash_map_manager_ex that is being
+// iterated over.
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> ACE_INLINE
+const ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>&
+ACE_Hash_Map_Const_Iterator_Base_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::map (void)
+{
+ ACE_TRACE ("ACE_Hash_Map_Const_Iterator_Base_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::map");
+ return *this->map_man_;
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> ACE_INLINE int
+ACE_Hash_Map_Const_Iterator_Base_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::operator== (const ACE_Hash_Map_Const_Iterator_Base_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK> &rhs) const
+{
+ ACE_TRACE ("ACE_Hash_Map_Const_Iterator_Base_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::operator==");
+ return this->map_man_ == rhs.map_man_
+ && this->index_ == rhs.index_
+ && this->next_ == rhs.next_;
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> ACE_INLINE int
+ACE_Hash_Map_Const_Iterator_Base_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::operator!= (const ACE_Hash_Map_Const_Iterator_Base_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK> &rhs) const
+{
+ ACE_TRACE ("ACE_Hash_Map_Const_Iterator_Base_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::operator!=");
+ return this->next_ != rhs.next_
+ || this->index_ != rhs.index_
+ || this->map_man_ != rhs.map_man_;
+}
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Hash_Map_Iterator_Ex)
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> ACE_INLINE void
+ACE_Hash_Map_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::dump (void) const
+{
+ ACE_TRACE ("ACE_Hash_Map_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::dump");
+
+ this->dump_i ();
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> ACE_INLINE
+ACE_Hash_Map_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::ACE_Hash_Map_Iterator_Ex (ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK> &mm,
+ int tail)
+ : ACE_Hash_Map_Iterator_Base_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK> (mm,
+ tail == 0 ? 1 : 0)
+{
+ ACE_TRACE ("ACE_Hash_Map_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::ACE_Hash_Map_Iterator_Ex");
+ if (tail == 0)
+ this->forward_i ();
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> ACE_INLINE int
+ACE_Hash_Map_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::advance (void)
+{
+ ACE_TRACE ("ACE_Hash_Map_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::advance");
+ return this->forward_i ();
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> ACE_INLINE
+ACE_Hash_Map_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK> &
+ACE_Hash_Map_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::operator++ (void)
+{
+ ACE_TRACE ("ACE_Hash_Map_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::operator++ (void)");
+
+ this->forward_i ();
+ return *this;
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> ACE_INLINE
+ACE_Hash_Map_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>
+ACE_Hash_Map_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::operator++ (int)
+{
+ ACE_TRACE ("ACE_Hash_Map_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::operator++ (int)");
+
+ ACE_Hash_Map_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK> retv (*this);
+ this->forward_i ();
+ return retv;
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> ACE_INLINE
+ACE_Hash_Map_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK> &
+ACE_Hash_Map_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::operator-- (void)
+{
+ ACE_TRACE ("ACE_Hash_Map_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::operator-- (void)");
+
+ this->reverse_i ();
+ return *this;
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> ACE_INLINE
+ACE_Hash_Map_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>
+ACE_Hash_Map_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::operator-- (int)
+{
+ ACE_TRACE ("ACE_Hash_Map_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::operator-- (int)");
+
+ ACE_Hash_Map_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK> retv (*this);
+ this->reverse_i ();
+ return retv;
+}
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Hash_Map_Const_Iterator_Ex)
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> ACE_INLINE void
+ACE_Hash_Map_Const_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::dump (void) const
+{
+ ACE_TRACE ("ACE_Hash_Map_Const_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::dump");
+
+ this->dump_i ();
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> ACE_INLINE
+ACE_Hash_Map_Const_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::ACE_Hash_Map_Const_Iterator_Ex (const ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK> &mm,
+ int tail)
+ : ACE_Hash_Map_Const_Iterator_Base_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK> (mm,
+ tail == 0 ? 1 : 0)
+{
+ ACE_TRACE ("ACE_Hash_Map_Const_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::ACE_Hash_Map_Const_Iterator_Ex");
+ if (tail == 0)
+ this->forward_i ();
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> ACE_INLINE int
+ACE_Hash_Map_Const_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::advance (void)
+{
+ ACE_TRACE ("ACE_Hash_Map_Const_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::advance");
+ return this->forward_i ();
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> ACE_INLINE
+ACE_Hash_Map_Const_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK> &
+ACE_Hash_Map_Const_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::operator++ (void)
+{
+ ACE_TRACE ("ACE_Hash_Map_Const_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::operator++ (void)");
+
+ this->forward_i ();
+ return *this;
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> ACE_INLINE
+ACE_Hash_Map_Const_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>
+ACE_Hash_Map_Const_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::operator++ (int)
+{
+ ACE_TRACE ("ACE_Hash_Map_Const_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::operator++ (int)");
+
+ ACE_Hash_Map_Const_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK> retv (*this);
+ this->forward_i ();
+ return retv;
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> ACE_INLINE
+ACE_Hash_Map_Const_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK> &
+ACE_Hash_Map_Const_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::operator-- (void)
+{
+ ACE_TRACE ("ACE_Hash_Map_Const_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::operator-- (void)");
+
+ this->reverse_i ();
+ return *this;
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> ACE_INLINE
+ACE_Hash_Map_Const_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>
+ACE_Hash_Map_Const_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::operator-- (int)
+{
+ ACE_TRACE ("ACE_Hash_Map_Const_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::operator-- (int)");
+
+ ACE_Hash_Map_Const_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK> retv (*this);
+ this->reverse_i ();
+ return retv;
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> ACE_INLINE
+ACE_Hash_Map_Bucket_Iterator<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::ACE_Hash_Map_Bucket_Iterator (ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK> &mm,
+ const EXT_ID &ext_id,
+ int tail)
+ : map_man_ (&mm)
+{
+ ACE_TRACE ("ACE_Hash_Map_Bucket_Iterator<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::ACE_Hash_Map_Bucket_Iterator");
+
+ this->index_ = this->map_man_->hash (ext_id) % this->map_man_->total_size_;
+ this->next_ = &this->map_man_->table_[this->index_];
+
+ if (tail == 0)
+ this->forward_i ();
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> ACE_INLINE
+ACE_Hash_Map_Bucket_Iterator<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK> &
+ACE_Hash_Map_Bucket_Iterator<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::operator++ (void)
+{
+ ACE_TRACE ("ACE_Hash_Map_Bucket_Iterator<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::operator++ (void)");
+
+ this->forward_i ();
+ return *this;
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> ACE_INLINE
+ACE_Hash_Map_Bucket_Iterator<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>
+ACE_Hash_Map_Bucket_Iterator<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::operator++ (int)
+{
+ ACE_TRACE ("ACE_Hash_Map_Bucket_Iterator<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::operator++ (int)");
+
+ ACE_Hash_Map_Bucket_Iterator<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK> retv (*this);
+ this->forward_i ();
+ return retv;
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> ACE_INLINE
+ACE_Hash_Map_Bucket_Iterator<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK> &
+ACE_Hash_Map_Bucket_Iterator<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::operator-- (void)
+{
+ ACE_TRACE ("ACE_Hash_Map_Bucket_Iterator<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::operator-- (void)");
+
+ this->reverse_i ();
+ return *this;
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> ACE_INLINE
+ACE_Hash_Map_Bucket_Iterator<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>
+ACE_Hash_Map_Bucket_Iterator<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::operator-- (int)
+{
+ ACE_TRACE ("ACE_Hash_Map_Bucket_Iterator<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::operator-- (int)");
+
+ ACE_Hash_Map_Bucket_Iterator<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK> retv (*this);
+ this->reverse_i ();
+ return retv;
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> int
+ACE_Hash_Map_Bucket_Iterator<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::forward_i (void)
+{
+ ACE_TRACE ("ACE_Hash_Map_Bucket_Iterator<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::forward_i");
+
+ this->next_ = this->next_->next_;
+ return this->next_ != &this->map_man_->table_[this->index_];
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> int
+ACE_Hash_Map_Bucket_Iterator<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::reverse_i (void)
+{
+ ACE_TRACE ("ACE_Hash_Map_Bucket_Iterator<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::reverse_i");
+
+ this->next_ = this->next_->prev_;
+ return this->next_ != &this->map_man_->table_[this->index_];
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> ACE_INLINE
+ACE_Hash_Map_Entry<EXT_ID, INT_ID> &
+ACE_Hash_Map_Bucket_Iterator<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::operator* (void) const
+{
+ ACE_TRACE ("ACE_Hash_Map_Bucket_Iterator<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::operator*");
+
+ return *this->next_;
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> ACE_INLINE
+ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK> &
+ACE_Hash_Map_Bucket_Iterator<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::map (void)
+{
+ ACE_TRACE ("ACE_Hash_Map_Bucket_Iterator<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::map");
+ return *this->map_man_;
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> ACE_INLINE int
+ACE_Hash_Map_Bucket_Iterator<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::operator== (const ACE_Hash_Map_Bucket_Iterator<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK> &rhs) const
+{
+ ACE_TRACE ("ACE_Hash_Map_Bucket_Iterator<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::operator==");
+ return this->map_man_ == rhs.map_man_
+ && this->index_ == rhs.index_
+ && this->next_ == rhs.next_;
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> ACE_INLINE int
+ACE_Hash_Map_Bucket_Iterator<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::operator!= (const ACE_Hash_Map_Bucket_Iterator<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK> &rhs) const
+{
+ ACE_TRACE ("ACE_Hash_Map_Bucket_Iterator<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::operator!=");
+ return this->next_ != rhs.next_
+ || this->index_ != rhs.index_
+ || this->map_man_ != rhs.map_man_;
+}
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Hash_Map_Reverse_Iterator_Ex)
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> ACE_INLINE void
+ACE_Hash_Map_Reverse_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::dump (void) const
+{
+ ACE_TRACE ("ACE_Hash_Map_Reverse_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::dump");
+
+ this->dump_i ();
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> ACE_INLINE
+ACE_Hash_Map_Reverse_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::ACE_Hash_Map_Reverse_Iterator_Ex (ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK> &mm, int head)
+ : ACE_Hash_Map_Iterator_Base_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK> (mm, head)
+{
+ ACE_TRACE ("ACE_Hash_Map_Reverse_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::ACE_Hash_Map_Reverse_Iterator_Ex");
+ if (head == 0)
+ this->reverse_i ();
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> ACE_INLINE int
+ACE_Hash_Map_Reverse_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::advance (void)
+{
+ ACE_TRACE ("ACE_Hash_Map_Reverse_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::advance");
+ return this->reverse_i ();
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> ACE_INLINE
+ACE_Hash_Map_Reverse_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK> &
+ACE_Hash_Map_Reverse_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::operator++ (void)
+{
+ ACE_TRACE ("ACE_Hash_Map_Reverse_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::operator++ (void)");
+
+ this->reverse_i ();
+ return *this;
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> ACE_INLINE
+ACE_Hash_Map_Reverse_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>
+ACE_Hash_Map_Reverse_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::operator++ (int)
+{
+ ACE_TRACE ("ACE_Hash_Map_Reverse_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::operator++ (int)");
+
+ ACE_Hash_Map_Reverse_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK> retv (*this);
+ this->reverse_i ();
+ return retv;
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> ACE_INLINE
+ACE_Hash_Map_Reverse_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK> &
+ACE_Hash_Map_Reverse_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::operator-- (void)
+{
+ ACE_TRACE ("ACE_Hash_Map_Reverse_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::operator-- (void)");
+
+ this->forward_i ();
+ return *this;
+}
+
+template <class EXT_ID, class INT_ID, class HASH_KEY, class COMPARE_KEYS, class ACE_LOCK> ACE_INLINE
+ACE_Hash_Map_Reverse_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>
+ACE_Hash_Map_Reverse_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::operator-- (int)
+{
+ ACE_TRACE ("ACE_Hash_Map_Reverse_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK>::operator-- (int)");
+
+ ACE_Hash_Map_Reverse_Iterator_Ex<EXT_ID, INT_ID, HASH_KEY, COMPARE_KEYS, ACE_LOCK> retv (*this);
+ this->forward_i ();
+ return retv;
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK>
+ACE_Hash_Map_Manager<EXT_ID, INT_ID, ACE_LOCK>::ACE_Hash_Map_Manager (ACE_Allocator *alloc)
+ : ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, ACE_Hash<EXT_ID>, ACE_Equal_To<EXT_ID>, ACE_LOCK> (alloc)
+{
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK>
+ACE_Hash_Map_Manager<EXT_ID, INT_ID, ACE_LOCK>::ACE_Hash_Map_Manager (size_t size,
+ ACE_Allocator *alloc)
+ : ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, ACE_Hash<EXT_ID>, ACE_Equal_To<EXT_ID>, ACE_LOCK> (size,
+ alloc)
+{
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> int
+ACE_Hash_Map_Manager<EXT_ID, INT_ID, ACE_LOCK>::equal (const EXT_ID &id1, const EXT_ID &id2)
+{
+ return ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, ACE_Hash<EXT_ID>, ACE_Equal_To<EXT_ID>, ACE_LOCK>::equal (id1, id2);
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> u_long
+ACE_Hash_Map_Manager<EXT_ID, INT_ID, ACE_LOCK>::hash (const EXT_ID &ext_id)
+{
+ return ACE_Hash_Map_Manager_Ex<EXT_ID, INT_ID, ACE_Hash<EXT_ID>, ACE_Equal_To<EXT_ID>, ACE_LOCK>::hash (ext_id);
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK>
+ACE_Hash_Map_Iterator<EXT_ID, INT_ID, ACE_LOCK>::ACE_Hash_Map_Iterator (ACE_Hash_Map_Manager<EXT_ID, INT_ID, ACE_LOCK> &mm,
+ int tail)
+ : ACE_Hash_Map_Iterator_Ex<EXT_ID, INT_ID, ACE_Hash<EXT_ID>, ACE_Equal_To<EXT_ID>, ACE_LOCK> (mm,
+ tail)
+{
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK>
+ACE_Hash_Map_Iterator<EXT_ID, INT_ID, ACE_LOCK>::ACE_Hash_Map_Iterator (const ACE_Hash_Map_Iterator_Ex<EXT_ID, INT_ID, ACE_Hash<EXT_ID>, ACE_Equal_To<EXT_ID>, ACE_LOCK> &base)
+ : ACE_Hash_Map_Iterator_Ex<EXT_ID, INT_ID, ACE_Hash<EXT_ID>, ACE_Equal_To<EXT_ID>, ACE_LOCK> (base)
+{
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> ACE_Hash_Map_Iterator<EXT_ID, INT_ID, ACE_LOCK> &
+ACE_Hash_Map_Iterator<EXT_ID, INT_ID, ACE_LOCK>::operator= (const ACE_Hash_Map_Iterator_Ex<EXT_ID, INT_ID, ACE_Hash<EXT_ID>, ACE_Equal_To<EXT_ID>, ACE_LOCK> &rhs)
+{
+ if (this != &rhs)
+ {
+ ACE_Hash_Map_Iterator_Ex<EXT_ID, INT_ID, ACE_Hash<EXT_ID>, ACE_Equal_To<EXT_ID>, ACE_LOCK> &base = *this;
+
+ base = rhs;
+ }
+
+ return *this;
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK>
+ACE_Hash_Map_Const_Iterator<EXT_ID, INT_ID, ACE_LOCK>::ACE_Hash_Map_Const_Iterator (const ACE_Hash_Map_Manager<EXT_ID, INT_ID, ACE_LOCK> &mm,
+ int tail)
+ : ACE_Hash_Map_Const_Iterator_Ex<EXT_ID, INT_ID, ACE_Hash<EXT_ID>, ACE_Equal_To<EXT_ID>, ACE_LOCK> (mm,
+ tail)
+{
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK>
+ACE_Hash_Map_Const_Iterator<EXT_ID, INT_ID, ACE_LOCK>::ACE_Hash_Map_Const_Iterator (const ACE_Hash_Map_Const_Iterator_Ex<EXT_ID, INT_ID, ACE_Hash<EXT_ID>, ACE_Equal_To<EXT_ID>, ACE_LOCK> &base)
+ : ACE_Hash_Map_Const_Iterator_Ex<EXT_ID, INT_ID, ACE_Hash<EXT_ID>, ACE_Equal_To<EXT_ID>, ACE_LOCK> (base)
+{
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> ACE_Hash_Map_Const_Iterator<EXT_ID, INT_ID, ACE_LOCK> &
+ACE_Hash_Map_Const_Iterator<EXT_ID, INT_ID, ACE_LOCK>::operator= (const ACE_Hash_Map_Const_Iterator_Ex<EXT_ID, INT_ID, ACE_Hash<EXT_ID>, ACE_Equal_To<EXT_ID>, ACE_LOCK> &rhs)
+{
+ if (this != &rhs)
+ {
+ ACE_Hash_Map_Const_Iterator_Ex<EXT_ID, INT_ID, ACE_Hash<EXT_ID>, ACE_Equal_To<EXT_ID>, ACE_LOCK> &base = *this;
+
+ base = rhs;
+ }
+
+ return *this;
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK>
+ACE_Hash_Map_Reverse_Iterator<EXT_ID, INT_ID, ACE_LOCK>::ACE_Hash_Map_Reverse_Iterator (ACE_Hash_Map_Manager<EXT_ID, INT_ID, ACE_LOCK> &mm,
+ int head)
+ : ACE_Hash_Map_Reverse_Iterator_Ex<EXT_ID, INT_ID, ACE_Hash<EXT_ID>, ACE_Equal_To<EXT_ID>, ACE_LOCK> (mm,
+ head)
+{
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK>
+ACE_Hash_Map_Reverse_Iterator<EXT_ID, INT_ID, ACE_LOCK>::ACE_Hash_Map_Reverse_Iterator (const ACE_Hash_Map_Reverse_Iterator_Ex<EXT_ID, INT_ID, ACE_Hash<EXT_ID>, ACE_Equal_To<EXT_ID>, ACE_LOCK> &base)
+ : ACE_Hash_Map_Reverse_Iterator_Ex<EXT_ID, INT_ID, ACE_Hash<EXT_ID>, ACE_Equal_To<EXT_ID>, ACE_LOCK> (base)
+{
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> ACE_Hash_Map_Reverse_Iterator<EXT_ID, INT_ID, ACE_LOCK> &
+ACE_Hash_Map_Reverse_Iterator<EXT_ID, INT_ID, ACE_LOCK>::operator= (const ACE_Hash_Map_Reverse_Iterator_Ex<EXT_ID, INT_ID, ACE_Hash<EXT_ID>, ACE_Equal_To<EXT_ID>, ACE_LOCK> &rhs)
+{
+ ACE_Hash_Map_Reverse_Iterator_Ex<EXT_ID, INT_ID, ACE_Hash<EXT_ID>, ACE_Equal_To<EXT_ID>, ACE_LOCK> &base = *this;
+
+ base = rhs;
+
+ return *this;
+}
diff --git a/ace/Utils/Templates/Hash_Map_With_Allocator_T.cpp b/ace/Utils/Templates/Hash_Map_With_Allocator_T.cpp
new file mode 100644
index 00000000000..fa2a44ca06d
--- /dev/null
+++ b/ace/Utils/Templates/Hash_Map_With_Allocator_T.cpp
@@ -0,0 +1,32 @@
+// Hash_Map_With_Allocator_T.cpp
+// $Id$
+
+#ifndef ACE_HASH_MAP_WITH_ALLOCATOR_T_CPP
+#define ACE_HASH_MAP_WITH_ALLOCATOR_T_CPP
+
+#include "ace/Hash_Map_With_Allocator_T.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#if !defined (__ACE_INLINE__)
+#include "ace/Hash_Map_With_Allocator_T.i"
+#endif /* __ACE_INLINE__ */
+
+template <class EXT_ID, class INT_ID>
+ACE_Hash_Map_With_Allocator<EXT_ID, INT_ID>::ACE_Hash_Map_With_Allocator (ACE_Allocator *alloc)
+ : ACE_Hash_Map_Manager<EXT_ID, INT_ID, ACE_Null_Mutex> (alloc)
+{
+ ACE_TRACE ("ACE_Hash_Map_With_Allocator<EXT_ID, INT_ID>::ACE_Hash_Map_With_Allocator");
+}
+
+template <class EXT_ID, class INT_ID>
+ACE_Hash_Map_With_Allocator<EXT_ID, INT_ID>::ACE_Hash_Map_With_Allocator (size_t size,
+ ACE_Allocator *alloc)
+ : ACE_Hash_Map_Manager<EXT_ID, INT_ID, ACE_Null_Mutex> (size, alloc)
+{
+ ACE_TRACE ("ACE_Hash_Map_With_Allocator<EXT_ID, INT_ID>::ACE_Hash_Map_With_Allocator");
+}
+
+#endif /* ACE_HASH_MAP_WITH_ALLOCATOR_T_CPP */
diff --git a/ace/Utils/Templates/Hash_Map_With_Allocator_T.h b/ace/Utils/Templates/Hash_Map_With_Allocator_T.h
new file mode 100644
index 00000000000..0b04fe130d8
--- /dev/null
+++ b/ace/Utils/Templates/Hash_Map_With_Allocator_T.h
@@ -0,0 +1,102 @@
+/* -*- C++ -*- */
+//=============================================================================
+/**
+ * @file Hash_Map_With_Allocator_T.h
+ *
+ * $Id$
+ *
+ * @author Marina Spivak <marina@cs.wustl.edu>
+ * @author Irfan Pyarali <irfan@cs.wustl.edu>
+ */
+//=============================================================================
+
+#ifndef ACE_HASH_MAP_WITH_ALLOCATOR_T_H
+#define ACE_HASH_MAP_WITH_ALLOCATOR_T_H
+#include "ace/pre.h"
+
+#include "ace/Hash_Map_Manager.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+/**
+ * @class ACE_Hash_Map_With_Allocator
+ *
+ * @brief This class is a thin wrapper around ACE_Hash_Map_Manager,
+ * which comes handy when ACE_Hash_Map_Manager is to be used with a
+ * non-nil ACE_Allocator. This wrapper insures that the appropriate
+ * allocator is in place for every operation that accesses or
+ * updates the hash map.
+ *
+ * If we use ACE_Hash_Map_Manager with a shared memory allocator
+ * (or memory-mapped file allocator, for example), the allocator
+ * pointer used by ACE_Hash_Map_Manager gets stored with it, in
+ * shared memory (or memory-mapped file). Naturally, this will
+ * cause horrible problems, since only the first process to set
+ * that pointer will be guaranteed the address of the allocator
+ * is meaningful! That is why we need this wrapper, which
+ * insures that appropriate allocator pointer is in place for
+ * each call.
+ */
+template <class EXT_ID, class INT_ID>
+class ACE_Hash_Map_With_Allocator :
+ public ACE_Hash_Map_Manager<EXT_ID, INT_ID, ACE_Null_Mutex>
+{
+public:
+ /// Constructor.
+ ACE_Hash_Map_With_Allocator (ACE_Allocator *alloc);
+
+ /// Constructor that specifies hash table size.
+ ACE_Hash_Map_With_Allocator (size_t size,
+ ACE_Allocator *alloc);
+
+ // = The following methods are Proxies to the corresponding methods
+ // in <ACE_Hash_Map_Manager>. Each method sets the allocator to
+ // the one specified by the invoking entity, and then calls the
+ // corresponding method in <ACE_Hash_Map_Manager> to do the
+ // actual work.
+
+ int bind (const EXT_ID &,
+ const INT_ID &,
+ ACE_Allocator *alloc);
+
+ int unbind (const EXT_ID &,
+ INT_ID &,
+ ACE_Allocator *alloc);
+
+ int unbind (const EXT_ID &,
+ ACE_Allocator *alloc);
+
+ int rebind (const EXT_ID &,
+ const INT_ID &,
+ EXT_ID &,
+ INT_ID &,
+ ACE_Allocator *alloc);
+
+ int find (const EXT_ID &,
+ INT_ID &,
+ ACE_Allocator *alloc);
+
+ /// Returns 0 if the <ext_id> is in the mapping, otherwise -1.
+ int find (const EXT_ID &,
+ ACE_Allocator *alloc);
+
+ int close (ACE_Allocator *alloc);
+};
+
+#if defined (__ACE_INLINE__)
+#include "ace/Hash_Map_With_Allocator_T.i"
+#endif /* __ACE_INLINE__ */
+
+#if defined (ACE_TEMPLATES_REQUIRE_SOURCE)
+#include "ace/Hash_Map_With_Allocator_T.cpp"
+#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */
+
+#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA)
+#pragma implementation ("Hash_Map_With_Allocator_T.cpp")
+#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */
+
+
+#include "ace/post.h"
+#endif /* ACE_HASH_MAP_WITH_ALLOCATOR_T_H */
diff --git a/ace/Utils/Templates/Hash_Map_With_Allocator_T.i b/ace/Utils/Templates/Hash_Map_With_Allocator_T.i
new file mode 100644
index 00000000000..5b8c42dde3d
--- /dev/null
+++ b/ace/Utils/Templates/Hash_Map_With_Allocator_T.i
@@ -0,0 +1,73 @@
+/* -*- C++ -*- */
+// $Id$
+
+// Hash_Map_With_Allocator_T.i
+
+
+template <class EXT_ID, class INT_ID> ACE_INLINE int
+ACE_Hash_Map_With_Allocator<EXT_ID, INT_ID>::close (ACE_Allocator *alloc)
+{
+ ACE_TRACE ("ACE_Hash_Map_With_Allocator<EXT_ID, INT_ID>::close");
+ this->allocator_ = alloc;
+ return this->close_i ();
+}
+
+template <class EXT_ID, class INT_ID> ACE_INLINE int
+ACE_Hash_Map_With_Allocator<EXT_ID, INT_ID>::bind (const EXT_ID &ext_id,
+ const INT_ID &int_id,
+ ACE_Allocator *alloc)
+{
+ ACE_TRACE ("ACE_Hash_Map_With_Allocator<EXT_ID, INT_ID>::bind");
+ this->allocator_ = alloc;
+ return this->bind_i (ext_id, int_id);
+}
+
+template <class EXT_ID, class INT_ID> ACE_INLINE int
+ACE_Hash_Map_With_Allocator<EXT_ID, INT_ID>::unbind (const EXT_ID &ext_id,
+ INT_ID &int_id,
+ ACE_Allocator *alloc)
+{
+ ACE_TRACE ("ACE_Hash_Map_With_Allocator<EXT_ID, INT_ID>::unbind");
+ this->allocator_ = alloc;
+ return this->unbind_i (ext_id, int_id);
+}
+
+template <class EXT_ID, class INT_ID> ACE_INLINE int
+ACE_Hash_Map_With_Allocator<EXT_ID, INT_ID>::unbind (const EXT_ID &ext_id,
+ ACE_Allocator *alloc)
+{
+ ACE_TRACE ("ACE_Hash_Map_With_Allocator<EXT_ID>::unbind");
+ this->allocator_ = alloc;
+ return this->unbind_i (ext_id);
+}
+
+template <class EXT_ID, class INT_ID> ACE_INLINE int
+ACE_Hash_Map_With_Allocator<EXT_ID, INT_ID>::rebind (const EXT_ID &ext_id,
+ const INT_ID &int_id,
+ EXT_ID &old_ext_id,
+ INT_ID &old_int_id,
+ ACE_Allocator *alloc)
+{
+ ACE_TRACE ("ACE_Hash_Map_With_Allocator<EXT_ID, INT_ID>::rebind");
+ this->allocator_ = alloc;
+ return this->rebind_i (ext_id, int_id, old_ext_id, old_int_id);
+}
+
+template <class EXT_ID, class INT_ID> ACE_INLINE int
+ACE_Hash_Map_With_Allocator<EXT_ID, INT_ID>::find (const EXT_ID &ext_id,
+ INT_ID &int_id,
+ ACE_Allocator *alloc)
+{
+ ACE_TRACE ("ACE_Hash_Map_With_Allocator<EXT_ID, INT_ID>::find");
+ this->allocator_ = alloc;
+ return this->find_i (ext_id, int_id);
+}
+
+template <class EXT_ID, class INT_ID> ACE_INLINE int
+ACE_Hash_Map_With_Allocator<EXT_ID, INT_ID>::find (const EXT_ID &ext_id,
+ ACE_Allocator *alloc)
+{
+ ACE_TRACE ("ACE_Hash_Map_With_Allocator<EXT_ID, INT_ID>::find");
+ this->allocator_ = alloc;
+ return this->find_i (ext_id);
+}
diff --git a/ace/Utils/Templates/Intrusive_List.cpp b/ace/Utils/Templates/Intrusive_List.cpp
new file mode 100644
index 00000000000..7a23921288b
--- /dev/null
+++ b/ace/Utils/Templates/Intrusive_List.cpp
@@ -0,0 +1,151 @@
+// $Id$
+
+#ifndef ACE_INTRUSIVE_LIST_C
+#define ACE_INTRUSIVE_LIST_C
+
+#include "ace/Intrusive_List.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#if !defined (__ACE_INLINE__)
+#include "ace/Intrusive_List.inl"
+#endif /* __ACE_INLINE__ */
+
+ACE_RCSID(ace, Intrusive_List, "$Id$")
+
+template <class T>
+ACE_Intrusive_List<T>::ACE_Intrusive_List (void)
+ : head_ (0)
+ , tail_ (0)
+{
+}
+
+template<class T>
+ACE_Intrusive_List<T>::~ACE_Intrusive_List (void)
+{
+}
+
+template<class T> void
+ACE_Intrusive_List<T>::push_back (T *node)
+{
+ if (this->tail_ == 0)
+ {
+ this->tail_ = node;
+ this->head_ = node;
+ node->next (0);
+ node->prev (0);
+ return;
+ }
+
+ this->tail_->next (node);
+ node->prev (this->tail_);
+ node->next (0);
+ this->tail_ = node;
+}
+
+template<class T> void
+ACE_Intrusive_List<T>::push_front (T *node)
+{
+ if (this->head_ == 0)
+ {
+ this->tail_ = node;
+ this->head_ = node;
+ node->next (0);
+ node->prev (0);
+ return;
+ }
+
+ this->head_->prev (node);
+ node->next (this->head_);
+ node->prev (0);
+ this->head_ = node;
+}
+
+template<class T> T *
+ACE_Intrusive_List<T>::pop_front (void)
+{
+ T *node = this->head_;
+ if (node == 0)
+ return 0;
+ this->remove_i (node);
+ return node;
+}
+
+template<class T> T *
+ACE_Intrusive_List<T>::pop_back (void)
+{
+ T *node = this->tail_;
+ if (node == 0)
+ return 0;
+ this->remove_i (node);
+ return node;
+}
+
+template<class T> void
+ACE_Intrusive_List<T>::remove (T *node)
+{
+ for (T *i = this->head_; i != 0; i = i->next ())
+ {
+ if (node == i)
+ {
+ this->remove_i (node);
+ return;
+ }
+ }
+}
+
+template<class T> void
+ACE_Intrusive_List<T>::remove_i (T *node)
+{
+ if (node->prev () != 0)
+ node->prev ()->next (node->next ());
+ else
+ this->head_ = node->next ();
+
+ if (node->next () != 0)
+ node->next ()->prev (node->prev ());
+ else
+ this->tail_ = node->prev ();
+
+ node->next (0);
+ node->prev (0);
+}
+
+#if 0
+template<class T> void
+ACE_Intrusive_List_Node<T>::check_invariants (void)
+{
+ ACE_ASSERT ((this->next () == 0) || (this->next ()->prev () == this));
+ ACE_ASSERT ((this->prev () == 0) || (this->prev ()->next () == this));
+}
+
+template<class T> void
+ACE_Intrusive_List<T>::check_invariants (void)
+{
+ ACE_ASSERT ((this->tail_ == 0) || (this->tail_->next () == 0));
+ ACE_ASSERT ((this->head_ == 0) || (this->head_->prev () == 0));
+ ACE_ASSERT (!((this->head_ == 0) ^ (this->tail_ == 0)));
+
+ int found_tail = 0;
+ for (T *i = this->head_; i != 0; i = i->next ())
+ {
+ if (i == this->tail_)
+ found_tail = 1;
+ i->check_invariants ();
+ }
+ ACE_ASSERT (this->tail_ == 0 || found_tail == 1);
+
+ int found_head = 0;
+ for (T *j = this->tail_; j != 0; j = j->prev ())
+ {
+ if (j == this->head_)
+ found_head = 1;
+ j->check_invariants ();
+ }
+ ACE_ASSERT (this->head_ == 0 || found_head == 1);
+}
+#endif /* 0 */
+
+#endif /* ACE_INTRUSIVE_LIST_C */
diff --git a/ace/Utils/Templates/Intrusive_List.h b/ace/Utils/Templates/Intrusive_List.h
new file mode 100644
index 00000000000..1340c654355
--- /dev/null
+++ b/ace/Utils/Templates/Intrusive_List.h
@@ -0,0 +1,131 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Intrusive_List.h
+ *
+ * $Id$
+ *
+ * @author Carlos O'Ryan <coryan@uci.edu>
+ */
+//=============================================================================
+
+#ifndef ACE_INTRUSIVE_LIST_H
+#define ACE_INTRUSIVE_LIST_H
+#include "ace/pre.h"
+
+#include "ace/config-all.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+/**
+ * @class ACE_Intrusive_List
+ *
+ * @brief Implement an intrusive double linked list
+ *
+ * Intrusive lists assume that the elements they contain the pointers
+ * required to build the list. They are useful as light-weight
+ * containers and free-lists.
+ *
+ * The template argument T must implement the following methods:
+ *
+ * - T* T::next () const;
+ * - void T::next (T *);
+ * - T* T::prev () const;
+ * - void T::prev (T* );
+ *
+ * A simple way to satisfy the Intrusive_List requirements would be to
+ * implement a helper class:
+ *
+ * class My_Object : public ACE_Intrusive_List_Node<My_Object> {<BR>
+ * ....<BR>
+ * };<BR>
+ *
+ * typedef ACE_Intrusive_List<My_Object> My_Object_List;
+ *
+ * However, ACE is supported on platforms that would surely get
+ * confused using such templates.
+ *
+ * @todo The ACE_Message_Queue is an example of an intrusive list (or
+ * queue) but it is not implemented in terms of this class.
+ *
+ */
+template <class T>
+class ACE_Intrusive_List
+{
+public:
+ // = Initialization and termination methods.
+ /// Constructor. Use user specified allocation strategy
+ /// if specified.
+ ACE_Intrusive_List (void);
+
+ /// Destructor.
+ ~ACE_Intrusive_List (void);
+
+ // = Check boundary conditions.
+
+ /// Returns 1 if the container is empty, otherwise returns 0.
+ int empty (void) const;
+
+ /// Insert an element at the beginning of the list
+ void push_front (T *node);
+
+ /// Insert an element at the end of the list
+ void push_back (T *node);
+
+ /// Remove the element at the beginning of the list
+ T *pop_front (void);
+
+ /// Remove the element at the end of the list
+ T *pop_back (void);
+
+ /// Get the element at the head of the queue
+ T *head (void) const;
+
+ /// Get the element at the tail of the queue
+ T *tail (void) const;
+
+ /// Remove a element from the list
+ /**
+ * Verify that the element is still in the list before removing it.
+ */
+ void remove (T *node);
+
+private:
+ /// Remove a element from the list
+ /**
+ * No attempts are performed to check if T* really belongs to the
+ * list. The effects of removing an invalid element are unspecified
+ */
+ void remove_i (T *node);
+
+ /** @name Disallow copying
+ *
+ */
+ //@{
+ ACE_Intrusive_List (const ACE_Intrusive_List<T> &);
+ ACE_Intrusive_List<T>& operator= (const ACE_Intrusive_List<T> &);
+ //@}
+
+private:
+ /// Head and tail of the list
+ T *head_;
+ T *tail_;
+};
+
+#if defined (__ACE_INLINE__)
+#include "ace/Intrusive_List.inl"
+#endif /* __ACE_INLINE__ */
+
+#if defined (ACE_TEMPLATES_REQUIRE_SOURCE)
+#include "ace/Intrusive_List.cpp"
+#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */
+
+#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA)
+#pragma implementation ("Intrusive_List.cpp")
+#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */
+
+#include "ace/post.h"
+#endif /* ACE_INTRUSIVE_LIST_H */
diff --git a/ace/Utils/Templates/Intrusive_List.inl b/ace/Utils/Templates/Intrusive_List.inl
new file mode 100644
index 00000000000..2c513b4584f
--- /dev/null
+++ b/ace/Utils/Templates/Intrusive_List.inl
@@ -0,0 +1,19 @@
+// $Id$
+
+template<class T> ACE_INLINE int
+ACE_Intrusive_List<T>::empty (void) const
+{
+ return this->head_ == 0;
+}
+
+template<class T> ACE_INLINE T *
+ACE_Intrusive_List<T>::head (void) const
+{
+ return this->head_;
+}
+
+template<class T> ACE_INLINE T *
+ACE_Intrusive_List<T>::tail (void) const
+{
+ return this->tail_;
+}
diff --git a/ace/Utils/Templates/Intrusive_List_Node.cpp b/ace/Utils/Templates/Intrusive_List_Node.cpp
new file mode 100644
index 00000000000..58002653d2e
--- /dev/null
+++ b/ace/Utils/Templates/Intrusive_List_Node.cpp
@@ -0,0 +1,25 @@
+// $Id$
+
+#ifndef ACE_INTRUSIVE_LIST_NODE_C
+#define ACE_INTRUSIVE_LIST_NODE_C
+
+#include "ace/Intrusive_List_Node.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#if !defined (__ACE_INLINE__)
+#include "ace/Intrusive_List_Node.inl"
+#endif /* __ACE_INLINE__ */
+
+ACE_RCSID(ace, Intrusive_List_Node, "$Id$")
+
+template<class T>
+ACE_Intrusive_List_Node<T>::ACE_Intrusive_List_Node (void)
+ : prev_ (0)
+ , next_ (0)
+{
+}
+
+#endif /* ACE_INTRUSIVE_LIST_NODE_C */
diff --git a/ace/Utils/Templates/Intrusive_List_Node.h b/ace/Utils/Templates/Intrusive_List_Node.h
new file mode 100644
index 00000000000..b376b3f97d2
--- /dev/null
+++ b/ace/Utils/Templates/Intrusive_List_Node.h
@@ -0,0 +1,81 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Intrusive_List_Node.h
+ *
+ * $Id$
+ *
+ * @author Carlos O'Ryan <coryan@uci.edu>
+ */
+//=============================================================================
+
+#ifndef ACE_INTRUSIVE_LIST_NODE_H
+#define ACE_INTRUSIVE_LIST_NODE_H
+#include "ace/pre.h"
+
+#include "ace/config-all.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+/**
+ * @class ACE_Intrusive_List_Node
+ *
+ * @brief Implement the requirements for ACE_Intrusive_List
+ *
+ * The class should be used as follows:
+ *
+ * class My_Object : public ACE_Intrusive_List_Node_Node<My_Object> {<BR>
+ * ....<BR>
+ * };<BR>
+ *
+ * However, ACE is supported on platforms that would surely get
+ * confused using such templates, the class is provided as a helper
+ * for our lucky users that only need portability to modern C++
+ * compilers.
+ *
+ */
+template <class T>
+class ACE_Intrusive_List_Node
+{
+public:
+ /** @name Accesors and modifiers to the next and previous pointers
+ *
+ */
+ //@{
+ T *prev (void) const;
+ void prev (T *);
+ T *next (void) const;
+ void next (T *);
+ //@}
+
+protected:
+ /// Constructor
+ /**
+ * The constructor is protected, because only derived classes should
+ * be instantiated.
+ */
+ ACE_Intrusive_List_Node (void);
+
+private:
+ /// Head and tail of the list
+ T *prev_;
+ T *next_;
+};
+
+#if defined (__ACE_INLINE__)
+#include "ace/Intrusive_List_Node.inl"
+#endif /* __ACE_INLINE__ */
+
+#if defined (ACE_TEMPLATES_REQUIRE_SOURCE)
+#include "ace/Intrusive_List_Node.cpp"
+#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */
+
+#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA)
+#pragma implementation ("Intrusive_List_Node.cpp")
+#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */
+
+#include "ace/post.h"
+#endif /* ACE_INTRUSIVE_LIST_NODE_H */
diff --git a/ace/Utils/Templates/Intrusive_List_Node.inl b/ace/Utils/Templates/Intrusive_List_Node.inl
new file mode 100644
index 00000000000..e7f2c5ee3eb
--- /dev/null
+++ b/ace/Utils/Templates/Intrusive_List_Node.inl
@@ -0,0 +1,25 @@
+// $Id$
+
+template<class T> ACE_INLINE T*
+ACE_Intrusive_List_Node<T>::prev (void) const
+{
+ return this->prev_;
+}
+
+template<class T> ACE_INLINE void
+ACE_Intrusive_List_Node<T>::prev (T *x)
+{
+ this->prev_ = x;
+}
+
+template<class T> ACE_INLINE T*
+ACE_Intrusive_List_Node<T>::next (void) const
+{
+ return this->next_;
+}
+
+template<class T> ACE_INLINE void
+ACE_Intrusive_List_Node<T>::next (T *x)
+{
+ this->next_ = x;
+}
diff --git a/ace/Utils/Templates/Managed_Object.cpp b/ace/Utils/Templates/Managed_Object.cpp
new file mode 100644
index 00000000000..6fd4ef61399
--- /dev/null
+++ b/ace/Utils/Templates/Managed_Object.cpp
@@ -0,0 +1,23 @@
+// $Id$
+
+#ifndef ACE_MANAGED_OBJECT_CPP
+#define ACE_MANAGED_OBJECT_CPP
+
+#include "Managed_Object.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#if !defined (__ACE_INLINE__)
+#include "Managed_Object.i"
+#endif /* __ACE_INLINE__ */
+
+ACE_RCSID(ace, Managed_Object, "$Id$")
+
+template <class TYPE>
+ACE_Cleanup_Adapter<TYPE>::~ACE_Cleanup_Adapter (void)
+{
+}
+
+#endif /* ACE_MANAGED_OBJECT_CPP */
diff --git a/ace/Utils/Templates/Managed_Object.h b/ace/Utils/Templates/Managed_Object.h
new file mode 100644
index 00000000000..ea65f7c7a6b
--- /dev/null
+++ b/ace/Utils/Templates/Managed_Object.h
@@ -0,0 +1,160 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Managed_Object.h
+ *
+ * $Id$
+ *
+ * @author David L. Levine
+ */
+//=============================================================================
+
+
+#ifndef ACE_MANAGED_OBJECT_H
+#define ACE_MANAGED_OBJECT_H
+#include "ace/pre.h"
+
+#include "ace/OS/OS.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "Object_Manager.h"
+
+/**
+ * @class ACE_Cleanup_Adapter
+ *
+ * @brief Adapter for ACE_Cleanup objects that allows them to be readily
+ * managed by the ACE_Object_Manager.
+ *
+ * This template class adapts an object of any type to be an
+ * ACE_Cleanup object. The object can then be destroyed
+ * type-safely by the ACE_Object_Manager. This class is
+ * typically used to replace a cast; but, it's a bit cleaner and
+ * allows insertion of, say, run-time type identification
+ * internally if desired.
+ */
+template <class TYPE>
+class ACE_Cleanup_Adapter : public ACE_Cleanup
+{
+public:
+ /// Default constructor.
+ ACE_Cleanup_Adapter (void);
+
+ /// Virtual destructor, needed by some compilers for vtable placement.
+ virtual ~ACE_Cleanup_Adapter (void);
+
+ /// Accessor for contained object.
+ TYPE &object (void);
+
+private:
+ ACE_UNIMPLEMENTED_FUNC (ACE_Cleanup_Adapter (const ACE_Cleanup_Adapter<TYPE> &))
+ ACE_UNIMPLEMENTED_FUNC (void operator= (const ACE_Cleanup_Adapter<TYPE> &))
+
+ /// Contained object.
+ TYPE object_;
+};
+
+/**
+ * @class ACE_Managed_Object
+ *
+ * @brief Wrapper for interface to allocate an object managed by the
+ * ACE_Object_Manager.
+ *
+ * This template class wraps an interface that is used to
+ * allocate and access an object that is managed by the
+ * ACE_Object_Manager. Because static template member functions
+ * are not supported by some compilers, it is a separate
+ * (template) class.
+ * This interface is typically used to replace a static object
+ * with one that is dynamically allocated. It helps to avoid
+ * problems with order of static object
+ * construction/destruction. Managed objects won't be allocated
+ * until needed, but should be allocated when first needed. And
+ * they are destroyed in the reverse order of construction.
+ * <get_preallocated_object> accesses a "preallocated" object,
+ * i.e., one that is identified by a value in the
+ * ACE_Object_Manager:: Preallocated_Object enum. These objects
+ * are used internally by the ACE library.
+ * Hooks are provided for the application to preallocate objects
+ * via the same mechanism.
+ * ACE_APPLICATION_PREALLOCATED_OBJECT_DECLARATIONS can be used
+ * to define enum values;
+ * ACE_APPLICATION_PREALLOCATED_OBJECT_DEFINITIONS can be used
+ * to define the corresponding objects. The format of the ACE
+ * internal library definitions should be followed. And
+ * similarly, ACE_APPLICATION_PREALLOCATED_ARRAY_DECLARATIONS
+ * and ACE_APPLICATION_PREALLOCATED_ARRAY_DEFINITIONS can be
+ * used to preallocate arrays.
+ * By default, preallocation uses dynamic allocation. The
+ * preallocated objects and arrays are allocated off the heap in
+ * the ACE_Object_Manager constructor. To statically place the
+ * preallocated objects in program global data instead of on the
+ * heap, #define ACE_HAS_STATIC_PREALLOCATION prior to building
+ * the ACE library.
+ */
+template <class TYPE>
+class ACE_Managed_Object
+{
+public:
+ static TYPE *get_preallocated_object (ACE_Object_Manager::Preallocated_Object id)
+ {
+ // The preallocated objects are in a separate, "read-only" array so
+ // that this function doesn't need a lock. Also, because it is
+ // intended _only_ for use with hard-code values, it performs no
+ // range checking on "id".
+
+ // Cast the return type of the the object pointer based
+ // on the type of the function template parameter.
+ return &((ACE_Cleanup_Adapter<TYPE> *)
+ ACE_Object_Manager::preallocated_object[id])->object ();
+ }
+ // Get the preallocated object identified by "id". Returns a
+ // pointer to the object. Beware: no error indication is provided,
+ // because it can _only_ be used for accessing preallocated objects.
+ // Note: the function definition is inlined here so that it compiles
+ // on AIX 4.1 w/xlC v. 3.01.
+
+ static TYPE *get_preallocated_array (ACE_Object_Manager::Preallocated_Array id)
+ {
+ // The preallocated array are in a separate, "read-only" array so
+ // that this function doesn't need a lock. Also, because it is
+ // intended _only_ for use with hard-code values, it performs no
+ // range checking on "id".
+
+ // Cast the return type of the the object pointer based
+ // on the type of the function template parameter.
+ return &((ACE_Cleanup_Adapter<TYPE> *)
+ ACE_Object_Manager::preallocated_array[id])->object ();
+ }
+ // Get the preallocated array identified by "id". Returns a
+ // pointer to the array. Beware: no error indication is provided,
+ // because it can _only_ be used for accessing preallocated arrays.
+ // Note: the function definition is inlined here so that it compiles
+ // on AIX 4.1 w/xlC v. 3.01.
+
+private:
+ // Disallow instantiation of this class.
+ ACE_UNIMPLEMENTED_FUNC (ACE_Managed_Object (void))
+ ACE_UNIMPLEMENTED_FUNC (ACE_Managed_Object (const ACE_Managed_Object<TYPE> &))
+ ACE_UNIMPLEMENTED_FUNC (void operator= (const ACE_Managed_Object<TYPE> &))
+
+ friend class this_prevents_compiler_warning_about_only_private_constructors;
+};
+
+#if defined (__ACE_INLINE__)
+#include "Managed_Object.i"
+#endif /* __ACE_INLINE__ */
+
+#if defined (ACE_TEMPLATES_REQUIRE_SOURCE)
+#include "Managed_Object.cpp"
+#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */
+
+#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA)
+#pragma implementation ("Managed_Object.cpp")
+#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */
+
+#include "ace/post.h"
+#endif /* ACE_MANAGED_OBJECT_H */
diff --git a/ace/Utils/Templates/Managed_Object.i b/ace/Utils/Templates/Managed_Object.i
new file mode 100644
index 00000000000..d4dd6043418
--- /dev/null
+++ b/ace/Utils/Templates/Managed_Object.i
@@ -0,0 +1,18 @@
+/* -*- C++ -*- */
+// $Id$
+
+template <class TYPE>
+ACE_INLINE
+ACE_Cleanup_Adapter<TYPE>::ACE_Cleanup_Adapter (void)
+ // Note: don't explicitly initialize "object_", because TYPE may not
+ // have a default constructor. Let the compiler figure it out . . .
+{
+}
+
+template <class TYPE>
+ACE_INLINE
+TYPE &
+ACE_Cleanup_Adapter<TYPE>::object (void)
+{
+ return this->object_;
+}
diff --git a/ace/Utils/Templates/Map_Manager.cpp b/ace/Utils/Templates/Map_Manager.cpp
new file mode 100644
index 00000000000..611bb778fc4
--- /dev/null
+++ b/ace/Utils/Templates/Map_Manager.cpp
@@ -0,0 +1,692 @@
+// $Id$
+
+#ifndef ACE_MAP_MANAGER_C
+#define ACE_MAP_MANAGER_C
+
+#include "ace/Memory/Malloc.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "ace/Svcconf/Service_Config.h"
+#include "ace/Utils/Templates/Map_Manager.h"
+
+#if !defined (__ACE_INLINE__)
+#include "ace/Utils/Templates/Map_Manager.i"
+#endif /* __ACE_INLINE__ */
+
+ACE_RCSID(ace, Map_Manager, "$Id$")
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Map_Entry)
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Map_Manager)
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Map_Const_Iterator_Base)
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Map_Iterator_Base)
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Map_Const_Iterator)
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Map_Iterator)
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Map_Reverse_Iterator)
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> int
+ACE_Map_Manager<EXT_ID, INT_ID, ACE_LOCK>::open (size_t size,
+ ACE_Allocator *alloc)
+{
+ ACE_WRITE_GUARD_RETURN (ACE_LOCK, ace_mon, this->lock_, -1);
+
+ // Close old map (if any).
+ this->close_i ();
+
+ // Use the user specified allocator or the default singleton one.
+ if (alloc == 0)
+ alloc = ACE_Allocator::instance ();
+
+ this->allocator_ = alloc;
+
+ // This assertion is here to help track a situation that shouldn't
+ // happen.
+ ACE_ASSERT (size != 0);
+
+ // Active_Map_Manager depends on the <slot_index_> being of fixed
+ // size. It cannot be size_t because size_t is 64-bits on 64-bit
+ // platform and 32-bits on 32-bit platforms. Size of the <slot_index_>
+ // has to be consistent across platforms. ACE_UIN32 is chosen as
+ // ACE_UIN32_MAX is big enough. The assert is to ensure that the user
+ // doesn't open the ACE_Map_Manager with a bigger size than we can
+ // handle.
+ ACE_ASSERT (size <= ACE_UINT32_MAX);
+
+ // Resize from 0 to <size>. Note that this will also set up the
+ // circular free list.
+ return this->resize_i ((ACE_UINT32) size);
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> int
+ACE_Map_Manager<EXT_ID, INT_ID, ACE_LOCK>::close_i (void)
+{
+ // Free entries.
+ this->free_search_structure ();
+
+ // Reset sizes.
+ this->total_size_ = 0;
+ this->cur_size_ = 0;
+
+ // Reset circular free list.
+ this->free_list_.next (this->free_list_id ());
+ this->free_list_.prev (this->free_list_id ());
+
+ // Reset circular occupied list.
+ this->occupied_list_.next (this->occupied_list_id ());
+ this->occupied_list_.prev (this->occupied_list_id ());
+
+ return 0;
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> int
+ACE_Map_Manager<EXT_ID, INT_ID, ACE_LOCK>::bind_i (const EXT_ID &ext_id,
+ const INT_ID &int_id)
+{
+ // Try to find the key.
+ ACE_UINT32 slot = 0;
+ int result = this->find_and_return_index (ext_id,
+ slot);
+
+ if (result == 0)
+ // We found the key. Nothing to change.
+ return 1;
+ else
+ // We didn't find the key.
+ return this->shared_bind (ext_id,
+ int_id);
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> int
+ACE_Map_Manager<EXT_ID, INT_ID, ACE_LOCK>::next_free (ACE_UINT32 &free_slot)
+{
+ // Look in the free list for an empty slot.
+ free_slot = this->free_list_.next ();
+
+ // If we do find a free slot, return successfully.
+ if (free_slot != this->free_list_id ())
+ return 0;
+
+#if defined (ACE_HAS_LAZY_MAP_MANAGER)
+
+ // Move any free slots from occupied list to free list.
+ this->move_all_free_slots_from_occupied_list ();
+
+ // Try again in case we found any free slots in the occupied list.
+ free_slot = this->free_list_.next ();
+
+ // If we do find a free slot, return successfully.
+ if (free_slot != this->free_list_id ())
+ return 0;
+
+#endif /* ACE_HAS_LAZY_MAP_MANAGER */
+
+ // Resize the map.
+ int result = this->resize_i (this->new_size ());
+
+ // Check for errors.
+ if (result == 0)
+ // New free slot.
+ free_slot = this->free_list_.next ();
+
+ return result;
+}
+
+#if defined (ACE_HAS_LAZY_MAP_MANAGER)
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> void
+ACE_Map_Manager<EXT_ID, INT_ID, ACE_LOCK>::move_all_free_slots_from_occupied_list (void)
+{
+ //
+ // In the case of lazy map managers, the movement of free slots from
+ // the occupied list to the free list is delayed until we run out of
+ // free slots in the free list.
+ //
+
+ // Go through the entire occupied list, moving free slots to the
+ // free list. Note that all free slots in the occupied list are
+ // moved in this loop.
+ for (ACE_UINT32 i = this->occupied_list_.next ();
+ i != this->occupied_list_id ();
+ )
+ {
+ //
+ // Note the trick used here: Information about the current slot
+ // is first noted; <i> then moves to the next occupied slot;
+ // only after this is the slot (potentially) moved from the
+ // occupied list to the free list. This order of things, i.e.,
+ // moving <i> before moving the free slot is necessary,
+ // otherwise we'll forget which our next occupied slot is.
+ //
+
+ // Note information about current slot.
+ ACE_Map_Entry<EXT_ID, INT_ID> &current_slot = this->search_structure_[i];
+ ACE_UINT32 position_of_current_slot = i;
+
+ // Move <i> to next occupied slot.
+ i = this->search_structure_[i].next ();
+
+ // If current slot is free
+ if (current_slot.free_)
+ {
+ // Reset free flag to zero before moving to free list.
+ current_slot.free_ = 0;
+
+ // Move from occupied list to free list.
+ this->move_from_occupied_list_to_free_list (position_of_current_slot);
+ }
+ }
+}
+
+#endif /* ACE_HAS_LAZY_MAP_MANAGER */
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> void
+ACE_Map_Manager<EXT_ID, INT_ID, ACE_LOCK>::shared_move (ACE_UINT32 slot,
+ ACE_Map_Entry<EXT_ID, INT_ID> &current_list,
+ ACE_UINT32 current_list_id,
+ ACE_Map_Entry<EXT_ID, INT_ID> &new_list,
+ ACE_UINT32 new_list_id)
+{
+ // Grab the entry.
+ ENTRY &entry = this->search_structure_[slot];
+
+ // Remove from current list.
+
+ // Fix the entry before us.
+ ACE_UINT32 current_list_prev = entry.prev ();
+
+ if (current_list_prev == current_list_id)
+ current_list.next (entry.next ());
+ else
+ this->search_structure_[current_list_prev].next (entry.next ());
+
+ // Fix the entry after us.
+ ACE_UINT32 current_list_next = entry.next ();
+
+ if (current_list_next == current_list_id)
+ current_list.prev (entry.prev ());
+ else
+ this->search_structure_[current_list_next].prev (entry.prev ());
+
+ // Add to new list.
+
+ // Fix us.
+ ACE_UINT32 new_list_next = new_list.next ();
+ entry.next (new_list_next);
+ entry.prev (new_list_id);
+
+ // Fix entry before us.
+ new_list.next (slot);
+
+ // Fix entry after us.
+ if (new_list_next == new_list_id)
+ new_list.prev (slot);
+ else
+ this->search_structure_[new_list_next].prev (slot);
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> int
+ACE_Map_Manager<EXT_ID, INT_ID, ACE_LOCK>::shared_bind (const EXT_ID &ext_id,
+ const INT_ID &int_id)
+{
+ // This function assumes that the find() has already been done, and
+ // therefore, simply adds to the map.
+
+ // Find an empty slot.
+ ACE_UINT32 slot = 0;
+ int result = this->next_free (slot);
+
+ if (result == 0)
+ {
+ // Copy key and value.
+ this->search_structure_[slot].int_id_ = int_id;
+ this->search_structure_[slot].ext_id_ = ext_id;
+
+ // Move from free list to occupied list
+ this->move_from_free_list_to_occupied_list (slot);
+
+ // Update the current size.
+ ++this->cur_size_;
+ }
+
+ return result;
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> int
+ACE_Map_Manager<EXT_ID, INT_ID, ACE_LOCK>::rebind_i (const EXT_ID &ext_id,
+ const INT_ID &int_id,
+ EXT_ID &old_ext_id,
+ INT_ID &old_int_id)
+{
+ // First try to find the key.
+ ACE_UINT32 slot = 0;
+ int result = this->find_and_return_index (ext_id,
+ slot);
+ if (result == 0)
+ {
+ // We found it, so make copies of the old entries and rebind
+ // current entries.
+ ENTRY &ss = this->search_structure_[slot];
+ old_ext_id = ss.ext_id_;
+ old_int_id = ss.int_id_;
+ ss.ext_id_ = ext_id;
+ ss.int_id_ = int_id;
+
+ // Sync changed entry.
+ this->allocator_->sync (&ss, sizeof ss);
+
+ return 1;
+ }
+ else
+ // We didn't find it, so let's add it.
+ return this->shared_bind (ext_id,
+ int_id);
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> int
+ACE_Map_Manager<EXT_ID, INT_ID, ACE_LOCK>::rebind_i (const EXT_ID &ext_id,
+ const INT_ID &int_id,
+ INT_ID &old_int_id)
+{
+ // First try to find the key.
+ ACE_UINT32 slot = 0;
+ int result = this->find_and_return_index (ext_id,
+ slot);
+ if (result == 0)
+ {
+ // We found it, so make copies of the old entries and rebind
+ // current entries.
+ ENTRY &ss = this->search_structure_[slot];
+ old_int_id = ss.int_id_;
+ ss.ext_id_ = ext_id;
+ ss.int_id_ = int_id;
+
+ // Sync changed entry.
+ this->allocator_->sync (&ss, sizeof ss);
+
+ return 1;
+ }
+ else
+ // We didn't find it, so let's add it.
+ return this->shared_bind (ext_id,
+ int_id);
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> int
+ACE_Map_Manager<EXT_ID, INT_ID, ACE_LOCK>::rebind_i (const EXT_ID &ext_id,
+ const INT_ID &int_id)
+{
+ // First try to find the key.
+ ACE_UINT32 slot = 0;
+ int result = this->find_and_return_index (ext_id,
+ slot);
+ if (result == 0)
+ {
+ // We found it, so rebind current entries.
+ ENTRY &ss = this->search_structure_[slot];
+ ss.ext_id_ = ext_id;
+ ss.int_id_ = int_id;
+
+ // Sync changed entry.
+ this->allocator_->sync (&ss, sizeof ss);
+
+ return 1;
+ }
+ else
+ // We didn't find it, so let's add it.
+ return this->shared_bind (ext_id,
+ int_id);
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> int
+ACE_Map_Manager<EXT_ID, INT_ID, ACE_LOCK>::trybind_i (const EXT_ID &ext_id,
+ INT_ID &int_id)
+{
+ // Try to find the key.
+ ACE_UINT32 slot = 0;
+ int result = this->find_and_return_index (ext_id,
+ slot);
+ if (result == 0)
+ {
+ // Key was found. Make a copy of value, but *don't* update
+ // anything in the map!
+ int_id = this->search_structure_[slot].int_id_;
+ return 1;
+ }
+ else
+ // We didn't find it, so let's bind it!
+ return this->bind_i (ext_id,
+ int_id);
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> int
+ACE_Map_Manager<EXT_ID, INT_ID, ACE_LOCK>::find_and_return_index (const EXT_ID &ext_id,
+ ACE_UINT32 &slot)
+{
+ // Go through the entire occupied list looking for the key.
+ for (ACE_UINT32 i = this->occupied_list_.next ();
+ i != this->occupied_list_id ();
+ i = this->search_structure_[i].next ())
+ {
+#if defined (ACE_HAS_LAZY_MAP_MANAGER)
+ if (this->search_structure_[i].free_)
+ continue;
+#endif /* ACE_HAS_LAZY_MAP_MANAGER */
+
+ if (this->equal (this->search_structure_[i].ext_id_,
+ ext_id))
+ {
+ // If found, return slot.
+ slot = i;
+ return 0;
+ }
+ }
+
+ // Key was not found.
+ return -1;
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> void
+ACE_Map_Manager<EXT_ID, INT_ID, ACE_LOCK>::unbind_all (void)
+{
+ // Go through the entire occupied list.
+ for (ACE_UINT32 i = this->occupied_list_.next ();
+ i != this->occupied_list_id ();
+ )
+ {
+ //
+ // Note the trick used here: Information about the current slot
+ // is first noted; <i> then moves to the next occupied slot;
+ // only after this is the slot (potentially) moved from the
+ // occupied list to the free list. This order of things, i.e.,
+ // moving <i> before moving the free slot is necessary,
+ // otherwise we'll forget which our next occupied slot is.
+ //
+
+ // Note information about current slot.
+ ACE_Map_Entry<EXT_ID, INT_ID> &current_slot =
+ this->search_structure_[i];
+ ACE_UINT32 position_of_current_slot = i;
+
+ // Move <i> to next occupied slot.
+ i = current_slot.next ();
+
+#if defined (ACE_HAS_LAZY_MAP_MANAGER)
+ if (current_slot.free_)
+ continue;
+#endif /* ACE_HAS_LAZY_MAP_MANAGER */
+
+ this->unbind_slot (position_of_current_slot);
+ }
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> int
+ACE_Map_Manager<EXT_ID, INT_ID, ACE_LOCK>::find_i (const EXT_ID &ext_id,
+ INT_ID &int_id)
+{
+ // Try to find the key.
+ ACE_UINT32 slot = 0;
+ int result = this->find_and_return_index (ext_id,
+ slot);
+ if (result == 0)
+ // Key was found. Make a copy of value.
+ int_id = this->search_structure_[slot].int_id_;
+
+ return result;
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> int
+ACE_Map_Manager<EXT_ID, INT_ID, ACE_LOCK>::unbind_and_return_index (const EXT_ID &ext_id,
+ ACE_UINT32 &slot)
+{
+ // Try to find the key.
+ int result = this->find_and_return_index (ext_id,
+ slot);
+
+ if (result == 0)
+ this->unbind_slot (slot);
+
+ return result;
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> void
+ACE_Map_Manager<EXT_ID, INT_ID, ACE_LOCK>::unbind_slot (ACE_UINT32 slot)
+{
+
+#if defined (ACE_HAS_LAZY_MAP_MANAGER)
+
+ //
+ // In the case of lazy map managers, the movement of free slots
+ // from the occupied list to the free list is delayed until we
+ // run out of free slots in the free list.
+ //
+
+ this->search_structure_[slot].free_ = 1;
+
+#else
+
+ // Move from occupied list to free list.
+ this->move_from_occupied_list_to_free_list (slot);
+
+#endif /* ACE_HAS_LAZY_MAP_MANAGER */
+
+ // Update the current size.
+ --this->cur_size_;
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> int
+ACE_Map_Manager<EXT_ID, INT_ID, ACE_LOCK>::unbind_i (const EXT_ID &ext_id,
+ INT_ID &int_id)
+{
+ // Unbind the entry.
+ ACE_UINT32 slot = 0;
+ int result = this->unbind_and_return_index (ext_id,
+ slot);
+ if (result == 0)
+ // If found, copy the value.
+ int_id = this->search_structure_[slot].int_id_;
+
+ return result;
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> int
+ACE_Map_Manager<EXT_ID, INT_ID, ACE_LOCK>::resize_i (ACE_UINT32 new_size)
+{
+ ACE_UINT32 i;
+ ENTRY *temp = 0;
+
+ // Allocate new memory.
+ ACE_ALLOCATOR_RETURN (temp,
+ (ENTRY *) this->allocator_->malloc (new_size * sizeof (ENTRY)),
+ -1);
+
+ // Copy over the occupied entires.
+ for (i = this->occupied_list_.next ();
+ i != this->occupied_list_id ();
+ i = this->search_structure_[i].next ())
+ // Call the copy constructor using operator placement new.
+ new (&(temp[i])) ENTRY (this->search_structure_[i]);
+
+ // Copy over the free entires.
+ for (i = this->free_list_.next ();
+ i != this->free_list_id ();
+ i = this->search_structure_[i].next ())
+ // Call the copy constructor using operator placement new.
+ new (&(temp[i])) ENTRY (this->search_structure_[i]);
+
+ // Construct the new elements.
+ for (i = this->total_size_; i < new_size; i++)
+ {
+ // Call the constructor for each element in the array using
+ // operator placement new. Note that this requires a default
+ // constructor for <EXT_ID> and <INT_ID>.
+ new (&(temp[i])) ENTRY;
+ temp[i].next (i + 1);
+ temp[i].prev (i - 1);
+
+#if defined (ACE_HAS_LAZY_MAP_MANAGER)
+
+ // Even though this slot is initially free, we need the <free_>
+ // flag to be zero so that we don't have to set it when the slot
+ // is moved to the occupied list. In addition, this flag has no
+ // meaning while this slot is in the free list.
+ temp[i].free_ = 0;
+
+#endif /* ACE_HAS_LAZY_MAP_MANAGER */
+
+ }
+
+ // Add new entries to the free list.
+ this->free_list_.next (this->total_size_);
+ this->free_list_.prev (new_size - 1);
+ temp[new_size - 1].next (this->free_list_id ());
+ temp[this->total_size_].prev (this->free_list_id ());
+
+ // Remove/free old elements, update the new totoal size.
+ this->free_search_structure ();
+ this->total_size_ = new_size;
+
+ // Start using new elements.
+ this->search_structure_ = temp;
+
+ return 0;
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> ACE_UINT32
+ACE_Map_Manager<EXT_ID, INT_ID, ACE_LOCK>::new_size (void)
+{
+ // Calculate the new size.
+ ACE_UINT32 current_size = this->total_size_;
+
+ if (current_size < MAX_EXPONENTIAL)
+ // Exponentially increase if we haven't reached MAX_EXPONENTIAL.
+ current_size *= 2;
+ else
+ // Linear increase if we have reached MAX_EXPONENTIAL.
+ current_size += LINEAR_INCREASE;
+
+ // This should be the new size.
+ return current_size;
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> void
+ACE_Map_Manager<EXT_ID, INT_ID, ACE_LOCK>::free_search_structure (void)
+{
+ // Free up the structure.
+ if (this->search_structure_ != 0)
+ {
+ for (ACE_UINT32 i = 0; i < this->total_size_; i++)
+ // Explicitly call the destructor.
+ {
+ ENTRY *ss = &this->search_structure_[i];
+ // The "if" second argument results in a no-op instead of
+ // deallocation.
+ ACE_DES_FREE_TEMPLATE2 (ss, ACE_NOOP,
+ ACE_Map_Entry, EXT_ID, INT_ID);
+ }
+
+ // Actually free the memory.
+ this->allocator_->free (this->search_structure_);
+ this->search_structure_ = 0;
+ }
+}
+
+template <class EXT_ID, class INT_ID> void
+ACE_Map_Entry<EXT_ID, INT_ID>::dump (void) const
+{
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("next_ = %d"), this->next_));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("prev_ = %d"), this->prev_));
+
+#if defined (ACE_HAS_LAZY_MAP_MANAGER)
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("free_ = %d"), this->free_));
+#endif /* ACE_HAS_LAZY_MAP_MANAGER */
+
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> void
+ACE_Map_Manager<EXT_ID, INT_ID, ACE_LOCK>::dump (void) const
+{
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("total_size_ = %d"), this->total_size_));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\ncur_size_ = %d"), this->cur_size_));
+ this->allocator_->dump ();
+ this->lock_.dump ();
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> void
+ACE_Map_Iterator_Base<EXT_ID, INT_ID, ACE_LOCK>::dump_i (void) const
+{
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("next_ = %d"), this->next_));
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> void
+ACE_Map_Const_Iterator_Base<EXT_ID, INT_ID, ACE_LOCK>::dump_i (void) const
+{
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("next_ = %d"), this->next_));
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK>
+ACE_Map_Entry<EXT_ID, INT_ID>&
+ACE_Map_Iterator_Base<EXT_ID, INT_ID, ACE_LOCK>::operator* (void) const
+{
+ // @@ This function should be inlined. We moved it here to avoid a
+ // compiler bug in SunCC 4.2. Once we know the correct patch to fix
+ // the compiler problem, it should be moved back to .i file again.
+ ACE_Map_Entry<EXT_ID, INT_ID> *retv = 0;
+
+ int result = this->next (retv);
+ ACE_ASSERT (result != 0);
+ ACE_UNUSED_ARG (result);
+
+ return *retv;
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK>
+ACE_Map_Entry<EXT_ID, INT_ID>&
+ACE_Map_Const_Iterator_Base<EXT_ID, INT_ID, ACE_LOCK>::operator* (void) const
+{
+ // @@ This function should be inlined. We moved it here to avoid a
+ // compiler bug in SunCC 4.2. Once we know the correct patch to fix
+ // the compiler problem, it should be moved back to .i file again.
+ ACE_Map_Entry<EXT_ID, INT_ID> *retv = 0;
+
+ int result = this->next (retv);
+ ACE_ASSERT (result != 0);
+ ACE_UNUSED_ARG (result);
+
+ return *retv;
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> void
+ACE_Map_Iterator<EXT_ID, INT_ID, ACE_LOCK>::dump (void) const
+{
+ this->dump_i ();
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> void
+ACE_Map_Const_Iterator<EXT_ID, INT_ID, ACE_LOCK>::dump (void) const
+{
+ this->dump_i ();
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> void
+ACE_Map_Reverse_Iterator<EXT_ID, INT_ID, ACE_LOCK>::dump (void) const
+{
+ this->dump_i ();
+}
+
+#endif /* ACE_MAP_MANAGER_C */
diff --git a/ace/Utils/Templates/Map_Manager.h b/ace/Utils/Templates/Map_Manager.h
new file mode 100644
index 00000000000..60e4c45b431
--- /dev/null
+++ b/ace/Utils/Templates/Map_Manager.h
@@ -0,0 +1,700 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Map_Manager.h
+ *
+ * $Id$
+ *
+ * @author Douglas C. Schmidt <schmidt@cs.wustl.edu>
+ */
+//=============================================================================
+
+#ifndef ACE_MAP_MANAGER_H
+#define ACE_MAP_MANAGER_H
+#include "ace/pre.h"
+
+#include "ace/OS/OS.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "ace/Threads/Synch.h"
+#include "ace/Logging/Log_Msg.h"
+
+// Forward declaration.
+class ACE_Allocator;
+
+/**
+ * @class ACE_Map_Entry
+ *
+ * @brief An entry in the Map.
+ */
+template <class EXT_ID, class INT_ID>
+class ACE_Map_Entry
+{
+public:
+# if ! defined (ACE_HAS_BROKEN_NOOP_DTORS)
+ /// We need this destructor to keep some compilers from complaining.
+ /// It's just a no-op, however.
+ ~ACE_Map_Entry (void);
+# endif /* ! defined (ACE_HAS_BROKEN_NOOP_DTORS) */
+
+ /// Key used to look up an entry.
+ EXT_ID ext_id_;
+
+ /// The contents of the entry itself.
+ INT_ID int_id_;
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+ // = These are really private, but unfortunately template friends
+ // are not portable.
+
+ /// Get/Set next entry.
+ ACE_UINT32 next (void) const;
+ void next (ACE_UINT32 n);
+
+ /// Get/Set prev entry.
+ ACE_UINT32 prev (void) const;
+ void prev (ACE_UINT32 p);
+
+ /// Keeps track of the next entry.
+ ACE_UINT32 next_;
+
+ /// Keeps track of the previous entry.
+ ACE_UINT32 prev_;
+
+#if defined (ACE_HAS_LAZY_MAP_MANAGER)
+
+ /// Is this entry free?
+ int free_;
+
+#endif /* ACE_HAS_LAZY_MAP_MANAGER */
+
+};
+
+// Forward decl.
+template <class EXT_ID, class INT_ID, class ACE_LOCK>
+class ACE_Map_Iterator_Base;
+
+// Forward decl.
+template <class EXT_ID, class INT_ID, class ACE_LOCK>
+class ACE_Map_Const_Iterator_Base;
+
+// Forward decl.
+template <class EXT_ID, class INT_ID, class ACE_LOCK>
+class ACE_Map_Iterator;
+
+// Forward decl.
+template <class EXT_ID, class INT_ID, class ACE_LOCK>
+class ACE_Map_Const_Iterator;
+
+// Forward decl.
+template <class EXT_ID, class INT_ID, class ACE_LOCK>
+class ACE_Map_Reverse_Iterator;
+
+/**
+ * @class ACE_Map_Manager
+ *
+ * @brief Define a map abstraction that associates <EXT_ID>s with
+ * <INT_ID>s.
+ *
+ * The <EXT_ID> must support <operator==>. This constraint can
+ * be alleviated via template specialization, as shown in the
+ * $ACE_ROOT/tests/Conn_Test.cpp test.
+ * This class uses an <ACE_Allocator> to allocate memory. The
+ * user can make this a persistant class by providing an
+ * <ACE_Allocator> with a persistable memory pool.
+ * This implementation of a map uses an array, which is searched
+ * linearly. For more efficient searching you should use the
+ * <ACE_Hash_Map_Manager>.
+ */
+template <class EXT_ID, class INT_ID, class ACE_LOCK>
+class ACE_Map_Manager
+{
+public:
+ friend class ACE_Map_Iterator_Base<EXT_ID, INT_ID, ACE_LOCK>;
+ friend class ACE_Map_Const_Iterator_Base<EXT_ID, INT_ID, ACE_LOCK>;
+ friend class ACE_Map_Iterator<EXT_ID, INT_ID, ACE_LOCK>;
+ friend class ACE_Map_Const_Iterator<EXT_ID, INT_ID, ACE_LOCK>;
+ friend class ACE_Map_Reverse_Iterator<EXT_ID, INT_ID, ACE_LOCK>;
+
+ // = Traits.
+ typedef EXT_ID KEY;
+ typedef INT_ID VALUE;
+ typedef ACE_Map_Entry<EXT_ID, INT_ID> ENTRY;
+ typedef ACE_Map_Iterator<EXT_ID, INT_ID, ACE_LOCK> ITERATOR;
+ typedef ACE_Map_Const_Iterator<EXT_ID, INT_ID, ACE_LOCK> CONST_ITERATOR;
+ typedef ACE_Map_Reverse_Iterator<EXT_ID, INT_ID, ACE_LOCK> REVERSE_ITERATOR;
+
+ typedef ACE_Map_Iterator<EXT_ID, INT_ID, ACE_LOCK> iterator;
+ typedef ACE_Map_Const_Iterator<EXT_ID, INT_ID, ACE_LOCK> const_iterator;
+ typedef ACE_Map_Reverse_Iterator<EXT_ID, INT_ID, ACE_LOCK> reverse_iterator;
+
+ // = Initialization and termination methods.
+ /// Initialize a <Map_Manager> with the <ACE_DEFAULT_MAP_SIZE>.
+ ACE_Map_Manager (ACE_Allocator *alloc = 0);
+
+ /// Initialize a <Map_Manager> with <size> entries.
+ ACE_Map_Manager (size_t size,
+ ACE_Allocator *alloc = 0);
+
+ /// Initialize a <Map_Manager> with size <length>.
+ int open (size_t length = ACE_DEFAULT_MAP_SIZE,
+ ACE_Allocator *alloc = 0);
+
+ /// Close down a <Map_Manager> and release dynamically allocated
+ /// resources.
+ int close (void);
+
+ /// Close down a <Map_Manager> and release dynamically allocated
+ /// resources.
+ ~ACE_Map_Manager (void);
+
+ /**
+ * Associate <ext_id> with <int_id>. If <ext_id> is already in the
+ * map then the <Map_Entry> is not changed. Returns 0 if a new
+ * entry is bound successfully, returns 1 if an attempt is made to
+ * bind an existing entry, and returns -1 if failures occur.
+ */
+ int bind (const EXT_ID &ext_id,
+ const INT_ID &int_id);
+
+ /**
+ * Reassociate <ext_id> with <int_id>. If <ext_id> is not in the
+ * map then behaves just like <bind>. Otherwise, store the old
+ * values of <ext_id> and <int_id> into the "out" parameters and
+ * rebind the new parameters. This is very useful if you need to
+ * have an atomic way of updating <Map_Entries> and you also need
+ * full control over memory allocation. Returns 0 if a new entry is
+ * bound successfully, returns 1 if an existing entry was rebound,
+ * and returns -1 if failures occur.
+ */
+ int rebind (const EXT_ID &ext_id,
+ const INT_ID &int_id,
+ EXT_ID &old_ext_id,
+ INT_ID &old_int_id);
+
+ /**
+ * Reassociate <ext_id> with <int_id>. If <ext_id> is not in the
+ * map then behaves just like <bind>. Otherwise, store the old
+ * values of <int_id> into the "out" parameter and rebind the new
+ * parameters. Returns 0 if a new entry is bound successfully,
+ * returns 1 if an existing entry was rebound, and returns -1 if
+ * failures occur.
+ */
+ int rebind (const EXT_ID &ext_id,
+ const INT_ID &int_id,
+ INT_ID &old_int_id);
+
+ /// Reassociate <ext_id> with <int_id>. Old values in the map are
+ /// ignored.
+ int rebind (const EXT_ID &ext_id,
+ const INT_ID &int_id);
+
+ /**
+ * Associate <ext_id> with <int_id> if and only if <ext_id> is not
+ * in the map. If <ext_id> is already in the map then the <int_id>
+ * parameter is overwritten with the existing value in the map
+ * Returns 0 if a new entry is bound successfully, returns 1 if an
+ * attempt is made to bind an existing entry, and returns -1 if
+ * failures occur.
+ */
+ int trybind (const EXT_ID &ext_id,
+ INT_ID &int_id);
+
+ /// Locate <ext_id> and pass out parameter via <int_id>.
+ /// Returns 0 if found, returns -1 if not found.
+ int find (const EXT_ID &ext_id,
+ INT_ID &int_id) const;
+
+ /// Returns 0 if the <ext_id> is in the mapping, otherwise -1.
+ int find (const EXT_ID &ext_id) const;
+
+ /**
+ * Unbind (remove) the <ext_id> from the map. Don't return the
+ * <int_id> to the caller (this is useful for collections where the
+ * <int_id>s are *not* dynamically allocated...) Returns 0 if
+ * successful, else -1.
+ */
+ int unbind (const EXT_ID &ext_id);
+
+ /**
+ * Break any association of <ext_id>. Returns the value of <int_id>
+ * in case the caller needs to deallocate memory. Returns 0 if
+ * successful, else -1.
+ */
+ int unbind (const EXT_ID &ext_id,
+ INT_ID &int_id);
+
+ /**
+ * Unbind all entires.
+ */
+ void unbind_all (void);
+
+ /// Return the current size of the map.
+ size_t current_size (void) const;
+
+ /// Return the total size of the map.
+ size_t total_size (void) const;
+
+ /**
+ * Returns a reference to the underlying <ACE_LOCK>. This makes it
+ * possible to acquire the lock explicitly, which can be useful in
+ * some cases if you instantiate the <ACE_Atomic_Op> with an
+ * <ACE_Recursive_Mutex> or <ACE_Process_Mutex>, or if you need to
+ * guard the state of an iterator. NOTE: the right name would be
+ * <lock>, but HP/C++ will choke on that!
+ */
+ ACE_LOCK &mutex (void);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ // = STL styled iterator factory functions.
+
+ /// Return forward iterator.
+ ACE_Map_Iterator<EXT_ID, INT_ID, ACE_LOCK> begin (void);
+ ACE_Map_Iterator<EXT_ID, INT_ID, ACE_LOCK> end (void);
+
+ /// Return reverse iterator.
+ ACE_Map_Reverse_Iterator<EXT_ID, INT_ID, ACE_LOCK> rbegin (void);
+ ACE_Map_Reverse_Iterator<EXT_ID, INT_ID, ACE_LOCK> rend (void);
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+protected:
+
+ // = The following methods do the actual work.
+
+ // These methods assume that the locks are held by the private
+ // methods.
+
+ /// Performs the binding of <ext_id> to <int_id>. Must be called
+ /// with locks held.
+ int bind_i (const EXT_ID &ext_id,
+ const INT_ID &int_id);
+
+ /// Bind an entry (without finding first). Must be called with locks
+ /// held.
+ int shared_bind (const EXT_ID &ext_id,
+ const INT_ID &int_id);
+
+ /// Performs a rebinding of <ext_it> to <int_id>. Also, recovers old
+ /// values. Must be called with locks held.
+ int rebind_i (const EXT_ID &ext_id,
+ const INT_ID &int_id,
+ EXT_ID &old_ext_id,
+ INT_ID &old_int_id);
+
+ /// Performs a rebinding of <ext_it> to <int_id>. Also, recovers old
+ /// values. Must be called with locks held.
+ int rebind_i (const EXT_ID &ext_id,
+ const INT_ID &int_id,
+ INT_ID &old_int_id);
+
+ /// Performs a rebinding of <ext_it> to <int_id>. Must be called
+ /// with locks held.
+ int rebind_i (const EXT_ID &ext_id,
+ const INT_ID &int_id);
+
+ /// Performs a conditional bind of <int_id> using <ext_id> as the
+ /// key. Must be called with locks held.
+ int trybind_i (const EXT_ID &ext_id,
+ INT_ID &int_id);
+
+ /// Performs a find of <int_id> using <ext_id> as the key. Must be
+ /// called with locks held.
+ int find_i (const EXT_ID &ext_id,
+ INT_ID &int_id);
+
+ /// Performs a find using <ext_id> as the key. Must be called with
+ /// locks held.
+ int find_and_return_index (const EXT_ID &ext_id,
+ ACE_UINT32 &slot);
+
+ /// Performs an unbind of <int_id> using <ext_id> as the key. Must
+ /// be called with locks held.
+ int unbind_i (const EXT_ID &ext_id,
+ INT_ID &int_id);
+
+ /// Performs an unbind using <ext_id> as the key. Must be called
+ /// with locks held.
+ int unbind_i (const EXT_ID &ext_id);
+
+ /// Performs an unbind using <ext_id> as the key. Must be called
+ /// with locks held.
+ int unbind_and_return_index (const EXT_ID &ext_id,
+ ACE_UINT32 &slot);
+
+ /// Unbind <slot>.
+ void unbind_slot (ACE_UINT32 slot);
+
+ /// Resize the map. Must be called with locks held.
+ int resize_i (ACE_UINT32 size);
+
+ /// Close down a <Map_Manager>. Must be called with locks held.
+ int close_i (void);
+
+ /// Returns 1 if <id1> == <id2>, else 0. This is defined as a
+ /// separate method to facilitate template specialization.
+ int equal (const EXT_ID &id1, const EXT_ID &id2);
+
+ /// This function returns the new size of the Map Manager. This
+ /// function is called when we run out of room and need to resize.
+ ACE_UINT32 new_size (void);
+
+ /// Explicitly call the destructors and free up the
+ /// <search_structure_>.
+ void free_search_structure (void);
+
+ /// Id of the free list sentinel.
+ ACE_UINT32 free_list_id (void) const;
+
+ /// Id of the occupied list sentinel.
+ ACE_UINT32 occupied_list_id (void) const;
+
+ /// Finds the next free slot.
+ int next_free (ACE_UINT32 &slot);
+
+ /// Move from free list to occupied list.
+ void move_from_free_list_to_occupied_list (ACE_UINT32 slot);
+
+ /// Move from occupied list to free list.
+ void move_from_occupied_list_to_free_list (ACE_UINT32 slot);
+
+#if defined (ACE_HAS_LAZY_MAP_MANAGER)
+
+ /**
+ * In the case of lazy map managers, the movement of free slots from
+ * the occupied list to the free list is delayed until we run out of
+ * free slots in the free list. This function goes through the
+ * entire occupied list, moving free slots to the free list.
+ */
+ void move_all_free_slots_from_occupied_list (void);
+
+#endif /* ACE_HAS_LAZY_MAP_MANAGER */
+
+ /// Move helper.
+ void shared_move (ACE_UINT32 slot,
+ ACE_Map_Entry<EXT_ID, INT_ID> &current_list,
+ ACE_UINT32 current_list_id,
+ ACE_Map_Entry<EXT_ID, INT_ID> &new_list,
+ ACE_UINT32 new_list_id);
+
+ /// Pointer to a memory allocator.
+ ACE_Allocator *allocator_;
+
+ /// Synchronization variable for the MT_SAFE <ACE_Map_Manager>.
+ ACE_LOCK lock_;
+
+ /// Implement the Map as a resizeable array of <ACE_Map_Entry>.
+ ACE_Map_Entry<EXT_ID, INT_ID> *search_structure_;
+
+ /// Total number of elements in this->search_structure_.
+ ACE_UINT32 total_size_;
+
+ /// Current size of the map.
+ ACE_UINT32 cur_size_;
+
+ /// Free list.
+ ACE_Map_Entry<EXT_ID, INT_ID> free_list_;
+
+ /// Occupied list.
+ ACE_Map_Entry<EXT_ID, INT_ID> occupied_list_;
+
+ enum
+ {
+ /// Grow map exponentially up to 64K
+ MAX_EXPONENTIAL = 64 * 1024,
+
+ /// Afterwards grow in chunks of 32K
+ LINEAR_INCREASE = 32 * 1024
+ };
+
+private:
+ // = Disallow these operations.
+ ACE_UNIMPLEMENTED_FUNC (void operator= (const ACE_Map_Manager<EXT_ID, INT_ID, ACE_LOCK> &))
+ ACE_UNIMPLEMENTED_FUNC (ACE_Map_Manager (const ACE_Map_Manager<EXT_ID, INT_ID, ACE_LOCK> &))
+};
+
+/**
+ * @class ACE_Map_Iterator_Base
+ *
+ * @brief Iterator for the <ACE_Map_Manager>.
+ *
+ * This class factors out common code from its templatized
+ * subclasses.
+ */
+template <class EXT_ID, class INT_ID, class ACE_LOCK>
+class ACE_Map_Iterator_Base
+{
+public:
+ // = Initialization method.
+ /// Contructor. If head != 0, the iterator constructed is positioned
+ /// at the head of the map, it is positioned at the end otherwise.
+ ACE_Map_Iterator_Base (ACE_Map_Manager <EXT_ID, INT_ID, ACE_LOCK> &mm);
+
+ // = Iteration methods.
+
+ /// Pass back the next <entry> that hasn't been seen in the Set.
+ /// Returns 0 when all items have been seen, else 1.
+ int next (ACE_Map_Entry<EXT_ID, INT_ID> *&next_entry) const;
+
+ /// Returns 1 when all items have been seen, else 0.
+ int done (void) const;
+
+ /// Returns a reference to the interal element <this> is pointing to.
+ ACE_Map_Entry<EXT_ID, INT_ID>& operator* (void) const;
+
+ /// Returns reference the Map_Manager that is being iterated
+ /// over.
+ ACE_Map_Manager<EXT_ID, INT_ID, ACE_LOCK>& map (void);
+
+ /// Check if two iterators point to the same position
+ int operator== (const ACE_Map_Iterator_Base<EXT_ID, INT_ID, ACE_LOCK> &) const;
+ int operator!= (const ACE_Map_Iterator_Base<EXT_ID, INT_ID, ACE_LOCK> &) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+protected:
+ /// Move forward by one element in the set. Returns 0 when there's
+ /// no more item in the set after the current items, else 1.
+ int forward_i (void);
+
+ /// Move backware by one element in the set. Returns 0 when there's
+ /// no more item in the set before the current item, else 1.
+ int reverse_i (void);
+
+ /// Dump the state of an object.
+ void dump_i (void) const;
+
+ /// Map we are iterating over.
+ ACE_Map_Manager <EXT_ID, INT_ID, ACE_LOCK> *map_man_;
+
+ /// Keeps track of how far we've advanced...
+ ACE_UINT32 next_;
+};
+
+/**
+ * @class ACE_Map_Const_Iterator_Base
+ *
+ * @brief Const iterator for the <ACE_Map_Manager>.
+ *
+ * This class factors out common code from its templatized
+ * subclasses.
+ */
+template <class EXT_ID, class INT_ID, class ACE_LOCK>
+class ACE_Map_Const_Iterator_Base
+{
+public:
+ // = Initialization method.
+ /// Contructor. If head != 0, the iterator constructed is positioned
+ /// at the head of the map, it is positioned at the end otherwise.
+ ACE_Map_Const_Iterator_Base (const ACE_Map_Manager <EXT_ID, INT_ID, ACE_LOCK> &mm);
+
+ // = Iteration methods.
+
+ /// Pass back the next <entry> that hasn't been seen in the Set.
+ /// Returns 0 when all items have been seen, else 1.
+ int next (ACE_Map_Entry<EXT_ID, INT_ID> *&next_entry) const;
+
+ /// Returns 1 when all items have been seen, else 0.
+ int done (void) const;
+
+ /// Returns a reference to the interal element <this> is pointing to.
+ ACE_Map_Entry<EXT_ID, INT_ID>& operator* (void) const;
+
+ /// Returns reference the Map_Manager that is being iterated
+ /// over.
+ const ACE_Map_Manager<EXT_ID, INT_ID, ACE_LOCK>& map (void) const;
+
+ /// Check if two iterators point to the same position
+ int operator== (const ACE_Map_Const_Iterator_Base<EXT_ID, INT_ID, ACE_LOCK> &) const;
+ int operator!= (const ACE_Map_Const_Iterator_Base<EXT_ID, INT_ID, ACE_LOCK> &) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+protected:
+ /// Move forward by one element in the set. Returns 0 when there's
+ /// no more item in the set after the current items, else 1.
+ int forward_i (void);
+
+ /// Move backware by one element in the set. Returns 0 when there's
+ /// no more item in the set before the current item, else 1.
+ int reverse_i (void);
+
+ /// Dump the state of an object.
+ void dump_i (void) const;
+
+ /// Map we are iterating over.
+ const ACE_Map_Manager <EXT_ID, INT_ID, ACE_LOCK> *map_man_;
+
+ /// Keeps track of how far we've advanced...
+ ACE_UINT32 next_;
+};
+
+/**
+ * @class ACE_Map_Iterator
+ *
+ * @brief Forward iterator for the <ACE_Map_Manager>.
+ *
+ * This class does not perform any internal locking of the
+ * <ACE_Map_Manager> it is iterating upon since locking is
+ * inherently inefficient and/or error-prone within an STL-style
+ * iterator. If you require locking, you can explicitly use an
+ * <ACE_Guard> or <ACE_Read_Guard> on the <ACE_Map_Manager>'s
+ * internal lock, which is accessible via its <mutex> method.
+ */
+template <class EXT_ID, class INT_ID, class ACE_LOCK>
+class ACE_Map_Iterator : public ACE_Map_Iterator_Base<EXT_ID, INT_ID, ACE_LOCK>
+{
+public:
+ // = Initialization method.
+ ACE_Map_Iterator (ACE_Map_Manager <EXT_ID, INT_ID, ACE_LOCK> &mm,
+ int pass_end = 0);
+
+ // = Iteration methods.
+
+ /// Move forward by one element in the set. Returns 0 when all the
+ /// items in the set have been seen, else 1.
+ int advance (void);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ // = STL styled iteration, compare, and reference functions.
+
+ /// Prefix advance.
+ ACE_Map_Iterator<EXT_ID, INT_ID, ACE_LOCK> &operator++ (void);
+
+ /// Postfix advance.
+ ACE_Map_Iterator<EXT_ID, INT_ID, ACE_LOCK> operator++ (int);
+
+ /// Prefix reverse.
+ ACE_Map_Iterator<EXT_ID, INT_ID, ACE_LOCK> &operator-- (void);
+
+ /// Postfix reverse.
+ ACE_Map_Iterator<EXT_ID, INT_ID, ACE_LOCK> operator-- (int);
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+};
+
+/**
+ * @class ACE_Map_Const_Iterator
+ *
+ * @brief Forward const iterator for the <ACE_Map_Manager>.
+ *
+ * This class does not perform any internal locking of the
+ * <ACE_Map_Manager> it is iterating upon since locking is
+ * inherently inefficient and/or error-prone within an STL-style
+ * iterator. If you require locking, you can explicitly use an
+ * <ACE_Guard> or <ACE_Read_Guard> on the <ACE_Map_Manager>'s
+ * internal lock, which is accessible via its <mutex> method.
+ */
+template <class EXT_ID, class INT_ID, class ACE_LOCK>
+class ACE_Map_Const_Iterator : public ACE_Map_Const_Iterator_Base<EXT_ID, INT_ID, ACE_LOCK>
+{
+public:
+ // = Initialization method.
+ ACE_Map_Const_Iterator (const ACE_Map_Manager <EXT_ID, INT_ID, ACE_LOCK> &mm,
+ int pass_end = 0);
+
+ // = Iteration methods.
+
+ /// Move forward by one element in the set. Returns 0 when all the
+ /// items in the set have been seen, else 1.
+ int advance (void);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ // = STL styled iteration, compare, and reference functions.
+
+ /// Prefix advance.
+ ACE_Map_Const_Iterator<EXT_ID, INT_ID, ACE_LOCK> &operator++ (void);
+
+ /// Postfix advance.
+ ACE_Map_Const_Iterator<EXT_ID, INT_ID, ACE_LOCK> operator++ (int);
+
+ /// Prefix reverse.
+ ACE_Map_Const_Iterator<EXT_ID, INT_ID, ACE_LOCK> &operator-- (void);
+
+ /// Postfix reverse.
+ ACE_Map_Const_Iterator<EXT_ID, INT_ID, ACE_LOCK> operator-- (int);
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+};
+
+/**
+ * @class ACE_Map_Reverse_Iterator
+ *
+ * @brief Reverse Iterator for the <ACE_Map_Manager>.
+ *
+ * This class does not perform any internal locking of the
+ * <ACE_Map_Manager> it is iterating upon since locking is
+ * inherently inefficient and/or error-prone within an STL-style
+ * iterator. If you require locking, you can explicitly use an
+ * <ACE_Guard> or <ACE_Read_Guard> on the <ACE_Map_Manager>'s
+ * internal lock, which is accessible via its <mutex> method.
+ */
+template <class EXT_ID, class INT_ID, class ACE_LOCK>
+class ACE_Map_Reverse_Iterator : public ACE_Map_Iterator_Base<EXT_ID, INT_ID, ACE_LOCK>
+{
+public:
+ // = Initialization method.
+ ACE_Map_Reverse_Iterator (ACE_Map_Manager <EXT_ID, INT_ID, ACE_LOCK> &mm,
+ int pass_end = 0);
+
+ // = Iteration methods.
+
+ /// Move forward by one element in the set. Returns 0 when all the
+ /// items in the set have been seen, else 1.
+ int advance (void);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ // = STL styled iteration, compare, and reference functions.
+
+ /// Prefix reverse.
+ ACE_Map_Reverse_Iterator<EXT_ID, INT_ID, ACE_LOCK> &operator++ (void);
+
+ /// Postfix reverse.
+ ACE_Map_Reverse_Iterator<EXT_ID, INT_ID, ACE_LOCK> operator++ (int);
+
+ /// Prefix advance.
+ ACE_Map_Reverse_Iterator<EXT_ID, INT_ID, ACE_LOCK> &operator-- (void);
+
+ /// Postfix advance.
+ ACE_Map_Reverse_Iterator<EXT_ID, INT_ID, ACE_LOCK> operator-- (int);
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+};
+
+#if defined (__ACE_INLINE__)
+#include "ace/Utils/Templates/Map_Manager.i"
+#endif /* __ACE_INLINE__ */
+
+#if defined (ACE_TEMPLATES_REQUIRE_SOURCE)
+#include "ace/Utils/Templates/Map_Manager.cpp"
+#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */
+
+#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA)
+#pragma implementation ("Map_Manager.cpp")
+#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */
+
+#include "ace/post.h"
+#endif /* ACE_MAP_MANAGER_H */
diff --git a/ace/Utils/Templates/Map_Manager.h~ b/ace/Utils/Templates/Map_Manager.h~
new file mode 100644
index 00000000000..4e38e192b91
--- /dev/null
+++ b/ace/Utils/Templates/Map_Manager.h~
@@ -0,0 +1,700 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Map_Manager.h
+ *
+ * $Id$
+ *
+ * @author Douglas C. Schmidt <schmidt@cs.wustl.edu>
+ */
+//=============================================================================
+
+#ifndef ACE_MAP_MANAGER_H
+#define ACE_MAP_MANAGER_H
+#include "ace/pre.h"
+
+#include "ace/OS.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "ace/Synch.h"
+#include "ace/Log_Msg.h"
+
+// Forward declaration.
+class ACE_Allocator;
+
+/**
+ * @class ACE_Map_Entry
+ *
+ * @brief An entry in the Map.
+ */
+template <class EXT_ID, class INT_ID>
+class ACE_Map_Entry
+{
+public:
+# if ! defined (ACE_HAS_BROKEN_NOOP_DTORS)
+ /// We need this destructor to keep some compilers from complaining.
+ /// It's just a no-op, however.
+ ~ACE_Map_Entry (void);
+# endif /* ! defined (ACE_HAS_BROKEN_NOOP_DTORS) */
+
+ /// Key used to look up an entry.
+ EXT_ID ext_id_;
+
+ /// The contents of the entry itself.
+ INT_ID int_id_;
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+ // = These are really private, but unfortunately template friends
+ // are not portable.
+
+ /// Get/Set next entry.
+ ACE_UINT32 next (void) const;
+ void next (ACE_UINT32 n);
+
+ /// Get/Set prev entry.
+ ACE_UINT32 prev (void) const;
+ void prev (ACE_UINT32 p);
+
+ /// Keeps track of the next entry.
+ ACE_UINT32 next_;
+
+ /// Keeps track of the previous entry.
+ ACE_UINT32 prev_;
+
+#if defined (ACE_HAS_LAZY_MAP_MANAGER)
+
+ /// Is this entry free?
+ int free_;
+
+#endif /* ACE_HAS_LAZY_MAP_MANAGER */
+
+};
+
+// Forward decl.
+template <class EXT_ID, class INT_ID, class ACE_LOCK>
+class ACE_Map_Iterator_Base;
+
+// Forward decl.
+template <class EXT_ID, class INT_ID, class ACE_LOCK>
+class ACE_Map_Const_Iterator_Base;
+
+// Forward decl.
+template <class EXT_ID, class INT_ID, class ACE_LOCK>
+class ACE_Map_Iterator;
+
+// Forward decl.
+template <class EXT_ID, class INT_ID, class ACE_LOCK>
+class ACE_Map_Const_Iterator;
+
+// Forward decl.
+template <class EXT_ID, class INT_ID, class ACE_LOCK>
+class ACE_Map_Reverse_Iterator;
+
+/**
+ * @class ACE_Map_Manager
+ *
+ * @brief Define a map abstraction that associates <EXT_ID>s with
+ * <INT_ID>s.
+ *
+ * The <EXT_ID> must support <operator==>. This constraint can
+ * be alleviated via template specialization, as shown in the
+ * $ACE_ROOT/tests/Conn_Test.cpp test.
+ * This class uses an <ACE_Allocator> to allocate memory. The
+ * user can make this a persistant class by providing an
+ * <ACE_Allocator> with a persistable memory pool.
+ * This implementation of a map uses an array, which is searched
+ * linearly. For more efficient searching you should use the
+ * <ACE_Hash_Map_Manager>.
+ */
+template <class EXT_ID, class INT_ID, class ACE_LOCK>
+class ACE_Map_Manager
+{
+public:
+ friend class ACE_Map_Iterator_Base<EXT_ID, INT_ID, ACE_LOCK>;
+ friend class ACE_Map_Const_Iterator_Base<EXT_ID, INT_ID, ACE_LOCK>;
+ friend class ACE_Map_Iterator<EXT_ID, INT_ID, ACE_LOCK>;
+ friend class ACE_Map_Const_Iterator<EXT_ID, INT_ID, ACE_LOCK>;
+ friend class ACE_Map_Reverse_Iterator<EXT_ID, INT_ID, ACE_LOCK>;
+
+ // = Traits.
+ typedef EXT_ID KEY;
+ typedef INT_ID VALUE;
+ typedef ACE_Map_Entry<EXT_ID, INT_ID> ENTRY;
+ typedef ACE_Map_Iterator<EXT_ID, INT_ID, ACE_LOCK> ITERATOR;
+ typedef ACE_Map_Const_Iterator<EXT_ID, INT_ID, ACE_LOCK> CONST_ITERATOR;
+ typedef ACE_Map_Reverse_Iterator<EXT_ID, INT_ID, ACE_LOCK> REVERSE_ITERATOR;
+
+ typedef ACE_Map_Iterator<EXT_ID, INT_ID, ACE_LOCK> iterator;
+ typedef ACE_Map_Const_Iterator<EXT_ID, INT_ID, ACE_LOCK> const_iterator;
+ typedef ACE_Map_Reverse_Iterator<EXT_ID, INT_ID, ACE_LOCK> reverse_iterator;
+
+ // = Initialization and termination methods.
+ /// Initialize a <Map_Manager> with the <ACE_DEFAULT_MAP_SIZE>.
+ ACE_Map_Manager (ACE_Allocator *alloc = 0);
+
+ /// Initialize a <Map_Manager> with <size> entries.
+ ACE_Map_Manager (size_t size,
+ ACE_Allocator *alloc = 0);
+
+ /// Initialize a <Map_Manager> with size <length>.
+ int open (size_t length = ACE_DEFAULT_MAP_SIZE,
+ ACE_Allocator *alloc = 0);
+
+ /// Close down a <Map_Manager> and release dynamically allocated
+ /// resources.
+ int close (void);
+
+ /// Close down a <Map_Manager> and release dynamically allocated
+ /// resources.
+ ~ACE_Map_Manager (void);
+
+ /**
+ * Associate <ext_id> with <int_id>. If <ext_id> is already in the
+ * map then the <Map_Entry> is not changed. Returns 0 if a new
+ * entry is bound successfully, returns 1 if an attempt is made to
+ * bind an existing entry, and returns -1 if failures occur.
+ */
+ int bind (const EXT_ID &ext_id,
+ const INT_ID &int_id);
+
+ /**
+ * Reassociate <ext_id> with <int_id>. If <ext_id> is not in the
+ * map then behaves just like <bind>. Otherwise, store the old
+ * values of <ext_id> and <int_id> into the "out" parameters and
+ * rebind the new parameters. This is very useful if you need to
+ * have an atomic way of updating <Map_Entries> and you also need
+ * full control over memory allocation. Returns 0 if a new entry is
+ * bound successfully, returns 1 if an existing entry was rebound,
+ * and returns -1 if failures occur.
+ */
+ int rebind (const EXT_ID &ext_id,
+ const INT_ID &int_id,
+ EXT_ID &old_ext_id,
+ INT_ID &old_int_id);
+
+ /**
+ * Reassociate <ext_id> with <int_id>. If <ext_id> is not in the
+ * map then behaves just like <bind>. Otherwise, store the old
+ * values of <int_id> into the "out" parameter and rebind the new
+ * parameters. Returns 0 if a new entry is bound successfully,
+ * returns 1 if an existing entry was rebound, and returns -1 if
+ * failures occur.
+ */
+ int rebind (const EXT_ID &ext_id,
+ const INT_ID &int_id,
+ INT_ID &old_int_id);
+
+ /// Reassociate <ext_id> with <int_id>. Old values in the map are
+ /// ignored.
+ int rebind (const EXT_ID &ext_id,
+ const INT_ID &int_id);
+
+ /**
+ * Associate <ext_id> with <int_id> if and only if <ext_id> is not
+ * in the map. If <ext_id> is already in the map then the <int_id>
+ * parameter is overwritten with the existing value in the map
+ * Returns 0 if a new entry is bound successfully, returns 1 if an
+ * attempt is made to bind an existing entry, and returns -1 if
+ * failures occur.
+ */
+ int trybind (const EXT_ID &ext_id,
+ INT_ID &int_id);
+
+ /// Locate <ext_id> and pass out parameter via <int_id>.
+ /// Returns 0 if found, returns -1 if not found.
+ int find (const EXT_ID &ext_id,
+ INT_ID &int_id) const;
+
+ /// Returns 0 if the <ext_id> is in the mapping, otherwise -1.
+ int find (const EXT_ID &ext_id) const;
+
+ /**
+ * Unbind (remove) the <ext_id> from the map. Don't return the
+ * <int_id> to the caller (this is useful for collections where the
+ * <int_id>s are *not* dynamically allocated...) Returns 0 if
+ * successful, else -1.
+ */
+ int unbind (const EXT_ID &ext_id);
+
+ /**
+ * Break any association of <ext_id>. Returns the value of <int_id>
+ * in case the caller needs to deallocate memory. Returns 0 if
+ * successful, else -1.
+ */
+ int unbind (const EXT_ID &ext_id,
+ INT_ID &int_id);
+
+ /**
+ * Unbind all entires.
+ */
+ void unbind_all (void);
+
+ /// Return the current size of the map.
+ size_t current_size (void) const;
+
+ /// Return the total size of the map.
+ size_t total_size (void) const;
+
+ /**
+ * Returns a reference to the underlying <ACE_LOCK>. This makes it
+ * possible to acquire the lock explicitly, which can be useful in
+ * some cases if you instantiate the <ACE_Atomic_Op> with an
+ * <ACE_Recursive_Mutex> or <ACE_Process_Mutex>, or if you need to
+ * guard the state of an iterator. NOTE: the right name would be
+ * <lock>, but HP/C++ will choke on that!
+ */
+ ACE_LOCK &mutex (void);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ // = STL styled iterator factory functions.
+
+ /// Return forward iterator.
+ ACE_Map_Iterator<EXT_ID, INT_ID, ACE_LOCK> begin (void);
+ ACE_Map_Iterator<EXT_ID, INT_ID, ACE_LOCK> end (void);
+
+ /// Return reverse iterator.
+ ACE_Map_Reverse_Iterator<EXT_ID, INT_ID, ACE_LOCK> rbegin (void);
+ ACE_Map_Reverse_Iterator<EXT_ID, INT_ID, ACE_LOCK> rend (void);
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+protected:
+
+ // = The following methods do the actual work.
+
+ // These methods assume that the locks are held by the private
+ // methods.
+
+ /// Performs the binding of <ext_id> to <int_id>. Must be called
+ /// with locks held.
+ int bind_i (const EXT_ID &ext_id,
+ const INT_ID &int_id);
+
+ /// Bind an entry (without finding first). Must be called with locks
+ /// held.
+ int shared_bind (const EXT_ID &ext_id,
+ const INT_ID &int_id);
+
+ /// Performs a rebinding of <ext_it> to <int_id>. Also, recovers old
+ /// values. Must be called with locks held.
+ int rebind_i (const EXT_ID &ext_id,
+ const INT_ID &int_id,
+ EXT_ID &old_ext_id,
+ INT_ID &old_int_id);
+
+ /// Performs a rebinding of <ext_it> to <int_id>. Also, recovers old
+ /// values. Must be called with locks held.
+ int rebind_i (const EXT_ID &ext_id,
+ const INT_ID &int_id,
+ INT_ID &old_int_id);
+
+ /// Performs a rebinding of <ext_it> to <int_id>. Must be called
+ /// with locks held.
+ int rebind_i (const EXT_ID &ext_id,
+ const INT_ID &int_id);
+
+ /// Performs a conditional bind of <int_id> using <ext_id> as the
+ /// key. Must be called with locks held.
+ int trybind_i (const EXT_ID &ext_id,
+ INT_ID &int_id);
+
+ /// Performs a find of <int_id> using <ext_id> as the key. Must be
+ /// called with locks held.
+ int find_i (const EXT_ID &ext_id,
+ INT_ID &int_id);
+
+ /// Performs a find using <ext_id> as the key. Must be called with
+ /// locks held.
+ int find_and_return_index (const EXT_ID &ext_id,
+ ACE_UINT32 &slot);
+
+ /// Performs an unbind of <int_id> using <ext_id> as the key. Must
+ /// be called with locks held.
+ int unbind_i (const EXT_ID &ext_id,
+ INT_ID &int_id);
+
+ /// Performs an unbind using <ext_id> as the key. Must be called
+ /// with locks held.
+ int unbind_i (const EXT_ID &ext_id);
+
+ /// Performs an unbind using <ext_id> as the key. Must be called
+ /// with locks held.
+ int unbind_and_return_index (const EXT_ID &ext_id,
+ ACE_UINT32 &slot);
+
+ /// Unbind <slot>.
+ void unbind_slot (ACE_UINT32 slot);
+
+ /// Resize the map. Must be called with locks held.
+ int resize_i (ACE_UINT32 size);
+
+ /// Close down a <Map_Manager>. Must be called with locks held.
+ int close_i (void);
+
+ /// Returns 1 if <id1> == <id2>, else 0. This is defined as a
+ /// separate method to facilitate template specialization.
+ int equal (const EXT_ID &id1, const EXT_ID &id2);
+
+ /// This function returns the new size of the Map Manager. This
+ /// function is called when we run out of room and need to resize.
+ ACE_UINT32 new_size (void);
+
+ /// Explicitly call the destructors and free up the
+ /// <search_structure_>.
+ void free_search_structure (void);
+
+ /// Id of the free list sentinel.
+ ACE_UINT32 free_list_id (void) const;
+
+ /// Id of the occupied list sentinel.
+ ACE_UINT32 occupied_list_id (void) const;
+
+ /// Finds the next free slot.
+ int next_free (ACE_UINT32 &slot);
+
+ /// Move from free list to occupied list.
+ void move_from_free_list_to_occupied_list (ACE_UINT32 slot);
+
+ /// Move from occupied list to free list.
+ void move_from_occupied_list_to_free_list (ACE_UINT32 slot);
+
+#if defined (ACE_HAS_LAZY_MAP_MANAGER)
+
+ /**
+ * In the case of lazy map managers, the movement of free slots from
+ * the occupied list to the free list is delayed until we run out of
+ * free slots in the free list. This function goes through the
+ * entire occupied list, moving free slots to the free list.
+ */
+ void move_all_free_slots_from_occupied_list (void);
+
+#endif /* ACE_HAS_LAZY_MAP_MANAGER */
+
+ /// Move helper.
+ void shared_move (ACE_UINT32 slot,
+ ACE_Map_Entry<EXT_ID, INT_ID> &current_list,
+ ACE_UINT32 current_list_id,
+ ACE_Map_Entry<EXT_ID, INT_ID> &new_list,
+ ACE_UINT32 new_list_id);
+
+ /// Pointer to a memory allocator.
+ ACE_Allocator *allocator_;
+
+ /// Synchronization variable for the MT_SAFE <ACE_Map_Manager>.
+ ACE_LOCK lock_;
+
+ /// Implement the Map as a resizeable array of <ACE_Map_Entry>.
+ ACE_Map_Entry<EXT_ID, INT_ID> *search_structure_;
+
+ /// Total number of elements in this->search_structure_.
+ ACE_UINT32 total_size_;
+
+ /// Current size of the map.
+ ACE_UINT32 cur_size_;
+
+ /// Free list.
+ ACE_Map_Entry<EXT_ID, INT_ID> free_list_;
+
+ /// Occupied list.
+ ACE_Map_Entry<EXT_ID, INT_ID> occupied_list_;
+
+ enum
+ {
+ /// Grow map exponentially up to 64K
+ MAX_EXPONENTIAL = 64 * 1024,
+
+ /// Afterwards grow in chunks of 32K
+ LINEAR_INCREASE = 32 * 1024
+ };
+
+private:
+ // = Disallow these operations.
+ ACE_UNIMPLEMENTED_FUNC (void operator= (const ACE_Map_Manager<EXT_ID, INT_ID, ACE_LOCK> &))
+ ACE_UNIMPLEMENTED_FUNC (ACE_Map_Manager (const ACE_Map_Manager<EXT_ID, INT_ID, ACE_LOCK> &))
+};
+
+/**
+ * @class ACE_Map_Iterator_Base
+ *
+ * @brief Iterator for the <ACE_Map_Manager>.
+ *
+ * This class factors out common code from its templatized
+ * subclasses.
+ */
+template <class EXT_ID, class INT_ID, class ACE_LOCK>
+class ACE_Map_Iterator_Base
+{
+public:
+ // = Initialization method.
+ /// Contructor. If head != 0, the iterator constructed is positioned
+ /// at the head of the map, it is positioned at the end otherwise.
+ ACE_Map_Iterator_Base (ACE_Map_Manager <EXT_ID, INT_ID, ACE_LOCK> &mm);
+
+ // = Iteration methods.
+
+ /// Pass back the next <entry> that hasn't been seen in the Set.
+ /// Returns 0 when all items have been seen, else 1.
+ int next (ACE_Map_Entry<EXT_ID, INT_ID> *&next_entry) const;
+
+ /// Returns 1 when all items have been seen, else 0.
+ int done (void) const;
+
+ /// Returns a reference to the interal element <this> is pointing to.
+ ACE_Map_Entry<EXT_ID, INT_ID>& operator* (void) const;
+
+ /// Returns reference the Map_Manager that is being iterated
+ /// over.
+ ACE_Map_Manager<EXT_ID, INT_ID, ACE_LOCK>& map (void);
+
+ /// Check if two iterators point to the same position
+ int operator== (const ACE_Map_Iterator_Base<EXT_ID, INT_ID, ACE_LOCK> &) const;
+ int operator!= (const ACE_Map_Iterator_Base<EXT_ID, INT_ID, ACE_LOCK> &) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+protected:
+ /// Move forward by one element in the set. Returns 0 when there's
+ /// no more item in the set after the current items, else 1.
+ int forward_i (void);
+
+ /// Move backware by one element in the set. Returns 0 when there's
+ /// no more item in the set before the current item, else 1.
+ int reverse_i (void);
+
+ /// Dump the state of an object.
+ void dump_i (void) const;
+
+ /// Map we are iterating over.
+ ACE_Map_Manager <EXT_ID, INT_ID, ACE_LOCK> *map_man_;
+
+ /// Keeps track of how far we've advanced...
+ ACE_UINT32 next_;
+};
+
+/**
+ * @class ACE_Map_Const_Iterator_Base
+ *
+ * @brief Const iterator for the <ACE_Map_Manager>.
+ *
+ * This class factors out common code from its templatized
+ * subclasses.
+ */
+template <class EXT_ID, class INT_ID, class ACE_LOCK>
+class ACE_Map_Const_Iterator_Base
+{
+public:
+ // = Initialization method.
+ /// Contructor. If head != 0, the iterator constructed is positioned
+ /// at the head of the map, it is positioned at the end otherwise.
+ ACE_Map_Const_Iterator_Base (const ACE_Map_Manager <EXT_ID, INT_ID, ACE_LOCK> &mm);
+
+ // = Iteration methods.
+
+ /// Pass back the next <entry> that hasn't been seen in the Set.
+ /// Returns 0 when all items have been seen, else 1.
+ int next (ACE_Map_Entry<EXT_ID, INT_ID> *&next_entry) const;
+
+ /// Returns 1 when all items have been seen, else 0.
+ int done (void) const;
+
+ /// Returns a reference to the interal element <this> is pointing to.
+ ACE_Map_Entry<EXT_ID, INT_ID>& operator* (void) const;
+
+ /// Returns reference the Map_Manager that is being iterated
+ /// over.
+ const ACE_Map_Manager<EXT_ID, INT_ID, ACE_LOCK>& map (void) const;
+
+ /// Check if two iterators point to the same position
+ int operator== (const ACE_Map_Const_Iterator_Base<EXT_ID, INT_ID, ACE_LOCK> &) const;
+ int operator!= (const ACE_Map_Const_Iterator_Base<EXT_ID, INT_ID, ACE_LOCK> &) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+protected:
+ /// Move forward by one element in the set. Returns 0 when there's
+ /// no more item in the set after the current items, else 1.
+ int forward_i (void);
+
+ /// Move backware by one element in the set. Returns 0 when there's
+ /// no more item in the set before the current item, else 1.
+ int reverse_i (void);
+
+ /// Dump the state of an object.
+ void dump_i (void) const;
+
+ /// Map we are iterating over.
+ const ACE_Map_Manager <EXT_ID, INT_ID, ACE_LOCK> *map_man_;
+
+ /// Keeps track of how far we've advanced...
+ ACE_UINT32 next_;
+};
+
+/**
+ * @class ACE_Map_Iterator
+ *
+ * @brief Forward iterator for the <ACE_Map_Manager>.
+ *
+ * This class does not perform any internal locking of the
+ * <ACE_Map_Manager> it is iterating upon since locking is
+ * inherently inefficient and/or error-prone within an STL-style
+ * iterator. If you require locking, you can explicitly use an
+ * <ACE_Guard> or <ACE_Read_Guard> on the <ACE_Map_Manager>'s
+ * internal lock, which is accessible via its <mutex> method.
+ */
+template <class EXT_ID, class INT_ID, class ACE_LOCK>
+class ACE_Map_Iterator : public ACE_Map_Iterator_Base<EXT_ID, INT_ID, ACE_LOCK>
+{
+public:
+ // = Initialization method.
+ ACE_Map_Iterator (ACE_Map_Manager <EXT_ID, INT_ID, ACE_LOCK> &mm,
+ int pass_end = 0);
+
+ // = Iteration methods.
+
+ /// Move forward by one element in the set. Returns 0 when all the
+ /// items in the set have been seen, else 1.
+ int advance (void);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ // = STL styled iteration, compare, and reference functions.
+
+ /// Prefix advance.
+ ACE_Map_Iterator<EXT_ID, INT_ID, ACE_LOCK> &operator++ (void);
+
+ /// Postfix advance.
+ ACE_Map_Iterator<EXT_ID, INT_ID, ACE_LOCK> operator++ (int);
+
+ /// Prefix reverse.
+ ACE_Map_Iterator<EXT_ID, INT_ID, ACE_LOCK> &operator-- (void);
+
+ /// Postfix reverse.
+ ACE_Map_Iterator<EXT_ID, INT_ID, ACE_LOCK> operator-- (int);
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+};
+
+/**
+ * @class ACE_Map_Const_Iterator
+ *
+ * @brief Forward const iterator for the <ACE_Map_Manager>.
+ *
+ * This class does not perform any internal locking of the
+ * <ACE_Map_Manager> it is iterating upon since locking is
+ * inherently inefficient and/or error-prone within an STL-style
+ * iterator. If you require locking, you can explicitly use an
+ * <ACE_Guard> or <ACE_Read_Guard> on the <ACE_Map_Manager>'s
+ * internal lock, which is accessible via its <mutex> method.
+ */
+template <class EXT_ID, class INT_ID, class ACE_LOCK>
+class ACE_Map_Const_Iterator : public ACE_Map_Const_Iterator_Base<EXT_ID, INT_ID, ACE_LOCK>
+{
+public:
+ // = Initialization method.
+ ACE_Map_Const_Iterator (const ACE_Map_Manager <EXT_ID, INT_ID, ACE_LOCK> &mm,
+ int pass_end = 0);
+
+ // = Iteration methods.
+
+ /// Move forward by one element in the set. Returns 0 when all the
+ /// items in the set have been seen, else 1.
+ int advance (void);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ // = STL styled iteration, compare, and reference functions.
+
+ /// Prefix advance.
+ ACE_Map_Const_Iterator<EXT_ID, INT_ID, ACE_LOCK> &operator++ (void);
+
+ /// Postfix advance.
+ ACE_Map_Const_Iterator<EXT_ID, INT_ID, ACE_LOCK> operator++ (int);
+
+ /// Prefix reverse.
+ ACE_Map_Const_Iterator<EXT_ID, INT_ID, ACE_LOCK> &operator-- (void);
+
+ /// Postfix reverse.
+ ACE_Map_Const_Iterator<EXT_ID, INT_ID, ACE_LOCK> operator-- (int);
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+};
+
+/**
+ * @class ACE_Map_Reverse_Iterator
+ *
+ * @brief Reverse Iterator for the <ACE_Map_Manager>.
+ *
+ * This class does not perform any internal locking of the
+ * <ACE_Map_Manager> it is iterating upon since locking is
+ * inherently inefficient and/or error-prone within an STL-style
+ * iterator. If you require locking, you can explicitly use an
+ * <ACE_Guard> or <ACE_Read_Guard> on the <ACE_Map_Manager>'s
+ * internal lock, which is accessible via its <mutex> method.
+ */
+template <class EXT_ID, class INT_ID, class ACE_LOCK>
+class ACE_Map_Reverse_Iterator : public ACE_Map_Iterator_Base<EXT_ID, INT_ID, ACE_LOCK>
+{
+public:
+ // = Initialization method.
+ ACE_Map_Reverse_Iterator (ACE_Map_Manager <EXT_ID, INT_ID, ACE_LOCK> &mm,
+ int pass_end = 0);
+
+ // = Iteration methods.
+
+ /// Move forward by one element in the set. Returns 0 when all the
+ /// items in the set have been seen, else 1.
+ int advance (void);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ // = STL styled iteration, compare, and reference functions.
+
+ /// Prefix reverse.
+ ACE_Map_Reverse_Iterator<EXT_ID, INT_ID, ACE_LOCK> &operator++ (void);
+
+ /// Postfix reverse.
+ ACE_Map_Reverse_Iterator<EXT_ID, INT_ID, ACE_LOCK> operator++ (int);
+
+ /// Prefix advance.
+ ACE_Map_Reverse_Iterator<EXT_ID, INT_ID, ACE_LOCK> &operator-- (void);
+
+ /// Postfix advance.
+ ACE_Map_Reverse_Iterator<EXT_ID, INT_ID, ACE_LOCK> operator-- (int);
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+};
+
+#if defined (__ACE_INLINE__)
+#include "ace/Map_Manager.i"
+#endif /* __ACE_INLINE__ */
+
+#if defined (ACE_TEMPLATES_REQUIRE_SOURCE)
+#include "ace/Map_Manager.cpp"
+#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */
+
+#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA)
+#pragma implementation ("Map_Manager.cpp")
+#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */
+
+#include "ace/post.h"
+#endif /* ACE_MAP_MANAGER_H */
diff --git a/ace/Utils/Templates/Map_Manager.i b/ace/Utils/Templates/Map_Manager.i
new file mode 100644
index 00000000000..0efe209c8eb
--- /dev/null
+++ b/ace/Utils/Templates/Map_Manager.i
@@ -0,0 +1,713 @@
+/* -*- C++ -*- */
+// $Id$
+
+# if ! defined (ACE_HAS_BROKEN_NOOP_DTORS)
+template <class EXT_ID, class INT_ID> ACE_INLINE
+ACE_Map_Entry<EXT_ID, INT_ID>::~ACE_Map_Entry (void)
+{
+ // No-op just to keep some compilers happy...
+}
+#endif /* ! defined (ACE_HAS_BROKEN_NOOP_DTORS) */
+
+template <class EXT_ID, class INT_ID> ACE_INLINE ACE_UINT32
+ACE_Map_Entry<EXT_ID, INT_ID>::next (void) const
+{
+ return this->next_;
+}
+
+template <class EXT_ID, class INT_ID> ACE_INLINE void
+ACE_Map_Entry<EXT_ID, INT_ID>::next (ACE_UINT32 n)
+{
+ this->next_ = n;
+}
+
+template <class EXT_ID, class INT_ID> ACE_INLINE ACE_UINT32
+ACE_Map_Entry<EXT_ID, INT_ID>::prev (void) const
+{
+ return this->prev_;
+}
+
+template <class EXT_ID, class INT_ID> ACE_INLINE void
+ACE_Map_Entry<EXT_ID, INT_ID>::prev (ACE_UINT32 p)
+{
+ this->prev_ = p;
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> ACE_INLINE
+ACE_Map_Manager<EXT_ID, INT_ID, ACE_LOCK>::ACE_Map_Manager (size_t size,
+ ACE_Allocator *alloc)
+ : allocator_ (0),
+ search_structure_ (0),
+ total_size_ (0),
+ cur_size_ (0)
+{
+ if (this->open (size, alloc) == -1)
+ ACE_ERROR ((LM_ERROR, ACE_LIB_TEXT ("ACE_Map_Manager\n")));
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> ACE_INLINE
+ACE_Map_Manager<EXT_ID, INT_ID, ACE_LOCK>::ACE_Map_Manager (ACE_Allocator *alloc)
+ : allocator_ (0),
+ search_structure_ (0),
+ total_size_ (0),
+ cur_size_ (0)
+{
+ if (this->open (ACE_DEFAULT_MAP_SIZE, alloc) == -1)
+ ACE_ERROR ((LM_ERROR, ACE_LIB_TEXT ("ACE_Map_Manager\n")));
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> ACE_INLINE int
+ACE_Map_Manager<EXT_ID, INT_ID, ACE_LOCK>::close (void)
+{
+ ACE_WRITE_GUARD_RETURN (ACE_LOCK, ace_mon, this->lock_, -1);
+
+ return this->close_i ();
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> ACE_INLINE
+ACE_Map_Manager<EXT_ID, INT_ID, ACE_LOCK>::~ACE_Map_Manager (void)
+{
+ this->close ();
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> ACE_INLINE int
+ACE_Map_Manager<EXT_ID, INT_ID, ACE_LOCK>::bind (const EXT_ID &ext_id,
+ const INT_ID &int_id)
+{
+ ACE_WRITE_GUARD_RETURN (ACE_LOCK, ace_mon, this->lock_, -1);
+
+ return this->bind_i (ext_id,
+ int_id);
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> ACE_INLINE int
+ACE_Map_Manager<EXT_ID, INT_ID, ACE_LOCK>::rebind (const EXT_ID &ext_id,
+ const INT_ID &int_id,
+ EXT_ID &old_ext_id,
+ INT_ID &old_int_id)
+{
+ ACE_WRITE_GUARD_RETURN (ACE_LOCK, ace_mon, this->lock_, -1);
+
+ return this->rebind_i (ext_id,
+ int_id,
+ old_ext_id,
+ old_int_id);
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> ACE_INLINE int
+ACE_Map_Manager<EXT_ID, INT_ID, ACE_LOCK>::rebind (const EXT_ID &ext_id,
+ const INT_ID &int_id,
+ INT_ID &old_int_id)
+{
+ ACE_WRITE_GUARD_RETURN (ACE_LOCK, ace_mon, this->lock_, -1);
+
+ return this->rebind_i (ext_id,
+ int_id,
+ old_int_id);
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> ACE_INLINE int
+ACE_Map_Manager<EXT_ID, INT_ID, ACE_LOCK>::rebind (const EXT_ID &ext_id,
+ const INT_ID &int_id)
+{
+ ACE_WRITE_GUARD_RETURN (ACE_LOCK, ace_mon, this->lock_, -1);
+
+ return this->rebind_i (ext_id,
+ int_id);
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> ACE_INLINE int
+ACE_Map_Manager<EXT_ID, INT_ID, ACE_LOCK>::trybind (const EXT_ID &ext_id,
+ INT_ID &int_id)
+{
+ ACE_WRITE_GUARD_RETURN (ACE_LOCK, ace_mon, this->lock_, -1);
+
+ return this->trybind_i (ext_id,
+ int_id);
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> ACE_INLINE int
+ACE_Map_Manager<EXT_ID, INT_ID, ACE_LOCK>::find (const EXT_ID &ext_id) const
+{
+ ACE_Map_Manager<EXT_ID, INT_ID, ACE_LOCK> *nc_this =
+ (ACE_Map_Manager<EXT_ID, INT_ID, ACE_LOCK> *) this;
+ ACE_READ_GUARD_RETURN (ACE_LOCK, ace_mon, nc_this->lock_, -1);
+
+ ACE_UINT32 slot = 0;
+ return nc_this->find_and_return_index (ext_id, slot);
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> ACE_INLINE int
+ACE_Map_Manager<EXT_ID, INT_ID, ACE_LOCK>::find (const EXT_ID &ext_id,
+ INT_ID &int_id) const
+{
+ ACE_Map_Manager<EXT_ID, INT_ID, ACE_LOCK> *nc_this =
+ (ACE_Map_Manager<EXT_ID, INT_ID, ACE_LOCK> *) this;
+ ACE_READ_GUARD_RETURN (ACE_LOCK, ace_mon, nc_this->lock_, -1);
+
+ return nc_this->find_i (ext_id, int_id);
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> ACE_INLINE int
+ACE_Map_Manager<EXT_ID, INT_ID, ACE_LOCK>::unbind_i (const EXT_ID &ext_id)
+{
+ // Unbind the entry.
+ ACE_UINT32 slot = 0;
+ return this->unbind_and_return_index (ext_id,
+ slot);
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> ACE_INLINE int
+ACE_Map_Manager<EXT_ID, INT_ID, ACE_LOCK>::unbind (const EXT_ID &ext_id,
+ INT_ID &int_id)
+{
+ ACE_WRITE_GUARD_RETURN (ACE_LOCK, ace_mon, this->lock_, -1);
+
+ return this->unbind_i (ext_id,
+ int_id);
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> ACE_INLINE int
+ACE_Map_Manager<EXT_ID, INT_ID, ACE_LOCK>::unbind (const EXT_ID &ext_id)
+{
+ ACE_WRITE_GUARD_RETURN (ACE_LOCK, ace_mon, this->lock_, -1);
+ return this->unbind_i (ext_id);
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> ACE_INLINE size_t
+ACE_Map_Manager<EXT_ID, INT_ID, ACE_LOCK>::current_size (void) const
+{
+ ACE_WRITE_GUARD_RETURN (ACE_LOCK, ace_mon, ACE_const_cast (ACE_LOCK &, this->lock_), ACE_static_cast (size_t, -1));
+ return this->cur_size_;
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> ACE_INLINE size_t
+ACE_Map_Manager<EXT_ID, INT_ID, ACE_LOCK>::total_size (void) const
+{
+ ACE_WRITE_GUARD_RETURN (ACE_LOCK, ace_mon, ACE_const_cast (ACE_LOCK &, this->lock_), ACE_static_cast (size_t, -1));
+ return this->total_size_;
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> ACE_INLINE ACE_LOCK &
+ACE_Map_Manager<EXT_ID, INT_ID, ACE_LOCK>::mutex (void)
+{
+ return this->lock_;
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> ACE_INLINE void
+ACE_Map_Manager<EXT_ID, INT_ID, ACE_LOCK>::move_from_free_list_to_occupied_list (ACE_UINT32 slot)
+{
+ this->shared_move (slot,
+ this->free_list_,
+ this->free_list_id (),
+ this->occupied_list_,
+ this->occupied_list_id ());
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> ACE_INLINE void
+ACE_Map_Manager<EXT_ID, INT_ID, ACE_LOCK>::move_from_occupied_list_to_free_list (ACE_UINT32 slot)
+{
+ this->shared_move (slot,
+ this->occupied_list_,
+ this->occupied_list_id (),
+ this->free_list_,
+ this->free_list_id ());
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> ACE_INLINE int
+ACE_Map_Manager<EXT_ID, INT_ID, ACE_LOCK>::equal (const EXT_ID &id1,
+ const EXT_ID &id2)
+{
+ return id1 == id2;
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> ACE_INLINE ACE_UINT32
+ACE_Map_Manager<EXT_ID, INT_ID, ACE_LOCK>::free_list_id (void) const
+{
+ // If you change ~0, please change
+ // ACE_Active_Map_Manager_Key::ACE_Active_Map_Manager_Key()
+ // accordingly.
+ return (ACE_UINT32) ~0;
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> ACE_INLINE ACE_UINT32
+ACE_Map_Manager<EXT_ID, INT_ID, ACE_LOCK>::occupied_list_id (void) const
+{
+ return (ACE_UINT32) ~1;
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> ACE_INLINE
+ACE_Map_Iterator<EXT_ID, INT_ID, ACE_LOCK>
+ACE_Map_Manager<EXT_ID, INT_ID, ACE_LOCK>::begin (void)
+{
+ return ACE_Map_Iterator<EXT_ID, INT_ID, ACE_LOCK> (*this);
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> ACE_INLINE
+ACE_Map_Iterator<EXT_ID, INT_ID, ACE_LOCK>
+ACE_Map_Manager<EXT_ID, INT_ID, ACE_LOCK>::end (void)
+{
+ return ACE_Map_Iterator<EXT_ID, INT_ID, ACE_LOCK> (*this, 1);
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> ACE_INLINE
+ACE_Map_Reverse_Iterator<EXT_ID, INT_ID, ACE_LOCK>
+ACE_Map_Manager<EXT_ID, INT_ID, ACE_LOCK>::rbegin (void)
+{
+ return ACE_Map_Reverse_Iterator<EXT_ID, INT_ID, ACE_LOCK> (*this);
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> ACE_INLINE
+ACE_Map_Reverse_Iterator<EXT_ID, INT_ID, ACE_LOCK>
+ACE_Map_Manager<EXT_ID, INT_ID, ACE_LOCK>::rend (void)
+{
+ return ACE_Map_Reverse_Iterator<EXT_ID, INT_ID, ACE_LOCK> (*this, 1);
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> ACE_INLINE
+ACE_Map_Iterator_Base<EXT_ID, INT_ID, ACE_LOCK>::ACE_Map_Iterator_Base (ACE_Map_Manager<EXT_ID, INT_ID, ACE_LOCK> &mm)
+ : map_man_ (&mm),
+ next_ (this->map_man_->occupied_list_id ())
+{
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> ACE_INLINE int
+ACE_Map_Iterator_Base<EXT_ID, INT_ID, ACE_LOCK>::next (ACE_Map_Entry<EXT_ID, INT_ID> *&mm) const
+{
+ if (this->next_ != this->map_man_->occupied_list_id ())
+ {
+ mm = &this->map_man_->search_structure_[this->next_];
+ return 1;
+ }
+ else
+ return 0;
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> ACE_INLINE int
+ACE_Map_Iterator_Base<EXT_ID, INT_ID, ACE_LOCK>::done (void) const
+{
+ return this->next_ == this->map_man_->occupied_list_id ();
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> ACE_INLINE int
+ACE_Map_Iterator_Base<EXT_ID, INT_ID, ACE_LOCK>::forward_i (void)
+{
+
+#if defined (ACE_HAS_LAZY_MAP_MANAGER)
+
+ while (1)
+ {
+ // Go to the next item in the list.
+ this->next_ = this->map_man_->search_structure_[this->next_].next ();
+
+ // Stop if we reach the end.
+ if (this->done ())
+ break;
+
+ // Break if we find a non-free slot.
+ if (!this->map_man_->search_structure_[this->next_].free_)
+ {
+ break;
+ }
+ }
+
+#else
+
+ this->next_ = this->map_man_->search_structure_[this->next_].next ();
+
+#endif /* ACE_HAS_LAZY_MAP_MANAGER */
+
+ return this->next_ != this->map_man_->occupied_list_id ();
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> ACE_INLINE int
+ACE_Map_Iterator_Base<EXT_ID, INT_ID, ACE_LOCK>::reverse_i (void)
+{
+
+#if defined (ACE_HAS_LAZY_MAP_MANAGER)
+
+ while (1)
+ {
+ // Go to the prev item in the list.
+ this->next_ = this->map_man_->search_structure_[this->next_].prev ();
+
+ // Stop if we reach the end.
+ if (this->done ())
+ break;
+
+ // Break if we find a non-free slot.
+ if (!this->map_man_->search_structure_[this->next_].free_)
+ {
+ break;
+ }
+ }
+
+#else
+
+ this->next_ = this->map_man_->search_structure_[this->next_].prev ();
+
+#endif /* ACE_HAS_LAZY_MAP_MANAGER */
+
+ return this->next_ != this->map_man_->occupied_list_id ();
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> ACE_INLINE
+ACE_Map_Manager<EXT_ID, INT_ID, ACE_LOCK> &
+ACE_Map_Iterator_Base<EXT_ID, INT_ID, ACE_LOCK>::map (void)
+{
+ return *this->map_man_;
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> ACE_INLINE int
+ACE_Map_Iterator_Base<EXT_ID, INT_ID, ACE_LOCK>::operator== (const ACE_Map_Iterator_Base<EXT_ID, INT_ID, ACE_LOCK> &rhs) const
+{
+ return (this->map_man_ == rhs.map_man_ &&
+ this->next_ == rhs.next_);
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> ACE_INLINE int
+ACE_Map_Iterator_Base<EXT_ID, INT_ID, ACE_LOCK>::operator!= (const ACE_Map_Iterator_Base<EXT_ID, INT_ID, ACE_LOCK> &rhs) const
+{
+ return !this->operator== (rhs);
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> ACE_INLINE
+ACE_Map_Const_Iterator_Base<EXT_ID, INT_ID, ACE_LOCK>::ACE_Map_Const_Iterator_Base (const ACE_Map_Manager<EXT_ID, INT_ID, ACE_LOCK> &mm)
+ : map_man_ (&mm),
+ next_ (this->map_man_->occupied_list_id ())
+{
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> ACE_INLINE int
+ACE_Map_Const_Iterator_Base<EXT_ID, INT_ID, ACE_LOCK>::next (ACE_Map_Entry<EXT_ID, INT_ID> *&mm) const
+{
+ if (this->next_ != this->map_man_->occupied_list_id ())
+ {
+ mm = &this->map_man_->search_structure_[this->next_];
+ return 1;
+ }
+ else
+ return 0;
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> ACE_INLINE int
+ACE_Map_Const_Iterator_Base<EXT_ID, INT_ID, ACE_LOCK>::done (void) const
+{
+ return this->next_ == this->map_man_->occupied_list_id ();
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> ACE_INLINE int
+ACE_Map_Const_Iterator_Base<EXT_ID, INT_ID, ACE_LOCK>::forward_i (void)
+{
+
+#if defined (ACE_HAS_LAZY_MAP_MANAGER)
+
+ while (1)
+ {
+ // Go to the next item in the list.
+ this->next_ = this->map_man_->search_structure_[this->next_].next ();
+
+ // Stop if we reach the end.
+ if (this->done ())
+ break;
+
+ // Break if we find a non-free slot.
+ if (!this->map_man_->search_structure_[this->next_].free_)
+ {
+ break;
+ }
+ }
+
+#else
+
+ this->next_ = this->map_man_->search_structure_[this->next_].next ();
+
+#endif /* ACE_HAS_LAZY_MAP_MANAGER */
+
+ return this->next_ != this->map_man_->occupied_list_id ();
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> ACE_INLINE int
+ACE_Map_Const_Iterator_Base<EXT_ID, INT_ID, ACE_LOCK>::reverse_i (void)
+{
+
+#if defined (ACE_HAS_LAZY_MAP_MANAGER)
+
+ while (1)
+ {
+ // Go to the prev item in the list.
+ this->next_ = this->map_man_->search_structure_[this->next_].prev ();
+
+ // Stop if we reach the end.
+ if (this->done ())
+ break;
+
+ // Break if we find a non-free slot.
+ if (!this->map_man_->search_structure_[this->next_].free_)
+ {
+ break;
+ }
+ }
+
+#else
+
+ this->next_ = this->map_man_->search_structure_[this->next_].prev ();
+
+#endif /* ACE_HAS_LAZY_MAP_MANAGER */
+
+ return this->next_ != this->map_man_->occupied_list_id ();
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> ACE_INLINE
+const ACE_Map_Manager<EXT_ID, INT_ID, ACE_LOCK> &
+ACE_Map_Const_Iterator_Base<EXT_ID, INT_ID, ACE_LOCK>::map (void) const
+{
+ return *this->map_man_;
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> ACE_INLINE int
+ACE_Map_Const_Iterator_Base<EXT_ID, INT_ID, ACE_LOCK>::operator== (const ACE_Map_Const_Iterator_Base<EXT_ID, INT_ID, ACE_LOCK> &rhs) const
+{
+ return (this->map_man_ == rhs.map_man_ &&
+ this->next_ == rhs.next_);
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> ACE_INLINE int
+ACE_Map_Const_Iterator_Base<EXT_ID, INT_ID, ACE_LOCK>::operator!= (const ACE_Map_Const_Iterator_Base<EXT_ID, INT_ID, ACE_LOCK> &rhs) const
+{
+ return !this->operator== (rhs);
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> ACE_INLINE
+ACE_Map_Iterator<EXT_ID, INT_ID, ACE_LOCK>::ACE_Map_Iterator (ACE_Map_Manager<EXT_ID, INT_ID, ACE_LOCK> &mm,
+ int pass_end)
+ : ACE_Map_Iterator_Base<EXT_ID, INT_ID, ACE_LOCK> (mm)
+{
+ if (!pass_end)
+ {
+
+#if defined (ACE_HAS_LAZY_MAP_MANAGER)
+
+ // Start here.
+ this->next_ = this->map_man_->occupied_list_.next ();
+
+ while (1)
+ {
+ // Stop if we reach the end.
+ if (this->done ())
+ break;
+
+ // Break if we find a non-free slot.
+ if (!this->map_man_->search_structure_[this->next_].free_)
+ {
+ break;
+ }
+
+ // Go to the next item in the list.
+ this->next_ = this->map_man_->search_structure_[this->next_].next ();
+ }
+
+#else
+
+ this->next_ = this->map_man_->occupied_list_.next ();
+
+#endif /* ACE_HAS_LAZY_MAP_MANAGER */
+
+ }
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> ACE_INLINE int
+ACE_Map_Iterator<EXT_ID, INT_ID, ACE_LOCK>::advance (void)
+{
+ return this->forward_i ();
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> ACE_INLINE
+ACE_Map_Iterator<EXT_ID, INT_ID, ACE_LOCK> &
+ACE_Map_Iterator<EXT_ID, INT_ID, ACE_LOCK>::operator++ (void)
+{
+ this->forward_i ();
+ return *this;
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> ACE_INLINE
+ACE_Map_Iterator<EXT_ID, INT_ID, ACE_LOCK>
+ACE_Map_Iterator<EXT_ID, INT_ID, ACE_LOCK>::operator++ (int)
+{
+ ACE_Map_Iterator<EXT_ID, INT_ID, ACE_LOCK> retv (*this);
+ this->forward_i ();
+ return retv;
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> ACE_INLINE
+ACE_Map_Iterator<EXT_ID, INT_ID, ACE_LOCK> &
+ACE_Map_Iterator<EXT_ID, INT_ID, ACE_LOCK>::operator-- (void)
+{
+ this->reverse_i ();
+ return *this;
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> ACE_INLINE
+ACE_Map_Iterator<EXT_ID, INT_ID, ACE_LOCK>
+ACE_Map_Iterator<EXT_ID, INT_ID, ACE_LOCK>::operator-- (int)
+{
+ ACE_Map_Iterator<EXT_ID, INT_ID, ACE_LOCK> retv (*this);
+ this->reverse_i ();
+ return retv;
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> ACE_INLINE
+ACE_Map_Const_Iterator<EXT_ID, INT_ID, ACE_LOCK>::ACE_Map_Const_Iterator (const ACE_Map_Manager<EXT_ID, INT_ID, ACE_LOCK> &mm,
+ int pass_end)
+ : ACE_Map_Const_Iterator_Base<EXT_ID, INT_ID, ACE_LOCK> (mm)
+{
+ if (!pass_end)
+ {
+
+#if defined (ACE_HAS_LAZY_MAP_MANAGER)
+
+ // Start here.
+ this->next_ = this->map_man_->occupied_list_.next ();
+
+ while (1)
+ {
+ // Stop if we reach the end.
+ if (this->done ())
+ break;
+
+ // Break if we find a non-free slot.
+ if (!this->map_man_->search_structure_[this->next_].free_)
+ {
+ break;
+ }
+
+ // Go to the next item in the list.
+ this->next_ = this->map_man_->search_structure_[this->next_].next ();
+ }
+
+#else
+
+ this->next_ = this->map_man_->occupied_list_.next ();
+
+#endif /* ACE_HAS_LAZY_MAP_MANAGER */
+
+ }
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> ACE_INLINE int
+ACE_Map_Const_Iterator<EXT_ID, INT_ID, ACE_LOCK>::advance (void)
+{
+ return this->forward_i ();
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> ACE_INLINE
+ACE_Map_Const_Iterator<EXT_ID, INT_ID, ACE_LOCK> &
+ACE_Map_Const_Iterator<EXT_ID, INT_ID, ACE_LOCK>::operator++ (void)
+{
+ this->forward_i ();
+ return *this;
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> ACE_INLINE
+ACE_Map_Const_Iterator<EXT_ID, INT_ID, ACE_LOCK>
+ACE_Map_Const_Iterator<EXT_ID, INT_ID, ACE_LOCK>::operator++ (int)
+{
+ ACE_Map_Const_Iterator<EXT_ID, INT_ID, ACE_LOCK> retv (*this);
+ this->forward_i ();
+ return retv;
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> ACE_INLINE
+ACE_Map_Const_Iterator<EXT_ID, INT_ID, ACE_LOCK> &
+ACE_Map_Const_Iterator<EXT_ID, INT_ID, ACE_LOCK>::operator-- (void)
+{
+ this->reverse_i ();
+ return *this;
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> ACE_INLINE
+ACE_Map_Const_Iterator<EXT_ID, INT_ID, ACE_LOCK>
+ACE_Map_Const_Iterator<EXT_ID, INT_ID, ACE_LOCK>::operator-- (int)
+{
+ ACE_Map_Const_Iterator<EXT_ID, INT_ID, ACE_LOCK> retv (*this);
+ this->reverse_i ();
+ return retv;
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> ACE_INLINE
+ACE_Map_Reverse_Iterator<EXT_ID, INT_ID, ACE_LOCK>::ACE_Map_Reverse_Iterator (ACE_Map_Manager<EXT_ID, INT_ID, ACE_LOCK> &mm,
+ int pass_end)
+ : ACE_Map_Iterator_Base<EXT_ID, INT_ID, ACE_LOCK> (mm)
+{
+ if (!pass_end)
+ {
+
+#if defined (ACE_HAS_LAZY_MAP_MANAGER)
+
+ // Start here.
+ this->next_ = this->map_man_->occupied_list_.prev ();
+
+ while (1)
+ {
+ // Stop if we reach the end.
+ if (this->done ())
+ break;
+
+ // Break if we find a non-free slot.
+ if (!this->map_man_->search_structure_[this->next_].free_)
+ {
+ break;
+ }
+
+ // Go to the prev item in the list.
+ this->next_ = this->map_man_->search_structure_[this->next_].prev ();
+ }
+
+#else
+
+ this->next_ = this->map_man_->occupied_list_.prev ();
+
+#endif /* ACE_HAS_LAZY_MAP_MANAGER */
+
+}
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> ACE_INLINE int
+ACE_Map_Reverse_Iterator<EXT_ID, INT_ID, ACE_LOCK>::advance (void)
+{
+ return this->reverse_i ();
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> ACE_INLINE
+ACE_Map_Reverse_Iterator<EXT_ID, INT_ID, ACE_LOCK> &
+ACE_Map_Reverse_Iterator<EXT_ID, INT_ID, ACE_LOCK>::operator++ (void)
+{
+ this->reverse_i ();
+ return *this;
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> ACE_INLINE
+ACE_Map_Reverse_Iterator<EXT_ID, INT_ID, ACE_LOCK>
+ACE_Map_Reverse_Iterator<EXT_ID, INT_ID, ACE_LOCK>::operator++ (int)
+{
+ ACE_Map_Reverse_Iterator<EXT_ID, INT_ID, ACE_LOCK> retv (*this);
+ this->reverse_i ();
+ return retv;
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> ACE_INLINE
+ACE_Map_Reverse_Iterator<EXT_ID, INT_ID, ACE_LOCK> &
+ACE_Map_Reverse_Iterator<EXT_ID, INT_ID, ACE_LOCK>::operator-- (void)
+{
+ this->forward_i ();
+ return *this;
+}
+
+template <class EXT_ID, class INT_ID, class ACE_LOCK> ACE_INLINE
+ACE_Map_Reverse_Iterator<EXT_ID, INT_ID, ACE_LOCK>
+ACE_Map_Reverse_Iterator<EXT_ID, INT_ID, ACE_LOCK>::operator-- (int)
+{
+ ACE_Map_Reverse_Iterator<EXT_ID, INT_ID, ACE_LOCK> retv (*this);
+ this->forward_i ();
+ return retv;
+}
diff --git a/ace/Utils/Templates/Map_T.cpp b/ace/Utils/Templates/Map_T.cpp
new file mode 100644
index 00000000000..e2329089630
--- /dev/null
+++ b/ace/Utils/Templates/Map_T.cpp
@@ -0,0 +1,18 @@
+// $Id$
+
+#ifndef ACE_MAP_T_C
+#define ACE_MAP_T_C
+
+#include "ace/Map_T.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#if !defined (__ACE_INLINE__)
+#include "ace/Map_T.i"
+#endif /* __ACE_INLINE__ */
+
+ACE_RCSID(ace, Map_T, "$Id$")
+
+#endif /* ACE_MAP_T_C */
diff --git a/ace/Utils/Templates/Map_T.h b/ace/Utils/Templates/Map_T.h
new file mode 100644
index 00000000000..9b4dd6038ad
--- /dev/null
+++ b/ace/Utils/Templates/Map_T.h
@@ -0,0 +1,1602 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Map_T.h
+ *
+ * $Id$
+ *
+ * @author Irfan Pyarali <irfan@cs.wustl.edu>
+ */
+//=============================================================================
+
+#ifndef ACE_MAP_T_H
+#define ACE_MAP_T_H
+#include "ace/pre.h"
+
+#include "ace/Map.h"
+#include "ace/Pair.h"
+#include "ace/Map_Manager.h"
+#include "ace/Hash_Map_Manager.h"
+#include "ace/Active_Map_Manager.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+/**
+ * @class ACE_Noop_Key_Generator
+ *
+ * @brief Defines a noop key generator.
+ */
+template <class T>
+class ACE_Noop_Key_Generator
+{
+public:
+
+ /// Functor method: generates a new key.
+ int operator () (T &);
+};
+
+/**
+ * @class ACE_Incremental_Key_Generator
+ *
+ * @brief Defines a simple incremental key generator.
+ *
+ * Generates a new key of type T by incrementing current
+ * value. Requirements on T are:
+ * - Constructor that accepts 0 in the constructor.
+ * - Prefix increment.
+ * - Assignment.
+ * Note that a primitive types such as u_long, int, etc., are
+ * suitable for this class.
+ */
+template <class T>
+class ACE_Incremental_Key_Generator
+{
+public:
+
+ /// Constructor.
+ ACE_Incremental_Key_Generator (void);
+
+ /// Functor method: generates a new key.
+ int operator () (T &t);
+
+ /// Returns the current value.
+ const T& current_value (void) const;
+
+protected:
+
+ /// Current value.
+ T t_;
+};
+
+/**
+ * @class ACE_Iterator_Impl
+ *
+ * @brief Defines a abstract iterator.
+ *
+ * Implementation to be provided by subclasses.
+ */
+template <class T>
+class ACE_Iterator_Impl
+{
+public:
+
+ /// Destructor.
+ virtual ~ACE_Iterator_Impl (void);
+
+ /// Clone.
+ virtual ACE_Iterator_Impl<T> *clone (void) const = 0;
+
+ /// Comparison.
+ virtual int compare (const ACE_Iterator_Impl<T> &rhs) const = 0;
+
+ /// Dereference.
+ virtual T dereference (void) const = 0;
+
+ /// Advance.
+ virtual void plus_plus (void) = 0;
+
+ /// Reverse.
+ virtual void minus_minus (void) = 0;
+};
+
+/**
+ * @class ACE_Reverse_Iterator_Impl
+ *
+ * @brief Defines a abstract reverse iterator.
+ *
+ * Implementation to be provided by subclasses.
+ */
+template <class T>
+class ACE_Reverse_Iterator_Impl
+{
+public:
+
+ /// Destructor.
+ virtual ~ACE_Reverse_Iterator_Impl (void);
+
+ /// Clone.
+ virtual ACE_Reverse_Iterator_Impl<T> *clone (void) const = 0;
+
+ /// Comparison.
+ virtual int compare (const ACE_Reverse_Iterator_Impl<T> &rhs) const = 0;
+
+ /// Dereference.
+ virtual T dereference (void) const = 0;
+
+ /// Advance.
+ virtual void plus_plus (void) = 0;
+
+ /// Reverse.
+ virtual void minus_minus (void) = 0;
+};
+
+/**
+ * @class ACE_Iterator
+ *
+ * @brief Defines the iterator interface.
+ *
+ * Implementation to be provided by forwarding.
+ */
+template <class T>
+class ACE_Iterator
+{
+public:
+
+ // = Traits.
+ typedef T value_type;
+ typedef ACE_Iterator_Impl<T> implementation;
+
+ /// Constructor.
+ ACE_Iterator (ACE_Iterator_Impl<T> *impl);
+
+ /// Copy constructor.
+ ACE_Iterator (const ACE_Iterator<T> &rhs);
+
+ /// Destructor.
+ ~ACE_Iterator (void);
+
+ /// Assignment operator.
+ ACE_Iterator<T> &operator= (const ACE_Iterator<T> &rhs);
+
+ /// Comparison operators.
+ int operator== (const ACE_Iterator<T> &rhs) const;
+ int operator!= (const ACE_Iterator<T> &rhs) const;
+
+ /// Dereference operator.
+ T operator *() const;
+
+ /// Prefix advance.
+ ACE_Iterator<T> &operator++ (void);
+
+ /// Postfix advance.
+ ACE_Iterator<T> operator++ (int);
+
+ /// Prefix reverse.
+ ACE_Iterator<T> &operator-- (void);
+
+ /// Postfix reverse.
+ ACE_Iterator<T> operator-- (int);
+
+ /// Accessor to implementation object.
+ ACE_Iterator_Impl<T> &impl (void);
+
+protected:
+
+ /// Implementation pointer.
+ ACE_Iterator_Impl<T> *implementation_;
+};
+
+/**
+ * @class ACE_Reverse_Iterator
+ *
+ * @brief Defines the reverse iterator interface.
+ *
+ * Implementation to be provided by forwarding.
+ */
+template <class T>
+class ACE_Reverse_Iterator
+{
+public:
+
+ // = Traits.
+ typedef T value_type;
+ typedef ACE_Reverse_Iterator_Impl<T> implementation;
+
+ /// Constructor.
+ ACE_Reverse_Iterator (ACE_Reverse_Iterator_Impl<T> *impl);
+
+ /// Copy constructor.
+ ACE_Reverse_Iterator (const ACE_Reverse_Iterator<T> &rhs);
+
+ /// Destructor.
+ ~ACE_Reverse_Iterator (void);
+
+ /// Assignment operator.
+ ACE_Reverse_Iterator<T> &operator= (const ACE_Reverse_Iterator<T> &rhs);
+
+ /// Comparison operators.
+ int operator== (const ACE_Reverse_Iterator<T> &rhs) const;
+ int operator!= (const ACE_Reverse_Iterator<T> &rhs) const;
+
+ /// Dereference operator.
+ T operator *() const;
+
+ /// Prefix advance.
+ ACE_Reverse_Iterator<T> &operator++ (void);
+
+ /// Postfix advance.
+ ACE_Reverse_Iterator<T> operator++ (int);
+
+ /// Prefix reverse.
+ ACE_Reverse_Iterator<T> &operator-- (void);
+
+ /// Postfix reverse.
+ ACE_Reverse_Iterator<T> operator-- (int);
+
+ /// Accessor to implementation object.
+ ACE_Reverse_Iterator_Impl<T> &impl (void);
+
+protected:
+
+ /// Implementation pointer.
+ ACE_Reverse_Iterator_Impl<T> *implementation_;
+};
+
+/**
+ * @class ACE_Map
+ *
+ * @brief Defines a map interface.
+ *
+ * Implementation to be provided by subclasses.
+ */
+template <class KEY, class VALUE>
+class ACE_Map
+{
+public:
+
+ // = Traits.
+ typedef KEY
+ key_type;
+ typedef VALUE
+ mapped_type;
+ typedef ACE_Reference_Pair<const KEY, VALUE>
+ value_type;
+ typedef ACE_Iterator<value_type>
+ iterator;
+ typedef ACE_Reverse_Iterator<value_type>
+ reverse_iterator;
+ typedef ACE_Iterator_Impl<value_type>
+ iterator_implementation;
+ typedef ACE_Reverse_Iterator_Impl<value_type>
+ reverse_iterator_implementation;
+
+ /// Close down and release dynamically allocated resources.
+ virtual ~ACE_Map (void);
+
+ /// Initialize a <Map> with size <length>.
+ virtual int open (size_t length = ACE_DEFAULT_MAP_SIZE,
+ ACE_Allocator *alloc = 0) = 0;
+
+ /// Close down a <Map> and release dynamically allocated resources.
+ virtual int close (void) = 0;
+
+ /**
+ * Add <key>/<value> pair to the map. If <key> is already in the
+ * map then no changes are made and 1 is returned. Returns 0 on a
+ * successful addition. This function fails for maps that do not
+ * allow user specified keys. <key> is an "in" parameter.
+ */
+ virtual int bind (const KEY &key,
+ const VALUE &value) = 0;
+
+ /**
+ * Add <key>/<value> pair to the map. <key> is an "inout" parameter
+ * and maybe modified/extended by the map to add additional
+ * information. To recover original key, call the <recover_key>
+ * method.
+ */
+ virtual int bind_modify_key (const VALUE &value,
+ KEY &key) = 0;
+
+ /**
+ * Produce a key and return it through <key> which is an "out"
+ * parameter. For maps that do not naturally produce keys, the map
+ * adapters will use the <KEY_GENERATOR> class to produce a key.
+ * However, the users are responsible for not jeopardizing this key
+ * production scheme by using user specified keys with keys produced
+ * by the key generator.
+ */
+ virtual int create_key (KEY &key) = 0;
+
+ /**
+ * Add <value> to the map, and the corresponding key produced by the
+ * Map is returned through <key> which is an "out" parameter. For
+ * maps that do not naturally produce keys, the map adapters will
+ * use the <KEY_GENERATOR> class to produce a key. However, the
+ * users are responsible for not jeopardizing this key production
+ * scheme by using user specified keys with keys produced by the key
+ * generator.
+ */
+ virtual int bind_create_key (const VALUE &value,
+ KEY &key) = 0;
+
+ /**
+ * Add <value> to the map. The user does not care about the
+ * corresponding key produced by the Map. For maps that do not
+ * naturally produce keys, the map adapters will use the
+ * <KEY_GENERATOR> class to produce a key. However, the users are
+ * responsible for not jeopardizing this key production scheme by
+ * using user specified keys with keys produced by the key
+ * generator.
+ */
+ virtual int bind_create_key (const VALUE &value) = 0;
+
+ /// Recovers the original key potentially modified by the map during
+ /// <bind_modify_key>.
+ virtual int recover_key (const KEY &modified_key,
+ KEY &original_key) = 0;
+
+ /**
+ * Reassociate <key> with <value>. The function fails if <key> is
+ * not in the map for maps that do not allow user specified keys.
+ * However, for maps that allow user specified keys, if the key is
+ * not in the map, a new <key>/<value> association is created.
+ */
+ virtual int rebind (const KEY &key,
+ const VALUE &value) = 0;
+
+ /**
+ * Reassociate <key> with <value>, storing the old value into the
+ * "out" parameter <old_value>. The function fails if <key> is not
+ * in the map for maps that do not allow user specified keys.
+ * However, for maps that allow user specified keys, if the key is
+ * not in the map, a new <key>/<value> association is created.
+ */
+ virtual int rebind (const KEY &key,
+ const VALUE &value,
+ VALUE &old_value) = 0;
+
+ /**
+ * Reassociate <key> with <value>, storing the old key and value
+ * into the "out" parameters <old_key> and <old_value>. The
+ * function fails if <key> is not in the map for maps that do not
+ * allow user specified keys. However, for maps that allow user
+ * specified keys, if the key is not in the map, a new <key>/<value>
+ * association is created.
+ */
+ virtual int rebind (const KEY &key,
+ const VALUE &value,
+ KEY &old_key,
+ VALUE &old_value) = 0;
+
+ /**
+ * Associate <key> with <value> if and only if <key> is not in the
+ * map. If <key> is already in the map, then the <value> parameter
+ * is overwritten with the existing value in the map. Returns 0 if a
+ * new <key>/<value> association is created. Returns 1 if an
+ * attempt is made to bind an existing entry. This function fails
+ * for maps that do not allow user specified keys.
+ */
+ virtual int trybind (const KEY &key,
+ VALUE &value) = 0;
+
+ /// Locate <value> associated with <key>.
+ virtual int find (const KEY &key,
+ VALUE &value) = 0;
+
+ /// Is <key> in the map?
+ virtual int find (const KEY &key) = 0;
+
+ /// Remove <key> from the map.
+ virtual int unbind (const KEY &key) = 0;
+
+ /// Remove <key> from the map, and return the <value> associated with
+ /// <key>.
+ virtual int unbind (const KEY &key,
+ VALUE &value) = 0;
+
+ /// Return the current size of the map.
+ virtual size_t current_size (void) const = 0;
+
+ /// Return the total size of the map.
+ virtual size_t total_size (void) const = 0;
+
+ /// Dump the state of an object.
+ virtual void dump (void) const = 0;
+
+ // = STL styled iterator factory functions.
+
+ /// Return forward iterator.
+ iterator begin (void);
+ iterator end (void);
+
+ /// Return reverse iterator.
+ reverse_iterator rbegin (void);
+ reverse_iterator rend (void);
+
+protected:
+
+ // = Protected no-op constructor.
+ ACE_Map (void);
+
+ /// Return forward iterator.
+ virtual ACE_Iterator_Impl<ACE_Reference_Pair<const KEY, VALUE> > *begin_impl (void) = 0;
+ virtual ACE_Iterator_Impl<ACE_Reference_Pair<const KEY, VALUE> > *end_impl (void) = 0;
+
+ /// Return reverse iterator.
+ virtual ACE_Reverse_Iterator_Impl<ACE_Reference_Pair<const KEY, VALUE> > *rbegin_impl (void) = 0;
+ virtual ACE_Reverse_Iterator_Impl<ACE_Reference_Pair<const KEY, VALUE> > *rend_impl (void) = 0;
+
+private:
+
+ // = Disallow these operations.
+ ACE_UNIMPLEMENTED_FUNC (void operator= (const ACE_Map<KEY, VALUE> &))
+ ACE_UNIMPLEMENTED_FUNC (ACE_Map (const ACE_Map<KEY, VALUE> &))
+};
+
+/**
+ * @class ACE_Map_Impl_Iterator_Adapter
+ *
+ * @brief Defines a iterator implementation for the Map_Impl class.
+ *
+ * Implementation to be provided by <IMPLEMENTATION>.
+ */
+template <class T, class IMPLEMENTATION, class ENTRY>
+class ACE_Map_Impl_Iterator_Adapter : public ACE_Iterator_Impl<T>
+{
+public:
+
+ // = Traits.
+ typedef IMPLEMENTATION
+ implementation;
+
+ /// Constructor.
+ ACE_Map_Impl_Iterator_Adapter (const IMPLEMENTATION &impl);
+
+ /// Destructor.
+ virtual ~ACE_Map_Impl_Iterator_Adapter (void);
+
+ /// Clone.
+ virtual ACE_Iterator_Impl<T> *clone (void) const;
+
+ /// Comparison.
+ virtual int compare (const ACE_Iterator_Impl<T> &rhs) const;
+
+ /// Dereference.
+ virtual T dereference (void) const;
+
+ /// Advance.
+ virtual void plus_plus (void);
+
+ /// Reverse.
+ virtual void minus_minus (void);
+
+ /// Accessor to implementation object.
+ IMPLEMENTATION &impl (void);
+
+protected:
+
+ /// All implementation details are forwarded to this class.
+ IMPLEMENTATION implementation_;
+};
+
+/**
+ * @class ACE_Map_Impl_Reverse_Iterator_Adapter
+ *
+ * @brief Defines a reverse iterator implementation for the Map_Impl class.
+ *
+ * Implementation to be provided by IMPLEMENTATION.
+ */
+template <class T, class IMPLEMENTATION, class ENTRY>
+class ACE_Map_Impl_Reverse_Iterator_Adapter : public ACE_Reverse_Iterator_Impl<T>
+{
+public:
+
+ // = Traits.
+ typedef IMPLEMENTATION
+ implementation;
+
+ /// Constructor.
+ ACE_Map_Impl_Reverse_Iterator_Adapter (const IMPLEMENTATION &impl);
+
+ /// Destructor.
+ virtual ~ACE_Map_Impl_Reverse_Iterator_Adapter (void);
+
+ /// Clone.
+ virtual ACE_Reverse_Iterator_Impl<T> *clone (void) const;
+
+ /// Comparison.
+ virtual int compare (const ACE_Reverse_Iterator_Impl<T> &rhs) const;
+
+ /// Dereference.
+ virtual T dereference (void) const;
+
+ /// Advance.
+ virtual void plus_plus (void);
+
+ /// Reverse.
+ virtual void minus_minus (void);
+
+ /// Accessor to implementation object.
+ IMPLEMENTATION &impl (void);
+
+protected:
+
+ /// All implementation details are forwarded to this class.
+ IMPLEMENTATION implementation_;
+};
+
+/**
+ * @class ACE_Map_Impl
+ *
+ * @brief Defines a map implementation.
+ *
+ * Implementation to be provided by <IMPLEMENTATION>.
+ */
+template <class KEY, class VALUE, class IMPLEMENTATION, class ITERATOR, class REVERSE_ITERATOR, class ENTRY>
+class ACE_Map_Impl : public ACE_Map<KEY, VALUE>
+{
+public:
+
+ // = Traits.
+ typedef ACE_Map_Impl_Iterator_Adapter<ACE_TYPENAME ACE_Map<KEY, VALUE>::value_type, ITERATOR, ENTRY>
+ iterator_impl;
+ typedef ACE_Map_Impl_Reverse_Iterator_Adapter<ACE_TYPENAME ACE_Map<KEY, VALUE>::value_type, REVERSE_ITERATOR, ENTRY>
+ reverse_iterator_impl;
+
+ typedef IMPLEMENTATION
+ implementation;
+
+ // = Initialization and termination methods.
+ /// Initialize with the <ACE_DEFAULT_MAP_SIZE>.
+ ACE_Map_Impl (ACE_Allocator *alloc = 0);
+
+ /// Initialize with <size> entries. The <size> parameter is ignored
+ /// by maps for which an initialize size does not make sense.
+ ACE_Map_Impl (size_t size,
+ ACE_Allocator *alloc = 0);
+
+ /// Close down and release dynamically allocated resources.
+ virtual ~ACE_Map_Impl (void);
+
+ /// Initialize a <Map> with size <length>.
+ virtual int open (size_t length = ACE_DEFAULT_MAP_SIZE,
+ ACE_Allocator *alloc = 0);
+
+ /// Close down a <Map> and release dynamically allocated resources.
+ virtual int close (void);
+
+ /**
+ * Add <key>/<value> pair to the map. If <key> is already in the
+ * map then no changes are made and 1 is returned. Returns 0 on a
+ * successful addition. This function fails for maps that do not
+ * allow user specified keys. <key> is an "in" parameter.
+ */
+ virtual int bind (const KEY &key,
+ const VALUE &value);
+
+ /**
+ * Add <key>/<value> pair to the map. <key> is an "inout" parameter
+ * and maybe modified/extended by the map to add additional
+ * information. To recover original key, call the <recover_key>
+ * method.
+ */
+ virtual int bind_modify_key (const VALUE &value,
+ KEY &key);
+
+ /**
+ * Produce a key and return it through <key> which is an "out"
+ * parameter. For maps that do not naturally produce keys, the map
+ * adapters will use the <KEY_GENERATOR> class to produce a key.
+ * However, the users are responsible for not jeopardizing this key
+ * production scheme by using user specified keys with keys produced
+ * by the key generator.
+ */
+ virtual int create_key (KEY &key);
+
+ /**
+ * Add <value> to the map, and the corresponding key produced by the
+ * Map is returned through <key> which is an "out" parameter. For
+ * maps that do not naturally produce keys, the map adapters will
+ * use the <KEY_GENERATOR> class to produce a key. However, the
+ * users are responsible for not jeopardizing this key production
+ * scheme by using user specified keys with keys produced by the key
+ * generator.
+ */
+ virtual int bind_create_key (const VALUE &value,
+ KEY &key);
+
+ /**
+ * Add <value> to the map. The user does not care about the
+ * corresponding key produced by the Map. For maps that do not
+ * naturally produce keys, the map adapters will use the
+ * <KEY_GENERATOR> class to produce a key. However, the users are
+ * responsible for not jeopardizing this key production scheme by
+ * using user specified keys with keys produced by the key
+ * generator.
+ */
+ virtual int bind_create_key (const VALUE &value);
+
+ /// Recovers the original key potentially modified by the map during
+ /// <bind_modify_key>.
+ virtual int recover_key (const KEY &modified_key,
+ KEY &original_key);
+
+ /**
+ * Reassociate <key> with <value>. The function fails if <key> is
+ * not in the map for maps that do not allow user specified keys.
+ * However, for maps that allow user specified keys, if the key is
+ * not in the map, a new <key>/<value> association is created.
+ */
+ virtual int rebind (const KEY &key,
+ const VALUE &value);
+
+ /**
+ * Reassociate <key> with <value>, storing the old value into the
+ * "out" parameter <old_value>. The function fails if <key> is not
+ * in the map for maps that do not allow user specified keys.
+ * However, for maps that allow user specified keys, if the key is
+ * not in the map, a new <key>/<value> association is created.
+ */
+ virtual int rebind (const KEY &key,
+ const VALUE &value,
+ VALUE &old_value);
+
+ /**
+ * Reassociate <key> with <value>, storing the old key and value
+ * into the "out" parameters <old_key> and <old_value>. The
+ * function fails if <key> is not in the map for maps that do not
+ * allow user specified keys. However, for maps that allow user
+ * specified keys, if the key is not in the map, a new <key>/<value>
+ * association is created.
+ */
+ virtual int rebind (const KEY &key,
+ const VALUE &value,
+ KEY &old_key,
+ VALUE &old_value);
+
+ /**
+ * Associate <key> with <value> if and only if <key> is not in the
+ * map. If <key> is already in the map, then the <value> parameter
+ * is overwritten with the existing value in the map. Returns 0 if a
+ * new <key>/<value> association is created. Returns 1 if an
+ * attempt is made to bind an existing entry. This function fails
+ * for maps that do not allow user specified keys.
+ */
+ virtual int trybind (const KEY &key,
+ VALUE &value);
+
+ /// Locate <value> associated with <key>.
+ virtual int find (const KEY &key,
+ VALUE &value);
+
+ /// Is <key> in the map?
+ virtual int find (const KEY &key);
+
+ /// Remove <key> from the map.
+ virtual int unbind (const KEY &key);
+
+ /// Remove <key> from the map, and return the <value> associated with
+ /// <key>.
+ virtual int unbind (const KEY &key,
+ VALUE &value);
+
+ /// Return the current size of the map.
+ virtual size_t current_size (void) const;
+
+ /// Return the total size of the map.
+ virtual size_t total_size (void) const;
+
+ /// Dump the state of an object.
+ virtual void dump (void) const;
+
+ /// Accessor to implementation object.
+ IMPLEMENTATION &impl (void);
+
+protected:
+
+ /// All implementation details are forwarded to this class.
+ IMPLEMENTATION implementation_;
+
+ // = STL styled iterator factory functions.
+
+ /// Return forward iterator.
+ virtual ACE_Iterator_Impl<ACE_Reference_Pair<const KEY, VALUE> > *begin_impl (void);
+ virtual ACE_Iterator_Impl<ACE_Reference_Pair<const KEY, VALUE> > *end_impl (void);
+
+ /// Return reverse iterator.
+ virtual ACE_Reverse_Iterator_Impl<ACE_Reference_Pair<const KEY, VALUE> > *rbegin_impl (void);
+ virtual ACE_Reverse_Iterator_Impl<ACE_Reference_Pair<const KEY, VALUE> > *rend_impl (void);
+
+private:
+
+ // = Disallow these operations.
+ ACE_UNIMPLEMENTED_FUNC (void operator= (const ACE_Map_Impl<KEY, VALUE, IMPLEMENTATION, ITERATOR, REVERSE_ITERATOR, ENTRY> &))
+ ACE_UNIMPLEMENTED_FUNC (ACE_Map_Impl (const ACE_Map_Impl<KEY, VALUE, IMPLEMENTATION, ITERATOR, REVERSE_ITERATOR, ENTRY> &))
+};
+
+/**
+ * @class ACE_Active_Map_Manager_Iterator_Adapter
+ *
+ * @brief Defines a iterator implementation for the Active_Map_Manager_Adapter.
+ *
+ * Implementation to be provided by ACE_Active_Map_Manager::iterator.
+ */
+template <class T, class VALUE>
+class ACE_Active_Map_Manager_Iterator_Adapter : public ACE_Iterator_Impl<T>
+{
+public:
+
+ // = Traits.
+ typedef ACE_TYPENAME ACE_Active_Map_Manager<VALUE>::iterator
+ implementation;
+
+ /// Constructor.
+ ACE_Active_Map_Manager_Iterator_Adapter (const ACE_Map_Iterator<ACE_Active_Map_Manager_Key, VALUE, ACE_Null_Mutex> &impl);
+
+ /// Destructor.
+ virtual ~ACE_Active_Map_Manager_Iterator_Adapter (void);
+
+ /// Clone.
+ virtual ACE_Iterator_Impl<T> *clone (void) const;
+
+ /// Comparison.
+ virtual int compare (const ACE_Iterator_Impl<T> &rhs) const;
+
+ /// Dereference.
+ virtual T dereference (void) const;
+
+ /// Advance.
+ virtual void plus_plus (void);
+
+ /// Reverse.
+ virtual void minus_minus (void);
+
+ /// Accessor to implementation object.
+ ACE_Map_Iterator<ACE_Active_Map_Manager_Key, VALUE, ACE_Null_Mutex> &impl (void);
+
+protected:
+
+ /// All implementation details are forwarded to this class.
+ ACE_Map_Iterator<ACE_Active_Map_Manager_Key, VALUE, ACE_Null_Mutex> implementation_;
+};
+
+/**
+ * @class ACE_Active_Map_Manager_Reverse_Iterator_Adapter
+ *
+ * @brief Defines a reverse iterator implementation for the Active_Map_Manager_Adapter.
+ *
+ * Implementation to be provided by ACE_Active_Map_Manager::reverse_iterator.
+ */
+template <class T, class VALUE>
+class ACE_Active_Map_Manager_Reverse_Iterator_Adapter : public ACE_Reverse_Iterator_Impl<T>
+{
+public:
+
+ // = Traits.
+ typedef ACE_TYPENAME ACE_Active_Map_Manager<VALUE>::reverse_iterator
+ implementation;
+
+ /// Constructor.
+ ACE_Active_Map_Manager_Reverse_Iterator_Adapter (const ACE_Map_Reverse_Iterator<ACE_Active_Map_Manager_Key, VALUE, ACE_Null_Mutex> &impl);
+
+ /// Destructor.
+ virtual ~ACE_Active_Map_Manager_Reverse_Iterator_Adapter (void);
+
+ /// Clone.
+ virtual ACE_Reverse_Iterator_Impl<T> *clone (void) const;
+
+ /// Comparison.
+ virtual int compare (const ACE_Reverse_Iterator_Impl<T> &rhs) const;
+
+ /// Dereference.
+ virtual T dereference (void) const;
+
+ /// Advance.
+ virtual void plus_plus (void);
+
+ /// Reverse.
+ virtual void minus_minus (void);
+
+ /// Accessor to implementation object.
+ ACE_Map_Reverse_Iterator<ACE_Active_Map_Manager_Key, VALUE, ACE_Null_Mutex> &impl (void);
+
+protected:
+
+ /// All implementation details are forwarded to this class.
+ ACE_Map_Reverse_Iterator<ACE_Active_Map_Manager_Key, VALUE, ACE_Null_Mutex> implementation_;
+};
+
+/**
+ * @class ACE_Active_Map_Manager_Adapter
+ *
+ * @brief Defines a map implementation.
+ *
+ * Implementation to be provided by <ACE_Active_Map_Manager>.
+ */
+template <class KEY, class VALUE, class KEY_ADAPTER>
+class ACE_Active_Map_Manager_Adapter : public ACE_Map<KEY, VALUE>
+{
+public:
+
+ // = Traits.
+ typedef ACE_Pair<KEY, VALUE>
+ expanded_value;
+ typedef ACE_Active_Map_Manager_Iterator_Adapter<ACE_Reference_Pair<const KEY, VALUE>, expanded_value>
+ iterator_impl;
+ typedef ACE_Active_Map_Manager_Reverse_Iterator_Adapter<ACE_Reference_Pair<const KEY, VALUE>, expanded_value>
+ reverse_iterator_impl;
+ typedef ACE_Active_Map_Manager<expanded_value>
+ implementation;
+
+ // = Initialization and termination methods.
+ /// Initialize with the <ACE_DEFAULT_MAP_SIZE>.
+ ACE_Active_Map_Manager_Adapter (ACE_Allocator *alloc = 0);
+
+ /// Initialize with <size> entries. The <size> parameter is ignored
+ /// by maps for which an initialize size does not make sense.
+ ACE_Active_Map_Manager_Adapter (size_t size,
+ ACE_Allocator *alloc = 0);
+
+ /// Close down and release dynamically allocated resources.
+ virtual ~ACE_Active_Map_Manager_Adapter (void);
+
+ /// Initialize a <Map> with size <length>.
+ virtual int open (size_t length = ACE_DEFAULT_MAP_SIZE,
+ ACE_Allocator *alloc = 0);
+
+ /// Close down a <Map> and release dynamically allocated resources.
+ virtual int close (void);
+
+ /**
+ * Add <key>/<value> pair to the map. If <key> is already in the
+ * map then no changes are made and 1 is returned. Returns 0 on a
+ * successful addition. This function fails for maps that do not
+ * allow user specified keys. <key> is an "in" parameter.
+ */
+ virtual int bind (const KEY &key,
+ const VALUE &value);
+
+ /**
+ * Add <key>/<value> pair to the map. <key> is an "inout" parameter
+ * and maybe modified/extended by the map to add additional
+ * information. To recover original key, call the <recover_key>
+ * method.
+ */
+ virtual int bind_modify_key (const VALUE &value,
+ KEY &key);
+
+ /**
+ * Produce a key and return it through <key> which is an "out"
+ * parameter. For maps that do not naturally produce keys, the map
+ * adapters will use the <KEY_GENERATOR> class to produce a key.
+ * However, the users are responsible for not jeopardizing this key
+ * production scheme by using user specified keys with keys produced
+ * by the key generator.
+ */
+ virtual int create_key (KEY &key);
+
+ /**
+ * Add <value> to the map, and the corresponding key produced by the
+ * Map is returned through <key> which is an "out" parameter. For
+ * maps that do not naturally produce keys, the map adapters will
+ * use the <KEY_GENERATOR> class to produce a key. However, the
+ * users are responsible for not jeopardizing this key production
+ * scheme by using user specified keys with keys produced by the key
+ * generator.
+ */
+ virtual int bind_create_key (const VALUE &value,
+ KEY &key);
+
+ /**
+ * Add <value> to the map. The user does not care about the
+ * corresponding key produced by the Map. For maps that do not
+ * naturally produce keys, the map adapters will use the
+ * <KEY_GENERATOR> class to produce a key. However, the users are
+ * responsible for not jeopardizing this key production scheme by
+ * using user specified keys with keys produced by the key
+ * generator.
+ */
+ virtual int bind_create_key (const VALUE &value);
+
+ /// Recovers the original key potentially modified by the map during
+ /// <bind_modify_key>.
+ virtual int recover_key (const KEY &modified_key,
+ KEY &original_key);
+
+ /**
+ * Reassociate <key> with <value>. The function fails if <key> is
+ * not in the map for maps that do not allow user specified keys.
+ * However, for maps that allow user specified keys, if the key is
+ * not in the map, a new <key>/<value> association is created.
+ */
+ virtual int rebind (const KEY &key,
+ const VALUE &value);
+
+ /**
+ * Reassociate <key> with <value>, storing the old value into the
+ * "out" parameter <old_value>. The function fails if <key> is not
+ * in the map for maps that do not allow user specified keys.
+ * However, for maps that allow user specified keys, if the key is
+ * not in the map, a new <key>/<value> association is created.
+ */
+ virtual int rebind (const KEY &key,
+ const VALUE &value,
+ VALUE &old_value);
+
+ /**
+ * Reassociate <key> with <value>, storing the old key and value
+ * into the "out" parameters <old_key> and <old_value>. The
+ * function fails if <key> is not in the map for maps that do not
+ * allow user specified keys. However, for maps that allow user
+ * specified keys, if the key is not in the map, a new <key>/<value>
+ * association is created.
+ */
+ virtual int rebind (const KEY &key,
+ const VALUE &value,
+ KEY &old_key,
+ VALUE &old_value);
+
+ /**
+ * Associate <key> with <value> if and only if <key> is not in the
+ * map. If <key> is already in the map, then the <value> parameter
+ * is overwritten with the existing value in the map. Returns 0 if a
+ * new <key>/<value> association is created. Returns 1 if an
+ * attempt is made to bind an existing entry. This function fails
+ * for maps that do not allow user specified keys.
+ */
+ virtual int trybind (const KEY &key,
+ VALUE &value);
+
+ /// Locate <value> associated with <key>.
+ virtual int find (const KEY &key,
+ VALUE &value);
+
+ /// Is <key> in the map?
+ virtual int find (const KEY &key);
+
+ /// Remove <key> from the map.
+ virtual int unbind (const KEY &key);
+
+ /// Remove <key> from the map, and return the <value> associated with
+ /// <key>.
+ virtual int unbind (const KEY &key,
+ VALUE &value);
+
+ /// Return the current size of the map.
+ virtual size_t current_size (void) const;
+
+ /// Return the total size of the map.
+ virtual size_t total_size (void) const;
+
+ /// Dump the state of an object.
+ virtual void dump (void) const;
+
+ /// Accessor to implementation object.
+ ACE_Active_Map_Manager<ACE_Pair<KEY, VALUE> > &impl (void);
+
+ /// Accessor to key adapter.
+ KEY_ADAPTER &key_adapter (void);
+
+protected:
+
+ /// Find helper.
+ virtual int find (const KEY &key,
+ expanded_value *&internal_value);
+
+ /// Unbind helper.
+ virtual int unbind (const KEY &key,
+ expanded_value *&internal_value);
+
+ /// All implementation details are forwarded to this class.
+ ACE_Active_Map_Manager<ACE_Pair<KEY, VALUE> > implementation_;
+
+ /// Adapts between the user key and the Active_Map_Manager_Key.
+ KEY_ADAPTER key_adapter_;
+
+ // = STL styled iterator factory functions.
+
+ /// Return forward iterator.
+ virtual ACE_Iterator_Impl<ACE_Reference_Pair<const KEY, VALUE> > *begin_impl (void);
+ virtual ACE_Iterator_Impl<ACE_Reference_Pair<const KEY, VALUE> > *end_impl (void);
+
+ /// Return reverse iterator.
+ virtual ACE_Reverse_Iterator_Impl<ACE_Reference_Pair<const KEY, VALUE> > *rbegin_impl (void);
+ virtual ACE_Reverse_Iterator_Impl<ACE_Reference_Pair<const KEY, VALUE> > *rend_impl (void);
+
+private:
+
+ // = Disallow these operations.
+ ACE_UNIMPLEMENTED_FUNC (void operator= (const ACE_Active_Map_Manager_Adapter<KEY, VALUE, KEY_ADAPTER> &))
+ ACE_UNIMPLEMENTED_FUNC (ACE_Active_Map_Manager_Adapter (const ACE_Active_Map_Manager_Adapter<KEY, VALUE, KEY_ADAPTER> &))
+};
+
+/**
+ * @class ACE_Hash_Map_Manager_Ex_Iterator_Adapter
+ *
+ * @brief Defines a iterator implementation for the Hash_Map_Manager_Adapter.
+ *
+ * Implementation to be provided by ACE_Hash_Map_Manager_Ex::iterator.
+ */
+template <class T, class KEY, class VALUE, class HASH_KEY, class COMPARE_KEYS>
+class ACE_Hash_Map_Manager_Ex_Iterator_Adapter : public ACE_Iterator_Impl<T>
+{
+public:
+
+ // = Traits.
+ typedef ACE_TYPENAME ACE_Hash_Map_Manager_Ex<KEY, VALUE, HASH_KEY, COMPARE_KEYS, ACE_Null_Mutex>::iterator
+ implementation;
+
+ /// Constructor.
+ ACE_Hash_Map_Manager_Ex_Iterator_Adapter (const ACE_Hash_Map_Iterator_Ex<KEY, VALUE, HASH_KEY, COMPARE_KEYS, ACE_Null_Mutex> &impl);
+
+ /// Destructor.
+ virtual ~ACE_Hash_Map_Manager_Ex_Iterator_Adapter (void);
+
+ /// Clone.
+ virtual ACE_Iterator_Impl<T> *clone (void) const;
+
+ /// Comparison.
+ virtual int compare (const ACE_Iterator_Impl<T> &rhs) const;
+
+ /// Dereference.
+ virtual T dereference (void) const;
+
+ /// Advance.
+ virtual void plus_plus (void);
+
+ /// Reverse.
+ virtual void minus_minus (void);
+
+ /// Accessor to implementation object.
+ ACE_Hash_Map_Iterator_Ex<KEY, VALUE, HASH_KEY, COMPARE_KEYS, ACE_Null_Mutex> &impl (void);
+
+protected:
+
+ /// All implementation details are forwarded to this class.
+ ACE_Hash_Map_Iterator_Ex<KEY, VALUE, HASH_KEY, COMPARE_KEYS, ACE_Null_Mutex> implementation_;
+};
+
+/**
+ * @class ACE_Hash_Map_Manager_Ex_Reverse_Iterator_Adapter
+ *
+ * @brief Defines a reverse iterator implementation for the Hash_Map_Manager_Adapter.
+ *
+ * Implementation to be provided by ACE_Hash_Map_Manager_Ex::reverse_iterator.
+ */
+template <class T, class KEY, class VALUE, class HASH_KEY, class COMPARE_KEYS>
+class ACE_Hash_Map_Manager_Ex_Reverse_Iterator_Adapter : public ACE_Reverse_Iterator_Impl<T>
+{
+public:
+
+ // = Traits.
+ typedef ACE_TYPENAME ACE_Hash_Map_Manager_Ex<KEY, VALUE, HASH_KEY, COMPARE_KEYS, ACE_Null_Mutex>::reverse_iterator
+ implementation;
+
+ /// Constructor.
+ ACE_Hash_Map_Manager_Ex_Reverse_Iterator_Adapter (const ACE_Hash_Map_Reverse_Iterator_Ex<KEY, VALUE, HASH_KEY, COMPARE_KEYS, ACE_Null_Mutex> &impl);
+
+ /// Destructor.
+ virtual ~ACE_Hash_Map_Manager_Ex_Reverse_Iterator_Adapter (void);
+
+ /// Clone.
+ virtual ACE_Reverse_Iterator_Impl<T> *clone (void) const;
+
+ /// Comparison.
+ virtual int compare (const ACE_Reverse_Iterator_Impl<T> &rhs) const;
+
+ /// Dereference.
+ virtual T dereference (void) const;
+
+ /// Advance.
+ virtual void plus_plus (void);
+
+ /// Reverse.
+ virtual void minus_minus (void);
+
+ /// Accessor to implementation object.
+ ACE_Hash_Map_Reverse_Iterator_Ex<KEY, VALUE, HASH_KEY, COMPARE_KEYS, ACE_Null_Mutex> &impl (void);
+
+protected:
+
+ /// All implementation details are forwarded to this class.
+ ACE_Hash_Map_Reverse_Iterator_Ex<KEY, VALUE, HASH_KEY, COMPARE_KEYS, ACE_Null_Mutex> implementation_;
+};
+
+/**
+ * @class ACE_Hash_Map_Manager_Ex_Adapter
+ *
+ * @brief Defines a map implementation.
+ *
+ * Implementation to be provided by <ACE_Hash_Map_Manager_Ex>.
+ */
+template <class KEY, class VALUE, class HASH_KEY, class COMPARE_KEYS, class KEY_GENERATOR>
+class ACE_Hash_Map_Manager_Ex_Adapter : public ACE_Map<KEY, VALUE>
+{
+public:
+
+ // = Traits.
+ typedef ACE_Hash_Map_Manager_Ex_Iterator_Adapter<ACE_Reference_Pair<const KEY, VALUE>, KEY, VALUE, HASH_KEY, COMPARE_KEYS>
+ iterator_impl;
+ typedef ACE_Hash_Map_Manager_Ex_Reverse_Iterator_Adapter<ACE_Reference_Pair<const KEY, VALUE>, KEY, VALUE, HASH_KEY, COMPARE_KEYS>
+ reverse_iterator_impl;
+ typedef ACE_Hash_Map_Manager_Ex<KEY, VALUE, HASH_KEY, COMPARE_KEYS, ACE_Null_Mutex>
+ implementation;
+
+ // = Initialization and termination methods.
+ /// Initialize with the <ACE_DEFAULT_MAP_SIZE>.
+ ACE_Hash_Map_Manager_Ex_Adapter (ACE_Allocator *alloc = 0);
+
+ /// Initialize with <size> entries. The <size> parameter is ignored
+ /// by maps for which an initialize size does not make sense.
+ ACE_Hash_Map_Manager_Ex_Adapter (size_t size,
+ ACE_Allocator *alloc = 0);
+
+ /// Close down and release dynamically allocated resources.
+ virtual ~ACE_Hash_Map_Manager_Ex_Adapter (void);
+
+ /// Initialize a <Map> with size <length>.
+ virtual int open (size_t length = ACE_DEFAULT_MAP_SIZE,
+ ACE_Allocator *alloc = 0);
+
+ /// Close down a <Map> and release dynamically allocated resources.
+ virtual int close (void);
+
+ /**
+ * Add <key>/<value> pair to the map. If <key> is already in the
+ * map then no changes are made and 1 is returned. Returns 0 on a
+ * successful addition. This function fails for maps that do not
+ * allow user specified keys. <key> is an "in" parameter.
+ */
+ virtual int bind (const KEY &key,
+ const VALUE &value);
+
+ /**
+ * Add <key>/<value> pair to the map. <key> is an "inout" parameter
+ * and maybe modified/extended by the map to add additional
+ * information. To recover original key, call the <recover_key>
+ * method.
+ */
+ virtual int bind_modify_key (const VALUE &value,
+ KEY &key);
+
+ /**
+ * Produce a key and return it through <key> which is an "out"
+ * parameter. For maps that do not naturally produce keys, the map
+ * adapters will use the <KEY_GENERATOR> class to produce a key.
+ * However, the users are responsible for not jeopardizing this key
+ * production scheme by using user specified keys with keys produced
+ * by the key generator.
+ */
+ virtual int create_key (KEY &key);
+
+ /**
+ * Add <value> to the map, and the corresponding key produced by the
+ * Map is returned through <key> which is an "out" parameter. For
+ * maps that do not naturally produce keys, the map adapters will
+ * use the <KEY_GENERATOR> class to produce a key. However, the
+ * users are responsible for not jeopardizing this key production
+ * scheme by using user specified keys with keys produced by the key
+ * generator.
+ */
+ virtual int bind_create_key (const VALUE &value,
+ KEY &key);
+
+ /**
+ * Add <value> to the map. The user does not care about the
+ * corresponding key produced by the Map. For maps that do not
+ * naturally produce keys, the map adapters will use the
+ * <KEY_GENERATOR> class to produce a key. However, the users are
+ * responsible for not jeopardizing this key production scheme by
+ * using user specified keys with keys produced by the key
+ * generator.
+ */
+ virtual int bind_create_key (const VALUE &value);
+
+ /// Recovers the original key potentially modified by the map during
+ /// <bind_modify_key>.
+ virtual int recover_key (const KEY &modified_key,
+ KEY &original_key);
+
+ /**
+ * Reassociate <key> with <value>. The function fails if <key> is
+ * not in the map for maps that do not allow user specified keys.
+ * However, for maps that allow user specified keys, if the key is
+ * not in the map, a new <key>/<value> association is created.
+ */
+ virtual int rebind (const KEY &key,
+ const VALUE &value);
+
+ /**
+ * Reassociate <key> with <value>, storing the old value into the
+ * "out" parameter <old_value>. The function fails if <key> is not
+ * in the map for maps that do not allow user specified keys.
+ * However, for maps that allow user specified keys, if the key is
+ * not in the map, a new <key>/<value> association is created.
+ */
+ virtual int rebind (const KEY &key,
+ const VALUE &value,
+ VALUE &old_value);
+
+ /**
+ * Reassociate <key> with <value>, storing the old key and value
+ * into the "out" parameters <old_key> and <old_value>. The
+ * function fails if <key> is not in the map for maps that do not
+ * allow user specified keys. However, for maps that allow user
+ * specified keys, if the key is not in the map, a new <key>/<value>
+ * association is created.
+ */
+ virtual int rebind (const KEY &key,
+ const VALUE &value,
+ KEY &old_key,
+ VALUE &old_value);
+
+ /**
+ * Associate <key> with <value> if and only if <key> is not in the
+ * map. If <key> is already in the map, then the <value> parameter
+ * is overwritten with the existing value in the map. Returns 0 if a
+ * new <key>/<value> association is created. Returns 1 if an
+ * attempt is made to bind an existing entry. This function fails
+ * for maps that do not allow user specified keys.
+ */
+ virtual int trybind (const KEY &key,
+ VALUE &value);
+
+ /// Locate <value> associated with <key>.
+ virtual int find (const KEY &key,
+ VALUE &value);
+
+ /// Is <key> in the map?
+ virtual int find (const KEY &key);
+
+ /// Remove <key> from the map.
+ virtual int unbind (const KEY &key);
+
+ /// Remove <key> from the map, and return the <value> associated with
+ /// <key>.
+ virtual int unbind (const KEY &key,
+ VALUE &value);
+
+ /// Return the current size of the map.
+ virtual size_t current_size (void) const;
+
+ /// Return the total size of the map.
+ virtual size_t total_size (void) const;
+
+ /// Dump the state of an object.
+ virtual void dump (void) const;
+
+ /// Accessor to implementation object.
+ ACE_Hash_Map_Manager_Ex<KEY, VALUE, HASH_KEY, COMPARE_KEYS, ACE_Null_Mutex> &impl (void);
+
+ /// Accessor to key generator.
+ KEY_GENERATOR &key_generator (void);
+
+protected:
+
+ /// All implementation details are forwarded to this class.
+ ACE_Hash_Map_Manager_Ex<KEY, VALUE, HASH_KEY, COMPARE_KEYS, ACE_Null_Mutex> implementation_;
+
+ /// Functor class used for generating key.
+ KEY_GENERATOR key_generator_;
+
+ // = STL styled iterator factory functions.
+
+ /// Return forward iterator.
+ virtual ACE_Iterator_Impl<ACE_Reference_Pair<const KEY, VALUE> > *begin_impl (void);
+ virtual ACE_Iterator_Impl<ACE_Reference_Pair<const KEY, VALUE> > *end_impl (void);
+
+ /// Return reverse iterator.
+ virtual ACE_Reverse_Iterator_Impl<ACE_Reference_Pair<const KEY, VALUE> > *rbegin_impl (void);
+ virtual ACE_Reverse_Iterator_Impl<ACE_Reference_Pair<const KEY, VALUE> > *rend_impl (void);
+
+private:
+
+ // = Disallow these operations.
+ ACE_UNIMPLEMENTED_FUNC (void operator= (const ACE_Hash_Map_Manager_Ex_Adapter<KEY, VALUE, HASH_KEY, COMPARE_KEYS, KEY_GENERATOR> &))
+ ACE_UNIMPLEMENTED_FUNC (ACE_Hash_Map_Manager_Ex_Adapter (const ACE_Hash_Map_Manager_Ex_Adapter<KEY, VALUE, HASH_KEY, COMPARE_KEYS, KEY_GENERATOR> &))
+};
+
+/**
+ * @class ACE_Map_Manager_Iterator_Adapter
+ *
+ * @brief Defines a iterator implementation for the Map_Manager_Adapter.
+ *
+ * Implementation to be provided by ACE_Map_Manager::iterator.
+ */
+template <class T, class KEY, class VALUE>
+class ACE_Map_Manager_Iterator_Adapter : public ACE_Iterator_Impl<T>
+{
+public:
+
+ // = Traits.
+ typedef ACE_TYPENAME ACE_Map_Manager<KEY, VALUE, ACE_Null_Mutex>::iterator
+ implementation;
+
+ /// Constructor.
+ ACE_Map_Manager_Iterator_Adapter (const ACE_Map_Iterator<KEY, VALUE, ACE_Null_Mutex> &impl);
+
+ /// Destructor.
+ virtual ~ACE_Map_Manager_Iterator_Adapter (void);
+
+ /// Clone.
+ virtual ACE_Iterator_Impl<T> *clone (void) const;
+
+ /// Comparison.
+ virtual int compare (const ACE_Iterator_Impl<T> &rhs) const;
+
+ /// Dereference.
+ virtual T dereference (void) const;
+
+ /// Advance.
+ virtual void plus_plus (void);
+
+ /// Reverse.
+ virtual void minus_minus (void);
+
+ /// Accessor to implementation object.
+ ACE_Map_Iterator<KEY, VALUE, ACE_Null_Mutex> &impl (void);
+
+protected:
+
+ /// All implementation details are forwarded to this class.
+ ACE_Map_Iterator<KEY, VALUE, ACE_Null_Mutex> implementation_;
+};
+
+/**
+ * @class ACE_Map_Manager_Reverse_Iterator_Adapter
+ *
+ * @brief Defines a reverse iterator implementation for the Map Manager.
+ *
+ * Implementation to be provided by ACE_Map_Manager::reverse_iterator.
+ */
+template <class T, class KEY, class VALUE>
+class ACE_Map_Manager_Reverse_Iterator_Adapter : public ACE_Reverse_Iterator_Impl<T>
+{
+public:
+
+ // = Traits.
+ typedef ACE_TYPENAME ACE_Map_Manager<KEY, VALUE, ACE_Null_Mutex>::reverse_iterator
+ implementation;
+
+ /// Constructor.
+ ACE_Map_Manager_Reverse_Iterator_Adapter (const ACE_Map_Reverse_Iterator<KEY, VALUE, ACE_Null_Mutex> &impl);
+
+ /// Destructor.
+ virtual ~ACE_Map_Manager_Reverse_Iterator_Adapter (void);
+
+ /// Clone.
+ virtual ACE_Reverse_Iterator_Impl<T> *clone (void) const;
+
+ /// Comparison.
+ virtual int compare (const ACE_Reverse_Iterator_Impl<T> &rhs) const;
+
+ /// Dereference.
+ virtual T dereference (void) const;
+
+ /// Advance.
+ virtual void plus_plus (void);
+
+ /// Reverse.
+ virtual void minus_minus (void);
+
+ /// Accessor to implementation object.
+ ACE_Map_Reverse_Iterator<KEY, VALUE, ACE_Null_Mutex> &impl (void);
+
+protected:
+
+ /// All implementation details are forwarded to this class.
+ ACE_Map_Reverse_Iterator<KEY, VALUE, ACE_Null_Mutex> implementation_;
+};
+
+/**
+ * @class ACE_Map_Manager_Adapter
+ *
+ * @brief Defines a map implementation.
+ *
+ * Implementation to be provided by <ACE_Map_Manager>.
+ */
+template <class KEY, class VALUE, class KEY_GENERATOR>
+class ACE_Map_Manager_Adapter : public ACE_Map<KEY, VALUE>
+{
+public:
+
+ // = Traits.
+ typedef ACE_Map_Manager_Iterator_Adapter<ACE_Reference_Pair<const KEY, VALUE>, KEY, VALUE>
+ iterator_impl;
+ typedef ACE_Map_Manager_Reverse_Iterator_Adapter<ACE_Reference_Pair<const KEY, VALUE>, KEY, VALUE>
+ reverse_iterator_impl;
+ typedef ACE_Map_Manager<KEY, VALUE, ACE_Null_Mutex>
+ implementation;
+
+ // = Initialization and termination methods.
+ /// Initialize with the <ACE_DEFAULT_MAP_SIZE>.
+ ACE_Map_Manager_Adapter (ACE_Allocator *alloc = 0);
+
+ /// Initialize with <size> entries. The <size> parameter is ignored
+ /// by maps for which an initialize size does not make sense.
+ ACE_Map_Manager_Adapter (size_t size,
+ ACE_Allocator *alloc = 0);
+
+ /// Close down and release dynamically allocated resources.
+ virtual ~ACE_Map_Manager_Adapter (void);
+
+ /// Initialize a <Map> with size <length>.
+ virtual int open (size_t length = ACE_DEFAULT_MAP_SIZE,
+ ACE_Allocator *alloc = 0);
+
+ /// Close down a <Map> and release dynamically allocated resources.
+ virtual int close (void);
+
+ /**
+ * Add <key>/<value> pair to the map. If <key> is already in the
+ * map then no changes are made and 1 is returned. Returns 0 on a
+ * successful addition. This function fails for maps that do not
+ * allow user specified keys. <key> is an "in" parameter.
+ */
+ virtual int bind (const KEY &key,
+ const VALUE &value);
+
+ /**
+ * Add <key>/<value> pair to the map. <key> is an "inout" parameter
+ * and maybe modified/extended by the map to add additional
+ * information. To recover original key, call the <recover_key>
+ * method.
+ */
+ virtual int bind_modify_key (const VALUE &value,
+ KEY &key);
+
+ /**
+ * Produce a key and return it through <key> which is an "out"
+ * parameter. For maps that do not naturally produce keys, the map
+ * adapters will use the <KEY_GENERATOR> class to produce a key.
+ * However, the users are responsible for not jeopardizing this key
+ * production scheme by using user specified keys with keys produced
+ * by the key generator.
+ */
+ virtual int create_key (KEY &key);
+
+ /**
+ * Add <value> to the map, and the corresponding key produced by the
+ * Map is returned through <key> which is an "out" parameter. For
+ * maps that do not naturally produce keys, the map adapters will
+ * use the <KEY_GENERATOR> class to produce a key. However, the
+ * users are responsible for not jeopardizing this key production
+ * scheme by using user specified keys with keys produced by the key
+ * generator.
+ */
+ virtual int bind_create_key (const VALUE &value,
+ KEY &key);
+
+ /**
+ * Add <value> to the map. The user does not care about the
+ * corresponding key produced by the Map. For maps that do not
+ * naturally produce keys, the map adapters will use the
+ * <KEY_GENERATOR> class to produce a key. However, the users are
+ * responsible for not jeopardizing this key production scheme by
+ * using user specified keys with keys produced by the key
+ * generator.
+ */
+ virtual int bind_create_key (const VALUE &value);
+
+ /// Recovers the original key potentially modified by the map during
+ /// <bind_modify_key>.
+ virtual int recover_key (const KEY &modified_key,
+ KEY &original_key);
+
+ /**
+ * Reassociate <key> with <value>. The function fails if <key> is
+ * not in the map for maps that do not allow user specified keys.
+ * However, for maps that allow user specified keys, if the key is
+ * not in the map, a new <key>/<value> association is created.
+ */
+ virtual int rebind (const KEY &key,
+ const VALUE &value);
+
+ /**
+ * Reassociate <key> with <value>, storing the old value into the
+ * "out" parameter <old_value>. The function fails if <key> is not
+ * in the map for maps that do not allow user specified keys.
+ * However, for maps that allow user specified keys, if the key is
+ * not in the map, a new <key>/<value> association is created.
+ */
+ virtual int rebind (const KEY &key,
+ const VALUE &value,
+ VALUE &old_value);
+
+ /**
+ * Reassociate <key> with <value>, storing the old key and value
+ * into the "out" parameters <old_key> and <old_value>. The
+ * function fails if <key> is not in the map for maps that do not
+ * allow user specified keys. However, for maps that allow user
+ * specified keys, if the key is not in the map, a new <key>/<value>
+ * association is created.
+ */
+ virtual int rebind (const KEY &key,
+ const VALUE &value,
+ KEY &old_key,
+ VALUE &old_value);
+
+ /**
+ * Associate <key> with <value> if and only if <key> is not in the
+ * map. If <key> is already in the map, then the <value> parameter
+ * is overwritten with the existing value in the map. Returns 0 if a
+ * new <key>/<value> association is created. Returns 1 if an
+ * attempt is made to bind an existing entry. This function fails
+ * for maps that do not allow user specified keys.
+ */
+ virtual int trybind (const KEY &key,
+ VALUE &value);
+
+ /// Locate <value> associated with <key>.
+ virtual int find (const KEY &key,
+ VALUE &value);
+
+ /// Is <key> in the map?
+ virtual int find (const KEY &key);
+
+ /// Remove <key> from the map.
+ virtual int unbind (const KEY &key);
+
+ /// Remove <key> from the map, and return the <value> associated with
+ /// <key>.
+ virtual int unbind (const KEY &key,
+ VALUE &value);
+
+ /// Return the current size of the map.
+ virtual size_t current_size (void) const;
+
+ /// Return the total size of the map.
+ virtual size_t total_size (void) const;
+
+ /// Dump the state of an object.
+ virtual void dump (void) const;
+
+ /// Accessor to implementation object.
+ ACE_Map_Manager<KEY, VALUE, ACE_Null_Mutex> &impl (void);
+
+ /// Accessor to key generator.
+ KEY_GENERATOR &key_generator (void);
+
+protected:
+
+ /// All implementation details are forwarded to this class.
+ ACE_Map_Manager<KEY, VALUE, ACE_Null_Mutex> implementation_;
+
+ /// Functor class used for generating key.
+ KEY_GENERATOR key_generator_;
+
+ // = STL styled iterator factory functions.
+
+ /// Return forward iterator.
+ virtual ACE_Iterator_Impl<ACE_Reference_Pair<const KEY, VALUE> > *begin_impl (void);
+ virtual ACE_Iterator_Impl<ACE_Reference_Pair<const KEY, VALUE> > *end_impl (void);
+
+ /// Return reverse iterator.
+ virtual ACE_Reverse_Iterator_Impl<ACE_Reference_Pair<const KEY, VALUE> > *rbegin_impl (void);
+ virtual ACE_Reverse_Iterator_Impl<ACE_Reference_Pair<const KEY, VALUE> > *rend_impl (void);
+
+private:
+
+ // = Disallow these operations.
+ ACE_UNIMPLEMENTED_FUNC (void operator= (const ACE_Map_Manager_Adapter<KEY, VALUE, KEY_GENERATOR> &))
+ ACE_UNIMPLEMENTED_FUNC (ACE_Map_Manager_Adapter (const ACE_Map_Manager_Adapter<KEY, VALUE, KEY_GENERATOR> &))
+};
+
+#if defined (__ACE_INLINE__)
+#include "ace/Map_T.i"
+#endif /* __ACE_INLINE__ */
+
+#if defined (ACE_TEMPLATES_REQUIRE_SOURCE)
+#include "ace/Map_T.cpp"
+#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */
+
+#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA)
+#pragma implementation ("Map_T.cpp")
+#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */
+
+#include "ace/post.h"
+#endif /* ACE_MAP_T_H */
diff --git a/ace/Utils/Templates/Map_T.i b/ace/Utils/Templates/Map_T.i
new file mode 100644
index 00000000000..b5c234a67d9
--- /dev/null
+++ b/ace/Utils/Templates/Map_T.i
@@ -0,0 +1,1723 @@
+// $Id$
+
+template <class T> ACE_INLINE int
+ACE_Noop_Key_Generator<T>::operator() (T &)
+{
+ return -1;
+}
+
+template <class T> ACE_INLINE
+ACE_Incremental_Key_Generator<T>::ACE_Incremental_Key_Generator (void)
+ : t_ (0)
+{
+}
+
+template <class T> ACE_INLINE int
+ACE_Incremental_Key_Generator<T>::operator() (T &t)
+{
+ t = ++this->t_;
+ return 0;
+}
+
+template <class T> ACE_INLINE const T &
+ACE_Incremental_Key_Generator<T>::current_value (void) const
+{
+ return this->t_;
+}
+
+template <class T> ACE_INLINE
+ACE_Iterator_Impl<T>::~ACE_Iterator_Impl (void)
+{
+}
+
+template <class T> ACE_INLINE
+ACE_Reverse_Iterator_Impl<T>::~ACE_Reverse_Iterator_Impl (void)
+{
+}
+
+template <class T> ACE_INLINE
+ACE_Iterator<T>::ACE_Iterator (ACE_Iterator_Impl<T> *impl)
+ : implementation_ (impl)
+{
+}
+
+template <class T> ACE_INLINE
+ACE_Iterator<T>::ACE_Iterator (const ACE_Iterator<T> &rhs)
+ : implementation_ (rhs.implementation_->clone ())
+{
+}
+
+template <class T> ACE_INLINE
+ACE_Iterator<T>::~ACE_Iterator (void)
+{
+ delete this->implementation_;
+}
+
+template <class T> ACE_INLINE ACE_Iterator<T> &
+ACE_Iterator<T>::operator= (const ACE_Iterator<T> &rhs)
+{
+ delete this->implementation_;
+ this->implementation_ = rhs.implementation_->clone ();
+ return *this;
+}
+
+template <class T> ACE_INLINE int
+ACE_Iterator<T>::operator== (const ACE_Iterator<T> &rhs) const
+{
+ return this->implementation_->compare (*rhs.implementation_);
+}
+
+template <class T> ACE_INLINE int
+ACE_Iterator<T>::operator!= (const ACE_Iterator<T> &rhs) const
+{
+ return !this->operator== (rhs);
+}
+
+template <class T> ACE_INLINE T
+ACE_Iterator<T>::operator* (void) const
+{
+ return this->implementation_->dereference ();
+}
+
+template <class T> ACE_INLINE ACE_Iterator<T> &
+ACE_Iterator<T>::operator++ (void)
+{
+ this->implementation_->plus_plus ();
+ return *this;
+}
+
+template <class T> ACE_INLINE ACE_Iterator<T>
+ACE_Iterator<T>::operator++ (int)
+{
+ ACE_Iterator<T> tmp = *this;
+ this->implementation_->plus_plus ();
+ return tmp;
+}
+
+template <class T> ACE_INLINE ACE_Iterator<T> &
+ACE_Iterator<T>::operator-- (void)
+{
+ this->implementation_->minus_minus ();
+ return *this;
+}
+
+template <class T> ACE_INLINE ACE_Iterator<T>
+ACE_Iterator<T>::operator-- (int)
+{
+ ACE_Iterator<T> tmp = *this;
+ this->implementation_->minus_minus ();
+ return tmp;
+}
+
+template <class T> ACE_INLINE ACE_Iterator_Impl<T> &
+ACE_Iterator<T>::impl (void)
+{
+ return *this->implementation_;
+}
+
+template <class T> ACE_INLINE
+ACE_Reverse_Iterator<T>::ACE_Reverse_Iterator (ACE_Reverse_Iterator_Impl<T> *impl)
+ : implementation_ (impl)
+{
+}
+
+template <class T> ACE_INLINE
+ACE_Reverse_Iterator<T>::ACE_Reverse_Iterator (const ACE_Reverse_Iterator<T> &rhs)
+ : implementation_ (rhs.implementation_->clone ())
+{
+}
+
+template <class T> ACE_INLINE
+ACE_Reverse_Iterator<T>::~ACE_Reverse_Iterator (void)
+{
+ delete this->implementation_;
+}
+
+template <class T> ACE_INLINE ACE_Reverse_Iterator<T> &
+ACE_Reverse_Iterator<T>::operator= (const ACE_Reverse_Iterator<T> &rhs)
+{
+ delete this->implementation_;
+ this->implementation_ = rhs.implementation_->clone ();
+ return *this;
+}
+
+template <class T> ACE_INLINE int
+ACE_Reverse_Iterator<T>::operator== (const ACE_Reverse_Iterator<T> &rhs) const
+{
+ return this->implementation_->compare (*rhs.implementation_);
+}
+
+template <class T> ACE_INLINE int
+ACE_Reverse_Iterator<T>::operator!= (const ACE_Reverse_Iterator<T> &rhs) const
+{
+ return !this->operator== (rhs);
+}
+
+template <class T> ACE_INLINE T
+ACE_Reverse_Iterator<T>::operator* (void) const
+{
+ return this->implementation_->dereference ();
+}
+
+template <class T> ACE_INLINE ACE_Reverse_Iterator<T> &
+ACE_Reverse_Iterator<T>::operator++ (void)
+{
+ this->implementation_->plus_plus ();
+ return *this;
+}
+
+template <class T> ACE_INLINE ACE_Reverse_Iterator<T>
+ACE_Reverse_Iterator<T>::operator++ (int)
+{
+ ACE_Reverse_Iterator<T> tmp = *this;
+ this->implementation_->plus_plus ();
+ return tmp;
+}
+
+template <class T> ACE_INLINE ACE_Reverse_Iterator<T> &
+ACE_Reverse_Iterator<T>::operator-- (void)
+{
+ this->implementation_->minus_minus ();
+ return *this;
+}
+
+template <class T> ACE_INLINE ACE_Reverse_Iterator<T>
+ACE_Reverse_Iterator<T>::operator-- (int)
+{
+ ACE_Reverse_Iterator<T> tmp = *this;
+ this->implementation_->minus_minus ();
+ return tmp;
+}
+
+template <class T> ACE_INLINE ACE_Reverse_Iterator_Impl<T> &
+ACE_Reverse_Iterator<T>::impl (void)
+{
+ return *this->implementation_;
+}
+
+template <class KEY, class VALUE> ACE_INLINE
+ACE_Map<KEY, VALUE>::ACE_Map (void)
+{
+}
+
+template <class KEY, class VALUE> ACE_INLINE
+ACE_Map<KEY, VALUE>::~ACE_Map (void)
+{
+}
+
+template <class KEY, class VALUE> ACE_INLINE ACE_Iterator<ACE_Reference_Pair<const KEY, VALUE> >
+ACE_Map<KEY, VALUE>::begin (void)
+{
+ return iterator (this->begin_impl ());
+}
+
+template <class KEY, class VALUE> ACE_INLINE ACE_Iterator<ACE_Reference_Pair<const KEY, VALUE> >
+ACE_Map<KEY, VALUE>::end (void)
+{
+ return iterator (this->end_impl ());
+}
+
+template <class KEY, class VALUE> ACE_INLINE ACE_Reverse_Iterator<ACE_Reference_Pair<const KEY, VALUE> >
+ACE_Map<KEY, VALUE>::rbegin (void)
+{
+ return reverse_iterator (this->rbegin_impl ());
+}
+
+template <class KEY, class VALUE> ACE_INLINE ACE_Reverse_Iterator<ACE_Reference_Pair<const KEY, VALUE> >
+ACE_Map<KEY, VALUE>::rend (void)
+{
+ return reverse_iterator (this->rend_impl ());
+}
+
+template <class T, class IMPLEMENTATION, class ENTRY> ACE_INLINE
+ACE_Map_Impl_Iterator_Adapter<T, IMPLEMENTATION, ENTRY>::ACE_Map_Impl_Iterator_Adapter (const IMPLEMENTATION &impl)
+ : implementation_ (impl)
+{
+}
+
+template <class T, class IMPLEMENTATION, class ENTRY> ACE_INLINE
+ACE_Map_Impl_Iterator_Adapter<T, IMPLEMENTATION, ENTRY>::~ACE_Map_Impl_Iterator_Adapter (void)
+{
+}
+
+template <class T, class IMPLEMENTATION, class ENTRY> ACE_INLINE ACE_Iterator_Impl<T> *
+ACE_Map_Impl_Iterator_Adapter<T, IMPLEMENTATION, ENTRY>::clone (void) const
+{
+ ACE_Iterator_Impl<T> *temp = 0;
+ ACE_NEW_RETURN (temp,
+ (ACE_Map_Impl_Iterator_Adapter<T, IMPLEMENTATION, ENTRY>) (*this),
+ 0);
+ return temp;
+}
+
+
+template <class T, class IMPLEMENTATION, class ENTRY> ACE_INLINE int
+ACE_Map_Impl_Iterator_Adapter<T, IMPLEMENTATION, ENTRY>::compare (const ACE_Iterator_Impl<T> &rhs) const
+{
+ const ACE_Map_Impl_Iterator_Adapter<T, IMPLEMENTATION, ENTRY> &rhs_local
+ = ACE_dynamic_cast_3_ref (const ACE_Map_Impl_Iterator_Adapter, T, IMPLEMENTATION, ENTRY, rhs);
+
+ return this->implementation_ == rhs_local.implementation_;
+}
+
+template <class T, class IMPLEMENTATION, class ENTRY> ACE_INLINE T
+ACE_Map_Impl_Iterator_Adapter<T, IMPLEMENTATION, ENTRY>::dereference () const
+{
+ ENTRY &entry = *this->implementation_;
+ return T (entry.ext_id_,
+ entry.int_id_);
+}
+
+template <class T, class IMPLEMENTATION, class ENTRY> ACE_INLINE void
+ACE_Map_Impl_Iterator_Adapter<T, IMPLEMENTATION, ENTRY>::plus_plus (void)
+{
+ ++this->implementation_;
+}
+
+template <class T, class IMPLEMENTATION, class ENTRY> ACE_INLINE void
+ACE_Map_Impl_Iterator_Adapter<T, IMPLEMENTATION, ENTRY>::minus_minus (void)
+{
+ --this->implementation_;
+}
+
+template <class T, class IMPLEMENTATION, class ENTRY> ACE_INLINE IMPLEMENTATION &
+ACE_Map_Impl_Iterator_Adapter<T, IMPLEMENTATION, ENTRY>::impl (void)
+{
+ return this->implementation_;
+}
+
+template <class T, class IMPLEMENTATION, class ENTRY> ACE_INLINE
+ACE_Map_Impl_Reverse_Iterator_Adapter<T, IMPLEMENTATION, ENTRY>::ACE_Map_Impl_Reverse_Iterator_Adapter (const IMPLEMENTATION &impl)
+ : implementation_ (impl)
+{
+}
+
+template <class T, class IMPLEMENTATION, class ENTRY> ACE_INLINE
+ACE_Map_Impl_Reverse_Iterator_Adapter<T, IMPLEMENTATION, ENTRY>::~ACE_Map_Impl_Reverse_Iterator_Adapter (void)
+{
+}
+
+template <class T, class IMPLEMENTATION, class ENTRY> ACE_INLINE ACE_Reverse_Iterator_Impl<T> *
+ACE_Map_Impl_Reverse_Iterator_Adapter<T, IMPLEMENTATION, ENTRY>::clone (void) const
+{
+ ACE_Reverse_Iterator_Impl<T> *temp = 0;
+ ACE_NEW_RETURN (temp,
+ (ACE_Map_Impl_Reverse_Iterator_Adapter<T, IMPLEMENTATION, ENTRY>) (*this),
+ 0);
+ return temp;
+}
+
+
+template <class T, class IMPLEMENTATION, class ENTRY> ACE_INLINE int
+ACE_Map_Impl_Reverse_Iterator_Adapter<T, IMPLEMENTATION, ENTRY>::compare (const ACE_Reverse_Iterator_Impl<T> &rhs) const
+{
+ const ACE_Map_Impl_Reverse_Iterator_Adapter<T, IMPLEMENTATION, ENTRY> &rhs_local
+ = ACE_dynamic_cast_3_ref (const ACE_Map_Impl_Reverse_Iterator_Adapter, T, IMPLEMENTATION, ENTRY, rhs);
+
+ return this->implementation_ == rhs_local.implementation_;
+}
+
+template <class T, class IMPLEMENTATION, class ENTRY> ACE_INLINE T
+ACE_Map_Impl_Reverse_Iterator_Adapter<T, IMPLEMENTATION, ENTRY>::dereference () const
+{
+ ENTRY &entry = *this->implementation_;
+ return T (entry.ext_id_,
+ entry.int_id_);
+}
+
+template <class T, class IMPLEMENTATION, class ENTRY> ACE_INLINE void
+ACE_Map_Impl_Reverse_Iterator_Adapter<T, IMPLEMENTATION, ENTRY>::plus_plus (void)
+{
+ ++this->implementation_;
+}
+
+template <class T, class IMPLEMENTATION, class ENTRY> ACE_INLINE void
+ACE_Map_Impl_Reverse_Iterator_Adapter<T, IMPLEMENTATION, ENTRY>::minus_minus (void)
+{
+ --this->implementation_;
+}
+
+template <class T, class IMPLEMENTATION, class ENTRY> ACE_INLINE IMPLEMENTATION &
+ACE_Map_Impl_Reverse_Iterator_Adapter<T, IMPLEMENTATION, ENTRY>::impl (void)
+{
+ return this->implementation_;
+}
+
+template <class KEY, class VALUE, class IMPLEMENTATION, class ITERATOR, class REVERSE_ITERATOR, class ENTRY> ACE_INLINE
+ACE_Map_Impl<KEY, VALUE, IMPLEMENTATION, ITERATOR, REVERSE_ITERATOR, ENTRY>::ACE_Map_Impl (ACE_Allocator *alloc)
+ : implementation_ (alloc)
+{
+}
+
+template <class KEY, class VALUE, class IMPLEMENTATION, class ITERATOR, class REVERSE_ITERATOR, class ENTRY> ACE_INLINE
+ACE_Map_Impl<KEY, VALUE, IMPLEMENTATION, ITERATOR, REVERSE_ITERATOR, ENTRY>::ACE_Map_Impl (size_t size,
+ ACE_Allocator *alloc)
+ : implementation_ (size,
+ alloc)
+{
+}
+
+template <class KEY, class VALUE, class IMPLEMENTATION, class ITERATOR, class REVERSE_ITERATOR, class ENTRY> ACE_INLINE
+ACE_Map_Impl<KEY, VALUE, IMPLEMENTATION, ITERATOR, REVERSE_ITERATOR, ENTRY>::~ACE_Map_Impl (void)
+{
+}
+
+template <class KEY, class VALUE, class IMPLEMENTATION, class ITERATOR, class REVERSE_ITERATOR, class ENTRY> ACE_INLINE int
+ACE_Map_Impl<KEY, VALUE, IMPLEMENTATION, ITERATOR, REVERSE_ITERATOR, ENTRY>::open (size_t length,
+ ACE_Allocator *alloc)
+{
+ return this->implementation_.open (length,
+ alloc);
+}
+
+template <class KEY, class VALUE, class IMPLEMENTATION, class ITERATOR, class REVERSE_ITERATOR, class ENTRY> ACE_INLINE int
+ACE_Map_Impl<KEY, VALUE, IMPLEMENTATION, ITERATOR, REVERSE_ITERATOR, ENTRY>::close (void)
+{
+ return this->implementation_.close ();
+}
+
+template <class KEY, class VALUE, class IMPLEMENTATION, class ITERATOR, class REVERSE_ITERATOR, class ENTRY> ACE_INLINE int
+ACE_Map_Impl<KEY, VALUE, IMPLEMENTATION, ITERATOR, REVERSE_ITERATOR, ENTRY>::bind (const KEY &key,
+ const VALUE &value)
+{
+ return this->implementation_.bind (key,
+ value);
+}
+
+template <class KEY, class VALUE, class IMPLEMENTATION, class ITERATOR, class REVERSE_ITERATOR, class ENTRY> ACE_INLINE int
+ACE_Map_Impl<KEY, VALUE, IMPLEMENTATION, ITERATOR, REVERSE_ITERATOR, ENTRY>::bind_modify_key (const VALUE &value,
+ KEY &key)
+{
+ return this->implementation_.bind_modify_key (value,
+ key);
+}
+
+template <class KEY, class VALUE, class IMPLEMENTATION, class ITERATOR, class REVERSE_ITERATOR, class ENTRY> ACE_INLINE int
+ACE_Map_Impl<KEY, VALUE, IMPLEMENTATION, ITERATOR, REVERSE_ITERATOR, ENTRY>::create_key (KEY &key)
+{
+ return this->implementation_.create_key (key);
+}
+
+template <class KEY, class VALUE, class IMPLEMENTATION, class ITERATOR, class REVERSE_ITERATOR, class ENTRY> ACE_INLINE int
+ACE_Map_Impl<KEY, VALUE, IMPLEMENTATION, ITERATOR, REVERSE_ITERATOR, ENTRY>::bind_create_key (const VALUE &value,
+ KEY &key)
+{
+ return this->implementation_.bind_create_key (value,
+ key);
+}
+
+template <class KEY, class VALUE, class IMPLEMENTATION, class ITERATOR, class REVERSE_ITERATOR, class ENTRY> ACE_INLINE int
+ACE_Map_Impl<KEY, VALUE, IMPLEMENTATION, ITERATOR, REVERSE_ITERATOR, ENTRY>::bind_create_key (const VALUE &value)
+{
+ return this->implementation_.bind_create_key (value);
+}
+
+template <class KEY, class VALUE, class IMPLEMENTATION, class ITERATOR, class REVERSE_ITERATOR, class ENTRY> ACE_INLINE int
+ACE_Map_Impl<KEY, VALUE, IMPLEMENTATION, ITERATOR, REVERSE_ITERATOR, ENTRY>::recover_key (const KEY &modified_key,
+ KEY &original_key)
+{
+ return this->implementation_.recover_key (modified_key,
+ original_key);
+}
+
+template <class KEY, class VALUE, class IMPLEMENTATION, class ITERATOR, class REVERSE_ITERATOR, class ENTRY> ACE_INLINE int
+ACE_Map_Impl<KEY, VALUE, IMPLEMENTATION, ITERATOR, REVERSE_ITERATOR, ENTRY>::rebind (const KEY &key,
+ const VALUE &value)
+{
+ return this->implementation_.rebind (key,
+ value);
+}
+
+template <class KEY, class VALUE, class IMPLEMENTATION, class ITERATOR, class REVERSE_ITERATOR, class ENTRY> ACE_INLINE int
+ACE_Map_Impl<KEY, VALUE, IMPLEMENTATION, ITERATOR, REVERSE_ITERATOR, ENTRY>::rebind (const KEY &key,
+ const VALUE &value,
+ VALUE &old_value)
+{
+ return this->implementation_.rebind (key,
+ value,
+ old_value);
+}
+
+template <class KEY, class VALUE, class IMPLEMENTATION, class ITERATOR, class REVERSE_ITERATOR, class ENTRY> ACE_INLINE int
+ACE_Map_Impl<KEY, VALUE, IMPLEMENTATION, ITERATOR, REVERSE_ITERATOR, ENTRY>::rebind (const KEY &key,
+ const VALUE &value,
+ KEY &old_key,
+ VALUE &old_value)
+{
+ return this->implementation_.rebind (key,
+ value,
+ old_key,
+ old_value);
+}
+
+template <class KEY, class VALUE, class IMPLEMENTATION, class ITERATOR, class REVERSE_ITERATOR, class ENTRY> ACE_INLINE int
+ACE_Map_Impl<KEY, VALUE, IMPLEMENTATION, ITERATOR, REVERSE_ITERATOR, ENTRY>::trybind (const KEY &key,
+ VALUE &value)
+{
+ return this->implementation_.trybind (key,
+ value);
+}
+
+template <class KEY, class VALUE, class IMPLEMENTATION, class ITERATOR, class REVERSE_ITERATOR, class ENTRY> ACE_INLINE int
+ACE_Map_Impl<KEY, VALUE, IMPLEMENTATION, ITERATOR, REVERSE_ITERATOR, ENTRY>::find (const KEY &key,
+ VALUE &value)
+{
+ return this->implementation_.find (key,
+ value);
+}
+
+template <class KEY, class VALUE, class IMPLEMENTATION, class ITERATOR, class REVERSE_ITERATOR, class ENTRY> ACE_INLINE int
+ACE_Map_Impl<KEY, VALUE, IMPLEMENTATION, ITERATOR, REVERSE_ITERATOR, ENTRY>::find (const KEY &key)
+{
+ return this->implementation_.find (key);
+}
+
+template <class KEY, class VALUE, class IMPLEMENTATION, class ITERATOR, class REVERSE_ITERATOR, class ENTRY> ACE_INLINE int
+ACE_Map_Impl<KEY, VALUE, IMPLEMENTATION, ITERATOR, REVERSE_ITERATOR, ENTRY>::unbind (const KEY &key)
+{
+ return this->implementation_.unbind (key);
+}
+
+template <class KEY, class VALUE, class IMPLEMENTATION, class ITERATOR, class REVERSE_ITERATOR, class ENTRY> ACE_INLINE int
+ACE_Map_Impl<KEY, VALUE, IMPLEMENTATION, ITERATOR, REVERSE_ITERATOR, ENTRY>::unbind (const KEY &key,
+ VALUE &value)
+{
+ return this->implementation_.unbind (key,
+ value);
+}
+
+template <class KEY, class VALUE, class IMPLEMENTATION, class ITERATOR, class REVERSE_ITERATOR, class ENTRY> ACE_INLINE size_t
+ACE_Map_Impl<KEY, VALUE, IMPLEMENTATION, ITERATOR, REVERSE_ITERATOR, ENTRY>::current_size (void) const
+{
+ return this->implementation_.current_size ();
+}
+
+template <class KEY, class VALUE, class IMPLEMENTATION, class ITERATOR, class REVERSE_ITERATOR, class ENTRY> ACE_INLINE size_t
+ACE_Map_Impl<KEY, VALUE, IMPLEMENTATION, ITERATOR, REVERSE_ITERATOR, ENTRY>::total_size (void) const
+{
+ return this->implementation_.total_size ();
+}
+
+template <class KEY, class VALUE, class IMPLEMENTATION, class ITERATOR, class REVERSE_ITERATOR, class ENTRY> ACE_INLINE void
+ACE_Map_Impl<KEY, VALUE, IMPLEMENTATION, ITERATOR, REVERSE_ITERATOR, ENTRY>::dump (void) const
+{
+ this->implementation_.dump ();
+}
+
+template <class KEY, class VALUE, class IMPLEMENTATION, class ITERATOR, class REVERSE_ITERATOR, class ENTRY> ACE_INLINE ACE_Iterator_Impl<ACE_Reference_Pair<const KEY, VALUE> > *
+ACE_Map_Impl<KEY, VALUE, IMPLEMENTATION, ITERATOR, REVERSE_ITERATOR, ENTRY>::begin_impl (void)
+{
+ ACE_Iterator_Impl<ACE_Reference_Pair<const KEY, VALUE> > *temp = 0;
+ ACE_NEW_RETURN (temp,
+ iterator_impl (this->implementation_.begin ()),
+ 0);
+ return temp;
+}
+
+template <class KEY, class VALUE, class IMPLEMENTATION, class ITERATOR, class REVERSE_ITERATOR, class ENTRY> ACE_INLINE ACE_Iterator_Impl<ACE_Reference_Pair<const KEY, VALUE> > *
+ACE_Map_Impl<KEY, VALUE, IMPLEMENTATION, ITERATOR, REVERSE_ITERATOR, ENTRY>::end_impl (void)
+{
+ ACE_Iterator_Impl<ACE_Reference_Pair<const KEY, VALUE> > *temp = 0;
+ ACE_NEW_RETURN (temp,
+ iterator_impl (this->implementation_.end ()),
+ 0);
+ return temp;
+}
+
+template <class KEY, class VALUE, class IMPLEMENTATION, class ITERATOR, class REVERSE_ITERATOR, class ENTRY> ACE_INLINE ACE_Reverse_Iterator_Impl<ACE_Reference_Pair<const KEY, VALUE> > *
+ACE_Map_Impl<KEY, VALUE, IMPLEMENTATION, ITERATOR, REVERSE_ITERATOR, ENTRY>::rbegin_impl (void)
+{
+ ACE_Reverse_Iterator_Impl<ACE_Reference_Pair<const KEY, VALUE> > *temp = 0;
+ ACE_NEW_RETURN (temp,
+ reverse_iterator_impl (this->implementation_.rbegin ()),
+ 0);
+ return temp;
+}
+
+template <class KEY, class VALUE, class IMPLEMENTATION, class ITERATOR, class REVERSE_ITERATOR, class ENTRY> ACE_INLINE ACE_Reverse_Iterator_Impl<ACE_Reference_Pair<const KEY, VALUE> > *
+ACE_Map_Impl<KEY, VALUE, IMPLEMENTATION, ITERATOR, REVERSE_ITERATOR, ENTRY>::rend_impl (void)
+{
+ ACE_Reverse_Iterator_Impl<ACE_Reference_Pair<const KEY, VALUE> > *temp = 0;
+ ACE_NEW_RETURN (temp,
+ reverse_iterator_impl (this->implementation_.rend ()),
+ 0);
+ return temp;
+}
+
+template <class KEY, class VALUE, class IMPLEMENTATION, class ITERATOR, class REVERSE_ITERATOR, class ENTRY> ACE_INLINE IMPLEMENTATION &
+ACE_Map_Impl<KEY, VALUE, IMPLEMENTATION, ITERATOR, REVERSE_ITERATOR, ENTRY>::impl (void)
+{
+ return this->implementation_;
+}
+
+template <class T, class VALUE> ACE_INLINE
+ACE_Active_Map_Manager_Iterator_Adapter<T, VALUE>::ACE_Active_Map_Manager_Iterator_Adapter (const ACE_Map_Iterator<ACE_Active_Map_Manager_Key, VALUE, ACE_Null_Mutex> &impl)
+ : implementation_ (impl)
+{
+}
+
+template <class T, class VALUE> ACE_INLINE
+ACE_Active_Map_Manager_Iterator_Adapter<T, VALUE>::~ACE_Active_Map_Manager_Iterator_Adapter (void)
+{
+}
+
+template <class T, class VALUE> ACE_INLINE ACE_Iterator_Impl<T> *
+ACE_Active_Map_Manager_Iterator_Adapter<T, VALUE>::clone (void) const
+{
+ ACE_Iterator_Impl<T> *temp = 0;
+ ACE_NEW_RETURN (temp,
+ (ACE_Active_Map_Manager_Iterator_Adapter<T, VALUE>) (*this),
+ 0);
+ return temp;
+}
+
+
+template <class T, class VALUE> ACE_INLINE int
+ACE_Active_Map_Manager_Iterator_Adapter<T, VALUE>::compare (const ACE_Iterator_Impl<T> &rhs) const
+{
+ const ACE_Active_Map_Manager_Iterator_Adapter<T, VALUE> &rhs_local
+ = ACE_dynamic_cast_2_ref (const ACE_Active_Map_Manager_Iterator_Adapter, T, VALUE, rhs);
+
+ return this->implementation_ == rhs_local.implementation_;
+}
+
+template <class T, class VALUE> ACE_INLINE T
+ACE_Active_Map_Manager_Iterator_Adapter<T, VALUE>::dereference () const
+{
+ // The following syntax is necessary to work around certain broken compilers.
+ // In particular, please do not prefix implementation_ with this->
+ return T ((*implementation_).int_id_.first (),
+ (*implementation_).int_id_.second ());
+}
+
+template <class T, class VALUE> ACE_INLINE void
+ACE_Active_Map_Manager_Iterator_Adapter<T, VALUE>::plus_plus (void)
+{
+ ++this->implementation_;
+}
+
+template <class T, class VALUE> ACE_INLINE void
+ACE_Active_Map_Manager_Iterator_Adapter<T, VALUE>::minus_minus (void)
+{
+ --this->implementation_;
+}
+
+template <class T, class VALUE> ACE_INLINE ACE_Map_Iterator<ACE_Active_Map_Manager_Key, VALUE, ACE_Null_Mutex> &
+ACE_Active_Map_Manager_Iterator_Adapter<T, VALUE>::impl (void)
+{
+ return this->implementation_;
+}
+
+template <class T, class VALUE> ACE_INLINE
+ACE_Active_Map_Manager_Reverse_Iterator_Adapter<T, VALUE>::ACE_Active_Map_Manager_Reverse_Iterator_Adapter (const ACE_Map_Reverse_Iterator<ACE_Active_Map_Manager_Key, VALUE, ACE_Null_Mutex> &impl)
+ : implementation_ (impl)
+{
+}
+
+template <class T, class VALUE> ACE_INLINE
+ACE_Active_Map_Manager_Reverse_Iterator_Adapter<T, VALUE>::~ACE_Active_Map_Manager_Reverse_Iterator_Adapter (void)
+{
+}
+
+template <class T, class VALUE> ACE_INLINE ACE_Reverse_Iterator_Impl<T> *
+ACE_Active_Map_Manager_Reverse_Iterator_Adapter<T, VALUE>::clone (void) const
+{
+ ACE_Reverse_Iterator_Impl<T> *temp = 0;
+ ACE_NEW_RETURN (temp,
+ (ACE_Active_Map_Manager_Reverse_Iterator_Adapter<T, VALUE>) (*this),
+ 0);
+ return temp;
+}
+
+
+template <class T, class VALUE> ACE_INLINE int
+ACE_Active_Map_Manager_Reverse_Iterator_Adapter<T, VALUE>::compare (const ACE_Reverse_Iterator_Impl<T> &rhs) const
+{
+ const ACE_Active_Map_Manager_Reverse_Iterator_Adapter<T, VALUE> &rhs_local
+ = ACE_dynamic_cast_2_ref (const ACE_Active_Map_Manager_Reverse_Iterator_Adapter, T, VALUE, rhs);
+
+ return this->implementation_ == rhs_local.implementation_;
+}
+
+template <class T, class VALUE> ACE_INLINE T
+ACE_Active_Map_Manager_Reverse_Iterator_Adapter<T, VALUE>::dereference () const
+{
+ // The following syntax is necessary to work around certain broken compilers.
+ // In particular, please do not prefix implementation_ with this->
+ return T ((*implementation_).int_id_.first (),
+ (*implementation_).int_id_.second ());
+}
+
+template <class T, class VALUE> ACE_INLINE void
+ACE_Active_Map_Manager_Reverse_Iterator_Adapter<T, VALUE>::plus_plus (void)
+{
+ ++this->implementation_;
+}
+
+template <class T, class VALUE> ACE_INLINE void
+ACE_Active_Map_Manager_Reverse_Iterator_Adapter<T, VALUE>::minus_minus (void)
+{
+ --this->implementation_;
+}
+
+template <class T, class VALUE> ACE_INLINE ACE_Map_Reverse_Iterator<ACE_Active_Map_Manager_Key, VALUE, ACE_Null_Mutex> &
+ACE_Active_Map_Manager_Reverse_Iterator_Adapter<T, VALUE>::impl (void)
+{
+ return this->implementation_;
+}
+
+template <class KEY, class VALUE, class KEY_ADAPTER> ACE_INLINE
+ACE_Active_Map_Manager_Adapter<KEY, VALUE, KEY_ADAPTER>::ACE_Active_Map_Manager_Adapter (ACE_Allocator *alloc)
+ : implementation_ (alloc)
+{
+}
+
+template <class KEY, class VALUE, class KEY_ADAPTER> ACE_INLINE
+ACE_Active_Map_Manager_Adapter<KEY, VALUE, KEY_ADAPTER>::ACE_Active_Map_Manager_Adapter (size_t size,
+ ACE_Allocator *alloc)
+ : implementation_ (size,
+ alloc)
+{
+}
+
+template <class KEY, class VALUE, class KEY_ADAPTER> ACE_INLINE
+ACE_Active_Map_Manager_Adapter<KEY, VALUE, KEY_ADAPTER>::~ACE_Active_Map_Manager_Adapter (void)
+{
+}
+
+template <class KEY, class VALUE, class KEY_ADAPTER> ACE_INLINE int
+ACE_Active_Map_Manager_Adapter<KEY, VALUE, KEY_ADAPTER>::open (size_t length,
+ ACE_Allocator *alloc)
+{
+ return this->implementation_.open (length,
+ alloc);
+}
+
+template <class KEY, class VALUE, class KEY_ADAPTER> ACE_INLINE int
+ACE_Active_Map_Manager_Adapter<KEY, VALUE, KEY_ADAPTER>::close (void)
+{
+ return this->implementation_.close ();
+}
+
+template <class KEY, class VALUE, class KEY_ADAPTER> ACE_INLINE int
+ACE_Active_Map_Manager_Adapter<KEY, VALUE, KEY_ADAPTER>::bind (const KEY &,
+ const VALUE &)
+{
+ ACE_NOTSUP_RETURN (-1);
+}
+
+template <class KEY, class VALUE, class KEY_ADAPTER> ACE_INLINE int
+ACE_Active_Map_Manager_Adapter<KEY, VALUE, KEY_ADAPTER>::bind_modify_key (const VALUE &value,
+ KEY &key)
+{
+ // Reserve a slot and create an active key.
+ expanded_value *internal_value = 0;
+ ACE_Active_Map_Manager_Key active_key;
+ int result = this->implementation_.bind (active_key,
+ internal_value);
+ if (result == 0)
+ {
+ // Encode the active key and the existing user key into key part
+ // of <expanded_value>.
+ result = this->key_adapter_.encode (key,
+ active_key,
+ internal_value->first ());
+ if (result == 0)
+ {
+ // Copy user value into <expanded_value>.
+ internal_value->second (value);
+ // Copy new, modified key back to the user key.
+ key = internal_value->first ();
+ }
+ else
+ {
+ // In case of errors, unbind from map.
+ this->implementation_.unbind (active_key);
+ }
+ }
+
+ return result;
+}
+
+template <class KEY, class VALUE, class KEY_ADAPTER> ACE_INLINE int
+ACE_Active_Map_Manager_Adapter<KEY, VALUE, KEY_ADAPTER>::create_key (KEY &)
+{
+ ACE_NOTSUP_RETURN (-1);
+}
+
+template <class KEY, class VALUE, class KEY_ADAPTER> ACE_INLINE int
+ACE_Active_Map_Manager_Adapter<KEY, VALUE, KEY_ADAPTER>::bind_create_key (const VALUE &value,
+ KEY &key)
+{
+ // Reserve a slot and create an active key.
+ expanded_value *internal_value = 0;
+ ACE_Active_Map_Manager_Key active_key;
+ int result = this->implementation_.bind (active_key,
+ internal_value);
+ if (result == 0)
+ {
+ // Encode the active key into key part of <expanded_value>.
+ result = this->key_adapter_.encode (internal_value->first (),
+ active_key,
+ internal_value->first ());
+ if (result == 0)
+ {
+ // Copy user value into <expanded_value>.
+ internal_value->second (value);
+ // Copy new, modified key to the user key.
+ key = internal_value->first ();
+ }
+ else
+ {
+ // In case of errors, unbind from map.
+ this->implementation_.unbind (active_key);
+ }
+ }
+
+ return result;
+}
+
+template <class KEY, class VALUE, class KEY_ADAPTER> ACE_INLINE int
+ACE_Active_Map_Manager_Adapter<KEY, VALUE, KEY_ADAPTER>::bind_create_key (const VALUE &value)
+{
+ // Reserve a slot and create an active key.
+ expanded_value *internal_value = 0;
+ ACE_Active_Map_Manager_Key active_key;
+ int result = this->implementation_.bind (active_key,
+ internal_value);
+ if (result == 0)
+ {
+ // Encode the active key into key part of <expanded_value>.
+ result = this->key_adapter_.encode (internal_value->first (),
+ active_key,
+ internal_value->first ());
+ if (result == 0)
+ {
+ // Copy user value into <expanded_value>.
+ internal_value->second (value);
+ }
+ else
+ {
+ // In case of errors, unbind from map.
+ this->implementation_.unbind (active_key);
+ }
+ }
+
+ return result;
+}
+
+template <class KEY, class VALUE, class KEY_ADAPTER> ACE_INLINE int
+ACE_Active_Map_Manager_Adapter<KEY, VALUE, KEY_ADAPTER>::recover_key (const KEY &modified_key,
+ KEY &original_key)
+{
+ // Ask the <key_adapter_> to help out with recovering the original
+ // user key, since it was the one that encode it in the first place.
+ return this->key_adapter_.decode (modified_key,
+ original_key);
+}
+
+template <class KEY, class VALUE, class KEY_ADAPTER> ACE_INLINE int
+ACE_Active_Map_Manager_Adapter<KEY, VALUE, KEY_ADAPTER>::find (const KEY &key,
+ ACE_Pair<KEY, VALUE> *&internal_value)
+{
+ // Ask the <key_adapter_> to recover the active key.
+ ACE_Active_Map_Manager_Key active_key;
+ int result = this->key_adapter_.decode (key,
+ active_key);
+ if (result == 0)
+ {
+ // Find recovered active key in map.
+ result = this->implementation_.find (active_key,
+ internal_value);
+ }
+
+ return result;
+}
+
+template <class KEY, class VALUE, class KEY_ADAPTER> ACE_INLINE int
+ACE_Active_Map_Manager_Adapter<KEY, VALUE, KEY_ADAPTER>::find (const KEY &key,
+ VALUE &value)
+{
+ expanded_value *internal_value = 0;
+ int result = this->find (key,
+ internal_value);
+
+ if (result == 0)
+ {
+ // Copy value.
+ value = internal_value->second ();
+ }
+
+ return result;
+}
+
+template <class KEY, class VALUE, class KEY_ADAPTER> ACE_INLINE int
+ACE_Active_Map_Manager_Adapter<KEY, VALUE, KEY_ADAPTER>::find (const KEY &key)
+{
+ expanded_value *internal_value = 0;
+ return this->find (key,
+ internal_value);
+}
+
+template <class KEY, class VALUE, class KEY_ADAPTER> ACE_INLINE int
+ACE_Active_Map_Manager_Adapter<KEY, VALUE, KEY_ADAPTER>::rebind (const KEY &key,
+ const VALUE &value)
+{
+ expanded_value *internal_value = 0;
+ int result = this->find (key,
+ internal_value);
+
+ if (result == 0)
+ {
+ // Reset value.
+ internal_value->second (value);
+ }
+
+ return result;
+}
+
+template <class KEY, class VALUE, class KEY_ADAPTER> ACE_INLINE int
+ACE_Active_Map_Manager_Adapter<KEY, VALUE, KEY_ADAPTER>::rebind (const KEY &key,
+ const VALUE &value,
+ VALUE &old_value)
+{
+ expanded_value *internal_value = 0;
+ int result = this->find (key,
+ internal_value);
+
+ if (result == 0)
+ {
+ // Copy old value.
+ old_value = internal_value->second ();
+
+ // Reset to new value.
+ internal_value->second (value);
+ }
+
+ return result;
+}
+
+template <class KEY, class VALUE, class KEY_ADAPTER> ACE_INLINE int
+ACE_Active_Map_Manager_Adapter<KEY, VALUE, KEY_ADAPTER>::rebind (const KEY &key,
+ const VALUE &value,
+ KEY &old_key,
+ VALUE &old_value)
+{
+ expanded_value *internal_value = 0;
+ int result = this->find (key,
+ internal_value);
+
+ if (result == 0)
+ {
+ // Copy old key and value.
+ old_key = internal_value->first ();
+ old_value = internal_value->second ();
+
+ // Reset to new value.
+ internal_value->second (value);
+ }
+
+ return result;
+}
+
+template <class KEY, class VALUE, class KEY_ADAPTER> ACE_INLINE int
+ACE_Active_Map_Manager_Adapter<KEY, VALUE, KEY_ADAPTER>::trybind (const KEY &,
+ VALUE &)
+{
+ ACE_NOTSUP_RETURN (-1);
+}
+
+template <class KEY, class VALUE, class KEY_ADAPTER> ACE_INLINE int
+ACE_Active_Map_Manager_Adapter<KEY, VALUE, KEY_ADAPTER>::unbind (const KEY &key,
+ ACE_Pair<KEY, VALUE> *&internal_value)
+{
+ // Ask the <key_adapter_> to recover the active key.
+ ACE_Active_Map_Manager_Key active_key;
+ int result = this->key_adapter_.decode (key,
+ active_key);
+ if (result == 0)
+ {
+ // Unbind recovered active key from map.
+ result = this->implementation_.unbind (active_key,
+ internal_value);
+ }
+
+ return result;
+}
+
+template <class KEY, class VALUE, class KEY_ADAPTER> ACE_INLINE int
+ACE_Active_Map_Manager_Adapter<KEY, VALUE, KEY_ADAPTER>::unbind (const KEY &key)
+{
+ expanded_value *internal_value = 0;
+ return this->unbind (key,
+ internal_value);
+}
+
+template <class KEY, class VALUE, class KEY_ADAPTER> ACE_INLINE int
+ACE_Active_Map_Manager_Adapter<KEY, VALUE, KEY_ADAPTER>::unbind (const KEY &key,
+ VALUE &value)
+{
+ expanded_value *internal_value = 0;
+ int result = this->unbind (key,
+ internal_value);
+
+ if (result == 0)
+ {
+ // Copy value.
+ value = internal_value->second ();
+ }
+
+ return result;
+}
+
+template <class KEY, class VALUE, class KEY_ADAPTER> ACE_INLINE size_t
+ACE_Active_Map_Manager_Adapter<KEY, VALUE, KEY_ADAPTER>::current_size (void) const
+{
+ return this->implementation_.current_size ();
+}
+
+template <class KEY, class VALUE, class KEY_ADAPTER> ACE_INLINE size_t
+ACE_Active_Map_Manager_Adapter<KEY, VALUE, KEY_ADAPTER>::total_size (void) const
+{
+ return this->implementation_.total_size ();
+}
+
+template <class KEY, class VALUE, class KEY_ADAPTER> ACE_INLINE void
+ACE_Active_Map_Manager_Adapter<KEY, VALUE, KEY_ADAPTER>::dump (void) const
+{
+ this->implementation_.dump ();
+}
+
+template <class KEY, class VALUE, class KEY_ADAPTER> ACE_INLINE ACE_Iterator_Impl<ACE_Reference_Pair<const KEY, VALUE> > *
+ACE_Active_Map_Manager_Adapter<KEY, VALUE, KEY_ADAPTER>::begin_impl (void)
+{
+ ACE_Iterator_Impl<ACE_Reference_Pair<const KEY, VALUE> > *temp = 0;
+ ACE_NEW_RETURN (temp,
+ iterator_impl (this->implementation_.begin ()),
+ 0);
+ return temp;
+}
+
+template <class KEY, class VALUE, class KEY_ADAPTER> ACE_INLINE ACE_Iterator_Impl<ACE_Reference_Pair<const KEY, VALUE> > *
+ACE_Active_Map_Manager_Adapter<KEY, VALUE, KEY_ADAPTER>::end_impl (void)
+{
+ ACE_Iterator_Impl<ACE_Reference_Pair<const KEY, VALUE> > *temp = 0;
+ ACE_NEW_RETURN (temp,
+ iterator_impl (this->implementation_.end ()),
+ 0);
+ return temp;
+}
+
+template <class KEY, class VALUE, class KEY_ADAPTER> ACE_INLINE ACE_Reverse_Iterator_Impl<ACE_Reference_Pair<const KEY, VALUE> > *
+ACE_Active_Map_Manager_Adapter<KEY, VALUE, KEY_ADAPTER>::rbegin_impl (void)
+{
+ ACE_Reverse_Iterator_Impl<ACE_Reference_Pair<const KEY, VALUE> > *temp = 0;
+ ACE_NEW_RETURN (temp,
+ reverse_iterator_impl (this->implementation_.rbegin ()),
+ 0);
+ return temp;
+}
+
+template <class KEY, class VALUE, class KEY_ADAPTER> ACE_INLINE ACE_Reverse_Iterator_Impl<ACE_Reference_Pair<const KEY, VALUE> > *
+ACE_Active_Map_Manager_Adapter<KEY, VALUE, KEY_ADAPTER>::rend_impl (void)
+{
+ ACE_Reverse_Iterator_Impl<ACE_Reference_Pair<const KEY, VALUE> > *temp = 0;
+ ACE_NEW_RETURN (temp,
+ reverse_iterator_impl (this->implementation_.rend ()),
+ 0);
+ return temp;
+}
+
+template <class KEY, class VALUE, class KEY_ADAPTER> ACE_INLINE ACE_Active_Map_Manager<ACE_Pair<KEY, VALUE> > &
+ACE_Active_Map_Manager_Adapter<KEY, VALUE, KEY_ADAPTER>::impl (void)
+{
+ return this->implementation_;
+}
+
+template <class KEY, class VALUE, class KEY_ADAPTER> ACE_INLINE KEY_ADAPTER &
+ACE_Active_Map_Manager_Adapter<KEY, VALUE, KEY_ADAPTER>::key_adapter (void)
+{
+ return this->key_adapter_;
+}
+
+template <class T, class KEY, class VALUE, class HASH_KEY, class COMPARE_KEYS> ACE_INLINE
+ACE_Hash_Map_Manager_Ex_Iterator_Adapter<T, KEY, VALUE, HASH_KEY, COMPARE_KEYS>::ACE_Hash_Map_Manager_Ex_Iterator_Adapter (const ACE_Hash_Map_Iterator_Ex<KEY, VALUE, HASH_KEY, COMPARE_KEYS, ACE_Null_Mutex> &impl)
+ : implementation_ (impl)
+{
+}
+
+template <class T, class KEY, class VALUE, class HASH_KEY, class COMPARE_KEYS> ACE_INLINE
+ACE_Hash_Map_Manager_Ex_Iterator_Adapter<T, KEY, VALUE, HASH_KEY, COMPARE_KEYS>::~ACE_Hash_Map_Manager_Ex_Iterator_Adapter (void)
+{
+}
+
+template <class T, class KEY, class VALUE, class HASH_KEY, class COMPARE_KEYS> ACE_INLINE ACE_Iterator_Impl<T> *
+ACE_Hash_Map_Manager_Ex_Iterator_Adapter<T, KEY, VALUE, HASH_KEY, COMPARE_KEYS>::clone (void) const
+{
+ ACE_Iterator_Impl<T> *temp = 0;
+ ACE_NEW_RETURN (temp,
+ (ACE_Hash_Map_Manager_Ex_Iterator_Adapter<T, KEY, VALUE, HASH_KEY, COMPARE_KEYS>) (*this),
+ 0);
+ return temp;
+}
+
+
+template <class T, class KEY, class VALUE, class HASH_KEY, class COMPARE_KEYS> ACE_INLINE int
+ACE_Hash_Map_Manager_Ex_Iterator_Adapter<T, KEY, VALUE, HASH_KEY, COMPARE_KEYS>::compare (const ACE_Iterator_Impl<T> &rhs) const
+{
+ const ACE_Hash_Map_Manager_Ex_Iterator_Adapter<T, KEY, VALUE, HASH_KEY, COMPARE_KEYS> &rhs_local
+ = ACE_dynamic_cast_5_ref (const ACE_Hash_Map_Manager_Ex_Iterator_Adapter, T, KEY, VALUE, HASH_KEY, COMPARE_KEYS, rhs);
+
+ return this->implementation_ == rhs_local.implementation_;
+}
+
+template <class T, class KEY, class VALUE, class HASH_KEY, class COMPARE_KEYS> ACE_INLINE T
+ACE_Hash_Map_Manager_Ex_Iterator_Adapter<T, KEY, VALUE, HASH_KEY, COMPARE_KEYS>::dereference () const
+{
+ // The following syntax is necessary to work around certain broken compilers.
+ // In particular, please do not prefix implementation_ with this->
+ return T ((*implementation_).ext_id_,
+ (*implementation_).int_id_);
+}
+
+template <class T, class KEY, class VALUE, class HASH_KEY, class COMPARE_KEYS> ACE_INLINE void
+ACE_Hash_Map_Manager_Ex_Iterator_Adapter<T, KEY, VALUE, HASH_KEY, COMPARE_KEYS>::plus_plus (void)
+{
+ ++this->implementation_;
+}
+
+template <class T, class KEY, class VALUE, class HASH_KEY, class COMPARE_KEYS> ACE_INLINE void
+ACE_Hash_Map_Manager_Ex_Iterator_Adapter<T, KEY, VALUE, HASH_KEY, COMPARE_KEYS>::minus_minus (void)
+{
+ --this->implementation_;
+}
+
+template <class T, class KEY, class VALUE, class HASH_KEY, class COMPARE_KEYS> ACE_INLINE ACE_Hash_Map_Iterator_Ex<KEY, VALUE, HASH_KEY, COMPARE_KEYS, ACE_Null_Mutex> &
+ACE_Hash_Map_Manager_Ex_Iterator_Adapter<T, KEY, VALUE, HASH_KEY, COMPARE_KEYS>::impl (void)
+{
+ return this->implementation_;
+}
+
+template <class T, class KEY, class VALUE, class HASH_KEY, class COMPARE_KEYS> ACE_INLINE
+ACE_Hash_Map_Manager_Ex_Reverse_Iterator_Adapter<T, KEY, VALUE, HASH_KEY, COMPARE_KEYS>::ACE_Hash_Map_Manager_Ex_Reverse_Iterator_Adapter (const ACE_Hash_Map_Reverse_Iterator_Ex<KEY, VALUE, HASH_KEY, COMPARE_KEYS, ACE_Null_Mutex> &impl)
+ : implementation_ (impl)
+{
+}
+
+template <class T, class KEY, class VALUE, class HASH_KEY, class COMPARE_KEYS> ACE_INLINE
+ACE_Hash_Map_Manager_Ex_Reverse_Iterator_Adapter<T, KEY, VALUE, HASH_KEY, COMPARE_KEYS>::~ACE_Hash_Map_Manager_Ex_Reverse_Iterator_Adapter (void)
+{
+}
+
+template <class T, class KEY, class VALUE, class HASH_KEY, class COMPARE_KEYS> ACE_INLINE ACE_Reverse_Iterator_Impl<T> *
+ACE_Hash_Map_Manager_Ex_Reverse_Iterator_Adapter<T, KEY, VALUE, HASH_KEY, COMPARE_KEYS>::clone (void) const
+{
+ ACE_Reverse_Iterator_Impl<T> *temp = 0;
+ ACE_NEW_RETURN (temp,
+ (ACE_Hash_Map_Manager_Ex_Reverse_Iterator_Adapter<T, KEY, VALUE, HASH_KEY, COMPARE_KEYS>) (*this),
+ 0);
+ return temp;
+}
+
+
+template <class T, class KEY, class VALUE, class HASH_KEY, class COMPARE_KEYS> ACE_INLINE int
+ACE_Hash_Map_Manager_Ex_Reverse_Iterator_Adapter<T, KEY, VALUE, HASH_KEY, COMPARE_KEYS>::compare (const ACE_Reverse_Iterator_Impl<T> &rhs) const
+{
+ const ACE_Hash_Map_Manager_Ex_Reverse_Iterator_Adapter<T, KEY, VALUE, HASH_KEY, COMPARE_KEYS> &rhs_local
+ = ACE_dynamic_cast_5_ref (const ACE_Hash_Map_Manager_Ex_Reverse_Iterator_Adapter, T, KEY, VALUE, HASH_KEY, COMPARE_KEYS, rhs);
+
+ return this->implementation_ == rhs_local.implementation_;
+}
+
+template <class T, class KEY, class VALUE, class HASH_KEY, class COMPARE_KEYS> ACE_INLINE T
+ACE_Hash_Map_Manager_Ex_Reverse_Iterator_Adapter<T, KEY, VALUE, HASH_KEY, COMPARE_KEYS>::dereference () const
+{
+ // The following syntax is necessary to work around certain broken compilers.
+ // In particular, please do not prefix implementation_ with this->
+ return T ((*implementation_).ext_id_,
+ (*implementation_).int_id_);
+}
+
+template <class T, class KEY, class VALUE, class HASH_KEY, class COMPARE_KEYS> ACE_INLINE void
+ACE_Hash_Map_Manager_Ex_Reverse_Iterator_Adapter<T, KEY, VALUE, HASH_KEY, COMPARE_KEYS>::plus_plus (void)
+{
+ ++this->implementation_;
+}
+
+template <class T, class KEY, class VALUE, class HASH_KEY, class COMPARE_KEYS> ACE_INLINE void
+ACE_Hash_Map_Manager_Ex_Reverse_Iterator_Adapter<T, KEY, VALUE, HASH_KEY, COMPARE_KEYS>::minus_minus (void)
+{
+ --this->implementation_;
+}
+
+template <class T, class KEY, class VALUE, class HASH_KEY, class COMPARE_KEYS> ACE_INLINE ACE_Hash_Map_Reverse_Iterator_Ex<KEY, VALUE, HASH_KEY, COMPARE_KEYS, ACE_Null_Mutex> &
+ACE_Hash_Map_Manager_Ex_Reverse_Iterator_Adapter<T, KEY, VALUE, HASH_KEY, COMPARE_KEYS>::impl (void)
+{
+ return this->implementation_;
+}
+
+template <class KEY, class VALUE, class HASH_KEY, class COMPARE_KEYS, class KEY_GENERATOR> ACE_INLINE
+ACE_Hash_Map_Manager_Ex_Adapter<KEY, VALUE, HASH_KEY, COMPARE_KEYS, KEY_GENERATOR>::ACE_Hash_Map_Manager_Ex_Adapter (ACE_Allocator *alloc)
+ : implementation_ (alloc)
+{
+}
+
+template <class KEY, class VALUE, class HASH_KEY, class COMPARE_KEYS, class KEY_GENERATOR> ACE_INLINE
+ACE_Hash_Map_Manager_Ex_Adapter<KEY, VALUE, HASH_KEY, COMPARE_KEYS, KEY_GENERATOR>::ACE_Hash_Map_Manager_Ex_Adapter (size_t size,
+ ACE_Allocator *alloc)
+ : implementation_ (size,
+ alloc)
+{
+}
+
+template <class KEY, class VALUE, class HASH_KEY, class COMPARE_KEYS, class KEY_GENERATOR> ACE_INLINE
+ACE_Hash_Map_Manager_Ex_Adapter<KEY, VALUE, HASH_KEY, COMPARE_KEYS, KEY_GENERATOR>::~ACE_Hash_Map_Manager_Ex_Adapter (void)
+{
+}
+
+template <class KEY, class VALUE, class HASH_KEY, class COMPARE_KEYS, class KEY_GENERATOR> ACE_INLINE int
+ACE_Hash_Map_Manager_Ex_Adapter<KEY, VALUE, HASH_KEY, COMPARE_KEYS, KEY_GENERATOR>::open (size_t length,
+ ACE_Allocator *alloc)
+{
+ return this->implementation_.open (length,
+ alloc);
+}
+
+template <class KEY, class VALUE, class HASH_KEY, class COMPARE_KEYS, class KEY_GENERATOR> ACE_INLINE int
+ACE_Hash_Map_Manager_Ex_Adapter<KEY, VALUE, HASH_KEY, COMPARE_KEYS, KEY_GENERATOR>::close (void)
+{
+ return this->implementation_.close ();
+}
+
+template <class KEY, class VALUE, class HASH_KEY, class COMPARE_KEYS, class KEY_GENERATOR> ACE_INLINE int
+ACE_Hash_Map_Manager_Ex_Adapter<KEY, VALUE, HASH_KEY, COMPARE_KEYS, KEY_GENERATOR>::bind (const KEY &key,
+ const VALUE &value)
+{
+ return this->implementation_.bind (key,
+ value);
+}
+
+template <class KEY, class VALUE, class HASH_KEY, class COMPARE_KEYS, class KEY_GENERATOR> ACE_INLINE int
+ACE_Hash_Map_Manager_Ex_Adapter<KEY, VALUE, HASH_KEY, COMPARE_KEYS, KEY_GENERATOR>::bind_modify_key (const VALUE &value,
+ KEY &key)
+{
+ return this->implementation_.bind (key,
+ value);
+}
+
+template <class KEY, class VALUE, class HASH_KEY, class COMPARE_KEYS, class KEY_GENERATOR> ACE_INLINE int
+ACE_Hash_Map_Manager_Ex_Adapter<KEY, VALUE, HASH_KEY, COMPARE_KEYS, KEY_GENERATOR>::create_key (KEY &key)
+{
+ // Invoke the user specified key generation functor.
+ return this->key_generator_ (key);
+}
+
+template <class KEY, class VALUE, class HASH_KEY, class COMPARE_KEYS, class KEY_GENERATOR> ACE_INLINE int
+ACE_Hash_Map_Manager_Ex_Adapter<KEY, VALUE, HASH_KEY, COMPARE_KEYS, KEY_GENERATOR>::bind_create_key (const VALUE &value,
+ KEY &key)
+{
+ // Invoke the user specified key generation functor.
+ int result = this->key_generator_ (key);
+
+ if (result == 0)
+ {
+ // Try to add.
+ result = this->implementation_.bind (key,
+ value);
+ }
+
+ return result;
+}
+
+template <class KEY, class VALUE, class HASH_KEY, class COMPARE_KEYS, class KEY_GENERATOR> ACE_INLINE int
+ACE_Hash_Map_Manager_Ex_Adapter<KEY, VALUE, HASH_KEY, COMPARE_KEYS, KEY_GENERATOR>::bind_create_key (const VALUE &value)
+{
+ KEY key;
+ return this->bind_create_key (value,
+ key);
+}
+
+template <class KEY, class VALUE, class HASH_KEY, class COMPARE_KEYS, class KEY_GENERATOR> ACE_INLINE int
+ACE_Hash_Map_Manager_Ex_Adapter<KEY, VALUE, HASH_KEY, COMPARE_KEYS, KEY_GENERATOR>::recover_key (const KEY &modified_key,
+ KEY &original_key)
+{
+ original_key = modified_key;
+ return 0;
+}
+
+template <class KEY, class VALUE, class HASH_KEY, class COMPARE_KEYS, class KEY_GENERATOR> ACE_INLINE int
+ACE_Hash_Map_Manager_Ex_Adapter<KEY, VALUE, HASH_KEY, COMPARE_KEYS, KEY_GENERATOR>::rebind (const KEY &key,
+ const VALUE &value)
+{
+ return this->implementation_.rebind (key,
+ value);
+}
+
+template <class KEY, class VALUE, class HASH_KEY, class COMPARE_KEYS, class KEY_GENERATOR> ACE_INLINE int
+ACE_Hash_Map_Manager_Ex_Adapter<KEY, VALUE, HASH_KEY, COMPARE_KEYS, KEY_GENERATOR>::rebind (const KEY &key,
+ const VALUE &value,
+ VALUE &old_value)
+{
+ return this->implementation_.rebind (key,
+ value,
+ old_value);
+}
+
+template <class KEY, class VALUE, class HASH_KEY, class COMPARE_KEYS, class KEY_GENERATOR> ACE_INLINE int
+ACE_Hash_Map_Manager_Ex_Adapter<KEY, VALUE, HASH_KEY, COMPARE_KEYS, KEY_GENERATOR>::rebind (const KEY &key,
+ const VALUE &value,
+ KEY &old_key,
+ VALUE &old_value)
+{
+ return this->implementation_.rebind (key,
+ value,
+ old_key,
+ old_value);
+}
+
+template <class KEY, class VALUE, class HASH_KEY, class COMPARE_KEYS, class KEY_GENERATOR> ACE_INLINE int
+ACE_Hash_Map_Manager_Ex_Adapter<KEY, VALUE, HASH_KEY, COMPARE_KEYS, KEY_GENERATOR>::trybind (const KEY &key,
+ VALUE &value)
+{
+ return this->implementation_.trybind (key,
+ value);
+}
+
+template <class KEY, class VALUE, class HASH_KEY, class COMPARE_KEYS, class KEY_GENERATOR> ACE_INLINE int
+ACE_Hash_Map_Manager_Ex_Adapter<KEY, VALUE, HASH_KEY, COMPARE_KEYS, KEY_GENERATOR>::find (const KEY &key,
+ VALUE &value)
+{
+ return this->implementation_.find (key,
+ value);
+}
+
+template <class KEY, class VALUE, class HASH_KEY, class COMPARE_KEYS, class KEY_GENERATOR> ACE_INLINE int
+ACE_Hash_Map_Manager_Ex_Adapter<KEY, VALUE, HASH_KEY, COMPARE_KEYS, KEY_GENERATOR>::find (const KEY &key)
+{
+ return this->implementation_.find (key);
+}
+
+template <class KEY, class VALUE, class HASH_KEY, class COMPARE_KEYS, class KEY_GENERATOR> ACE_INLINE int
+ACE_Hash_Map_Manager_Ex_Adapter<KEY, VALUE, HASH_KEY, COMPARE_KEYS, KEY_GENERATOR>::unbind (const KEY &key)
+{
+ return this->implementation_.unbind (key);
+}
+
+template <class KEY, class VALUE, class HASH_KEY, class COMPARE_KEYS, class KEY_GENERATOR> ACE_INLINE int
+ACE_Hash_Map_Manager_Ex_Adapter<KEY, VALUE, HASH_KEY, COMPARE_KEYS, KEY_GENERATOR>::unbind (const KEY &key,
+ VALUE &value)
+{
+ return this->implementation_.unbind (key,
+ value);
+}
+
+template <class KEY, class VALUE, class HASH_KEY, class COMPARE_KEYS, class KEY_GENERATOR> ACE_INLINE size_t
+ACE_Hash_Map_Manager_Ex_Adapter<KEY, VALUE, HASH_KEY, COMPARE_KEYS, KEY_GENERATOR>::current_size (void) const
+{
+ return this->implementation_.current_size ();
+}
+
+template <class KEY, class VALUE, class HASH_KEY, class COMPARE_KEYS, class KEY_GENERATOR> ACE_INLINE size_t
+ACE_Hash_Map_Manager_Ex_Adapter<KEY, VALUE, HASH_KEY, COMPARE_KEYS, KEY_GENERATOR>::total_size (void) const
+{
+ return this->implementation_.total_size ();
+}
+
+template <class KEY, class VALUE, class HASH_KEY, class COMPARE_KEYS, class KEY_GENERATOR> ACE_INLINE void
+ACE_Hash_Map_Manager_Ex_Adapter<KEY, VALUE, HASH_KEY, COMPARE_KEYS, KEY_GENERATOR>::dump (void) const
+{
+ this->implementation_.dump ();
+}
+
+template <class KEY, class VALUE, class HASH_KEY, class COMPARE_KEYS, class KEY_GENERATOR> ACE_INLINE ACE_Iterator_Impl<ACE_Reference_Pair<const KEY, VALUE> > *
+ACE_Hash_Map_Manager_Ex_Adapter<KEY, VALUE, HASH_KEY, COMPARE_KEYS, KEY_GENERATOR>::begin_impl (void)
+{
+ ACE_Iterator_Impl<ACE_Reference_Pair<const KEY, VALUE> > *temp = 0;
+ ACE_NEW_RETURN (temp,
+ iterator_impl (this->implementation_.begin ()),
+ 0);
+ return temp;
+}
+
+template <class KEY, class VALUE, class HASH_KEY, class COMPARE_KEYS, class KEY_GENERATOR> ACE_INLINE ACE_Iterator_Impl<ACE_Reference_Pair<const KEY, VALUE> > *
+ACE_Hash_Map_Manager_Ex_Adapter<KEY, VALUE, HASH_KEY, COMPARE_KEYS, KEY_GENERATOR>::end_impl (void)
+{
+ ACE_Iterator_Impl<ACE_Reference_Pair<const KEY, VALUE> > *temp = 0;
+ ACE_NEW_RETURN (temp,
+ iterator_impl (this->implementation_.end ()),
+ 0);
+ return temp;
+}
+
+template <class KEY, class VALUE, class HASH_KEY, class COMPARE_KEYS, class KEY_GENERATOR> ACE_INLINE ACE_Reverse_Iterator_Impl<ACE_Reference_Pair<const KEY, VALUE> > *
+ACE_Hash_Map_Manager_Ex_Adapter<KEY, VALUE, HASH_KEY, COMPARE_KEYS, KEY_GENERATOR>::rbegin_impl (void)
+{
+ ACE_Reverse_Iterator_Impl<ACE_Reference_Pair<const KEY, VALUE> > *temp = 0;
+ ACE_NEW_RETURN (temp,
+ reverse_iterator_impl (this->implementation_.rbegin ()),
+ 0);
+ return temp;
+}
+
+template <class KEY, class VALUE, class HASH_KEY, class COMPARE_KEYS, class KEY_GENERATOR> ACE_INLINE ACE_Reverse_Iterator_Impl<ACE_Reference_Pair<const KEY, VALUE> > *
+ACE_Hash_Map_Manager_Ex_Adapter<KEY, VALUE, HASH_KEY, COMPARE_KEYS, KEY_GENERATOR>::rend_impl (void)
+{
+ ACE_Reverse_Iterator_Impl<ACE_Reference_Pair<const KEY, VALUE> > *temp = 0;
+ ACE_NEW_RETURN (temp,
+ reverse_iterator_impl (this->implementation_.rend ()),
+ 0);
+ return temp;
+}
+
+template <class KEY, class VALUE, class HASH_KEY, class COMPARE_KEYS, class KEY_GENERATOR> ACE_INLINE ACE_Hash_Map_Manager_Ex<KEY, VALUE, HASH_KEY, COMPARE_KEYS, ACE_Null_Mutex> &
+ACE_Hash_Map_Manager_Ex_Adapter<KEY, VALUE, HASH_KEY, COMPARE_KEYS, KEY_GENERATOR>::impl (void)
+{
+ return this->implementation_;
+}
+
+template <class KEY, class VALUE, class HASH_KEY, class COMPARE_KEYS, class KEY_GENERATOR> ACE_INLINE KEY_GENERATOR &
+ACE_Hash_Map_Manager_Ex_Adapter<KEY, VALUE, HASH_KEY, COMPARE_KEYS, KEY_GENERATOR>::key_generator (void)
+{
+ return this->key_generator_;
+}
+
+template <class T, class KEY, class VALUE> ACE_INLINE
+ACE_Map_Manager_Iterator_Adapter<T, KEY, VALUE>::ACE_Map_Manager_Iterator_Adapter (const ACE_Map_Iterator<KEY, VALUE, ACE_Null_Mutex> &impl)
+ : implementation_ (impl)
+{
+}
+
+template <class T, class KEY, class VALUE> ACE_INLINE
+ACE_Map_Manager_Iterator_Adapter<T, KEY, VALUE>::~ACE_Map_Manager_Iterator_Adapter (void)
+{
+}
+
+template <class T, class KEY, class VALUE> ACE_INLINE ACE_Iterator_Impl<T> *
+ACE_Map_Manager_Iterator_Adapter<T, KEY, VALUE>::clone (void) const
+{
+ ACE_Iterator_Impl<T> *temp = 0;
+ ACE_NEW_RETURN (temp,
+ (ACE_Map_Manager_Iterator_Adapter<T, KEY, VALUE>) (*this),
+ 0);
+ return temp;
+}
+
+
+template <class T, class KEY, class VALUE> ACE_INLINE int
+ACE_Map_Manager_Iterator_Adapter<T, KEY, VALUE>::compare (const ACE_Iterator_Impl<T> &rhs) const
+{
+ const ACE_Map_Manager_Iterator_Adapter<T, KEY, VALUE> &rhs_local
+ = ACE_dynamic_cast_3_ref (const ACE_Map_Manager_Iterator_Adapter, T, KEY, VALUE, rhs);
+
+ return this->implementation_ == rhs_local.implementation_;
+}
+
+template <class T, class KEY, class VALUE> ACE_INLINE T
+ACE_Map_Manager_Iterator_Adapter<T, KEY, VALUE>::dereference () const
+{
+ // The following syntax is necessary to work around certain broken compilers.
+ // In particular, please do not prefix implementation_ with this->
+ return T ((*implementation_).ext_id_,
+ (*implementation_).int_id_);
+}
+
+template <class T, class KEY, class VALUE> ACE_INLINE void
+ACE_Map_Manager_Iterator_Adapter<T, KEY, VALUE>::plus_plus (void)
+{
+ ++this->implementation_;
+}
+
+template <class T, class KEY, class VALUE> ACE_INLINE void
+ACE_Map_Manager_Iterator_Adapter<T, KEY, VALUE>::minus_minus (void)
+{
+ --this->implementation_;
+}
+
+template <class T, class KEY, class VALUE> ACE_INLINE ACE_Map_Iterator<KEY, VALUE, ACE_Null_Mutex> &
+ACE_Map_Manager_Iterator_Adapter<T, KEY, VALUE>::impl (void)
+{
+ return this->implementation_;
+}
+
+template <class T, class KEY, class VALUE> ACE_INLINE
+ACE_Map_Manager_Reverse_Iterator_Adapter<T, KEY, VALUE>::ACE_Map_Manager_Reverse_Iterator_Adapter (const ACE_Map_Reverse_Iterator<KEY, VALUE, ACE_Null_Mutex> &impl)
+ : implementation_ (impl)
+{
+}
+
+template <class T, class KEY, class VALUE> ACE_INLINE
+ACE_Map_Manager_Reverse_Iterator_Adapter<T, KEY, VALUE>::~ACE_Map_Manager_Reverse_Iterator_Adapter (void)
+{
+}
+
+template <class T, class KEY, class VALUE> ACE_INLINE ACE_Reverse_Iterator_Impl<T> *
+ACE_Map_Manager_Reverse_Iterator_Adapter<T, KEY, VALUE>::clone (void) const
+{
+ ACE_Reverse_Iterator_Impl<T> *temp = 0;
+ ACE_NEW_RETURN (temp,
+ (ACE_Map_Manager_Reverse_Iterator_Adapter<T, KEY, VALUE>) (*this),
+ 0);
+ return temp;
+}
+
+
+template <class T, class KEY, class VALUE> ACE_INLINE int
+ACE_Map_Manager_Reverse_Iterator_Adapter<T, KEY, VALUE>::compare (const ACE_Reverse_Iterator_Impl<T> &rhs) const
+{
+ const ACE_Map_Manager_Reverse_Iterator_Adapter<T, KEY, VALUE> &rhs_local
+ = ACE_dynamic_cast_3_ref (const ACE_Map_Manager_Reverse_Iterator_Adapter, T, KEY, VALUE, rhs);
+
+ return this->implementation_ == rhs_local.implementation_;
+}
+
+template <class T, class KEY, class VALUE> ACE_INLINE T
+ACE_Map_Manager_Reverse_Iterator_Adapter<T, KEY, VALUE>::dereference () const
+{
+ // The following syntax is necessary to work around certain broken compilers.
+ // In particular, please do not prefix implementation_ with this->
+ return T ((*implementation_).ext_id_,
+ (*implementation_).int_id_);
+}
+
+template <class T, class KEY, class VALUE> ACE_INLINE void
+ACE_Map_Manager_Reverse_Iterator_Adapter<T, KEY, VALUE>::plus_plus (void)
+{
+ ++this->implementation_;
+}
+
+template <class T, class KEY, class VALUE> ACE_INLINE void
+ACE_Map_Manager_Reverse_Iterator_Adapter<T, KEY, VALUE>::minus_minus (void)
+{
+ --this->implementation_;
+}
+
+template <class T, class KEY, class VALUE> ACE_INLINE ACE_Map_Reverse_Iterator<KEY, VALUE, ACE_Null_Mutex> &
+ACE_Map_Manager_Reverse_Iterator_Adapter<T, KEY, VALUE>::impl (void)
+{
+ return this->implementation_;
+}
+
+template <class KEY, class VALUE, class KEY_GENERATOR> ACE_INLINE
+ACE_Map_Manager_Adapter<KEY, VALUE, KEY_GENERATOR>::ACE_Map_Manager_Adapter (ACE_Allocator *alloc)
+ : implementation_ (alloc)
+{
+}
+
+template <class KEY, class VALUE, class KEY_GENERATOR> ACE_INLINE
+ACE_Map_Manager_Adapter<KEY, VALUE, KEY_GENERATOR>::ACE_Map_Manager_Adapter (size_t size,
+ ACE_Allocator *alloc)
+ : implementation_ (size,
+ alloc)
+{
+}
+
+template <class KEY, class VALUE, class KEY_GENERATOR> ACE_INLINE
+ACE_Map_Manager_Adapter<KEY, VALUE, KEY_GENERATOR>::~ACE_Map_Manager_Adapter (void)
+{
+}
+
+template <class KEY, class VALUE, class KEY_GENERATOR> ACE_INLINE int
+ACE_Map_Manager_Adapter<KEY, VALUE, KEY_GENERATOR>::open (size_t length,
+ ACE_Allocator *alloc)
+{
+ return this->implementation_.open (length,
+ alloc);
+}
+
+template <class KEY, class VALUE, class KEY_GENERATOR> ACE_INLINE int
+ACE_Map_Manager_Adapter<KEY, VALUE, KEY_GENERATOR>::close (void)
+{
+ return this->implementation_.close ();
+}
+
+template <class KEY, class VALUE, class KEY_GENERATOR> ACE_INLINE int
+ACE_Map_Manager_Adapter<KEY, VALUE, KEY_GENERATOR>::bind (const KEY &key,
+ const VALUE &value)
+{
+ return this->implementation_.bind (key,
+ value);
+}
+
+template <class KEY, class VALUE, class KEY_GENERATOR> ACE_INLINE int
+ACE_Map_Manager_Adapter<KEY, VALUE, KEY_GENERATOR>::bind_modify_key (const VALUE &value,
+ KEY &key)
+{
+ return this->implementation_.bind (key,
+ value);
+}
+
+template <class KEY, class VALUE, class KEY_GENERATOR> ACE_INLINE int
+ACE_Map_Manager_Adapter<KEY, VALUE, KEY_GENERATOR>::create_key (KEY &key)
+{
+ // Invoke the user specified key generation functor.
+ return this->key_generator_ (key);
+}
+
+template <class KEY, class VALUE, class KEY_GENERATOR> ACE_INLINE int
+ACE_Map_Manager_Adapter<KEY, VALUE, KEY_GENERATOR>::bind_create_key (const VALUE &value,
+ KEY &key)
+{
+ // Invoke the user specified key generation functor.
+ int result = this->key_generator_ (key);
+
+ if (result == 0)
+ {
+ // Try to add.
+ result = this->implementation_.bind (key,
+ value);
+ }
+
+ return result;
+}
+
+template <class KEY, class VALUE, class KEY_GENERATOR> ACE_INLINE int
+ACE_Map_Manager_Adapter<KEY, VALUE, KEY_GENERATOR>::bind_create_key (const VALUE &value)
+{
+ KEY key;
+ return this->bind_create_key (value,
+ key);
+}
+
+template <class KEY, class VALUE, class KEY_GENERATOR> ACE_INLINE int
+ACE_Map_Manager_Adapter<KEY, VALUE, KEY_GENERATOR>::recover_key (const KEY &modified_key,
+ KEY &original_key)
+{
+ original_key = modified_key;
+ return 0;
+}
+
+template <class KEY, class VALUE, class KEY_GENERATOR> ACE_INLINE int
+ACE_Map_Manager_Adapter<KEY, VALUE, KEY_GENERATOR>::rebind (const KEY &key,
+ const VALUE &value)
+{
+ return this->implementation_.rebind (key,
+ value);
+}
+
+template <class KEY, class VALUE, class KEY_GENERATOR> ACE_INLINE int
+ACE_Map_Manager_Adapter<KEY, VALUE, KEY_GENERATOR>::rebind (const KEY &key,
+ const VALUE &value,
+ VALUE &old_value)
+{
+ return this->implementation_.rebind (key,
+ value,
+ old_value);
+}
+
+template <class KEY, class VALUE, class KEY_GENERATOR> ACE_INLINE int
+ACE_Map_Manager_Adapter<KEY, VALUE, KEY_GENERATOR>::rebind (const KEY &key,
+ const VALUE &value,
+ KEY &old_key,
+ VALUE &old_value)
+{
+ return this->implementation_.rebind (key,
+ value,
+ old_key,
+ old_value);
+}
+
+template <class KEY, class VALUE, class KEY_GENERATOR> ACE_INLINE int
+ACE_Map_Manager_Adapter<KEY, VALUE, KEY_GENERATOR>::trybind (const KEY &key,
+ VALUE &value)
+{
+ return this->implementation_.trybind (key,
+ value);
+}
+
+template <class KEY, class VALUE, class KEY_GENERATOR> ACE_INLINE int
+ACE_Map_Manager_Adapter<KEY, VALUE, KEY_GENERATOR>::find (const KEY &key,
+ VALUE &value)
+{
+ return this->implementation_.find (key,
+ value);
+}
+
+template <class KEY, class VALUE, class KEY_GENERATOR> ACE_INLINE int
+ACE_Map_Manager_Adapter<KEY, VALUE, KEY_GENERATOR>::find (const KEY &key)
+{
+ return this->implementation_.find (key);
+}
+
+template <class KEY, class VALUE, class KEY_GENERATOR> ACE_INLINE int
+ACE_Map_Manager_Adapter<KEY, VALUE, KEY_GENERATOR>::unbind (const KEY &key)
+{
+ return this->implementation_.unbind (key);
+}
+
+template <class KEY, class VALUE, class KEY_GENERATOR> ACE_INLINE int
+ACE_Map_Manager_Adapter<KEY, VALUE, KEY_GENERATOR>::unbind (const KEY &key,
+ VALUE &value)
+{
+ return this->implementation_.unbind (key,
+ value);
+}
+
+template <class KEY, class VALUE, class KEY_GENERATOR> ACE_INLINE size_t
+ACE_Map_Manager_Adapter<KEY, VALUE, KEY_GENERATOR>::current_size (void) const
+{
+ return this->implementation_.current_size ();
+}
+
+template <class KEY, class VALUE, class KEY_GENERATOR> ACE_INLINE size_t
+ACE_Map_Manager_Adapter<KEY, VALUE, KEY_GENERATOR>::total_size (void) const
+{
+ return this->implementation_.total_size ();
+}
+
+template <class KEY, class VALUE, class KEY_GENERATOR> ACE_INLINE void
+ACE_Map_Manager_Adapter<KEY, VALUE, KEY_GENERATOR>::dump (void) const
+{
+ this->implementation_.dump ();
+}
+
+template <class KEY, class VALUE, class KEY_GENERATOR> ACE_INLINE ACE_Iterator_Impl<ACE_Reference_Pair<const KEY, VALUE> > *
+ACE_Map_Manager_Adapter<KEY, VALUE, KEY_GENERATOR>::begin_impl (void)
+{
+ ACE_Iterator_Impl<ACE_Reference_Pair<const KEY, VALUE> > *temp = 0;
+ ACE_NEW_RETURN (temp,
+ iterator_impl (this->implementation_.begin ()),
+ 0);
+ return temp;
+}
+
+template <class KEY, class VALUE, class KEY_GENERATOR> ACE_INLINE ACE_Iterator_Impl<ACE_Reference_Pair<const KEY, VALUE> > *
+ACE_Map_Manager_Adapter<KEY, VALUE, KEY_GENERATOR>::end_impl (void)
+{
+ ACE_Iterator_Impl<ACE_Reference_Pair<const KEY, VALUE> > *temp = 0;
+ ACE_NEW_RETURN (temp,
+ iterator_impl (this->implementation_.end ()),
+ 0);
+ return temp;
+}
+
+template <class KEY, class VALUE, class KEY_GENERATOR> ACE_INLINE ACE_Reverse_Iterator_Impl<ACE_Reference_Pair<const KEY, VALUE> > *
+ACE_Map_Manager_Adapter<KEY, VALUE, KEY_GENERATOR>::rbegin_impl (void)
+{
+ ACE_Reverse_Iterator_Impl<ACE_Reference_Pair<const KEY, VALUE> > *temp = 0;
+ ACE_NEW_RETURN (temp,
+ reverse_iterator_impl (this->implementation_.rbegin ()),
+ 0);
+ return temp;
+}
+
+template <class KEY, class VALUE, class KEY_GENERATOR> ACE_INLINE ACE_Reverse_Iterator_Impl<ACE_Reference_Pair<const KEY, VALUE> > *
+ACE_Map_Manager_Adapter<KEY, VALUE, KEY_GENERATOR>::rend_impl (void)
+{
+ ACE_Reverse_Iterator_Impl<ACE_Reference_Pair<const KEY, VALUE> > *temp = 0;
+ ACE_NEW_RETURN (temp,
+ reverse_iterator_impl (this->implementation_.rend ()),
+ 0);
+ return temp;
+}
+
+template <class KEY, class VALUE, class KEY_GENERATOR> ACE_INLINE ACE_Map_Manager<KEY, VALUE, ACE_Null_Mutex> &
+ACE_Map_Manager_Adapter<KEY, VALUE, KEY_GENERATOR>::impl (void)
+{
+ return this->implementation_;
+}
+
+template <class KEY, class VALUE, class KEY_GENERATOR> ACE_INLINE KEY_GENERATOR &
+ACE_Map_Manager_Adapter<KEY, VALUE, KEY_GENERATOR>::key_generator (void)
+{
+ return this->key_generator_;
+}
diff --git a/ace/Utils/Templates/Message_Block_T.cpp b/ace/Utils/Templates/Message_Block_T.cpp
new file mode 100644
index 00000000000..4916fd211e7
--- /dev/null
+++ b/ace/Utils/Templates/Message_Block_T.cpp
@@ -0,0 +1,46 @@
+// $Id$
+
+#if !defined (ACE_MESSAGE_BLOCK_T_C)
+#define ACE_MESSAGE_BLOCK_T_C
+
+
+ACE_RCSID(ace, Message_Block_T, "$Id$")
+
+#if !defined (__ACE_INLINE__)
+#include "ace/Message_Block_T.i"
+#endif /* __ACE_INLINE__ */
+
+template<class L>
+ACE_Locked_Data_Block<L>::~ACE_Locked_Data_Block (void)
+{
+}
+
+template<class ACE_LOCK> ACE_Data_Block *
+ACE_Locked_Data_Block<ACE_LOCK>::clone_nocopy (ACE_Message_Block::Message_Flags mask) const
+{
+ ACE_TRACE ("ACE_Locked_Data_Block::clone_nocopy");
+
+ // You always want to clear this one to prevent memory leaks but you
+ // might add some others later.
+ const ACE_Message_Block::Message_Flags always_clear =
+ ACE_Message_Block::DONT_DELETE;
+
+ ACE_Locked_Data_Block<ACE_LOCK> *nb;
+
+ ACE_NEW_MALLOC_RETURN (nb,
+ ACE_static_cast(ACE_Locked_Data_Block<ACE_LOCK>*,
+ this->data_block_allocator ()->malloc (sizeof (ACE_Locked_Data_Block<ACE_LOCK>))),
+ ACE_Locked_Data_Block<ACE_LOCK> (this->size (),
+ this->msg_type (),
+ 0,
+ this->allocator_strategy (),
+ this->flags (),
+ this->data_block_allocator ()),
+ 0);
+
+ // Set new flags minus the mask...
+ nb->clr_flags (mask | always_clear);
+ return nb;
+}
+
+#endif /* ACE_MESSAGE_BLOCK_T_C */
diff --git a/ace/Utils/Templates/Message_Block_T.h b/ace/Utils/Templates/Message_Block_T.h
new file mode 100644
index 00000000000..93dc5505b8d
--- /dev/null
+++ b/ace/Utils/Templates/Message_Block_T.h
@@ -0,0 +1,83 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Message_Block_T.h
+ *
+ * $Id$
+ *
+ * @author Doug Schmidt & Carlos O'Ryan
+ */
+//=============================================================================
+
+
+#ifndef ACE_MESSAGE_BLOCK_T_H
+#define ACE_MESSAGE_BLOCK_T_H
+#include "ace/pre.h"
+
+#include "ace/Message_Block.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+/**
+ * @class ACE_Locked_Data_Block
+ *
+ * @brief A Data_Block with a concrete locking strategy.
+ *
+ * Data_Blocks can be parametric on the kind of lock they use; in
+ * many cases the lifetime of the lock is tied to the lifetime of
+ * the Data_Block itself. But since Data_Blocks are reference
+ * counted it is hard for users to control the lock lifetime.
+ * This class is parametric over the kind of lock used.
+ */
+template <class ACE_LOCK>
+class ACE_Locked_Data_Block : public ACE_Data_Block
+{
+public:
+ // = Initialization and termination methods.
+ /// Default "do-nothing" constructor.
+ ACE_Locked_Data_Block (void);
+
+ /// Initialize.
+ ACE_Locked_Data_Block (size_t size,
+ ACE_Message_Block::ACE_Message_Type msg_type,
+ const char *msg_data,
+ ACE_Allocator *allocator_strategy,
+ ACE_Message_Block::Message_Flags flags,
+ ACE_Allocator *data_block_allocator);
+
+ /// Delete all the resources held in the message.
+ virtual ~ACE_Locked_Data_Block (void);
+
+ /**
+ * Return an exact "deep copy" of the message, the dynamic type is
+ * ACE_Locked_Data_Block<>
+ * See the documentation in Message_Block.h for details.
+ */
+ virtual ACE_Data_Block *clone_nocopy (ACE_Message_Block::Message_Flags mask = 0) const;
+
+private:
+ /// The lock
+ ACE_LOCK lock_;
+
+ // = Disallow these operations.
+ ACE_UNIMPLEMENTED_FUNC (ACE_Locked_Data_Block<ACE_LOCK> &operator= (const ACE_Locked_Data_Block<ACE_LOCK> &))
+ ACE_UNIMPLEMENTED_FUNC (ACE_Locked_Data_Block (const ACE_Locked_Data_Block<ACE_LOCK> &))
+};
+
+#if defined (__ACE_INLINE__)
+#include "ace/Message_Block_T.i"
+#endif /* __ACE_INLINE__ */
+
+#if defined (ACE_TEMPLATES_REQUIRE_SOURCE)
+#include "ace/Message_Block_T.cpp"
+#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */
+
+#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA)
+#pragma implementation ("Message_Block_T.cpp")
+#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */
+
+#include "ace/post.h"
+#endif /* ACE_MESSAGE_BLOCK_T_H */
diff --git a/ace/Utils/Templates/Message_Block_T.i b/ace/Utils/Templates/Message_Block_T.i
new file mode 100644
index 00000000000..279dcaa704d
--- /dev/null
+++ b/ace/Utils/Templates/Message_Block_T.i
@@ -0,0 +1,29 @@
+/* -*- C++ -*- */
+// $Id$
+
+// Message_Block_T.i
+
+
+template<class ACE_LOCK> ACE_INLINE
+ACE_Locked_Data_Block<ACE_LOCK>::ACE_Locked_Data_Block (void)
+{
+ this->locking_strategy_ = &this->lock_;
+}
+
+template<class ACE_LOCK> ACE_INLINE
+ACE_Locked_Data_Block<ACE_LOCK>::
+ACE_Locked_Data_Block (size_t size,
+ ACE_Message_Block::ACE_Message_Type msg_type,
+ const char *msg_data,
+ ACE_Allocator *allocator_strategy,
+ ACE_Message_Block::Message_Flags flags,
+ ACE_Allocator *data_block_allocator)
+ : ACE_Data_Block (size,
+ msg_type,
+ msg_data,
+ allocator_strategy,
+ &lock_,
+ flags,
+ data_block_allocator)
+{
+}
diff --git a/ace/Utils/Templates/Node.cpp b/ace/Utils/Templates/Node.cpp
new file mode 100644
index 00000000000..91e989d739b
--- /dev/null
+++ b/ace/Utils/Templates/Node.cpp
@@ -0,0 +1,46 @@
+// $Id$
+
+#ifndef ACE_NODE_C
+#define ACE_NODE_C
+
+#include "ace/Node.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+ACE_RCSID(ace, Node, "$Id$")
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Node)
+
+# if ! defined (ACE_HAS_BROKEN_NOOP_DTORS)
+ template <class T>
+ACE_Node<T>::~ACE_Node (void)
+{
+}
+# endif /* ! defined (ACE_HAS_BROKEN_NOOP_DTORS) */
+
+template <class T>
+ACE_Node<T>::ACE_Node (const T &i, ACE_Node<T> *n)
+ : next_ (n),
+ item_ (i)
+{
+ // ACE_TRACE ("ACE_Node<T>::ACE_Node");
+}
+
+template <class T>
+ACE_Node<T>::ACE_Node (ACE_Node<T> *n, int)
+ : next_ (n)
+{
+ // ACE_TRACE ("ACE_Node<T>::ACE_Node");
+}
+
+template <class T>
+ACE_Node<T>::ACE_Node (const ACE_Node<T> &s)
+ : next_ (s.next_),
+ item_ (s.item_)
+{
+ // ACE_TRACE ("ACE_Node<T>::ACE_Node");
+}
+
+#endif /* ACE_NODE_C */
diff --git a/ace/Utils/Templates/Node.h b/ace/Utils/Templates/Node.h
new file mode 100644
index 00000000000..3d69213bf26
--- /dev/null
+++ b/ace/Utils/Templates/Node.h
@@ -0,0 +1,77 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Node.h
+ *
+ * $Id$
+ *
+ * @author Doug Schmidt
+ */
+//=============================================================================
+
+
+#ifndef ACE_NODE_H
+#define ACE_NODE_H
+#include "ace/pre.h"
+
+#include "ace/config-all.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+// Forward declarations.
+template <class T> class ACE_Unbounded_Set;
+template <class T> class ACE_Unbounded_Set_Iterator;
+template <class T> class ACE_Unbounded_Set_Const_Iterator;
+template <class T> class ACE_Unbounded_Queue;
+template <class T> class ACE_Unbounded_Queue_Iterator;
+template <class T> class ACE_Unbounded_Stack;
+template <class T> class ACE_Unbounded_Stack_Iterator;
+
+/**
+ * @class ACE_Node
+ *
+ * @brief Implementation element in a Queue, Set, and Stack.
+ */
+template<class T>
+class ACE_Node
+{
+public:
+ friend class ACE_Unbounded_Queue<T>;
+ friend class ACE_Unbounded_Queue_Iterator<T>;
+ friend class ACE_Unbounded_Set<T>;
+ friend class ACE_Unbounded_Set_Iterator<T>;
+ friend class ACE_Unbounded_Set_Const_Iterator<T>;
+ friend class ACE_Unbounded_Stack<T>;
+ friend class ACE_Unbounded_Stack_Iterator<T>;
+
+# if ! defined (ACE_HAS_BROKEN_NOOP_DTORS)
+ /// This isn't necessary, but it keeps some compilers happy.
+ ~ACE_Node (void);
+# endif /* ! defined (ACE_HAS_BROKEN_NOOP_DTORS) */
+
+private:
+ // = Initialization methods
+ ACE_Node (const T &i, ACE_Node<T> *n);
+ ACE_Node (ACE_Node<T> *n = 0, int = 0);
+ ACE_Node (const ACE_Node<T> &n);
+
+ /// Pointer to next element in the list of <ACE_Node>s.
+ ACE_Node<T> *next_;
+
+ /// Current value of the item in this node.
+ T item_;
+};
+
+#if defined (ACE_TEMPLATES_REQUIRE_SOURCE)
+#include "ace/Node.cpp"
+#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */
+
+#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA)
+#pragma implementation ("Node.cpp")
+#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */
+
+#include "ace/post.h"
+#endif /* ACE_NODE_H */
diff --git a/ace/Utils/Templates/Pair_T.cpp b/ace/Utils/Templates/Pair_T.cpp
new file mode 100644
index 00000000000..27e7f6d34df
--- /dev/null
+++ b/ace/Utils/Templates/Pair_T.cpp
@@ -0,0 +1,18 @@
+// $Id$
+
+#ifndef ACE_PAIR_T_C
+#define ACE_PAIR_T_C
+
+#include "ace/Pair_T.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#if !defined (__ACE_INLINE__)
+#include "ace/Pair_T.i"
+#endif /* __ACE_INLINE__ */
+
+ACE_RCSID(ace, Pair_T, "$Id$")
+
+#endif /* ACE_PAIR_T_C */
diff --git a/ace/Utils/Templates/Pair_T.h b/ace/Utils/Templates/Pair_T.h
new file mode 100644
index 00000000000..3d0a9a7575d
--- /dev/null
+++ b/ace/Utils/Templates/Pair_T.h
@@ -0,0 +1,111 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Pair_T.h
+ *
+ * $Id$
+ *
+ * @author Irfan Pyarali <irfan@cs.wustl.edu>
+ */
+//=============================================================================
+
+
+#ifndef ACE_PAIR_T_H
+#define ACE_PAIR_T_H
+#include "ace/pre.h"
+
+#include "ace/Pair.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+/**
+ * @class ACE_Pair
+ *
+ * @brief Defines a pair.
+ *
+ * Similar to the STL pair.
+ */
+template <class T1, class T2>
+class ACE_Pair
+{
+public:
+
+ // = Traits.
+ typedef T1 first_type;
+ typedef T2 second_type;
+
+ // = Initialization and termination methods.
+ /// Constructor.
+ ACE_Pair (const T1 &t1,
+ const T2 &t2);
+
+ /// Default constructor.
+ ACE_Pair (void);
+
+ /// Get/Set first.
+ T1 &first (void);
+ const T1 &first (void) const;
+ void first (const T1 &t1);
+
+ /// Access second.
+ T2 &second (void);
+ const T2 &second (void) const;
+ void second (const T2 &t2);
+
+protected:
+
+ T1 first_;
+ T2 second_;
+};
+
+/**
+ * @class ACE_Reference_Pair
+ *
+ * @brief Defines a pair that only hold references.
+ *
+ * Similar to the STL pair (but restricted to holding references
+ * and not copies).
+ */
+template <class T1, class T2>
+class ACE_Reference_Pair
+{
+public:
+
+ // = Traits.
+ typedef T1 first_type;
+ typedef T2 second_type;
+
+ // = Initialization and termination methods.
+ /// Constructor.
+ ACE_Reference_Pair (T1 &t1,
+ T2 &t2);
+
+ /// Access first.
+ T1 &first (void) const;
+
+ /// Access second.
+ T2 &second (void) const;
+
+protected:
+
+ T1 &first_;
+ T2 &second_;
+};
+
+#if defined (__ACE_INLINE__)
+#include "ace/Pair_T.i"
+#endif /* __ACE_INLINE__ */
+
+#if defined (ACE_TEMPLATES_REQUIRE_SOURCE)
+#include "ace/Pair_T.cpp"
+#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */
+
+#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA)
+#pragma implementation ("Pair_T.cpp")
+#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */
+
+#include "ace/post.h"
+#endif /* ACE_PAIR_T_H */
diff --git a/ace/Utils/Templates/Pair_T.i b/ace/Utils/Templates/Pair_T.i
new file mode 100644
index 00000000000..7ef61c9cf44
--- /dev/null
+++ b/ace/Utils/Templates/Pair_T.i
@@ -0,0 +1,72 @@
+// $Id$
+
+template <class T1, class T2> ACE_INLINE
+ACE_Pair<T1, T2>::ACE_Pair (const T1 &t1,
+ const T2 &t2)
+ : first_ (t1),
+ second_ (t2)
+{
+}
+
+template <class T1, class T2> ACE_INLINE
+ACE_Pair<T1, T2>::ACE_Pair (void)
+{
+}
+
+template <class T1, class T2> ACE_INLINE T1 &
+ACE_Pair<T1, T2>::first (void)
+{
+ return this->first_;
+}
+
+template <class T1, class T2> ACE_INLINE const T1 &
+ACE_Pair<T1, T2>::first (void) const
+{
+ return this->first_;
+}
+
+template <class T1, class T2> ACE_INLINE void
+ACE_Pair<T1, T2>::first (const T1 &t1)
+{
+ this->first_ = t1;
+}
+
+template <class T1, class T2> ACE_INLINE T2 &
+ACE_Pair<T1, T2>::second (void)
+{
+ return this->second_;
+}
+
+template <class T1, class T2> ACE_INLINE const T2 &
+ACE_Pair<T1, T2>::second (void) const
+{
+ return this->second_;
+}
+
+template <class T1, class T2> ACE_INLINE void
+ACE_Pair<T1, T2>::second (const T2 &t2)
+{
+ this->second_ = t2;
+}
+
+template <class T1, class T2> ACE_INLINE
+ACE_Reference_Pair<T1, T2>::ACE_Reference_Pair (T1 &t1,
+ T2 &t2)
+ : first_ (t1),
+ second_ (t2)
+{
+}
+
+template <class T1, class T2> ACE_INLINE T1 &
+ACE_Reference_Pair<T1, T2>::first (void) const
+{
+ return this->first_;
+}
+
+template <class T1, class T2> ACE_INLINE T2 &
+ACE_Reference_Pair<T1, T2>::second (void) const
+{
+ return this->second_;
+}
+
+////////////////////////////////////////////////////////////////////////////////
diff --git a/ace/Utils/Templates/RB_Tree.cpp b/ace/Utils/Templates/RB_Tree.cpp
new file mode 100644
index 00000000000..086999af7c6
--- /dev/null
+++ b/ace/Utils/Templates/RB_Tree.cpp
@@ -0,0 +1,1078 @@
+// $Id$
+
+// RB_Tree.cpp
+
+#ifndef ACE_RB_TREE_C
+#define ACE_RB_TREE_C
+
+#include "ace/RB_Tree.h"
+#include "ace/SString.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#if !defined (__ACE_INLINE__)
+#include "ace/RB_Tree.i"
+#endif /* __ACE_INLINE__ */
+
+ACE_RCSID(ace, RB_Tree, "$Id$")
+
+// Constructor.
+
+template <class EXT_ID, class INT_ID>
+ACE_RB_Tree_Node<EXT_ID, INT_ID>::ACE_RB_Tree_Node (const EXT_ID &k, const INT_ID &t)
+ : k_ (k),
+ t_ (t),
+ color_ (RED),
+ parent_ (0),
+ left_ (0),
+ right_ (0)
+{
+ ACE_TRACE ("ACE_RB_Tree_Node<EXT_ID, INT_ID>::ACE_RB_Tree_Node (const EXT_ID &k, const INT_ID &t)");
+}
+
+
+// Destructor.
+
+template <class EXT_ID, class INT_ID>
+ACE_RB_Tree_Node<EXT_ID, INT_ID>::~ACE_RB_Tree_Node (void)
+{
+ ACE_TRACE ("ACE_RB_Tree_Node<EXT_ID, INT_ID>::~ACE_RB_Tree_Node");
+
+ // Delete left sub-tree.
+ delete left_;
+
+ // Delete right sub_tree.
+ delete right_;
+}
+
+// Constructor.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK>
+ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::ACE_RB_Tree (ACE_Allocator *alloc)
+ : allocator_ (alloc),
+ root_ (0),
+ current_size_ (0)
+{
+ ACE_TRACE ("ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::"
+ "ACE_RB_Tree (ACE_Allocator *alloc)");
+ if (this->open (alloc) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("ACE_RB_Tree::ACE_RB_Tree\n")));
+}
+
+// Copy constructor.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK>
+ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::ACE_RB_Tree (const ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK> &rbt)
+ : allocator_ (rbt.allocator_),
+ root_ (0),
+ current_size_ (0)
+{
+ ACE_TRACE ("ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::"
+ "ACE_RB_Tree (const ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK> &rbt)");
+ ACE_WRITE_GUARD (ACE_LOCK, ace_mon, this->lock_);
+
+ // Make a deep copy of the passed tree.
+ ACE_RB_Tree_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK> iter(rbt);
+
+ for (iter.first ();
+
+ iter.is_done () == 0; iter.next ())
+ insert_i (*(iter.key ()),
+ *(iter.item ()));
+}
+
+// Destructor.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK>
+ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::~ACE_RB_Tree ()
+{
+ ACE_TRACE ("ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::~ACE_RB_Tree");
+
+ // Use the locked public method, to be totally safe, as the class
+ // can be used with an allocator and placement new.
+ this->close ();
+}
+
+// Assignment operator.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK> void
+ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::operator = (const ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK> &rbt)
+{
+ ACE_TRACE ("ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::operator =");
+ ACE_WRITE_GUARD (ACE_LOCK, ace_mon, this->lock_);
+
+ if (this != &rbt)
+ {
+ // Clear out the existing tree.
+ close_i ();
+
+ // Make a deep copy of the passed tree.
+ ACE_RB_Tree_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK> iter(rbt);
+
+ for (iter.first ();
+ iter.is_done () == 0;
+ iter.next ())
+ insert_i (*(iter.key ()),
+ *(iter.item ()));
+
+ // Use the same allocator as the rhs.
+ allocator_ = rbt.allocator_;
+ }
+}
+// Less than comparison function for keys, default functor
+// implementation returns 1 if k1 < k2, 0 otherwise.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK> int
+ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::lessthan (const EXT_ID &k1, const EXT_ID &k2)
+{
+ ACE_TRACE ("ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::lessthan");
+ return this->compare_keys_ (k1, k2);
+}
+
+// Method for right rotation of the tree about a given node.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK> void
+ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::RB_rotate_right (ACE_RB_Tree_Node<EXT_ID, INT_ID> *x)
+{
+ ACE_TRACE ("ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::RB_rotate_right");
+
+ if (!x)
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("%p\n"),
+ ACE_LIB_TEXT ("\nerror: x is a null pointer in ")
+ ACE_LIB_TEXT ("ACE_RB_Tree<EXT_ID, INT_ID>::RB_rotate_right\n")));
+ else if (! (x->left()))
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("%p\n"),
+ ACE_LIB_TEXT ("\nerror: x->left () is a null pointer in ")
+ ACE_LIB_TEXT ("ACE_RB_Tree<EXT_ID, INT_ID>::RB_rotate_right\n")));
+ else
+ {
+ ACE_RB_Tree_Node<EXT_ID, INT_ID> * y;
+ y = x->left ();
+ x->left (y->right ());
+ if (y->right ())
+ y->right ()->parent (x);
+ y->parent (x->parent ());
+ if (x->parent ())
+ {
+ if (x == x->parent ()->right ())
+ x->parent ()->right (y);
+ else
+ x->parent ()->left (y);
+ }
+ else
+ root_ = y;
+ y->right (x);
+ x->parent (y);
+ }
+}
+
+// Method for left rotation of the tree about a given node.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK> void
+ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::RB_rotate_left (ACE_RB_Tree_Node<EXT_ID, INT_ID> * x)
+{
+ ACE_TRACE ("ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::RB_rotate_left");
+
+ if (! x)
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("%p\n"),
+ ACE_LIB_TEXT ("\nerror: x is a null pointer in ")
+ ACE_LIB_TEXT ("ACE_RB_Tree<EXT_ID, INT_ID>::RB_rotate_left\n")));
+ else if (! (x->right()))
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("%p\n"),
+ ACE_LIB_TEXT ("\nerror: x->right () is a null pointer ")
+ ACE_LIB_TEXT ("in ACE_RB_Tree<EXT_ID, INT_ID>::RB_rotate_left\n")));
+ else
+ {
+ ACE_RB_Tree_Node<EXT_ID, INT_ID> * y;
+ y = x->right ();
+ x->right (y->left ());
+ if (y->left ())
+ y->left ()->parent (x);
+ y->parent (x->parent ());
+ if (x->parent ())
+ {
+ if (x == x->parent ()->left ())
+ x->parent ()->left (y);
+ else
+ x->parent ()->right (y);
+ }
+ else
+ root_ = y;
+ y->left (x);
+ x->parent (y);
+ }
+}
+
+// Method for restoring Red-Black properties after a specific deletion case.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK> void
+ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::
+RB_delete_fixup (ACE_RB_Tree_Node<EXT_ID, INT_ID> *x,
+ ACE_RB_Tree_Node<EXT_ID, INT_ID> *parent)
+{
+ ACE_TRACE ("ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::RB_delete_fixup");
+
+ while (x != this->root_
+ && (!x
+ || x->color () == ACE_RB_Tree_Node_Base::BLACK))
+ {
+ if (x == parent->left ())
+ {
+ ACE_RB_Tree_Node<EXT_ID, INT_ID> *w = parent->right ();
+ if (w && w->color () == ACE_RB_Tree_Node_Base::RED)
+ {
+ w->color (ACE_RB_Tree_Node_Base::BLACK);
+ parent->color (ACE_RB_Tree_Node_Base::RED);
+ RB_rotate_left (parent);
+ w = parent->right ();
+ }
+ // CLR pp. 263 says that nil nodes are implicitly colored BLACK
+ if (w
+ && (!w->left ()
+ || w->left ()->color () == ACE_RB_Tree_Node_Base::BLACK)
+ && (!w->right ()
+ || w->right ()->color () == ACE_RB_Tree_Node_Base::BLACK))
+ {
+ w->color (ACE_RB_Tree_Node_Base::RED);
+ x = parent;
+ parent = x->parent ();
+ }
+ else
+ {
+ // CLR pp. 263 says that nil nodes are implicitly colored BLACK
+ if (w
+ && (!w->right ()
+ || w->right ()->color () == ACE_RB_Tree_Node_Base::BLACK))
+ {
+ if (w->left ())
+ w->left ()->color (ACE_RB_Tree_Node_Base::BLACK);
+ w->color (ACE_RB_Tree_Node_Base::RED);
+ RB_rotate_right (w);
+ w = parent->right ();
+ }
+ if (w)
+ {
+ w->color (parent->color ());
+ if (w->right ())
+ w->right ()->color (ACE_RB_Tree_Node_Base::BLACK);
+ }
+ parent->color (ACE_RB_Tree_Node_Base::BLACK);
+ RB_rotate_left (parent);
+ x = root_;
+ }
+ }
+ else
+ {
+ ACE_RB_Tree_Node<EXT_ID, INT_ID> *w = parent->left ();
+ if (w && w->color () == ACE_RB_Tree_Node_Base::RED)
+ {
+ w->color (ACE_RB_Tree_Node_Base::BLACK);
+ parent->color (ACE_RB_Tree_Node_Base::RED);
+ RB_rotate_right (parent);
+ w = parent->left ();
+ }
+ // CLR pp. 263 says that nil nodes are implicitly colored BLACK
+ if (w
+ && (!w->left ()
+ || w->left ()->color () == ACE_RB_Tree_Node_Base::BLACK)
+ && (!w->right ()
+ || w->right ()->color () == ACE_RB_Tree_Node_Base::BLACK))
+ {
+ w->color (ACE_RB_Tree_Node_Base::RED);
+ x = parent;
+ parent = x->parent ();
+ }
+ else
+ {
+ // CLR pp. 263 says that nil nodes are implicitly colored BLACK
+ if (w
+ && (!w->left ()
+ || w->left ()->color () == ACE_RB_Tree_Node_Base::BLACK))
+ {
+ w->color (ACE_RB_Tree_Node_Base::RED);
+ if (w->right ())
+ w->right ()->color (ACE_RB_Tree_Node_Base::BLACK);
+ RB_rotate_left (w);
+ w = parent->left ();
+ }
+ if (w)
+ {
+ w->color (parent->color ());
+ if (w->left ())
+ w->left ()->color (ACE_RB_Tree_Node_Base::BLACK);
+ }
+ parent->color (ACE_RB_Tree_Node_Base::BLACK);
+ RB_rotate_right (parent);
+ x = root_;
+ }
+ }
+ }
+
+ if (x)
+ x->color (ACE_RB_Tree_Node_Base::BLACK);
+}
+
+// Return a pointer to a matching node if there is one, a pointer to
+// the node under which to insert the item if the tree is not empty
+// and there is no such match, or 0 if the tree is empty.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK> ACE_RB_Tree_Node<EXT_ID, INT_ID> *
+ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::find_node (const EXT_ID &k, ACE_RB_Tree_Base::RB_SearchResult &result)
+{
+ ACE_TRACE ("ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::find_node");
+
+ // Start at the root.
+ ACE_RB_Tree_Node<EXT_ID, INT_ID> *current = root_;
+
+ while (current)
+ {
+ // While there are more nodes to examine.
+ if (this->lessthan (current->key (), k))
+ {
+ // If the search key is greater than the current node's key.
+ if (current->right ())
+ // If the right subtree is not empty, search to the right.
+ current = current->right ();
+ else
+ {
+ // If the right subtree is empty, we're done searching,
+ // and are positioned to the left of the insertion point.
+ result = LEFT;
+ break;
+ }
+ }
+ else if (this->lessthan (k, current->key ()))
+ {
+ // Else if the search key is less than the current node's key.
+ if (current->left ())
+ // If the left subtree is not empty, search to the left.
+ current = current->left ();
+ else
+ {
+ // If the left subtree is empty, we're done searching,
+ // and are positioned to the right of the insertion point.
+ result = RIGHT;
+ break;
+ }
+ }
+ else
+ {
+ // If the keys match exactly, we're done as well.
+ result = EXACT;
+ break;
+ }
+ }
+
+ return current;
+}
+
+// Rebalance the tree after insertion of a node.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK> void
+ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::RB_rebalance (ACE_RB_Tree_Node<EXT_ID, INT_ID> * x)
+{
+ ACE_TRACE ("ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::RB_rebalance");
+
+ ACE_RB_Tree_Node<EXT_ID, INT_ID> *y = 0;
+
+ while (x &&
+ x->parent ()
+ && x->parent ()->color () == ACE_RB_Tree_Node_Base::RED)
+ {
+ if (! x->parent ()->parent ())
+ {
+ // If we got here, something is drastically wrong!
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("%p\n"),
+ ACE_LIB_TEXT ("\nerror: parent's parent is null in ")
+ ACE_LIB_TEXT ("ACE_RB_Tree<EXT_ID, INT_ID>::RB_rebalance\n")));
+ return;
+ }
+
+ if (x->parent () == x->parent ()->parent ()->left ())
+ {
+ y = x->parent ()->parent ()->right ();
+ if (y && y->color () == ACE_RB_Tree_Node_Base::RED)
+ {
+ // Handle case 1 (see CLR book, pp. 269).
+ x->parent ()->color (ACE_RB_Tree_Node_Base::BLACK);
+ y->color (ACE_RB_Tree_Node_Base::BLACK);
+ x->parent ()->parent ()->color (ACE_RB_Tree_Node_Base::RED);
+ x = x->parent ()->parent ();
+ }
+ else
+ {
+ if (x == x->parent ()->right ())
+ {
+ // Transform case 2 into case 3 (see CLR book, pp. 269).
+ x = x->parent ();
+ RB_rotate_left (x);
+ }
+
+ // Handle case 3 (see CLR book, pp. 269).
+ x->parent ()->color (ACE_RB_Tree_Node_Base::BLACK);
+ x->parent ()->parent ()->color (ACE_RB_Tree_Node_Base::RED);
+ RB_rotate_right (x->parent ()->parent ());
+ }
+ }
+ else
+ {
+ y = x->parent ()->parent ()->left ();
+ if (y && y->color () == ACE_RB_Tree_Node_Base::RED)
+ {
+ // Handle case 1 (see CLR book, pp. 269).
+ x->parent ()->color (ACE_RB_Tree_Node_Base::BLACK);
+ y->color (ACE_RB_Tree_Node_Base::BLACK);
+ x->parent ()->parent ()->color (ACE_RB_Tree_Node_Base::RED);
+ x = x->parent ()->parent ();
+ }
+ else
+ {
+ if (x == x->parent ()->left ())
+ {
+ // Transform case 2 into case 3 (see CLR book, pp. 269).
+ x = x->parent ();
+ RB_rotate_right (x);
+ }
+
+ // Handle case 3 (see CLR book, pp. 269).
+ x->parent ()->color (ACE_RB_Tree_Node_Base::BLACK);
+ x->parent ()->parent ()->color (ACE_RB_Tree_Node_Base::RED);
+ RB_rotate_left (x->parent ()->parent ());
+ }
+ }
+ }
+}
+
+// Method to find the successor node of the given node in the tree.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK> ACE_RB_Tree_Node<EXT_ID, INT_ID> *
+ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::RB_tree_successor (ACE_RB_Tree_Node<EXT_ID, INT_ID> *x) const
+{
+ ACE_TRACE ("ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::RB_tree_successor");
+
+ if (x == 0)
+ return 0;
+
+ if (x->right ())
+ return RB_tree_minimum (x->right ());
+
+ ACE_RB_Tree_Node<EXT_ID, INT_ID> *y = x->parent ();
+ while ((y) && (x == y->right ()))
+ {
+ x = y;
+ y = y->parent ();
+ }
+
+ return y;
+}
+
+// Method to find the predecessor node of the given node in the tree.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK> ACE_RB_Tree_Node<EXT_ID, INT_ID> *
+ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::RB_tree_predecessor (ACE_RB_Tree_Node<EXT_ID, INT_ID> *x) const
+{
+ ACE_TRACE ("ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::RB_tree_predecessor");
+ if (x == 0)
+ return 0;
+
+ if (x->left ())
+ return RB_tree_maximum (x->left ());
+
+ ACE_RB_Tree_Node<EXT_ID, INT_ID> *y = x->parent ();
+
+ while ((y) && (x == y->left ()))
+ {
+ x = y;
+ y = y->parent ();
+ }
+
+ return y;
+}
+
+// Method to find the minimum node of the subtree rooted at the given node.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK> ACE_RB_Tree_Node<EXT_ID, INT_ID> *
+ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::RB_tree_minimum (ACE_RB_Tree_Node<EXT_ID, INT_ID> *x) const
+{
+ ACE_TRACE ("ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::RB_tree_minimum");
+
+ while ((x) && (x->left ()))
+ x = x->left ();
+
+ return x;
+}
+
+// Method to find the maximum node of the subtree rooted at the given node.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK> ACE_RB_Tree_Node<EXT_ID, INT_ID> *
+ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::RB_tree_maximum (ACE_RB_Tree_Node<EXT_ID, INT_ID> *x) const
+{
+ ACE_TRACE ("ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::RB_tree_maximum");
+
+ while ((x) && (x->right ()))
+ x = x->right ();
+
+ return x;
+}
+
+// Close down an RB_Tree. this method should only be called with
+// locks already held.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK> int
+ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::close_i ()
+{
+ ACE_TRACE ("ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::close_i");
+
+ delete root_;
+ current_size_ = 0;
+ root_ = 0;
+
+ return 0;
+}
+
+// Returns a pointer to the item corresponding to the given key, or 0
+// if it cannot find the key in the tree. This method should only be
+// called with locks already held.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK> int
+ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::find_i (const EXT_ID &k,
+ ACE_RB_Tree_Node<EXT_ID, INT_ID>* &entry)
+{
+ ACE_TRACE ("ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::find_i");
+
+ // Try to find a match.
+ RB_SearchResult result = LEFT;
+ ACE_RB_Tree_Node<EXT_ID, INT_ID> *current = find_node (k, result);
+
+ if (current && result == EXACT)
+ {
+ // Found an exact match: return a pointer to the node.
+ entry = current;
+ return 0;
+ }
+ else
+ // The node is not there.
+ return -1;
+}
+
+// Inserts a *copy* of the key and the item into the tree: both the
+// key type EXT_ID and the item type INT_ID must have well defined
+// semantics for copy construction and < comparison. This method
+// returns a pointer to the inserted item copy, or 0 if an error
+// occurred. NOTE: if an identical key already exists in the tree, no
+// new item is created, and the returned pointer addresses the
+// existing item associated with the existing key. This method should
+// only be called with locks already held.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK> INT_ID *
+ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::insert_i (const EXT_ID &k, const INT_ID &t)
+{
+ ACE_TRACE ("ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::insert_i (const EXT_ID &k, const INT_ID &t)");
+
+ // Find the closest matching node, if there is one.
+ RB_SearchResult result = LEFT;
+ ACE_RB_Tree_Node<EXT_ID, INT_ID> *current = find_node (k, result);
+ if (current)
+ {
+ // If the keys match, just return a pointer to the node's item.
+ if (result == EXACT)
+ return &current->item ();
+
+ // Otherwise if we're to the left of the insertion point, insert
+ // into the right subtree.
+ else if (result == LEFT)
+ {
+ if (current->right ())
+ {
+ // If there is already a right subtree, complain.
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_LIB_TEXT ("%p\n"),
+ ACE_LIB_TEXT ("\nright subtree already present in ")
+ ACE_LIB_TEXT ("ACE_RB_Tree<EXT_ID, INT_ID>::insert_i\n")),
+ 0);
+ }
+ else
+ {
+ // The right subtree is empty: insert new node there.
+ ACE_RB_Tree_Node<EXT_ID, INT_ID> *tmp = 0;
+
+ ACE_NEW_RETURN (tmp,
+ (ACE_RB_Tree_Node<EXT_ID, INT_ID>) (k, t),
+ 0);
+ current->right (tmp);
+
+ // If the node was successfully inserted, set its
+ // parent, rebalance the tree, color the root black, and
+ // return a pointer to the inserted item.
+ INT_ID *item = &(current->right ()->item ());
+ current->right ()->parent (current);
+ RB_rebalance (current->right ());
+ root_->color (ACE_RB_Tree_Node_Base::BLACK);
+ ++current_size_;
+ return item;
+ }
+ }
+ // Otherwise, we're to the right of the insertion point, so
+ // insert into the left subtree.
+ else // (result == RIGHT)
+ {
+ if (current->left ())
+ // If there is already a left subtree, complain.
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_LIB_TEXT ("%p\n"),
+ ACE_LIB_TEXT ("\nleft subtree already present in ")
+ ACE_LIB_TEXT ("ACE_RB_Tree<EXT_ID, INT_ID>::insert_i\n")),
+ 0);
+ else
+ {
+ // The left subtree is empty: insert new node there.
+ ACE_RB_Tree_Node<EXT_ID, INT_ID> *tmp = 0;
+ ACE_NEW_RETURN (tmp,
+ (ACE_RB_Tree_Node<EXT_ID, INT_ID>) (k, t),
+ 0);
+ current->left (tmp);
+
+ // If the node was successfully inserted, set its
+ // parent, rebalance the tree, color the root black, and
+ // return a pointer to the inserted item.
+ INT_ID *item = &current->left ()->item ();
+ current->left ()->parent (current);
+ RB_rebalance (current->left ());
+ root_->color (ACE_RB_Tree_Node_Base::BLACK);
+ ++current_size_;
+ return item;
+ }
+ }
+ }
+ else
+ {
+ // The tree is empty: insert at the root and color the root
+ // black.
+ ACE_NEW_RETURN (root_,
+ (ACE_RB_Tree_Node<EXT_ID, INT_ID>) (k, t),
+ 0);
+ if (root_)
+ {
+ root_->color (ACE_RB_Tree_Node_Base::BLACK);
+ ++current_size_;
+ return &root_->item ();
+ }
+ }
+ return 0;
+}
+
+// Inserts a *copy* of the key and the item into the tree: both the
+// key type EXT_ID and the item type INT_ID must have well defined
+// semantics for copy construction. The default implementation also
+// requires that the key type support well defined < semantics. This
+// method passes back a pointer to the inserted (or existing) node,
+// and the search status. If the node already exists, the method
+// returns 1. If the node does not exist, and a new one is
+// successfully created, and the method returns 0. If there was an
+// error, the method returns -1.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK> int
+ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::insert_i (const EXT_ID &k,
+ const INT_ID &t,
+ ACE_RB_Tree_Node<EXT_ID, INT_ID> *&entry)
+{
+ ACE_TRACE ("ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::insert_i (const EXT_ID &k, const INT_ID &t, "
+ "ACE_RB_Tree_Node<EXT_ID, INT_ID> *&entry)");
+
+ // Find the closest matching node, if there is one.
+ RB_SearchResult result = LEFT;
+ ACE_RB_Tree_Node<EXT_ID, INT_ID> *current = find_node (k, result);
+ if (current)
+ {
+ // If the keys match, just return a pointer to the node's item.
+ if (result == EXACT)
+ {
+ entry = current;
+ return 1;
+ }
+ // Otherwise if we're to the left of the insertion
+ // point, insert into the right subtree.
+ else if (result == LEFT)
+ {
+ if (current->right ())
+ {
+ // If there is already a right subtree, complain.
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_LIB_TEXT ("%p\n"),
+ ACE_LIB_TEXT ("\nright subtree already present in ")
+ ACE_LIB_TEXT ("ACE_RB_Tree<EXT_ID, INT_ID>::insert_i\n")),
+ -1);
+ }
+ else
+ {
+ // The right subtree is empty: insert new node there.
+ ACE_RB_Tree_Node<EXT_ID, INT_ID> *tmp = 0;
+ ACE_NEW_RETURN (tmp,
+ (ACE_RB_Tree_Node<EXT_ID, INT_ID>) (k, t),
+ -1);
+ current->right (tmp);
+
+ // If the node was successfully inserted, set its parent, rebalance
+ // the tree, color the root black, and return a pointer to the
+ // inserted item.
+ entry = current->right ();
+ current->right ()->parent (current);
+ RB_rebalance (current->right ());
+ root_->color (ACE_RB_Tree_Node_Base::BLACK);
+ ++current_size_;
+ return 0;
+ }
+ }
+ // Otherwise, we're to the right of the insertion point, so
+ // insert into the left subtree.
+ else // (result == RIGHT)
+ {
+ if (current->left ())
+ // If there is already a left subtree, complain.
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_LIB_TEXT ("%p\n"),
+ ACE_LIB_TEXT ("\nleft subtree already present in ")
+ ACE_LIB_TEXT ("ACE_RB_Tree<EXT_ID, INT_ID>::insert_i\n")),
+ -1);
+ else
+ {
+ // The left subtree is empty: insert new node there.
+ ACE_RB_Tree_Node<EXT_ID, INT_ID> *tmp = 0;
+ ACE_NEW_RETURN (tmp,
+ (ACE_RB_Tree_Node<EXT_ID, INT_ID>) (k, t),
+ -1);
+ current->left (tmp);
+ // If the node was successfully inserted, set its
+ // parent, rebalance the tree, color the root black, and
+ // return a pointer to the inserted item.
+ entry = current->left ();
+ current->left ()->parent (current);
+ RB_rebalance (current->left ());
+ root_->color (ACE_RB_Tree_Node_Base::BLACK);
+ ++current_size_;
+ return 0;
+ }
+ }
+ }
+ else
+ {
+ // The tree is empty: insert at the root and color the root black.
+ ACE_NEW_RETURN (root_,
+ (ACE_RB_Tree_Node<EXT_ID, INT_ID>) (k, t),
+ -1);
+ root_->color (ACE_RB_Tree_Node_Base::BLACK);
+ ++current_size_;
+ entry = root_;
+ return 0;
+ }
+}
+
+// Removes the item associated with the given key from the tree and
+// destroys it. Returns 1 if it found the item and successfully
+// destroyed it, 0 if it did not find the item, or -1 if an error
+// occurred. This method should only be called with locks already
+// held.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK> int
+ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::remove_i (const EXT_ID &k, INT_ID &i)
+{
+ ACE_TRACE ("ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::remove_i (const EXT_ID &k, INT_ID &i)");
+
+ // Find a matching node, if there is one.
+ ACE_RB_Tree_Node<EXT_ID, INT_ID> *z;
+ RB_SearchResult result = LEFT;
+ z = find_node (k, result);
+
+ // If there is a matching node: remove and destroy it.
+ if (z && result == EXACT)
+ {
+ // Return the internal id stored in the deleted node.
+ i = z->item ();
+ return -1 == this->remove_i (z) ? -1 : 1;
+ }
+ else
+ {
+ // No matching node was found: return 0.
+ return 0;
+ }
+}
+
+/// Recursive function to dump the state of an object.
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK> void
+ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::
+dump_i (ACE_RB_Tree_Node<EXT_ID, INT_ID> *node) const
+{
+ if (node)
+ {
+ dump_node_i (*node);
+
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\ndown left\n")));
+ this->dump_i (node->left ());
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\nup left\n")));
+
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\ndown right\n")));
+ this->dump_i (node->right ());
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\nup right\n")));
+ }
+ else
+ {
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\nNULL POINTER (BLACK)\n")));
+ }
+}
+
+
+/// Function to dump node itself. Does not show parameterized node contents
+/// in its basic form, but template specialization can be used to
+/// provide definitions for various EXT_ID and INT_ID types.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK> void
+ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::
+dump_node_i (ACE_RB_Tree_Node<EXT_ID, INT_ID> &node) const
+{
+ const char * color_str = (node.color () == ACE_RB_Tree_Node_Base::RED)
+ ? "RED" : "BLACK";
+
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT (" color=[%s]\n"), color_str));
+}
+
+/// Tests the red-black invariant(s) throughout the whole tree.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK> int
+ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::test_invariant (void)
+{
+ ACE_TRACE ("ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::test_invariant");
+ ACE_READ_GUARD_RETURN (ACE_LOCK, ace_mon, this->lock_, -1);
+
+ // Recurse from the root, starting with the measured black height at
+ // 0, and the expected black height at -1, which will cause the
+ // count from first measured path to a leaf to be used as the
+ // expected one from that point onward (the key is to check
+ // consistency).
+ int expected_black_height = -1;
+ if (this->test_invariant_recurse (this->root_, expected_black_height, 0) == 0)
+ {
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("invariant holds\n")));
+ return 0;
+ }
+
+ return -1;
+}
+
+/// Recursive function to test the red-black invariant(s) at all nodes in a subtree.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK> int
+ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::test_invariant_recurse (ACE_RB_Tree_Node<EXT_ID, INT_ID> *x,
+ int & expected_black_height,
+ int measured_black_height)
+{
+ ACE_TRACE ("ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::test_invariant_recurse");
+
+ if (!x)
+ {
+ // Count each leaf (zero pointer) as a black node (per CLR algorithm description).
+ ++measured_black_height;
+
+ if (expected_black_height == -1)
+ {
+ expected_black_height = measured_black_height;
+ }
+ else if (expected_black_height != measured_black_height)
+ {
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_LIB_TEXT ("\nexpected_black_height = %d but ")
+ ACE_LIB_TEXT ("\nmeasured_black_height = %d in ")
+ ACE_LIB_TEXT ("ACE_RB_Tree<EXT_ID, INT_ID>::test_invariant_recurse\n"),
+ expected_black_height, measured_black_height),
+ -1);
+ }
+
+ return 0;
+ }
+
+ // Check the invariant that a red node cannot have a red child.
+ if (x->color () == ACE_RB_Tree_Node_Base::RED)
+ {
+ if (x->left () && x->left ()->color () == ACE_RB_Tree_Node_Base::RED)
+ {
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_LIB_TEXT ("%p\n"),
+ ACE_LIB_TEXT ("\nRED parent has RED left child in ")
+ ACE_LIB_TEXT ("ACE_RB_Tree<EXT_ID, INT_ID>::test_invariant_recurse\n")),
+ -1);
+ }
+
+ if (x->right () && x->right ()->color () == ACE_RB_Tree_Node_Base::RED)
+ {
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_LIB_TEXT ("%p\n"),
+ ACE_LIB_TEXT ("\nRED parent has RED right child in ")
+ ACE_LIB_TEXT ("ACE_RB_Tree<EXT_ID, INT_ID>::test_invariant_recurse\n")),
+ -1);
+ }
+ }
+ else
+ {
+ // Count each black node traversed.
+ ++measured_black_height;
+ }
+
+ return (test_invariant_recurse (x->left (), expected_black_height, measured_black_height) == 0)
+ ? test_invariant_recurse (x->right (), expected_black_height, measured_black_height)
+ : -1;
+}
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK> int
+ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::remove_i (ACE_RB_Tree_Node<EXT_ID, INT_ID> *z)
+{
+ ACE_TRACE ("ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::remove_i (ACE_RB_Tree_Node<EXT_ID, INT_ID> *z)");
+
+ // Delete the node and reorganize the tree to satisfy the Red-Black
+ // properties.
+
+ ACE_RB_Tree_Node<EXT_ID, INT_ID> *x;
+ ACE_RB_Tree_Node<EXT_ID, INT_ID> *y;
+ ACE_RB_Tree_Node<EXT_ID, INT_ID> *parent;
+
+ if (z->left () && z->right ())
+ y = RB_tree_successor (z);
+ else
+ y = z;
+
+ if (y->left ())
+ x = y->left ();
+ else
+ x = y->right ();
+
+ parent = y->parent ();
+ if (x)
+ {
+ x->parent (parent);
+ }
+
+ if (parent)
+ {
+ if (y == parent->left ())
+ parent->left (x);
+ else
+ parent->right (x);
+ }
+ else
+ this->root_ = x;
+
+ if (y != z)
+ {
+ // Copy the elements of y into z.
+ z->key () = y->key ();
+ z->item () = y->item ();
+ }
+
+ // CLR pp. 263 says that nil nodes are implicitly colored BLACK
+ if (!y || y->color () == ACE_RB_Tree_Node_Base::BLACK)
+ RB_delete_fixup (x, parent);
+
+ y->parent (0);
+ y->right (0);
+ y->left (0);
+ delete y;
+ --current_size_;
+
+ return 0;
+}
+
+ACE_ALLOC_HOOK_DEFINE(ACE_RB_Tree_Iterator_Base)
+
+// Constructor.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK>
+ACE_RB_Tree_Iterator_Base<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::ACE_RB_Tree_Iterator_Base (const ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK> &tree, int set_first)
+ : tree_ (&tree), node_ (0)
+{
+ ACE_TRACE ("ACE_RB_Tree_Iterator_Base<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::ACE_RB_Tree_Iterator_Base (ACE_RB_Tree, int)");
+
+ // Position the iterator at the first (or last) node in the tree.
+ if (set_first)
+ node_ = tree_->RB_tree_minimum (tree_->root_);
+ else
+ node_ = tree_->RB_tree_maximum (tree_->root_);
+}
+
+// Copy constructor.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK>
+ACE_RB_Tree_Iterator_Base<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::ACE_RB_Tree_Iterator_Base (const ACE_RB_Tree_Iterator_Base<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK> &iter)
+ : tree_ (iter.tree_),
+ node_ (iter.node_)
+{
+ ACE_TRACE ("ACE_RB_Tree_Iterator_Base<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::ACE_RB_Tree_Iterator_Base (ACE_RB_Tree_Iterator_Base)");
+}
+
+// Assignment operator.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK> void
+ACE_RB_Tree_Iterator_Base<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::operator= (const ACE_RB_Tree_Iterator_Base<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK> &iter)
+{
+ ACE_TRACE ("ACE_RB_Tree_Iterator_Base<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::operator=");
+ if (this != &iter)
+ {
+ tree_ = iter.tree_;
+ node_ = iter.node_;
+ }
+}
+
+// Destructor.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK>
+ACE_RB_Tree_Iterator_Base<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::~ACE_RB_Tree_Iterator_Base ()
+{
+ ACE_TRACE ("ACE_RB_Tree_Iterator_Base<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::~ACE_RB_Tree_Iterator_Base");
+}
+
+ACE_ALLOC_HOOK_DEFINE(ACE_RB_Tree_Iterator)
+
+// Constructor.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK>
+ACE_RB_Tree_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::ACE_RB_Tree_Iterator (const ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK> &tree,
+ int set_first)
+ : ACE_RB_Tree_Iterator_Base<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK> (tree, set_first)
+{
+ ACE_TRACE ("ACE_RB_Tree_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::ACE_RB_Tree_Iterator");
+}
+
+// Destructor.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK>
+ACE_RB_Tree_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::~ACE_RB_Tree_Iterator ()
+{
+ ACE_TRACE ("ACE_RB_Tree_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::~ACE_RB_Tree_Iterator");
+}
+
+ACE_ALLOC_HOOK_DEFINE(ACE_RB_Tree_Reverse_Iterator)
+
+// Constructor.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK>
+ACE_RB_Tree_Reverse_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::ACE_RB_Tree_Reverse_Iterator (const ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK> &tree, int set_last)
+ : ACE_RB_Tree_Iterator_Base<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK> (tree, set_last ? 0 : 1)
+{
+ ACE_TRACE ("ACE_RB_Tree_Reverse_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::ACE_RB_Tree_Reverse_Iterator");
+}
+
+// Destructor.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK>
+ACE_RB_Tree_Reverse_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::~ACE_RB_Tree_Reverse_Iterator ()
+{
+ ACE_TRACE ("ACE_RB_Tree_Reverse_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::~ACE_RB_Tree_Reverse_Iterator");
+}
+
+
+#endif /* !defined (ACE_RB_TREE_C) */
diff --git a/ace/Utils/Templates/RB_Tree.h b/ace/Utils/Templates/RB_Tree.h
new file mode 100644
index 00000000000..12e127f7a00
--- /dev/null
+++ b/ace/Utils/Templates/RB_Tree.h
@@ -0,0 +1,798 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file RB_Tree.h
+ *
+ * $Id$
+ *
+ * @author Chris Gill
+ */
+//=============================================================================
+
+
+#ifndef ACE_RB_TREE_H
+#define ACE_RB_TREE_H
+#include "ace/pre.h"
+
+#include "ace/OS.h"
+#include "ace/Functor.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+// Forward decl.
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK>
+class ACE_RB_Tree_Iterator_Base;
+
+// Forward decl.
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK>
+class ACE_RB_Tree_Iterator;
+
+// Forward decl.
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK>
+class ACE_RB_Tree_Reverse_Iterator;
+
+// Forward decl.
+class ACE_Allocator;
+
+class ACE_RB_Tree_Node_Base
+{
+public:
+ enum RB_Tree_Node_Color {RED, BLACK};
+};
+
+/**
+ * @class ACE_RB_Tree_Node
+ *
+ * @brief Implements a node in a Red-Black Tree ADT.
+ */
+template <class EXT_ID, class INT_ID>
+class ACE_RB_Tree_Node : public ACE_RB_Tree_Node_Base
+{
+public:
+ // = Initialization and termination methods.
+
+ /// Constructor.
+ ACE_RB_Tree_Node (const EXT_ID &k, const INT_ID &t);
+
+ /// Destructor.
+ ~ACE_RB_Tree_Node (void);
+
+ /// Key accessor.
+ EXT_ID &key (void);
+
+ /// Item accessor.
+ INT_ID &item (void);
+
+ /// Set color of the node.
+ void color (RB_Tree_Node_Color c);
+
+ /// Get color of the node.
+ RB_Tree_Node_Color color (void);
+
+ /// Accessor for node's parent pointer.
+ ACE_RB_Tree_Node<EXT_ID, INT_ID> *parent (void);
+
+ /// Mutator for node's parent pointer.
+ void parent (ACE_RB_Tree_Node<EXT_ID, INT_ID> * p);
+
+ /// Accessor for node's left child pointer.
+ ACE_RB_Tree_Node<EXT_ID, INT_ID> *left (void);
+
+ /// Mutator for node's left child pointer.
+ void left (ACE_RB_Tree_Node<EXT_ID, INT_ID> *l);
+
+ /// Accessor for node's right child pointer.
+ ACE_RB_Tree_Node<EXT_ID, INT_ID> *right (void);
+
+ /// Mutator for node's right child pointer
+ void right (ACE_RB_Tree_Node<EXT_ID, INT_ID> * r);
+
+private:
+
+ /// The key.
+ EXT_ID k_;
+
+ /// The item.
+ INT_ID t_;
+
+ /// Color of the node.
+ RB_Tree_Node_Color color_;
+
+ /// Pointer to node's parent.
+ ACE_RB_Tree_Node<EXT_ID, INT_ID> *parent_;
+
+ /// Pointer to node's left child.
+ ACE_RB_Tree_Node<EXT_ID, INT_ID> *left_;
+
+ /// Pointer to node's right child.
+ ACE_RB_Tree_Node<EXT_ID, INT_ID> *right_;
+};
+
+class ACE_RB_Tree_Base
+{
+public:
+ /// Search result enumeration.
+ enum RB_SearchResult {LEFT, EXACT, RIGHT};
+};
+
+/**
+ * @class ACE_RB_Tree
+ *
+ * @brief Implements a Red-Black Tree ADT, according to T. H. Corman,
+ * C. E. Leiserson, and R. L. Rivest, "Introduction to Algorithms"
+ * 1990, MIT, chapter 14.
+ *
+ * A number of Changes have been made to this class template
+ * in order to conform to the ACE_Hash_Map_Manager_Ex
+ * interface. All previously supported public methods are
+ * still part of this class. However, these are marked as
+ * DEPRECATED and will be removed from this class in
+ * a future version of ACE. Please migrate your code
+ * to the appropriate public methods indicated in the
+ * method deprecation comments.
+ * This class uses an <ACE_Allocator> to allocate memory. The
+ * user can make this a persistent class by providing an
+ * <ACE_Allocator> with a persistable memory pool.
+ */
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK>
+class ACE_RB_Tree : public ACE_RB_Tree_Base
+{
+
+public:
+ friend class ACE_RB_Tree_Iterator_Base<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>;
+ friend class ACE_RB_Tree_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>;
+ friend class ACE_RB_Tree_Reverse_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>;
+
+ typedef EXT_ID KEY;
+ typedef INT_ID VALUE;
+ typedef ACE_RB_Tree_Node<EXT_ID, INT_ID> ENTRY;
+
+ // = ACE-style iterator typedefs.
+ typedef ACE_RB_Tree_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK> ITERATOR;
+ typedef ACE_RB_Tree_Reverse_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK> REVERSE_ITERATOR;
+
+ // = STL-style iterator typedefs.
+ typedef ACE_RB_Tree_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK> iterator;
+ typedef ACE_RB_Tree_Reverse_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK> reverse_iterator;
+
+ // = Initialization and termination methods.
+
+ /// Constructor.
+ ACE_RB_Tree (ACE_Allocator *alloc = 0);
+
+ /// Copy constructor.
+ ACE_RB_Tree (const ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK> &rbt);
+
+ /// Initialize an RB Tree.
+ int open (ACE_Allocator *alloc = 0);
+
+ /// Close down an RB_Tree and release dynamically allocated
+ /// resources.
+ int close (void);
+
+ /// Destructor.
+ virtual ~ACE_RB_Tree (void);
+
+ // = insertion, removal, and search methods.
+
+ /**
+ * Associate <ext_id> with <int_id>. If <ext_id> is already in the
+ * tree then the <ACE_RB_Tree_Node> is not changed. Returns 0 if a
+ * new entry is bound successfully, returns 1 if an attempt is made
+ * to bind an existing entry, and returns -1 if failures occur.
+ */
+ int bind (const EXT_ID &item,
+ const INT_ID &int_id);
+
+ /**
+ * Same as a normal bind, except the tree entry is also passed back
+ * to the caller. The entry in this case will either be the newly
+ * created entry, or the existing one.
+ */
+ int bind (const EXT_ID &ext_id,
+ const INT_ID &int_id,
+ ACE_RB_Tree_Node<EXT_ID, INT_ID> *&entry);
+
+
+ /**
+ * Associate <ext_id> with <int_id> if and only if <ext_id> is not
+ * in the tree. If <ext_id> is already in the tree then the <int_id>
+ * parameter is assigned the existing value in the tree. Returns 0
+ * if a new entry is bound successfully, returns 1 if an attempt is
+ * made to bind an existing entry, and returns -1 if failures occur.
+ */
+ int trybind (const EXT_ID &ext_id,
+ INT_ID &int_id);
+
+ /**
+ * Same as a normal trybind, except the tree entry is also passed
+ * back to the caller. The entry in this case will either be the
+ * newly created entry, or the existing one.
+ */
+ int trybind (const EXT_ID &ext_id,
+ INT_ID &int_id,
+ ACE_RB_Tree_Node<EXT_ID, INT_ID> *&entry);
+
+ /**
+ * Reassociate <ext_id> with <int_id>. If <ext_id> is not in the
+ * tree then behaves just like <bind>. Returns 0 if a new entry is
+ * bound successfully, returns 1 if an existing entry was rebound,
+ * and returns -1 if failures occur.
+ */
+ int rebind (const EXT_ID &ext_id,
+ const INT_ID &int_id);
+
+ /**
+ * Same as a normal rebind, except the tree entry is also passed back
+ * to the caller. The entry in this case will either be the newly
+ * created entry, or the existing one.
+ */
+ int rebind (const EXT_ID &ext_id,
+ const INT_ID &int_id,
+ ACE_RB_Tree_Node<EXT_ID, INT_ID> *&entry);
+
+ /**
+ * Associate <ext_id> with <int_id>. If <ext_id> is not in the tree
+ * then behaves just like <bind>. Otherwise, store the old value of
+ * <int_id> into the "out" parameter and rebind the new parameters.
+ * Returns 0 if a new entry is bound successfully, returns 1 if an
+ * existing entry was rebound, and returns -1 if failures occur.
+ */
+ int rebind (const EXT_ID &ext_id,
+ const INT_ID &int_id,
+ INT_ID &old_int_id);
+
+ /**
+ * Same as a normal rebind, except the tree entry is also passed back
+ * to the caller. The entry in this case will either be the newly
+ * created entry, or the existing one.
+ */
+ int rebind (const EXT_ID &ext_id,
+ const INT_ID &int_id,
+ INT_ID &old_int_id,
+ ACE_RB_Tree_Node<EXT_ID, INT_ID> *&entry);
+
+ /**
+ * Associate <ext_id> with <int_id>. If <ext_id> is not in the tree
+ * then behaves just like <bind>. Otherwise, store the old values
+ * of <ext_id> and <int_id> into the "out" parameters and rebind the
+ * new parameters. This is very useful if you need to have an
+ * atomic way of updating <ACE_RB_Tree_Nodes> and you also need
+ * full control over memory allocation. Returns 0 if a new entry is
+ * bound successfully, returns 1 if an existing entry was rebound,
+ * and returns -1 if failures occur.
+ */
+ int rebind (const EXT_ID &ext_id,
+ const INT_ID &int_id,
+ EXT_ID &old_ext_id,
+ INT_ID &old_int_id);
+
+ /**
+ * Same as a normal rebind, except the tree entry is also passed back
+ * to the caller. The entry in this case will either be the newly
+ * created entry, or the existing one.
+ */
+ int rebind (const EXT_ID &ext_id,
+ const INT_ID &int_id,
+ EXT_ID &old_ext_id,
+ INT_ID &old_int_id,
+ ACE_RB_Tree_Node<EXT_ID, INT_ID> *&entry);
+
+ /// Locate <ext_id> and pass out parameter via <int_id>. If found,
+ /// return 0, returns -1 if not found.
+ int find (const EXT_ID &ext_id,
+ INT_ID &int_id);
+
+ /// Locate <ext_id> and pass out parameter via <entry>. If found,
+ /// return 0, returns -1 if not found.
+ int find (const EXT_ID &ext_id,
+ ACE_RB_Tree_Node<EXT_ID, INT_ID> *&entry);
+
+ /**
+ * Unbind (remove) the <ext_id> from the tree. Don't return the
+ * <int_id> to the caller (this is useful for collections where the
+ * <int_id>s are *not* dynamically allocated...)
+ */
+ int unbind (const EXT_ID &ext_id);
+
+ /// Break any association of <ext_id>. Returns the value of <int_id>
+ /// in case the caller needs to deallocate memory.
+ int unbind (const EXT_ID &ext_id,
+ INT_ID &int_id);
+
+ /**
+ * Remove entry from tree. This method should be used with *extreme*
+ * caution, and only for optimization purposes. The node being passed
+ * in had better have been allocated by the tree that is unbinding it.
+ */
+ int unbind (ACE_RB_Tree_Node<EXT_ID, INT_ID> *entry);
+
+ // = Public helper methods.
+
+ /// Returns the current number of nodes in the tree.
+ size_t current_size (void) const;
+
+ /// Assignment operator.
+ void operator= (const ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK> &rbt);
+
+ /// Less than comparison function for keys, using comparison functor.
+ virtual int lessthan (const EXT_ID &k1, const EXT_ID &k2);
+
+ /**
+ * Returns a reference to the underlying <ACE_LOCK>. This makes it
+ * possible to acquire the lock explicitly, which can be useful in
+ * some cases if you instantiate the <ACE_Atomic_Op> with an
+ * <ACE_Recursive_Mutex> or <ACE_Process_Mutex>, or if you need to
+ * guard the state of an iterator. NOTE: the right name would be
+ * <lock>, but HP/C++ will choke on that!
+ */
+ ACE_LOCK &mutex (void);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ // = STL styled iterator factory functions.
+
+ /// Return forward iterator positioned at first node in tree.
+ ACE_RB_Tree_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK> begin (void);
+
+ /// Return forward iterator positioned at last node in tree.
+ ACE_RB_Tree_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK> end (void);
+
+ /// Return reverse iterator positioned at last node in tree.
+ ACE_RB_Tree_Reverse_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK> rbegin (void);
+
+ /// Return reverse iterator positioned at first node in tree.
+ ACE_RB_Tree_Reverse_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK> rend (void);
+
+ /// Recursively tests the invariant red-black properties at each
+ /// node of the tree. Returns 0 if invariant holds, else -1.
+ /// This method is computationally expensive, and should only be
+ /// called for testing purposes, and not in code that depends on the
+ /// algorithmic complexity bounds provided by the other methods.
+ int test_invariant (void);
+
+ // = DEPRECATED methods.
+ // Please migrate your code to use the new methods instead
+
+ /**
+ * Returns a pointer to the item corresponding to the
+ * given key, or 0 if it cannot find the key in the tree.
+ *
+ * @deprecated signature will change to become
+ * int find (const EXT_ID &ext_id); which will return
+ * 0 if the <ext_id> is in the tree, otherwise -1.
+ */
+ INT_ID* find (const EXT_ID &k);
+
+ /**
+ * Inserts a *copy* of the key and the item into the tree: both the
+ * key type EXT_ID and the item type INT_ID must have well defined semantics
+ * for copy construction. The default implementation also requires that
+ * the key type support well defined < semantics. This method returns a
+ * pointer to the inserted item copy, or 0 if an error occurred.
+ * NOTE: if an identical key already exists in the tree, no new item
+ * is created, and the returned pointer addresses the existing item
+ * associated with the existing key.
+ * @deprecated
+ */
+ INT_ID* insert (const EXT_ID &k, const INT_ID &t);
+
+ /**
+ * Removes the item associated with the given key from the tree and
+ * destroys it. Returns 1 if it found the item and successfully
+ * destroyed it, 0 if it did not find the item, or -1 if an error
+ * occurred.
+ * @deprecated
+ */
+ int remove (const EXT_ID &k);
+
+ /// Destroys all nodes and sets the root pointer null.
+ /// @deprecated
+ void clear (void);
+
+protected:
+
+ // = Protected methods. These should only be called with locks held.
+
+ /// Recursively tests the invariant red-black properties at each
+ /// node of the tree. Returns 0 if invariant holds, else -1.
+ int test_invariant_recurse (ACE_RB_Tree_Node<EXT_ID, INT_ID> * x,
+ int & expected_black_height,
+ int measured_black_height);
+
+ /// Method for right rotation of the tree about a given node.
+ void RB_rotate_right (ACE_RB_Tree_Node<EXT_ID, INT_ID> * x);
+
+ /// Method for left rotation of the tree about a given node.
+ void RB_rotate_left (ACE_RB_Tree_Node<EXT_ID, INT_ID> * x);
+
+ /// Method for restoring Red-Black properties after deletion.
+ void RB_delete_fixup (ACE_RB_Tree_Node<EXT_ID, INT_ID> * x,
+ ACE_RB_Tree_Node<EXT_ID, INT_ID> * parent);
+
+ /// Method to find the successor node of the given node in the tree.
+ ACE_RB_Tree_Node<EXT_ID, INT_ID> *
+ RB_tree_successor (ACE_RB_Tree_Node<EXT_ID, INT_ID> *x) const;
+
+ /// Method to find the predecessor node of the given node in the
+ /// tree.
+ ACE_RB_Tree_Node<EXT_ID, INT_ID> *
+ RB_tree_predecessor (ACE_RB_Tree_Node<EXT_ID, INT_ID> *x) const;
+
+ /// Method to find the minimum node of the subtree rooted at the
+ /// given node.
+ ACE_RB_Tree_Node<EXT_ID, INT_ID> *
+ RB_tree_minimum (ACE_RB_Tree_Node<EXT_ID, INT_ID> *x) const;
+
+ /// Method to find the maximum node of the subtree rooted at the
+ /// given node.
+ ACE_RB_Tree_Node<EXT_ID, INT_ID> *
+ RB_tree_maximum (ACE_RB_Tree_Node<EXT_ID, INT_ID> *x) const;
+
+ /**
+ * Returns a pointer to a matching node if there is one, a pointer
+ * to the node under which to insert the item if the tree is not
+ * empty and there is no such match, or 0 if the tree is empty.
+ * It stores the result of the search in the result argument:
+ * LEFT if the node is to the left of the node to be inserted,
+ * RIGHT if the node is to the right of the node to be inserted,
+ * or EXACT if an exactly matching node already exists.
+ */
+ ACE_RB_Tree_Node<EXT_ID, INT_ID> *find_node (const EXT_ID &k,
+ ACE_RB_Tree_Base::RB_SearchResult &result);
+
+ /// Rebalance the tree after insertion of a node.
+ void RB_rebalance (ACE_RB_Tree_Node<EXT_ID, INT_ID> * x);
+
+ /// Close down an RB_Tree. this method should
+ /// only be called with locks already held.
+ int close_i (void);
+
+ /**
+ * Retrieves a pointer to the item corresponding to the
+ * given key. Returns 0 for success, or -1 if it cannot find the key
+ * in the tree.
+ */
+ int find_i (const EXT_ID &ext_id, ACE_RB_Tree_Node<EXT_ID, INT_ID>* &entry);
+
+ /**
+ * Inserts a *copy* of the key and the item into the tree: both the
+ * key type EXT_ID and the item type INT_ID must have well defined semantics
+ * for copy construction. The default implementation also requires that
+ * the key type support well defined < semantics. This method returns a
+ * pointer to the inserted item copy, or 0 if an error occurred.
+ * NOTE: if an identical key already exists in the tree, no new item
+ * is created, and the returned pointer addresses the existing item
+ * associated with the existing key.
+ */
+ INT_ID* insert_i (const EXT_ID &k, const INT_ID &t);
+
+ /**
+ * Inserts a *copy* of the key and the item into the tree: both the
+ * key type EXT_ID and the item type INT_ID must have well defined semantics
+ * for copy construction. The default implementation also requires that
+ * the key type support well defined < semantics. This method passes back
+ * a pointer to the inserted (or existing) node, and the search status. If
+ * the node already exists, the method returns 1. If the node does not
+ * exist, and a new one is successfully created, and the method returns 0.
+ * If there was an error, the method returns -1.
+ */
+ int insert_i (const EXT_ID &k, const INT_ID &t,
+ ACE_RB_Tree_Node<EXT_ID, INT_ID> *&entry);
+
+ /**
+ * Removes the item associated with the given key from the tree and
+ * destroys it. Returns 1 if it found the item and successfully
+ * destroyed it, 0 if it did not find the item, or -1 if an error
+ * occurred. Returns the stored internal id in the second argument.
+ */
+ int remove_i (const EXT_ID &k, INT_ID &i);
+
+ /// Removes the item associated with the given key from the tree and
+ /// destroys it.
+ int remove_i (ACE_RB_Tree_Node<EXT_ID, INT_ID> *z);
+
+ /// Recursive function to dump the state of an object.
+ void dump_i (ACE_RB_Tree_Node<EXT_ID, INT_ID> *node) const;
+
+ /// Function to dump node contents. Does nothing in its
+ /// basic form, but template specialization can be used to
+ /// provide definitions for various EXT_ID and INT_ID types.
+ void dump_node_i (ACE_RB_Tree_Node<EXT_ID, INT_ID> &node) const;
+
+private:
+
+ // = Private members.
+
+ /// Pointer to a memory allocator.
+ ACE_Allocator *allocator_;
+
+ /// Synchronization variable for the MT_SAFE <ACE_RB_Tree>.
+ ACE_LOCK lock_;
+
+ /// The root of the tree.
+ ACE_RB_Tree_Node<EXT_ID, INT_ID> *root_;
+
+ /// Comparison functor for comparing nodes in the tree.
+ COMPARE_KEYS compare_keys_;
+
+ /// The current number of nodes in the tree.
+ size_t current_size_;
+};
+
+/**
+ * @class ACE_RB_Tree_Iterator_Base
+ *
+ * @brief Implements a common base class for iterators for a Red-Black Tree ADT.
+ */
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK>
+class ACE_RB_Tree_Iterator_Base
+{
+
+public:
+
+ /// Assignment operator: copies both the tree reference and the position in the tree.
+ void operator= (const ACE_RB_Tree_Iterator_Base<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK> &iter);
+
+ // = Iteration methods.
+
+ /// Returns 1 when the iteration has completed, otherwise 0.
+ int done (void) const;
+
+ /// STL-like iterator dereference operator: returns a reference
+ /// to the node underneath the iterator.
+ ACE_RB_Tree_Node<EXT_ID, INT_ID> & operator* (void) const;
+
+ /// Returns a const reference to the tree over which we're iterating.
+ const ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK> &tree (void);
+
+ /// Comparison operator: returns 1 if both iterators point to the same position, otherwise 0.
+ int operator== (const ACE_RB_Tree_Iterator_Base<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK> &) const;
+
+ /// Comparison operator: returns 1 if the iterators point to different positions, otherwise 0.
+ int operator!= (const ACE_RB_Tree_Iterator_Base<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK> &) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+protected:
+
+ // = Initialization and termination methods.
+
+ /// Create the singular iterator. No valid iterator can be equal to
+ /// it, it is illegal to dereference a singular iterator, etc. etc.
+ ACE_RB_Tree_Iterator_Base (void);
+
+ /**
+ * Constructor. Takes an ACE_RB_Tree over which to iterate, and
+ * an integer indicating (if non-zero) to position the iterator
+ * at the first element in the tree (if this integer is 0, the
+ * iterator is positioned at the last element in the tree).
+ */
+ ACE_RB_Tree_Iterator_Base (const ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK> &tree,
+ int set_first);
+
+ /// Copy constructor.
+ ACE_RB_Tree_Iterator_Base (const ACE_RB_Tree_Iterator_Base<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK> &iter);
+
+ /// Destructor.
+ ~ACE_RB_Tree_Iterator_Base (void);
+
+ // = Internal methods
+
+ /// Move forward by one element in the tree. Returns 0 when
+ /// there are no more elements in the tree, otherwise 1.
+ int forward_i (void);
+
+ /// Move back by one element in the tree. Returns 0 when
+ /// there are no more elements in the tree, otherwise 1.
+ int reverse_i (void);
+
+ /// Dump the state of an object.
+ void dump_i (void) const;
+
+ // = Protected members.
+
+ /// Reference to the ACE_RB_Tree over which we're iterating.
+ const ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK> *tree_;
+
+ /// Pointer to the node currently under the iterator.
+ ACE_RB_Tree_Node <EXT_ID, INT_ID> *node_;
+
+};
+
+/**
+ * @class ACE_RB_Tree_Iterator
+ *
+ * @brief Implements an iterator for a Red-Black Tree ADT.
+ */
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK>
+class ACE_RB_Tree_Iterator : public ACE_RB_Tree_Iterator_Base<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>
+{
+
+public:
+
+ // = Initialization and termination methods.
+ /**
+ * Create the singular iterator.
+ * It is illegal to deference the iterator, no valid iterator is
+ * equal to a singular iterator, etc. etc.
+ */
+ ACE_RB_Tree_Iterator (void);
+
+ /**
+ * Constructor. Takes an ACE_RB_Tree over which to iterate, and
+ * an integer indicating (if non-zero) to position the iterator
+ * at the first element in the tree (if this integer is 0, the
+ * iterator is positioned at the last element in the tree).
+ */
+ ACE_RB_Tree_Iterator (const ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK> &tree,
+ int set_first = 1);
+
+ /// Destructor.
+ ~ACE_RB_Tree_Iterator (void);
+
+ // = ACE-style iteration methods.
+
+ /// Move forward by one element in the tree. Returns
+ /// 0 when all elements have been seen, else 1.
+ int advance (void);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ // = STL-style iteration methods.
+
+ /// Prefix advance.
+ ACE_RB_Tree_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK> & operator++ (void);
+
+ /// Postfix advance.
+ ACE_RB_Tree_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK> operator++ (int);
+
+ /// Prefix reverse.
+ ACE_RB_Tree_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK> & operator-- (void);
+
+ /// Postfix reverse.
+ ACE_RB_Tree_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK> operator-- (int);
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+ /**
+ * Passes back the <entry> under the iterator. Returns 0 if
+ * the iteration has completed, otherwise 1. This method must
+ * be declared and defined in both the derived forward and
+ * reverse iterator classes rather than in the base iterator
+ * class because of a method signature resolution problem
+ * caused by the existence of the deprecated next (void)
+ * method in the derived forward iterator class. When that
+ * deprecated method is removed, this method should be removed
+ * from the derived classes and placed in the base class.
+ */
+ int next (ACE_RB_Tree_Node<EXT_ID, INT_ID> *&next_entry) const;
+
+ // = DEPRECATED methods. Please migrate your code to use the new methods instead
+
+ /// Accessor for key of node under iterator (if any).
+ /// DEPRECATED
+ EXT_ID *key (void);
+
+ /// Accessor for item of node under iterator (if any).
+ /// DEPRECATED
+ INT_ID *item (void);
+
+ /// Move to the first item in the iteration (and in the tree).
+ /// DEPRECATED
+ int first (void);
+
+ /// Move to the last item in the iteration (and in the tree).
+ /// DEPRECATED
+ int last (void);
+
+ /// Move to the next item in the iteration (and in the tree).
+ /// DEPRECATED
+ int next (void);
+
+ /// Move to the previous item in the iteration (and in the tree).
+ /// DEPRECATED
+ int previous (void);
+
+ /**
+ * Returns 0 if the iterator is positioned over a valid ACE_RB_Tree
+ * node, returns 1 if not.
+ * DEPRECATED: use the base class <done> method instead.
+ */
+ int is_done (void);
+
+};
+
+/**
+ * @class ACE_RB_Tree_Reverse_Iterator
+ *
+ * @brief Implements a reverse iterator for a Red-Black Tree ADT.
+ */
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK>
+class ACE_RB_Tree_Reverse_Iterator : public ACE_RB_Tree_Iterator_Base<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>
+{
+
+public:
+
+ // = Initialization and termination methods.
+ /**
+ * Create the singular iterator.
+ * It is illegal to deference the iterator, no valid iterator is
+ * equal to a singular iterator, etc. etc.
+ */
+ ACE_RB_Tree_Reverse_Iterator (void);
+
+ /**
+ * Constructor. Takes an ACE_RB_Tree over which to iterate, and
+ * an integer indicating (if non-zero) to position the iterator
+ * at the last element in the tree (if this integer is 0, the
+ * iterator is positioned at the first element in the tree).
+ */
+ ACE_RB_Tree_Reverse_Iterator (const ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK> &tree,
+ int set_last = 1);
+
+ /// Destructor.
+ ~ACE_RB_Tree_Reverse_Iterator (void);
+
+ // = ACE-style iteration methods.
+
+ /// Move forward by one element in the tree. Returns
+ /// 0 when all elements have been seen, else 1.
+ int advance (void);
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ // = STL-style iteration methods.
+
+ /// Prefix advance.
+ ACE_RB_Tree_Reverse_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK> & operator++ (void);
+
+ /// Postfix advance.
+ ACE_RB_Tree_Reverse_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK> operator++ (int);
+
+ /// Prefix reverse.
+ ACE_RB_Tree_Reverse_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK> & operator-- (void);
+
+ /// Postfix reverse.
+ ACE_RB_Tree_Reverse_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK> operator-- (int);
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+ /**
+ * Passes back the <entry> under the iterator. Returns 0 if
+ * the iteration has completed, otherwise 1. This method must
+ * be declared and defined in both the derived forward and
+ * reverse iterator classes rather than in the base iterator
+ * class because of a method signature resolution problem
+ * caused by the existence of the deprecated next (void)
+ * method in the derived forward iterator class. When that
+ * deprecated method is removed, this method should be removed
+ * from the derived classes and placed in the base class.
+ */
+ int next (ACE_RB_Tree_Node<EXT_ID, INT_ID> *&next_entry) const;
+
+};
+
+#if defined (__ACE_INLINE__)
+#include "ace/RB_Tree.i"
+#endif /* __ACE_INLINE__ */
+
+#if defined (ACE_TEMPLATES_REQUIRE_SOURCE)
+#include "ace/RB_Tree.cpp"
+#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */
+
+#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA)
+#pragma implementation ("RB_Tree.cpp")
+#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */
+
+#include "ace/post.h"
+#endif /* ! defined (ACE_RB_TREE_H) */
diff --git a/ace/Utils/Templates/RB_Tree.i b/ace/Utils/Templates/RB_Tree.i
new file mode 100644
index 00000000000..55deff16026
--- /dev/null
+++ b/ace/Utils/Templates/RB_Tree.i
@@ -0,0 +1,1152 @@
+/* -*- C++ -*- */
+// $Id$
+
+#include "ace/Synch.h"
+#include "ace/Malloc.h"
+
+/////////////////////////////////////////////////////
+// template class ACE_RB_Tree_Node<EXT_ID, INT_ID> //
+/////////////////////////////////////////////////////
+
+// Key accessor.
+
+template <class EXT_ID, class INT_ID>
+ACE_INLINE EXT_ID &
+ACE_RB_Tree_Node<EXT_ID, INT_ID>::key ()
+{
+ ACE_TRACE ("ACE_RB_Tree_Node<EXT_ID, INT_ID>::key");
+ return k_;
+}
+
+
+// Item accessor.
+
+template <class EXT_ID, class INT_ID>
+ACE_INLINE INT_ID &
+ACE_RB_Tree_Node<EXT_ID, INT_ID>::item ()
+{
+ ACE_TRACE ("ACE_RB_Tree_Node<EXT_ID, INT_ID>:item");
+ return t_;
+}
+
+
+// Set color of the node.
+
+template <class EXT_ID, class INT_ID>
+ACE_INLINE void
+ACE_RB_Tree_Node<EXT_ID, INT_ID>::color (ACE_RB_Tree_Node_Base::RB_Tree_Node_Color c)
+{
+ ACE_TRACE ("ACE_RB_Tree_Node<EXT_ID, INT_ID>::color mutator");
+ color_ = c;
+}
+
+
+// Get color of the node.
+
+template <class EXT_ID, class INT_ID>
+ACE_INLINE ACE_RB_Tree_Node_Base::RB_Tree_Node_Color
+ACE_RB_Tree_Node<EXT_ID, INT_ID>::color ()
+{
+ ACE_TRACE ("ACE_RB_Tree_Node<EXT_ID, INT_ID>::color accessor");
+ return color_;
+}
+
+
+// Accessor for node's parent pointer.
+
+template <class EXT_ID, class INT_ID>
+ACE_INLINE ACE_RB_Tree_Node<EXT_ID, INT_ID> *
+ACE_RB_Tree_Node<EXT_ID, INT_ID>::parent ()
+{
+ ACE_TRACE ("ACE_RB_Tree_Node<EXT_ID, INT_ID>::parent accessor");
+ return parent_;
+}
+
+
+// Mutator for node's parent pointer.
+
+template <class EXT_ID, class INT_ID>
+ACE_INLINE void
+ACE_RB_Tree_Node<EXT_ID, INT_ID>::parent (ACE_RB_Tree_Node<EXT_ID, INT_ID> * p)
+{
+ ACE_TRACE ("ACE_RB_Tree_Node<EXT_ID, INT_ID>::parent mutator");
+ parent_ = p;
+}
+
+
+
+// Accessor for node's left child pointer.
+
+template <class EXT_ID, class INT_ID>
+ACE_INLINE ACE_RB_Tree_Node<EXT_ID, INT_ID> *
+ACE_RB_Tree_Node<EXT_ID, INT_ID>::left ()
+{
+ ACE_TRACE ("ACE_RB_Tree_Node<EXT_ID, INT_ID>::left accessor");
+ return left_;
+}
+
+
+// Mutator for node's left child pointer.
+
+template <class EXT_ID, class INT_ID>
+ACE_INLINE void
+ACE_RB_Tree_Node<EXT_ID, INT_ID>::left (ACE_RB_Tree_Node<EXT_ID, INT_ID> * l)
+{
+ ACE_TRACE ("ACE_RB_Tree_Node<EXT_ID, INT_ID>::left mutator");
+ left_ = l;
+}
+
+
+// Accessor for node's right child pointer.
+
+template <class EXT_ID, class INT_ID>
+ACE_INLINE ACE_RB_Tree_Node<EXT_ID, INT_ID> *
+ACE_RB_Tree_Node<EXT_ID, INT_ID>::right ()
+{
+ ACE_TRACE ("ACE_RB_Tree_Node<EXT_ID, INT_ID>::right accessor");
+ return right_;
+}
+
+
+// Mutator for node's right child pointer.
+
+template <class EXT_ID, class INT_ID>
+ACE_INLINE void
+ACE_RB_Tree_Node<EXT_ID, INT_ID>::right (ACE_RB_Tree_Node<EXT_ID, INT_ID> * r)
+{
+ ACE_TRACE ("ACE_RB_Tree_Node<EXT_ID, INT_ID>::right mutator");
+ right_ = r;
+}
+
+
+
+////////////////////////////////////////////////////////////////////////
+// template class ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK> //
+////////////////////////////////////////////////////////////////////////
+
+
+// Initialize an RB Tree.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK>
+ACE_INLINE int
+ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::open (ACE_Allocator *alloc)
+{
+ ACE_TRACE ("ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::open");
+ ACE_WRITE_GUARD_RETURN (ACE_LOCK, ace_mon, this->lock_, -1);
+
+ // Calling this->close_i () ensures we release previously allocated
+ // memory before allocating new memory.
+ this->close_i ();
+
+ // If we were passed an allocator use it,
+ // otherwise use the default instance.
+
+ if (alloc == 0)
+ alloc = ACE_Allocator::instance ();
+
+ this->allocator_ = alloc;
+
+ return 0;
+}
+
+// Close down an RB_Tree and release dynamically allocated
+// resources.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK>
+ACE_INLINE int
+ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::close (void)
+{
+ ACE_TRACE ("ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::close");
+ ACE_WRITE_GUARD_RETURN (ACE_LOCK, ace_mon, this->lock_, -1);
+
+ return this->close_i ();
+}
+
+
+// Associate <ext_id> with <int_id>. If <ext_id> is already in the
+// tree then the <ACE_RB_Tree_Node> is not changed. Returns 0 if a
+// new entry is bound successfully, returns 1 if an attempt is made
+// to bind an existing entry, and returns -1 if failures occur.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK>
+ACE_INLINE int
+ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::bind (const EXT_ID &ext_id,
+ const INT_ID &int_id)
+{
+ ACE_TRACE ("ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::bind (const EXT_ID &item, const INT_ID &int_id)");
+ ACE_WRITE_GUARD_RETURN (ACE_LOCK, ace_mon, this->lock_, -1);
+
+ ACE_RB_Tree_Node<EXT_ID, INT_ID> *entry;
+ return this->insert_i (ext_id, int_id, entry);
+}
+
+
+// Same as a normal bind, except the tree entry is also passed back
+// to the caller. The entry in this case will either be the newly
+// created entry, or the existing one.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK>
+ACE_INLINE int
+ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::bind (const EXT_ID &ext_id,
+ const INT_ID &int_id,
+ ACE_RB_Tree_Node<EXT_ID, INT_ID> *&entry)
+{
+ ACE_TRACE ("ACE_RB_Tree::bind (const EXT_ID &ext_id, const INT_ID &int_id, "
+ "ACE_RB_Tree_Node<EXT_ID, INT_ID> *&entry)");
+ ACE_WRITE_GUARD_RETURN (ACE_LOCK, ace_mon, this->lock_, -1);
+
+ return this->insert_i (ext_id, int_id, entry);
+}
+
+
+// Associate <ext_id> with <int_id> if and only if <ext_id> is not
+// in the tree. If <ext_id> is already in the tree then the <int_id>
+// parameter is assigned the existing value in the tree. Returns 0
+// if a new entry is bound successfully, returns 1 if an attempt is
+// made to bind an existing entry, and returns -1 if failures occur.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK>
+ACE_INLINE int
+ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::trybind (const EXT_ID &ext_id,
+ INT_ID &int_id)
+{
+ ACE_TRACE ("ACE_RB_Tree::trybind (const EXT_ID &ext_id, INT_ID &int_id)");
+ ACE_WRITE_GUARD_RETURN (ACE_LOCK, ace_mon, this->lock_, -1);
+
+ ACE_RB_Tree_Node<EXT_ID, INT_ID> *entry;
+ int result = this->insert_i (ext_id, int_id, entry);
+
+ if (result == 1)
+ {
+ int_id = entry->item ();
+ }
+
+ return result;
+}
+
+
+// Same as a normal trybind, except the tree entry is also passed
+// back to the caller. The entry in this case will either be the
+// newly created entry, or the existing one.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK>
+ACE_INLINE int
+ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::trybind (const EXT_ID &ext_id,
+ INT_ID &int_id,
+ ACE_RB_Tree_Node<EXT_ID, INT_ID> *&entry)
+{
+ ACE_TRACE ("ACE_RB_Tree::trybind (const EXT_ID &ext_id, INT_ID &int_id, "
+ "ACE_RB_Tree_Node<EXT_ID, INT_ID> *&entry)");
+ ACE_WRITE_GUARD_RETURN (ACE_LOCK, ace_mon, this->lock_, -1);
+
+ int result = this->insert_i (ext_id, int_id, entry);
+
+ if (result == 1)
+ {
+ int_id = entry->item ();
+ }
+
+
+ return result;
+}
+
+
+// Reassociate <ext_id> with <int_id>. If <ext_id> is not in the
+// tree then behaves just like <bind>. Returns 0 if a new entry is
+// bound successfully, returns 1 if an existing entry was rebound,
+// and returns -1 if failures occur.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK>
+ACE_INLINE int
+ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::rebind (const EXT_ID &ext_id,
+ const INT_ID &int_id)
+{
+ ACE_TRACE ("ACE_RB_Tree::rebind (const EXT_ID &ext_id, const INT_ID &int_id)");
+ ACE_WRITE_GUARD_RETURN (ACE_LOCK, ace_mon, this->lock_, -1);
+
+ ACE_RB_Tree_Node<EXT_ID, INT_ID> *entry;
+ int result = this->insert_i (ext_id, int_id, entry);
+
+ if (result == 1)
+ {
+ entry->key () = ext_id;
+ entry->item () = int_id;
+ }
+
+ return result;
+}
+
+
+// Same as a normal rebind, except the tree entry is also passed back
+// to the caller. The entry in this case will either be the newly
+// created entry, or the existing one.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK>
+ACE_INLINE int
+ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::rebind (const EXT_ID &ext_id,
+ const INT_ID &int_id,
+ ACE_RB_Tree_Node<EXT_ID, INT_ID> *&entry)
+{
+ ACE_TRACE ("ACE_RB_Tree::rebind (const EXT_ID &ext_id, const INT_ID &int_id, "
+ "ACE_RB_Tree_Node<EXT_ID, INT_ID> *&entry)");
+ ACE_WRITE_GUARD_RETURN (ACE_LOCK, ace_mon, this->lock_, -1);
+
+ int result = this->insert_i (ext_id, int_id, entry);
+
+ if (result == 1)
+ {
+ entry->key () = ext_id;
+ entry->item () = int_id;
+ }
+
+ return result;
+}
+
+
+// Associate <ext_id> with <int_id>. If <ext_id> is not in the tree
+// then behaves just like <bind>. Otherwise, store the old value of
+// <int_id> into the "out" parameter and rebind the new parameters.
+// Returns 0 if a new entry is bound successfully, returns 1 if an
+// existing entry was rebound, and returns -1 if failures occur.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK>
+ACE_INLINE int
+ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::rebind (const EXT_ID &ext_id,
+ const INT_ID &int_id,
+ INT_ID &old_int_id)
+{
+ ACE_TRACE ("ACE_RB_Tree::rebind (const EXT_ID &ext_id, "
+ "const INT_ID &int_id, INT_ID &old_int_id)");
+ ACE_WRITE_GUARD_RETURN (ACE_LOCK, ace_mon, this->lock_, -1);
+
+ ACE_RB_Tree_Node<EXT_ID, INT_ID> *entry;
+ int result = this->insert_i (ext_id, int_id, entry);
+
+ if (result == 1)
+ {
+ old_int_id = entry->item ();
+ entry->key () = ext_id;
+ entry->item () = int_id;
+ }
+
+ return result;
+}
+
+
+// Same as a normal rebind, except the tree entry is also passed back
+// to the caller. The entry in this case will either be the newly
+// created entry, or the existing one.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK>
+ACE_INLINE int
+ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::rebind (const EXT_ID &ext_id,
+ const INT_ID &int_id,
+ INT_ID &old_int_id,
+ ACE_RB_Tree_Node<EXT_ID, INT_ID> *&entry)
+{
+ ACE_TRACE ("ACE_RB_Tree::rebind (const EXT_ID &ext_id, const INT_ID &int_id,"
+ "INT_ID &old_int_id, ACE_RB_Tree_Node<EXT_ID, INT_ID> *&entry)");
+ ACE_WRITE_GUARD_RETURN (ACE_LOCK, ace_mon, this->lock_, -1);
+
+ int result = this->insert_i (ext_id, int_id, entry);
+
+ if (result == 1)
+ {
+ old_int_id = entry->item ();
+ entry->key () = ext_id;
+ entry->item () = int_id;
+ }
+
+ return result;
+}
+
+
+// Associate <ext_id> with <int_id>. If <ext_id> is not in the tree
+// then behaves just like <bind>. Otherwise, store the old values
+// of <ext_id> and <int_id> into the "out" parameters and rebind the
+// new parameters. This is very useful if you need to have an
+// atomic way of updating <ACE_RB_Tree_Nodes> and you also need
+// full control over memory allocation. Returns 0 if a new entry is
+// bound successfully, returns 1 if an existing entry was rebound,
+// and returns -1 if failures occur.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK>
+ACE_INLINE int
+ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::rebind (const EXT_ID &ext_id,
+ const INT_ID &int_id,
+ EXT_ID &old_ext_id,
+ INT_ID &old_int_id)
+{
+ ACE_TRACE ("ACE_RB_Tree::rebind (const EXT_ID &ext_id, const INT_ID &int_id,"
+ "EXT_ID &old_ext_id, INT_ID &old_int_id)");
+ ACE_WRITE_GUARD_RETURN (ACE_LOCK, ace_mon, this->lock_, -1);
+
+ ACE_RB_Tree_Node<EXT_ID, INT_ID> *entry;
+ int result = this->insert_i (ext_id, int_id, entry);
+
+ if (result == 1)
+ {
+ old_ext_id = entry->key ();
+ old_int_id = entry->item ();
+ entry->key () = ext_id;
+ entry->item () = int_id;
+ }
+
+ return result;
+}
+
+
+// Same as a normal rebind, except the tree entry is also passed back
+// to the caller. The entry in this case will either be the newly
+// created entry, or the existing one.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK>
+ACE_INLINE int
+ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::rebind (const EXT_ID &ext_id,
+ const INT_ID &int_id,
+ EXT_ID &old_ext_id,
+ INT_ID &old_int_id,
+ ACE_RB_Tree_Node<EXT_ID, INT_ID> *&entry)
+{
+ ACE_TRACE ("ACE_RB_Tree::rebind (const EXT_ID &ext_id, const INT_ID &int_id, "
+ "EXT_ID &old_ext_id, INT_ID &old_int_id, "
+ "ACE_RB_Tree_Node<EXT_ID, INT_ID> *&entry)");
+ ACE_WRITE_GUARD_RETURN (ACE_LOCK, ace_mon, this->lock_, -1);
+
+ int result = this->insert_i (ext_id, int_id, entry);
+
+ if (result == 1)
+ {
+ old_ext_id = entry->key ();
+ old_int_id = entry->item ();
+ entry->key () = ext_id;
+ entry->item () = int_id;
+ }
+
+ return result;
+}
+
+
+// Locate <ext_id> and pass out parameter via <int_id>. If found,
+// return 0, returns -1 if not found.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK>
+ACE_INLINE int
+ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::find (const EXT_ID &ext_id,
+ INT_ID &int_id)
+{
+ ACE_TRACE ("ACE_RB_Tree::find (const EXT_ID &ext_id, INT_ID &int_id)");
+ ACE_READ_GUARD_RETURN (ACE_LOCK, ace_mon, this->lock_, -1);
+
+ ACE_RB_Tree_Node<EXT_ID, INT_ID> *entry = 0;
+
+ int result = this->find_i (ext_id, entry);
+ if (result == 0)
+ {
+ int_id = entry->item ();
+ }
+
+ return result;
+}
+
+// Locate <ext_id> and pass out parameter via <entry>. If found,
+// return 0, returns -1 if not found.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK>
+ACE_INLINE int
+ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::find (const EXT_ID &ext_id,
+ ACE_RB_Tree_Node<EXT_ID, INT_ID> *&entry)
+{
+ ACE_TRACE ("ACE_RB_Tree::find (const EXT_ID &ext_id, ACE_RB_Tree_Node<EXT_ID, INT_ID> *&entry)");
+ ACE_READ_GUARD_RETURN (ACE_LOCK, ace_mon, this->lock_, -1);
+
+ return this->find_i (ext_id, entry);
+}
+
+
+// Unbind (remove) the <ext_id> from the tree. Don't return the
+// <int_id> to the caller (this is useful for collections where the
+// <int_id>s are *not* dynamically allocated...).
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK>
+ACE_INLINE int
+ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::unbind (const EXT_ID &ext_id)
+{
+ ACE_TRACE ("ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::unbind (const EXT_ID &ext_id)");
+ ACE_WRITE_GUARD_RETURN (ACE_LOCK, ace_mon, this->lock_, -1);
+
+ INT_ID int_id;
+ int result = this->remove_i (ext_id, int_id);
+
+ // Remap the return codes from the internal method: this
+ // is maintained this way in support of deprecated methods,
+ // and will be cleaned up when these methods are removed.
+ switch (result)
+ {
+ case 1:
+ // If the node was found and deleted, return success.
+ return 0;
+ case 0:
+ // If nothing was found, set errno and break.
+ errno = ENOENT;
+ break;
+ case -1:
+ // If an error happened, just break.
+ break;
+ }
+
+ // Return an error if we didn't already return success.
+ return -1;
+}
+
+
+// Break any association of <ext_id>. Returns the value of <int_id>
+// in case the caller needs to deallocate memory.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK>
+ACE_INLINE int
+ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::unbind (const EXT_ID &ext_id,
+ INT_ID &int_id)
+{
+ ACE_TRACE ("ACE_RB_Tree::unbind (const EXT_ID &ext_id, INT_ID &int_id)");
+ ACE_WRITE_GUARD_RETURN (ACE_LOCK, ace_mon, this->lock_, -1);
+
+ int result = this->remove_i (ext_id, int_id);
+
+ // Remap the return codes from the internal method: this
+ // is maintained this way in support of deprecated methods,
+ // and will be cleaned up when these methods are removed.
+ switch (result)
+ {
+ case 1:
+ // If the node was found and deleted, return success.
+ return 0;
+ case 0:
+ // If nothing was found, set errno and break.
+ errno = ENOENT;
+ break;
+ case -1:
+ // If an error happened, just break.
+ break;
+ }
+
+ // Return an error if we didn't already return success.
+ return -1;
+}
+
+
+// Remove entry from the tree. This method should be used with *extreme*
+// caution, and only for optimization purposes. The node being passed
+// in had better have been allocated by the tree that is unbinding it.
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK>
+ACE_INLINE int
+ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::unbind (ACE_RB_Tree_Node<EXT_ID, INT_ID> *entry)
+{
+ ACE_TRACE ("ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::unbind (ACE_RB_Tree_Node<EXT_ID, INT_ID> *entry)");
+ ACE_WRITE_GUARD_RETURN (ACE_LOCK, ace_mon, this->lock_, -1);
+
+ return this->remove_i (entry);
+}
+
+
+// Returns a reference to the underlying <ACE_LOCK>. This makes it
+// possible to acquire the lock explicitly, which can be useful in
+// some cases if you instantiate the <ACE_Atomic_Op> with an
+// <ACE_Recursive_Mutex> or <ACE_Process_Mutex>, or if you need to
+// guard the state of an iterator. NOTE: the right name would be
+// <lock>, but HP/C++ will choke on that!
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK>
+ACE_INLINE ACE_LOCK &
+ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::mutex (void)
+{
+ ACE_TRACE ("ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::mutex");
+ return this->lock_;
+}
+
+
+// Dump the state of an object.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK>
+ACE_INLINE void
+ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::dump (void) const
+{
+ ACE_TRACE ("ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::dump");
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\ncurrent_size_ = %d\n"), this->current_size_));
+ this->allocator_->dump ();
+ this->lock_.dump ();
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\nDumping nodes from root\n")));
+ this->dump_i (this->root_);
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+
+// Return forward iterator positioned at first node in tree.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK>
+ACE_INLINE ACE_RB_Tree_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>
+ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::begin (void)
+{
+ ACE_TRACE ("ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::begin");
+
+ return ACE_RB_Tree_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK> (*this);
+}
+
+
+// Return forward iterator positioned at last node in tree.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK>
+ACE_INLINE ACE_RB_Tree_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>
+ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::end (void)
+{
+ ACE_TRACE ("ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::end");
+
+ return ACE_RB_Tree_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK> ();
+}
+
+
+// Return reverse iterator positioned at last node in tree.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK>
+ACE_INLINE ACE_RB_Tree_Reverse_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>
+ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::rbegin (void)
+{
+ ACE_TRACE ("ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::rbegin");
+
+ return ACE_RB_Tree_Reverse_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK> (*this);
+}
+
+
+// Return reverse iterator positioned at first node in tree.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK>
+ACE_INLINE ACE_RB_Tree_Reverse_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>
+ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::rend (void)
+{
+ ACE_TRACE ("ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::rend");
+
+ return ACE_RB_Tree_Reverse_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK> ();
+}
+
+
+// Returns a pointer to the item corresponding to the given key,
+// or 0 if it cannot find the key in the tree. DEPRECATED.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK>
+ACE_INLINE INT_ID*
+ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::find (const EXT_ID &k)
+{
+ ACE_TRACE ("ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::find (const EXT_ID &k)");
+
+ // The reinterpret cast is to ensure that when this deprecated method is removed, and
+ // is replaced (as planned) by a find method that takes the same argument signature
+ // but returns an int, that the compiler will cough if this return macro is not
+ // changed to just return an int (whose value will be -1). Please leave this as is.
+ ACE_READ_GUARD_RETURN (ACE_LOCK, ace_mon, this->lock_, ACE_reinterpret_cast(INT_ID*, 0L));
+
+ ACE_RB_Tree_Node<EXT_ID, INT_ID> *entry;
+ int result = this->find_i (k, entry);
+ return (result == 0) ? &(entry->item ()) : 0;
+}
+
+// Inserts a *copy* of the key and the item into the tree:
+// both the key type EXT_ID and the item type INT_ID must have well
+// defined semantics for copy construction and < comparison.
+// This method returns a pointer to the inserted item copy,
+// or 0 if an error occurred. NOTE: if an identical key
+// already exists in the tree, no new item is created, and
+// the returned pointer addresses the existing item
+// associated with the existing key. DEPRECATED.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK>
+ACE_INLINE INT_ID*
+ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::insert (const EXT_ID &k, const INT_ID &t)
+{
+ ACE_TRACE ("ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::insert");
+ ACE_WRITE_GUARD_RETURN (ACE_LOCK, ace_mon, this->lock_, ACE_reinterpret_cast(INT_ID*, 0L));
+
+ return this->insert_i (k, t);
+}
+
+
+// Removes the item associated with the given key from the
+// tree and destroys it. Returns 1 if it found the item
+// and successfully destroyed it, 0 if it did not find the
+// item, or -1 if an error occurred. DEPRECATED.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK>
+ACE_INLINE int
+ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::remove (const EXT_ID &k)
+{
+ ACE_TRACE ("ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::remove");
+ ACE_WRITE_GUARD_RETURN (ACE_LOCK, ace_mon, this->lock_, -1);
+
+ INT_ID i;
+ return this->remove_i (k, i);
+}
+
+
+// Destroys all nodes and sets the root pointer null. DEPRECATED
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK>
+ACE_INLINE void
+ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::clear ()
+{
+ ACE_TRACE ("ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::clear");
+ ACE_WRITE_GUARD (ACE_LOCK, ace_mon, this->lock_);
+
+ this->close_i ();
+}
+
+// Returns the current number of nodes in the tree.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK>
+ACE_INLINE size_t
+ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::current_size () const
+{
+ ACE_TRACE ("ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::current_size");
+ return current_size_;
+}
+
+
+///////////////////////////////////////////////////////////////////////
+// template class //
+// ACE_RB_Tree_Iterator_Base<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK> //
+///////////////////////////////////////////////////////////////////////
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK>
+ACE_INLINE
+ACE_RB_Tree_Iterator_Base<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::ACE_RB_Tree_Iterator_Base (void)
+ : tree_ (0), node_ (0)
+{
+ ACE_TRACE ("ACE_RB_Tree_Iterator_Base<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::ACE_RB_Tree_Iterator_Base (void)");
+}
+
+// Returns 1 when the iteration has completed, otherwise 0.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK>
+ACE_INLINE int
+ACE_RB_Tree_Iterator_Base<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::done (void) const
+{
+ ACE_TRACE ("ACE_RB_Tree_Iterator_Base<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::done");
+
+ return node_ ? 0 : 1;
+}
+
+
+// STL-like iterator dereference operator: returns a reference
+// to the node underneath the iterator.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK>
+ACE_INLINE ACE_RB_Tree_Node<EXT_ID, INT_ID> &
+ACE_RB_Tree_Iterator_Base<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::operator* (void) const
+{
+ ACE_TRACE ("ACE_RB_Tree_Iterator_Base<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::operator*");
+ return *(this->node_);
+}
+
+
+// Returns a reference to the tree over which we're iterating.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK>ACE_INLINE const ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK> &
+ACE_RB_Tree_Iterator_Base<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::tree (void)
+{
+ ACE_TRACE ("ACE_RB_Tree_Iterator_Base<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::tree");
+ return *tree_;
+}
+
+
+// Comparison operator: returns 1 if both iterators point to the same position, otherwise 0.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK>
+ACE_INLINE int
+ACE_RB_Tree_Iterator_Base<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::operator==
+ (const ACE_RB_Tree_Iterator_Base<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK> &rbt) const
+{
+ ACE_TRACE ("ACE_RB_Tree_Iterator_Base<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::operator==");
+ return (this->node_ == rbt.node_) ? 1 : 0;
+}
+
+
+// Comparison operator: returns 1 if the iterators point to different positions, otherwise 0.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK>
+ACE_INLINE int
+ACE_RB_Tree_Iterator_Base<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::operator!=
+ (const ACE_RB_Tree_Iterator_Base<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK> &rbt) const
+{
+ ACE_TRACE ("ACE_RB_Tree_Iterator_Base<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::operator!=");
+ return (this->node_ == rbt.node_) ? 0 : 1;
+}
+
+
+// Move forward by one element in the tree. Returns 0 when
+// there are no more elements in the tree, otherwise 1.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK>
+ACE_INLINE int
+ACE_RB_Tree_Iterator_Base<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::forward_i (void)
+{
+ ACE_TRACE ("ACE_RB_Tree_Iterator_Base<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::forward_i");
+
+ if (node_)
+ {
+ node_ = tree_->RB_tree_successor (node_);
+ }
+
+ return node_ ? 1 : 0;
+}
+
+
+// Move back by one element in the tree. Returns 0 when
+// there are no more elements in the tree, otherwise 1.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK>
+ACE_INLINE int
+ACE_RB_Tree_Iterator_Base<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::reverse_i (void)
+{
+ ACE_TRACE ("ACE_RB_Tree_Iterator_Base<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::reverse_i");
+
+ if (node_)
+ {
+ node_ = tree_->RB_tree_predecessor (node_);
+ }
+
+ return node_ ? 1 : 0;
+}
+
+
+// Dump the state of an object.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK>
+ACE_INLINE void
+ACE_RB_Tree_Iterator_Base<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::dump_i (void) const
+{
+ ACE_TRACE ("ACE_RB_Tree_Iterator_Base<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::dump_i");
+
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\nnode_ = %x\n"), this->node_));
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+
+//////////////////////////////////////////////////////////////////
+// template class //
+// ACE_RB_Tree_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK> //
+//////////////////////////////////////////////////////////////////
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK>
+ACE_INLINE
+ACE_RB_Tree_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::ACE_RB_Tree_Iterator (void)
+ : ACE_RB_Tree_Iterator_Base<EXT_ID,INT_ID,COMPARE_KEYS,ACE_LOCK> ()
+{
+ ACE_TRACE ("ACE_RB_Tree_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::ACE_RB_Tree_Iterator (void)");
+}
+
+// Move forward by one element in the tree. Returns
+// 0 when all elements have been seen, else 1.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK>
+ACE_INLINE int
+ACE_RB_Tree_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::advance (void)
+{
+ ACE_TRACE ("ACE_RB_Tree_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::advance");
+
+ return this->forward_i ();
+}
+
+
+// Dump the state of an object.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK>
+ACE_INLINE void
+ACE_RB_Tree_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::dump (void) const
+{
+ ACE_TRACE ("ACE_RB_Tree_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::dump");
+
+ this->dump_i ();
+}
+
+
+// Prefix advance.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK>
+ACE_INLINE ACE_RB_Tree_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK> &
+ACE_RB_Tree_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::operator++ (void)
+{
+ ACE_TRACE ("ACE_RB_Tree_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK> operator++ (void)");
+
+ this->forward_i ();
+ return *this;
+}
+
+
+// Postfix advance.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK>
+ACE_INLINE ACE_RB_Tree_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>
+ACE_RB_Tree_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::operator++ (int)
+{
+ ACE_TRACE ("ACE_RB_Tree_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK> operator++ (int)");
+
+ ACE_RB_Tree_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK> retv (*this);
+ this->forward_i ();
+ return retv;
+}
+
+
+// Prefix reverse.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK>
+ACE_INLINE ACE_RB_Tree_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK> &
+ACE_RB_Tree_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::operator-- (void)
+{
+ ACE_TRACE ("ACE_RB_Tree_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK> operator-- (void)");
+
+ this->reverse_i ();
+ return *this;
+}
+
+
+// Postfix reverse.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK>
+ACE_INLINE ACE_RB_Tree_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>
+ACE_RB_Tree_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::operator-- (int)
+{
+ ACE_TRACE ("ACE_RB_Tree_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK> operator-- (int)");
+
+ ACE_RB_Tree_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK> retv (*this);
+ this->reverse_i ();
+ return retv;
+}
+
+
+// Passes back the <entry> under the iterator. Returns 0 if
+// the iteration has completed, otherwise 1. This method must
+// be declared and defined in both the derived forward and
+// reverse iterator classes rather than in the base iterator
+// class because of a method signature resolution problem
+// caused by the existence of the deprecated next (void)
+// method in the derived forward iterator class. When that
+// deprecated method is removed, this method should be removed
+// from the derived classes and placed in the base class.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK>
+ACE_INLINE int
+ACE_RB_Tree_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::next (ACE_RB_Tree_Node<EXT_ID, INT_ID> *&next_entry) const
+{
+ ACE_TRACE ("ACE_RB_Tree_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::next");
+
+ if (this->node_)
+ {
+ next_entry = this->node_;
+ return 1;
+ }
+
+ return 0;
+}
+
+
+// Accessor for key of node under iterator (if any). DEPRECATED.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK>
+ACE_INLINE EXT_ID *
+ACE_RB_Tree_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::key ()
+{
+ ACE_TRACE ("ACE_RB_Tree_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::key");
+ return this->node_ ? (&(this->node_->key ())) : 0;
+}
+
+
+// Accessor for item of node under iterator (if any). DEPRECATED.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK>
+ACE_INLINE INT_ID *
+ACE_RB_Tree_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::item ()
+{
+ ACE_TRACE ("ACE_RB_Tree_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::item");
+ return this->node_ ? (&(this->node_->item ())) : 0;
+}
+
+
+// Move to the first item in the tree. DEPRECATED.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK>
+ACE_INLINE int
+ACE_RB_Tree_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::first ()
+{
+ ACE_TRACE ("ACE_RB_Tree_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::first");
+ this->node_ = this->tree_->RB_tree_minimum (this->tree_->root_);
+ return this->node_ ? 1 : 0;
+}
+
+
+// Move to the last item in the tree. DEPRECATED.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK>
+ACE_INLINE int
+ACE_RB_Tree_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::last ()
+{
+ ACE_TRACE ("ACE_RB_Tree_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::last");
+ this->node_ = this->tree_->RB_tree_maximum (this->tree_->root_);
+ return this->node_ ? 1 : 0;
+}
+
+
+// Moves to the next item in the tree,
+// returns 1 if there is a next item, 0 otherwise. DEPRECATED.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK>
+ACE_INLINE int
+ACE_RB_Tree_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::next ()
+{
+ ACE_TRACE ("ACE_RB_Tree_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::next");
+ this->node_ = this->tree_->RB_tree_successor (this->node_);
+ return this->node_ ? 1 : 0;
+}
+
+
+// Moves to the previous item in the tree,
+// returns 1 if there is a previous item, 0 otherwise. DEPRECATED.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK>
+ACE_INLINE int
+ACE_RB_Tree_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::previous ()
+{
+ ACE_TRACE ("ACE_RB_Tree_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::previous");
+ this->node_ = this->tree_->RB_tree_predecessor (this->node_);
+ return this->node_ ? 1 : 0;
+}
+
+
+// Returns 0 if the iterator is positioned over a valid ACE_RB_Tree
+// node, returns 1 if not. DEPRECATED.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK>
+ACE_INLINE int
+ACE_RB_Tree_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::is_done ()
+{
+ ACE_TRACE ("ACE_RB_Tree_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::is_done");
+ return this->node_ ? 0 : 1;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+// template class //
+// ACE_RB_Tree_Reverse_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK> //
+//////////////////////////////////////////////////////////////////////////
+
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK>
+ACE_INLINE
+ACE_RB_Tree_Reverse_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::ACE_RB_Tree_Reverse_Iterator (void)
+ : ACE_RB_Tree_Iterator_Base<EXT_ID,INT_ID,COMPARE_KEYS,ACE_LOCK> ()
+{
+ ACE_TRACE ("ACE_RB_Tree_Reverse_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::ACE_RB_Tree_Reverse_Iterator (void)");
+}
+
+// Move forward by one element in the tree. Returns
+// 0 when all elements have been seen, else 1.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK>
+ACE_INLINE int
+ACE_RB_Tree_Reverse_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::advance (void)
+{
+ ACE_TRACE ("ACE_RB_Tree_Reverse_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::advance");
+
+ return this->reverse_i ();
+}
+
+
+// Dump the state of an object.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK>
+ACE_INLINE void
+ACE_RB_Tree_Reverse_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::dump (void) const
+{
+ ACE_TRACE ("ACE_RB_Tree_Reverse_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::dump");
+
+ this->dump_i ();
+}
+
+
+// Prefix advance.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK>
+ACE_INLINE ACE_RB_Tree_Reverse_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK> &
+ACE_RB_Tree_Reverse_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::operator++ (void)
+{
+ ACE_TRACE ("ACE_RB_Tree_Reverse_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::operator++ (void)");
+
+ this->reverse_i ();
+ return *this;
+}
+
+
+// Postfix advance.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK>
+ACE_INLINE ACE_RB_Tree_Reverse_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>
+ACE_RB_Tree_Reverse_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::operator++ (int)
+{
+ ACE_TRACE ("ACE_RB_Tree_Reverse_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::operator++ (int)");
+
+ ACE_RB_Tree_Reverse_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK> retv (*this);
+ this->reverse_i ();
+ return retv;
+}
+
+
+// Prefix reverse.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK>
+ACE_INLINE ACE_RB_Tree_Reverse_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK> &
+ACE_RB_Tree_Reverse_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::operator-- (void)
+{
+ ACE_TRACE ("ACE_RB_Tree_Reverse_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::operator-- (void)");
+
+ this->forward_i ();
+ return *this;
+}
+
+
+// Postfix reverse.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK>
+ACE_INLINE ACE_RB_Tree_Reverse_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>
+ACE_RB_Tree_Reverse_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::operator-- (int)
+{
+ ACE_TRACE ("ACE_RB_Tree_Reverse_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::operator-- (int)");
+
+ ACE_RB_Tree_Reverse_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK> retv (*this);
+ this->forward_i ();
+ return retv;
+}
+
+
+// Passes back the <entry> under the iterator. Returns 0 if
+// the iteration has completed, otherwise 1. This method must
+// be declared and defined in both the derived forward and
+// reverse iterator classes rather than in the base iterator
+// class because of a method signature resolution problem
+// caused by the existence of the deprecated next (void)
+// method in the derived forward iterator class. When that
+// deprecated method is removed, this method should be removed
+// from the derived classes and placed in the base class.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK>
+ACE_INLINE int
+ACE_RB_Tree_Reverse_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::next (ACE_RB_Tree_Node<EXT_ID, INT_ID> *&next_entry) const
+{
+ ACE_TRACE ("ACE_RB_Tree_Reverse_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::next");
+
+ if (this->node_)
+ {
+ next_entry = this->node_;
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/ace/Utils/Templates/Singleton.cpp b/ace/Utils/Templates/Singleton.cpp
new file mode 100644
index 00000000000..aada3c07206
--- /dev/null
+++ b/ace/Utils/Templates/Singleton.cpp
@@ -0,0 +1,385 @@
+// $Id$
+
+#ifndef ACE_SINGLETON_C
+#define ACE_SINGLETON_C
+
+#include "ace/Singleton.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "ace/Synch_T.h"
+#include "ace/Object_Manager.h"
+#include "ace/Log_Msg.h"
+
+#if !defined (__ACE_INLINE__)
+#include "ace/Singleton.i"
+#endif /* __ACE_INLINE__ */
+
+ACE_RCSID (ace,
+ Singleton,
+ "$Id$")
+
+template <class TYPE, class ACE_LOCK> void
+ACE_Singleton<TYPE, ACE_LOCK>::dump (void)
+{
+ ACE_TRACE ("ACE_Singleton<TYPE, ACE_LOCK>::dump");
+
+#if !defined (ACE_LACKS_STATIC_DATA_MEMBER_TEMPLATES)
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("instance_ = %x"),
+ ACE_Singleton<TYPE, ACE_LOCK>::instance_i ()));
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+#endif /* ACE_LACKS_STATIC_DATA_MEMBER_TEMPLATES */
+}
+
+template <class TYPE, class ACE_LOCK> ACE_Singleton<TYPE, ACE_LOCK> *&
+ACE_Singleton<TYPE, ACE_LOCK>::instance_i (void)
+{
+#if defined (ACE_LACKS_STATIC_DATA_MEMBER_TEMPLATES)
+ // Pointer to the Singleton instance. This works around a bug with
+ // G++ and it's (mis-)handling of templates and statics...
+ static ACE_Singleton<TYPE, ACE_LOCK> *singleton_ = 0;
+
+ return singleton_;
+#else
+ return ACE_Singleton<TYPE, ACE_LOCK>::singleton_;
+#endif /* ACE_LACKS_STATIC_DATA_MEMBER_TEMPLATES */
+}
+
+template <class TYPE, class ACE_LOCK> TYPE *
+ACE_Singleton<TYPE, ACE_LOCK>::instance (void)
+{
+ ACE_TRACE ("ACE_Singleton<TYPE, ACE_LOCK>::instance");
+
+ ACE_Singleton<TYPE, ACE_LOCK> *&singleton =
+ ACE_Singleton<TYPE, ACE_LOCK>::instance_i ();
+
+ // Perform the Double-Check pattern...
+ if (singleton == 0)
+ {
+ if (ACE_Object_Manager::starting_up () ||
+ ACE_Object_Manager::shutting_down ())
+ {
+ // The program is still starting up, and therefore assumed
+ // to be single threaded. There's no need to double-check.
+ // Or, the ACE_Object_Manager instance has been destroyed,
+ // so the preallocated lock is not available. Either way,
+ // don't register for destruction with the
+ // ACE_Object_Manager: we'll have to leak this instance.
+
+ ACE_NEW_RETURN (singleton, (ACE_Singleton<TYPE, ACE_LOCK>), 0);
+ }
+ else
+ {
+#if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0)
+ // Obtain a lock from the ACE_Object_Manager. The pointer
+ // is static, so we only obtain one per ACE_Singleton
+ // instantiation.
+ static ACE_LOCK *lock = 0;
+ if (ACE_Object_Manager::get_singleton_lock (lock) != 0)
+ // Failed to acquire the lock!
+ return 0;
+
+ ACE_GUARD_RETURN (ACE_LOCK, ace_mon, *lock, 0);
+
+ if (singleton == 0)
+ {
+#endif /* ACE_MT_SAFE */
+ ACE_NEW_RETURN (singleton, (ACE_Singleton<TYPE, ACE_LOCK>), 0);
+
+ // Register for destruction with ACE_Object_Manager.
+ ACE_Object_Manager::at_exit (singleton);
+#if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0)
+ }
+#endif /* ACE_MT_SAFE */
+ }
+ }
+
+ return &singleton->instance_;
+}
+
+template <class TYPE, class ACE_LOCK> void
+ACE_Singleton<TYPE, ACE_LOCK>::cleanup (void *)
+{
+ delete this;
+ ACE_Singleton<TYPE, ACE_LOCK>::instance_i () = 0;
+}
+
+#if !defined (ACE_LACKS_STATIC_DATA_MEMBER_TEMPLATES)
+// Pointer to the Singleton instance.
+template <class TYPE, class ACE_LOCK> ACE_Singleton<TYPE, ACE_LOCK> *
+ACE_Singleton<TYPE, ACE_LOCK>::singleton_ = 0;
+
+template <class TYPE, class ACE_LOCK> ACE_Unmanaged_Singleton<TYPE, ACE_LOCK> *
+ACE_Unmanaged_Singleton<TYPE, ACE_LOCK>::singleton_ = 0;
+#endif /* !defined (ACE_LACKS_STATIC_DATA_MEMBER_TEMPLATES) */
+
+template <class TYPE, class ACE_LOCK> void
+ACE_Unmanaged_Singleton<TYPE, ACE_LOCK>::dump (void)
+{
+ ACE_TRACE ("ACE_Unmanaged_Singleton<TYPE, ACE_LOCK>::dump");
+
+#if !defined (ACE_LACKS_STATIC_DATA_MEMBER_TEMPLATES)
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("instance_ = %x"),
+ ACE_Unmanaged_Singleton<TYPE, ACE_LOCK>::instance_i ()));
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+#endif /* ACE_LACKS_STATIC_DATA_MEMBER_TEMPLATES */
+}
+
+template <class TYPE, class ACE_LOCK>
+ACE_Unmanaged_Singleton<TYPE, ACE_LOCK> *&
+ACE_Unmanaged_Singleton<TYPE, ACE_LOCK>::instance_i (void)
+{
+#if defined (ACE_LACKS_STATIC_DATA_MEMBER_TEMPLATES)
+ // Pointer to the Singleton instance. This works around a bug with
+ // G++ and it's (mis-)handling of templates and statics...
+ static ACE_Unmanaged_Singleton<TYPE, ACE_LOCK> *singleton_ = 0;
+
+ return singleton_;
+#else
+ return ACE_Unmanaged_Singleton<TYPE, ACE_LOCK>::singleton_;
+#endif /* ACE_LACKS_STATIC_DATA_MEMBER_TEMPLATES */
+}
+
+template <class TYPE, class ACE_LOCK> TYPE *
+ACE_Unmanaged_Singleton<TYPE, ACE_LOCK>::instance (void)
+{
+ ACE_TRACE ("ACE_Unmanaged_Singleton<TYPE, ACE_LOCK>::instance");
+
+ ACE_Unmanaged_Singleton<TYPE, ACE_LOCK> *&singleton =
+ ACE_Unmanaged_Singleton<TYPE, ACE_LOCK>::instance_i ();
+
+ // Perform the Double-Check pattern...
+ if (singleton == 0)
+ {
+ if (ACE_Object_Manager::starting_up () ||
+ ACE_Object_Manager::shutting_down ())
+ {
+ // The program is still starting up, and therefore assumed
+ // to be single threaded. There's no need to double-check.
+ // Or, the ACE_Object_Manager instance has been destroyed,
+ // so the preallocated lock is not available. Either way,
+ // don't register for destruction with the
+ // ACE_Object_Manager: we'll have to leak this instance.
+
+ ACE_NEW_RETURN (singleton, (ACE_Unmanaged_Singleton<TYPE, ACE_LOCK>),
+ 0);
+ }
+ else
+ {
+#if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0)
+ // Obtain a lock from the ACE_Object_Manager. The pointer
+ // is static, so we only obtain one per
+ // ACE_Unmanaged_Singleton instantiation.
+ static ACE_LOCK *lock = 0;
+ if (ACE_Object_Manager::get_singleton_lock (lock) != 0)
+ // Failed to acquire the lock!
+ return 0;
+
+ ACE_GUARD_RETURN (ACE_LOCK, ace_mon, *lock, 0);
+#endif /* ACE_MT_SAFE */
+
+ if (singleton == 0)
+ ACE_NEW_RETURN (singleton,
+ (ACE_Unmanaged_Singleton<TYPE, ACE_LOCK>),
+ 0);
+ }
+ }
+
+ return &singleton->instance_;
+}
+
+template <class TYPE, class ACE_LOCK> void
+ACE_Unmanaged_Singleton<TYPE, ACE_LOCK>::close (void)
+{
+ ACE_Unmanaged_Singleton<TYPE, ACE_LOCK> *&singleton =
+ ACE_Unmanaged_Singleton<TYPE, ACE_LOCK>::instance_i ();
+
+ if (singleton)
+ singleton->cleanup ();
+}
+
+template <class TYPE, class ACE_LOCK> void
+ACE_TSS_Singleton<TYPE, ACE_LOCK>::dump (void)
+{
+ ACE_TRACE ("ACE_TSS_Singleton<TYPE, ACE_LOCK>::dump");
+
+#if !defined (ACE_LACKS_STATIC_DATA_MEMBER_TEMPLATES)
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("instance_ = %x"),
+ ACE_TSS_Singleton<TYPE, ACE_LOCK>::instance_i ()));
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+#endif /* ACE_LACKS_STATIC_DATA_MEMBER_TEMPLATES */
+}
+
+template <class TYPE, class ACE_LOCK> ACE_TSS_Singleton<TYPE, ACE_LOCK> *&
+ACE_TSS_Singleton<TYPE, ACE_LOCK>::instance_i (void)
+{
+#if defined (ACE_LACKS_STATIC_DATA_MEMBER_TEMPLATES)
+ // Pointer to the Singleton instance. This works around a bug with
+ // G++ and it's (mis-)handling of templates and statics...
+ static ACE_TSS_Singleton<TYPE, ACE_LOCK> *singleton_ = 0;
+
+ return singleton_;
+#else
+ return ACE_TSS_Singleton<TYPE, ACE_LOCK>::singleton_;
+#endif /* ACE_LACKS_STATIC_DATA_MEMBER_TEMPLATES */
+}
+
+template <class TYPE, class ACE_LOCK> TYPE *
+ACE_TSS_Singleton<TYPE, ACE_LOCK>::instance (void)
+{
+ ACE_TRACE ("ACE_TSS_Singleton<TYPE, ACE_LOCK>::instance");
+
+ ACE_TSS_Singleton<TYPE, ACE_LOCK> *&singleton =
+ ACE_TSS_Singleton<TYPE, ACE_LOCK>::instance_i ();
+
+ // Perform the Double-Check pattern...
+ if (singleton == 0)
+ {
+ if (ACE_Object_Manager::starting_up () ||
+ ACE_Object_Manager::shutting_down ())
+ {
+ // The program is still starting up, and therefore assumed
+ // to be single threaded. There's no need to double-check.
+ // Or, the ACE_Object_Manager instance has been destroyed,
+ // so the preallocated lock is not available. Either way,
+ // don't register for destruction with the
+ // ACE_Object_Manager: we'll have to leak this instance.
+
+ ACE_NEW_RETURN (singleton, (ACE_TSS_Singleton<TYPE, ACE_LOCK>), 0);
+ }
+ else
+ {
+#if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0)
+
+ // Obtain a lock from the ACE_Object_Manager. The pointer
+ // is static, so we only obtain one per ACE_Singleton instantiation.
+ static ACE_LOCK *lock = 0;
+ if (ACE_Object_Manager::get_singleton_lock (lock) != 0)
+ // Failed to acquire the lock!
+ return 0;
+
+ ACE_GUARD_RETURN (ACE_LOCK, ace_mon, *lock, 0);
+
+ if (singleton == 0)
+ {
+#endif /* ACE_MT_SAFE */
+ ACE_NEW_RETURN (singleton, (ACE_TSS_Singleton<TYPE, ACE_LOCK>),
+ 0);
+
+ // Register for destruction with ACE_Object_Manager.
+ ACE_Object_Manager::at_exit (singleton);
+#if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0)
+ }
+#endif /* ACE_MT_SAFE */
+ }
+ }
+
+ return ACE_TSS_GET (&singleton->instance_, TYPE);
+}
+
+template <class TYPE, class ACE_LOCK> void
+ACE_TSS_Singleton<TYPE, ACE_LOCK>::cleanup (void *)
+{
+ delete this;
+ ACE_TSS_Singleton<TYPE, ACE_LOCK>::instance_i () = 0;
+}
+
+template <class TYPE, class ACE_LOCK> void
+ACE_Unmanaged_TSS_Singleton<TYPE, ACE_LOCK>::dump (void)
+{
+ ACE_TRACE ("ACE_Unmanaged_TSS_Singleton<TYPE, ACE_LOCK>::dump");
+
+#if !defined (ACE_LACKS_STATIC_DATA_MEMBER_TEMPLATES)
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("instance_ = %x"),
+ ACE_Unmanaged_TSS_Singleton<TYPE, ACE_LOCK>::instance_i ()));
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+#endif /* ACE_LACKS_STATIC_DATA_MEMBER_TEMPLATES */
+}
+
+template <class TYPE, class ACE_LOCK>
+ACE_Unmanaged_TSS_Singleton<TYPE, ACE_LOCK> *&
+ACE_Unmanaged_TSS_Singleton<TYPE, ACE_LOCK>::instance_i (void)
+{
+#if defined (ACE_LACKS_STATIC_DATA_MEMBER_TEMPLATES)
+ // Pointer to the Singleton instance. This works around a bug with
+ // G++ and it's (mis-)handling of templates and statics...
+ static ACE_Unmanaged_TSS_Singleton<TYPE, ACE_LOCK> *singleton_ = 0;
+
+ return singleton_;
+#else
+ return ACE_Unmanaged_TSS_Singleton<TYPE, ACE_LOCK>::singleton_;
+#endif /* ACE_LACKS_STATIC_DATA_MEMBER_TEMPLATES */
+}
+
+template <class TYPE, class ACE_LOCK> TYPE *
+ACE_Unmanaged_TSS_Singleton<TYPE, ACE_LOCK>::instance (void)
+{
+ ACE_TRACE ("ACE_Unmanaged_TSS_Singleton<TYPE, ACE_LOCK>::instance");
+
+ ACE_Unmanaged_TSS_Singleton<TYPE, ACE_LOCK> *&singleton =
+ ACE_Unmanaged_TSS_Singleton<TYPE, ACE_LOCK>::instance_i ();
+
+ // Perform the Double-Check pattern...
+ if (singleton == 0)
+ {
+ if (ACE_Object_Manager::starting_up () ||
+ ACE_Object_Manager::shutting_down ())
+ {
+ // The program is still starting up, and therefore assumed
+ // to be single threaded. There's no need to double-check.
+ // Or, the ACE_Object_Manager instance has been destroyed,
+ // so the preallocated lock is not available. Either way,
+ // don't register for destruction with the
+ // ACE_Object_Manager: we'll have to leak this instance.
+
+ ACE_NEW_RETURN (singleton,
+ (ACE_Unmanaged_TSS_Singleton<TYPE, ACE_LOCK>),
+ 0);
+ }
+ else
+ {
+#if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0)
+ // Obtain a lock from the ACE_Object_Manager. The pointer
+ // is static, so we only obtain one per
+ // ACE_Unmanaged_Singleton instantiation.
+ static ACE_LOCK *lock = 0;
+ if (ACE_Object_Manager::get_singleton_lock (lock) != 0)
+ // Failed to acquire the lock!
+ return 0;
+
+ ACE_GUARD_RETURN (ACE_LOCK, ace_mon, *lock, 0);
+#endif /* ACE_MT_SAFE */
+
+ if (singleton == 0)
+ ACE_NEW_RETURN (singleton,
+ (ACE_Unmanaged_TSS_Singleton<TYPE, ACE_LOCK>),
+ 0);
+ }
+ }
+
+ return ACE_TSS_GET (&singleton->instance_, TYPE);
+}
+
+template <class TYPE, class ACE_LOCK> void
+ACE_Unmanaged_TSS_Singleton<TYPE, ACE_LOCK>::close (void)
+{
+ ACE_Unmanaged_TSS_Singleton<TYPE, ACE_LOCK> *&singleton =
+ ACE_Unmanaged_TSS_Singleton<TYPE, ACE_LOCK>::instance_i ();
+
+ if (singleton)
+ singleton->cleanup ();
+}
+
+#if !defined (ACE_LACKS_STATIC_DATA_MEMBER_TEMPLATES)
+// Pointer to the Singleton instance.
+template <class TYPE, class ACE_LOCK> ACE_TSS_Singleton <TYPE, ACE_LOCK> *
+ACE_TSS_Singleton<TYPE, ACE_LOCK>::singleton_ = 0;
+
+template <class TYPE, class ACE_LOCK>
+ACE_Unmanaged_TSS_Singleton<TYPE, ACE_LOCK> *
+ACE_Unmanaged_TSS_Singleton<TYPE, ACE_LOCK>::singleton_ = 0;
+#endif /* !defined (ACE_LACKS_STATIC_DATA_MEMBER_TEMPLATES) */
+
+#endif /* ACE_SINGLETON_C */
diff --git a/ace/Utils/Templates/Singleton.h b/ace/Utils/Templates/Singleton.h
new file mode 100644
index 00000000000..49d9edb11f1
--- /dev/null
+++ b/ace/Utils/Templates/Singleton.h
@@ -0,0 +1,250 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Singleton.h
+ *
+ * $Id$
+ *
+ * @brief
+ *
+ * @author Tim Harrison <harrison@cs.wustl.edu>,
+ * Douglas C. Schmidt <schmidt@cs.wustl.edu>,
+ * Chris Lahey,
+ * Rich Christy, and
+ * David Levine <levine@cs.wustl.edu>.
+ */
+//=============================================================================
+
+
+#ifndef ACE_SINGLETON_H
+#define ACE_SINGLETON_H
+#include "ace/pre.h"
+
+#include "ace/Synch.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+/**
+ * @class ACE_Singleton
+ *
+ * @brief A Singleton Adapter uses the Adapter pattern to turn ordinary
+ * classes into Singletons optimized with the Double-Checked
+ * Locking optimization pattern.
+ *
+ * This implementation is a slight variation on the GoF
+ * Singleton pattern. In particular, a single
+ * <ACE_Singleton<TYPE, ACE_LOCK> > instance is allocated here,
+ * not a <TYPE> instance. The reason for this is to allow
+ * registration with the <ACE_Object_Manager>, so that the
+ * Singleton can be cleaned up when the process exits. For this
+ * scheme to work, a (static) <cleanup> function must be
+ * provided. <ACE_Singleton> provides one so that TYPE doesn't
+ * need to.
+ * If you want to make sure that only the singleton instance of
+ * <T> is created, and that users cannot create their own
+ * instances of <T>, do the following to class <T>:
+ * (a) Make the constructor of <T> private (or protected)
+ * (b) Make Singleton a friend of <T>
+ * Here is an example:
+ * @verbatim
+ * class foo
+ * {
+ * friend class ACE_Singleton<foo, ACE_Null_Mutex>;
+ * private:
+ * foo () { cout << "foo constructed" << endl; }
+ * ~foo () { cout << "foo destroyed" << endl; }
+ * };
+ * typedef ACE_Singleton<foo, ACE_Null_Mutex> FOO;
+ * @endverbatim
+ *
+ * NOTE: the best types to use for ACE_LOCK are
+ * ACE_Recursive_Thread_Mutex and ACE_Null_Mutex.
+ * ACE_Recursive_Thread_Mutex should be used in multi-threaded
+ * programs in which it is possible for more than one thread to
+ * access the <ACE_Singleton<TYPE, ACE_LOCK>> instance.
+ * ACE_Null_Mutex can be used otherwise. The reason that these
+ * types of locks are best has to do with their allocation by
+ * the ACE_Object_Manager. Single ACE_Recursive_Thread_Mutex
+ * and ACE_Null_Mutex instances are used for all ACE_Singleton
+ * instantiations. However, other types of locks are allocated
+ * per ACE_Singleton instantiation.
+ */
+template <class TYPE, class ACE_LOCK>
+class ACE_Singleton : public ACE_Cleanup
+{
+public:
+ /// Global access point to the Singleton.
+ static TYPE *instance (void);
+
+ /// Cleanup method, used by <ace_cleanup_destroyer> to destroy the
+ /// <ACE_Singleton>.
+ virtual void cleanup (void *param = 0);
+
+ /// Dump the state of the object.
+ static void dump (void);
+
+protected:
+ /// Default constructor.
+ ACE_Singleton (void);
+
+ /// Contained instance.
+ TYPE instance_;
+
+#if !defined (ACE_LACKS_STATIC_DATA_MEMBER_TEMPLATES)
+ /// Pointer to the Singleton (ACE_Cleanup) instance.
+ static ACE_Singleton<TYPE, ACE_LOCK> *singleton_;
+#endif /* ACE_LACKS_STATIC_DATA_MEMBER_TEMPLATES */
+
+ /// Get pointer to the Singleton instance.
+ static ACE_Singleton<TYPE, ACE_LOCK> *&instance_i (void);
+};
+
+/**
+ * @class ACE_Unmanaged_Singleton
+ *
+ * @brief Same as <ACE_Singleton>, except does _not_ register with
+ * <ACE_Object_Manager> for destruction.
+ *
+ * This version of <ACE_Singleton> can be used if, for example,
+ * its DLL will be unloaded before the <ACE_Object_Manager>
+ * destroys the instance. Unlike with <ACE_Singleton>, the
+ * application is responsible for explicitly destroying the
+ * instance after it is no longer needed (if it wants to avoid
+ * memory leaks, at least). The <close> static member function
+ * must be used to explicitly destroy the Singleton.
+ * Usage is the same as for ACE_Singleton, but note that if you
+ * you declare a friend, the friend class must still be an
+ * *ACE_Singleton*<T, [ACE_LOCK]>, not an ACE_Unmanaged_Singleton.
+ */
+template <class TYPE, class ACE_LOCK>
+class ACE_Unmanaged_Singleton : public ACE_Singleton <TYPE, ACE_LOCK>
+{
+public:
+ /// Global access point to the Singleton.
+ static TYPE *instance (void);
+
+ /// Explicitly delete the Singleton instance.
+ static void close (void);
+
+ /// Dump the state of the object.
+ static void dump (void);
+
+protected:
+ /// Default constructor.
+ ACE_Unmanaged_Singleton (void);
+
+#if !defined (ACE_LACKS_STATIC_DATA_MEMBER_TEMPLATES)
+ /// Pointer to the Singleton (ACE_Cleanup) instance.
+ static ACE_Unmanaged_Singleton<TYPE, ACE_LOCK> *singleton_;
+#endif /* ACE_LACKS_STATIC_DATA_MEMBER_TEMPLATES */
+
+ /// Get pointer to the Singleton instance.
+ static ACE_Unmanaged_Singleton<TYPE, ACE_LOCK> *&instance_i (void);
+};
+
+/**
+ * @class ACE_TSS_Singleton
+ *
+ * @brief This class uses the Adapter pattern to turn ordinary classes
+ * into Thread-specific Singletons optimized with the
+ * Double-Checked Locking optimization pattern.
+ *
+ * This implementation is another variation on the GoF Singleton
+ * pattern. In this case, a single <ACE_TSS_Singleton<TYPE,
+ * LOCK> > instance is allocated here, not a <TYPE> instance.
+ * Each call to the <instance> static method returns a Singleton
+ * whose pointer resides in thread-specific storage. As with
+ * <ACE_Singleton>, we use the <ACE_Object_Manager> so that the
+ * Singleton can be cleaned up when the process exits. For this
+ * scheme to work, a (static) <cleanup> function must be
+ * provided. <ACE_Singleton> provides one so that TYPE doesn't
+ * need to.
+ */
+template <class TYPE, class ACE_LOCK>
+class ACE_TSS_Singleton : public ACE_Cleanup
+{
+public:
+ /// Global access point to the Singleton.
+ static TYPE *instance (void);
+
+ /// Cleanup method, used by <ace_cleanup_destroyer> to destroy the
+ /// singleton.
+ virtual void cleanup (void *param = 0);
+
+ /// Dump the state of the object.
+ static void dump (void);
+
+protected:
+ /// Default constructor.
+ ACE_TSS_Singleton (void);
+
+ /// Contained instance.
+ ACE_TSS_TYPE (TYPE) instance_;
+
+#if !defined (ACE_LACKS_STATIC_DATA_MEMBER_TEMPLATES)
+ /// Pointer to the Singleton (ACE_Cleanup) instance.
+ static ACE_TSS_Singleton<TYPE, ACE_LOCK> *singleton_;
+#endif /* ACE_LACKS_STATIC_DATA_MEMBER_TEMPLATES */
+
+ /// Get pointer to the TSS Singleton instance.
+ static ACE_TSS_Singleton<TYPE, ACE_LOCK> *&instance_i (void);
+};
+
+/**
+ * @class ACE_Unmanaged_TSS_Singleton
+ *
+ * @brief Same as <ACE_TSS_Singleton>, except does _not_ register with
+ * <ACE_Object_Manager> for destruction.
+ *
+ * This version of <ACE_TSS_Singleton> can be used if, for
+ * example, its DLL will be unloaded before the
+ * <ACE_Object_Manager> destroys the instance. Unlike with
+ * <ACE_Singleton>, the application is responsible for
+ * explicitly destroying the instance after it is no longer
+ * needed (if it wants to avoid memory leaks, at least). The
+ * <close> static member function must be used to explicitly
+ * destroy the Singleton.
+ */
+template <class TYPE, class ACE_LOCK>
+class ACE_Unmanaged_TSS_Singleton : public ACE_TSS_Singleton <TYPE, ACE_LOCK>
+{
+public:
+ /// Global access point to the Singleton.
+ static TYPE *instance (void);
+
+ /// Explicitly delete the Singleton instance.
+ static void close (void);
+
+ /// Dump the state of the object.
+ static void dump (void);
+
+protected:
+ /// Default constructor.
+ ACE_Unmanaged_TSS_Singleton (void);
+
+#if !defined (ACE_LACKS_STATIC_DATA_MEMBER_TEMPLATES)
+ /// Pointer to the Singleton (ACE_Cleanup) instance.
+ static ACE_Unmanaged_TSS_Singleton<TYPE, ACE_LOCK> *singleton_;
+#endif /* ACE_LACKS_STATIC_DATA_MEMBER_TEMPLATES */
+
+ /// Get pointer to the Singleton instance.
+ static ACE_Unmanaged_TSS_Singleton<TYPE, ACE_LOCK> *&instance_i (void);
+};
+
+#if defined (__ACE_INLINE__)
+#include "ace/Singleton.i"
+#endif /* __ACE_INLINE__ */
+
+#if defined (ACE_TEMPLATES_REQUIRE_SOURCE)
+#include "ace/Singleton.cpp"
+#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */
+
+#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA)
+#pragma implementation ("Singleton.cpp")
+#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */
+
+#include "ace/post.h"
+#endif /* ACE_SINGLETON_H */
diff --git a/ace/Utils/Templates/Singleton.i b/ace/Utils/Templates/Singleton.i
new file mode 100644
index 00000000000..38e37fc3d7c
--- /dev/null
+++ b/ace/Utils/Templates/Singleton.i
@@ -0,0 +1,27 @@
+/* -*- C++ -*- */
+// $Id$
+
+// Default constructors.
+//
+// Note: don't explicitly initialize "instance_", because TYPE may not
+// have a default constructor. Let the compiler figure it out . . .
+
+template <class TYPE, class ACE_LOCK> ACE_INLINE
+ACE_Singleton<TYPE, ACE_LOCK>::ACE_Singleton (void)
+{
+}
+
+template <class TYPE, class ACE_LOCK> ACE_INLINE
+ACE_Unmanaged_Singleton<TYPE, ACE_LOCK>::ACE_Unmanaged_Singleton (void)
+{
+}
+
+template <class TYPE, class ACE_LOCK> ACE_INLINE
+ACE_TSS_Singleton<TYPE, ACE_LOCK>::ACE_TSS_Singleton (void)
+{
+}
+
+template <class TYPE, class ACE_LOCK> ACE_INLINE
+ACE_Unmanaged_TSS_Singleton<TYPE, ACE_LOCK>::ACE_Unmanaged_TSS_Singleton (void)
+{
+}
diff --git a/ace/Utils/Templates/String_Base.cpp b/ace/Utils/Templates/String_Base.cpp
new file mode 100644
index 00000000000..5277aed1b16
--- /dev/null
+++ b/ace/Utils/Templates/String_Base.cpp
@@ -0,0 +1,181 @@
+// $Id$
+
+#include "ace/Malloc.h"
+#include "ace/String_Base.h"
+#include "ace/Auto_Ptr.h"
+
+#if !defined (ACE_LACKS_IOSTREAM_TOTALLY)
+# include "ace/streams.h"
+#endif /* ! ACE_LACKS_IOSTREAM_TOTALLY */
+
+#if !defined (__ACE_INLINE__)
+#include "ace/String_Base.i"
+#endif /* __ACE_INLINE__ */
+
+ACE_RCSID(ace, String_Base, "String_Base.cpp,v 4.61 2001/03/04 00:55:30 brunsch Exp")
+
+ACE_ALLOC_HOOK_DEFINE(ACE_String_Base)
+
+template <class CHAR>
+CHAR ACE_String_Base<CHAR>::NULL_String_ = '\0';
+
+// this method might benefit from a little restructuring.
+template <class CHAR> void
+ACE_String_Base<CHAR>::set (const CHAR *s,
+ size_t len,
+ int release)
+{
+ // Case 1. Going from memory to more memory
+ size_t new_buf_len = len + 1;
+ if (s != 0 && len != 0 && release && this->buf_len_ < new_buf_len)
+ {
+ CHAR *temp;
+ ACE_ALLOCATOR (temp,
+ (CHAR *) this->allocator_->malloc (new_buf_len * sizeof (CHAR)));
+
+ if (this->release_)
+ this->allocator_->free (this->rep_);
+
+ this->rep_ = temp;
+ this->buf_len_ = new_buf_len;
+ this->release_ = 1;
+ this->len_ = len;
+ ACE_OS::memcpy (this->rep_, s, len * sizeof (CHAR));
+ // NUL terminate.
+ this->rep_[len] = '\0';
+ }
+
+ // Case 2. No memory allocation is necessary.
+ else
+ {
+ // Free memory if necessary and figure out future ownership
+ if (!release || s == 0 || len == 0)
+ if (this->release_)
+ {
+ this->allocator_->free (this->rep_);
+ this->release_ = 0;
+ }
+ // else - stay with whatever value for release_ we have.
+
+ // Populate data.
+ if (s == 0 || len == 0)
+ {
+ this->buf_len_ = 0;
+ this->len_ = 0;
+ this->rep_ = &ACE_String_Base<CHAR>::NULL_String_;
+ }
+ else if (!release)
+ {
+ this->buf_len_ = len;
+ this->len_ = len;
+ this->rep_ = (CHAR *) s;
+ }
+ else
+ {
+ ACE_OS::memcpy (this->rep_, s, len * sizeof (CHAR));
+ // NUL terminate.
+ this->rep_[len] = 0;
+ this->len_ = len;
+ }
+ }
+}
+
+// Return substring.
+template <class CHAR> ACE_String_Base<CHAR>
+ACE_String_Base<CHAR>::substring (size_t offset,
+ ssize_t length) const
+{
+ ACE_String_Base<CHAR> nil;
+ size_t count = length;
+
+ // case 1. empty string
+ if (this->len_ == 0)
+ return nil;
+
+ // case 2. start pos past our end
+ if (offset >= this->len_)
+ return nil;
+ // No length == empty string.
+ else if (length == 0)
+ return nil;
+ // Get all remaining bytes.
+ else if (length == -1 || count > (this->len_ - offset))
+ count = this->len_ - offset;
+
+ return ACE_String_Base<CHAR> (&this->rep_[offset],
+ count,
+ this->allocator_);
+}
+
+// Concat operator (does copy memory).
+
+template <class CHAR> ACE_String_Base<CHAR> &
+ACE_String_Base<CHAR>::operator+= (const ACE_String_Base<CHAR> &s)
+{
+ ACE_TRACE ("ACE_String_Base<CHAR>::operator+=");
+
+ if (s.len_ > 0)
+ {
+ size_t new_buf_len = this->len_ + s.len_ + 1;
+
+ // case 1. No memory allocation needed.
+ if (this->buf_len_ >= new_buf_len)
+ // Copy in data from new string.
+ ACE_OS::memcpy (this->rep_ + this->len_,
+ s.rep_,
+ s.len_ * sizeof (CHAR));
+
+ // case 2. Memory reallocation is needed
+ else
+ {
+ CHAR *t = 0;
+
+ ACE_ALLOCATOR_RETURN (t,
+ (CHAR *) this->allocator_->malloc (new_buf_len *
+ sizeof (CHAR)),
+ *this);
+
+ // Copy memory from old string into new string.
+ ACE_OS::memcpy (t,
+ this->rep_,
+ this->len_ * sizeof (CHAR));
+
+ ACE_OS::memcpy (t + this->len_,
+ s.rep_,
+ s.len_ * sizeof (CHAR));
+
+ if (this->release_)
+ this->allocator_->free (this->rep_);
+
+ this->release_ = 1;
+ this->rep_ = t;
+ this->buf_len_ = new_buf_len;
+ }
+
+ this->len_ += s.len_;
+ this->rep_[this->len_] = '\0';
+ }
+
+ return *this;
+}
+
+template <class CHAR> void
+ACE_String_Base<CHAR>::resize (size_t len, CHAR c)
+{
+ ACE_TRACE ("ACE_String_Base<CHAR>::resize");
+
+ // Only reallocate if we don't have enough space...
+ if (this->buf_len_ <= len)
+ {
+ if (this->buf_len_ != 0)
+ this->allocator_->free (this->rep_);
+ this->rep_ = (CHAR *)
+ this->allocator_->malloc ((len + 1) * sizeof (CHAR));
+ this->buf_len_ = len + 1;
+ }
+
+ this->len_ = 0;
+ ACE_OS::memset (this->rep_,
+ c,
+ this->buf_len_ * sizeof (CHAR));
+}
diff --git a/ace/Utils/Templates/String_Base.h b/ace/Utils/Templates/String_Base.h
new file mode 100644
index 00000000000..8cbe11f1783
--- /dev/null
+++ b/ace/Utils/Templates/String_Base.h
@@ -0,0 +1,235 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file String_Base.h
+ *
+ * $Id$
+ *
+ * @author Douglas C. Schmidt (schmidt@cs.wustl.edu)
+ * @author Nanbor Wang <nanbor@cs.wustl.edu>
+ */
+//=============================================================================
+
+#ifndef ACE_STRING_BASE_H
+#define ACE_STRING_BASE_H
+#include "ace/pre.h"
+
+#include "ace/ACE.h"
+#include "ace/String_Base_Const.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+// Forward decl.
+class ACE_Allocator;
+
+/**
+ * @class ACE_String_Base
+ *
+ * @brief This class provides a wrapper facade for C strings.
+ *
+ * This class uses an <ACE_Allocator> to allocate memory. The
+ * user can make this a persistant class by providing an
+ * ACE_Allocator with a persistable memory pool. This class is
+ * optimized for efficiency, so it doesn't provide any internal
+ * locking.
+ * NOTE: if an instance of this class is constructed from or
+ * assigned an empty string (with first element of '\0'), then it
+ * is _not_ allocated new space. Instead, its internal
+ * representation is set equal to a global empty string.
+ * CAUTION: in cases when ACE_String_Base is constructed from a
+ * provided buffer with the release parameter set to 0,
+ * ACE_String_Base is not guaranteed to be '\0' terminated.
+ */
+template <class CHAR>
+class ACE_Export ACE_String_Base : public ACE_String_Base_Const
+{
+public:
+ /// Default constructor.
+ ACE_String_Base (ACE_Allocator *alloc = 0);
+
+ /**
+ * Constructor that copies @a s into dynamically allocated memory.
+ * If @a release is non-0 then the @a ACE_allocator is responsible for
+ * freeing this memory. Memory is _not_ allocated/freed if @a release
+ * is 0.
+ */
+ ACE_String_Base (const CHAR *s,
+ ACE_Allocator *alloc = 0,
+ int release = 1);
+
+ /**
+ * Constructor that copies <len> CHARs of <s> into dynamically
+ * allocated memory (will NUL terminate the result). If <release>
+ * is non-0 then the <ACE_allocator> is responsible for freeing this
+ * memory. Memory is _not_ allocated/freed if <release> is 0.
+ */
+ ACE_String_Base (const CHAR *s,
+ size_t len,
+ ACE_Allocator *alloc = 0,
+ int release = 1);
+
+ /// Copy constructor.
+ ACE_String_Base (const ACE_String_Base<CHAR> &);
+
+ /// Constructor that copies @a c into dynamically allocated memory.
+ ACE_String_Base (CHAR c, ACE_Allocator *alloc = 0);
+
+ /// Constructor that dynamically allocate @a len long of char array
+ /// and initialize it to @a c using @a alloc to allocate the memory.
+ ACE_String_Base (size_t len, CHAR c = 0, ACE_Allocator *alloc = 0);
+
+ /// Deletes the memory...
+ ~ACE_String_Base (void);
+
+ /// Return the <slot'th> character in the string (doesn't perform
+ /// bounds checking).
+ const CHAR &operator [] (size_t slot) const;
+
+ /// Return the <slot'th> character by reference in the string
+ /// (doesn't perform bounds checking).
+ CHAR &operator [] (size_t slot);
+
+ /// Assignment operator (does copy memory).
+ ACE_String_Base<CHAR> &operator = (const ACE_String_Base<CHAR> &);
+
+ /// Copy @a s into this @a ACE_String_Base. Memory is _not_
+ /// allocated/freed if @a release is 0.
+ void set (const CHAR *s, int release = 1);
+
+ /// Copy @a len bytes of @a s (will NUL terminate the result).
+ /// Memory is _not_ allocated/freed if @a release is 0.
+ void set (const CHAR *s,
+ size_t len,
+ int release);
+
+ /// Clear this string. Memory is _not_ freed is <release> is 0.
+ void clear (int release = 0);
+
+ /**
+ * Return a substring given an offset and length, if length == -1
+ * use rest of str. Return empty substring if offset or
+ * offset/length are invalid.
+ */
+ ACE_String_Base<CHAR> substring (size_t offset, ssize_t length = -1) const;
+
+ /// Same as <substring>.
+ ACE_String_Base<CHAR> substr (size_t offset, ssize_t length = -1) const;
+
+ /// Concat operator (copies memory).
+ ACE_String_Base<CHAR> &operator += (const ACE_String_Base<CHAR> &);
+
+ /// Returns a hash value for this string.
+ u_long hash (void) const;
+
+ /// Return the length of the string.
+ size_t length (void) const;
+
+ /// Get a copy of the underlying representation.
+ CHAR *rep (void) const;
+
+ /**
+ * Get at the underlying representation directly!
+ * _Don't_ even think about casting the result to (char *) and modifying it,
+ * if it has length 0!
+ */
+ const CHAR *fast_rep (void) const;
+
+ /// Same as STL String's <c_str> and <fast_rep>.
+ const CHAR *c_str (void) const;
+
+ /// Comparison operator that will match substrings. Returns the
+ /// slot of the first location that matches, else -1.
+ int strstr (const ACE_String_Base<CHAR> &s) const;
+
+ /// Find <str> starting at pos. Returns the slot of the first
+ /// location that matches (will be >= pos), else npos.
+ int find (const ACE_String_Base<CHAR> &str, int pos = 0) const;
+
+ /// Find <s> starting at pos. Returns the slot of the first
+ /// location that matches (will be >= pos), else npos.
+ int find (const CHAR *s, int pos = 0) const;
+
+ /// Find <c> starting at pos. Returns the slot of the first
+ /// location that matches (will be >= pos), else npos.
+ int find (CHAR c, int pos = 0) const;
+
+ /// Find <c> starting at pos (counting from the end). Returns the
+ /// slot of the first location that matches, else npos.
+ int rfind (CHAR c, int pos = npos) const;
+
+ /// Equality comparison operator (must match entire string).
+ int operator == (const ACE_String_Base<CHAR> &s) const;
+
+ /// Less than comparison operator.
+ int operator < (const ACE_String_Base<CHAR> &s) const;
+
+ /// Greater than comparison operator.
+ int operator > (const ACE_String_Base<CHAR> &s) const;
+
+ /// Inequality comparison operator.
+ int operator != (const ACE_String_Base<CHAR> &s) const;
+
+ /// Performs a <strcmp>-style comparison.
+ int compare (const ACE_String_Base<CHAR> &s) const;
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /**
+ * This method is designed for high-performance. Please use with
+ * care ;-) If the current size of the string is less than <len>,
+ * the string is resized to the new length. The data is zero'd
+ * out after this operation.
+ */
+ void resize (size_t len, CHAR c = 0);
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+protected:
+ /// Pointer to a memory allocator.
+ ACE_Allocator *allocator_;
+
+ /// Length of the ACE_String_Base data (not counting the trailing '\0').
+ size_t len_;
+
+ /// Length of the ACE_String_Base data buffer. Keeping track of the
+ /// length allows to avoid unnecessary dynamic allocations.
+ size_t buf_len_;
+
+ /// Pointer to data.
+ CHAR *rep_;
+
+ /// Flag that indicates if we own the memory
+ int release_;
+
+ /// Represents the "NULL" string to simplify the internal logic.
+ static CHAR NULL_String_;
+};
+
+template <class CHAR> ACE_INLINE
+ACE_String_Base<CHAR> operator + (const ACE_String_Base<CHAR> &,
+ const ACE_String_Base<CHAR> &);
+template <class CHAR> ACE_INLINE
+ACE_String_Base<CHAR> operator + (const ACE_String_Base<CHAR> &,
+ const CHAR *);
+template <class CHAR> ACE_INLINE
+ACE_String_Base<CHAR> operator + (const CHAR* ,
+ const ACE_String_Base<CHAR> &);
+#if defined (__ACE_INLINE__)
+#include "ace/String_Base.i"
+#endif /* __ACE_INLINE__ */
+
+#if defined (ACE_TEMPLATES_REQUIRE_SOURCE)
+#include "ace/String_Base.cpp"
+#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */
+
+#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA)
+#pragma implementation ("String_Base.cpp")
+#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */
+
+#include "ace/post.h"
+#endif /* ACE_STRING_BASE_H */
diff --git a/ace/Utils/Templates/String_Base.i b/ace/Utils/Templates/String_Base.i
new file mode 100644
index 00000000000..63691853cf5
--- /dev/null
+++ b/ace/Utils/Templates/String_Base.i
@@ -0,0 +1,358 @@
+/* -*- C++ -*- */
+// $Id$
+
+#include "ace/Malloc_Base.h"
+
+// Default constructor.
+
+template <class CHAR> ACE_INLINE
+ACE_String_Base<CHAR>::ACE_String_Base (ACE_Allocator *alloc)
+ : allocator_ (alloc ? alloc : ACE_Allocator::instance ()),
+ len_ (0),
+ buf_len_ (0),
+ rep_ (&ACE_String_Base<CHAR>::NULL_String_),
+ release_ (0)
+{
+ ACE_TRACE ("ACE_String_Base<CHAR>::ACE_String_Base");
+}
+
+// Constructor that actually copies memory.
+
+template <class CHAR> ACE_INLINE
+ACE_String_Base<CHAR>::ACE_String_Base (const CHAR *s,
+ ACE_Allocator *alloc,
+ int release)
+ : allocator_ (alloc ? alloc : ACE_Allocator::instance ()),
+ len_ (0),
+ buf_len_ (0),
+ rep_ (0),
+ release_ (0)
+{
+ ACE_TRACE ("ACE_String_Base<CHAR>::ACE_String_Base");
+
+ size_t length;
+ if (s != 0)
+ length = ACE_OS::strlen (s);
+ else
+ length = 0;
+
+ this->set (s, length, release);
+}
+
+template <class CHAR> ACE_INLINE
+ACE_String_Base<CHAR>::ACE_String_Base (CHAR c,
+ ACE_Allocator *alloc)
+ : allocator_ (alloc ? alloc : ACE_Allocator::instance ()),
+ len_ (0),
+ buf_len_ (0),
+ rep_ (0),
+ release_ (0)
+{
+ ACE_TRACE ("ACE_String_Base<CHAR>::ACE_String_Base");
+
+ this->set (&c, 1, 1);
+}
+
+// Constructor that actually copies memory.
+
+template <class CHAR> ACE_INLINE
+ACE_String_Base<CHAR>::ACE_String_Base (const CHAR *s,
+ size_t len,
+ ACE_Allocator *alloc,
+ int release)
+ : allocator_ (alloc ? alloc : ACE_Allocator::instance ()),
+ len_ (0),
+ buf_len_ (0),
+ rep_ (0),
+ release_ (0)
+{
+ ACE_TRACE ("ACE_String_Base<CHAR>::ACE_String_Base");
+
+ this->set (s, len, release);
+}
+
+// Copy constructor.
+
+template <class CHAR> ACE_INLINE
+ACE_String_Base<CHAR>::ACE_String_Base (const ACE_String_Base<CHAR> &s)
+ : allocator_ (s.allocator_ ? s.allocator_ : ACE_Allocator::instance ()),
+ len_ (0),
+ buf_len_ (0),
+ rep_ (0),
+ release_ (0)
+{
+ ACE_TRACE ("ACE_String_Base<CHAR>::ACE_String_Base");
+
+ this->set (s.rep_, s.len_, 1);
+}
+
+template <class CHAR> ACE_INLINE
+ACE_String_Base<CHAR>::ACE_String_Base (size_t len, CHAR c, ACE_Allocator *alloc)
+ : allocator_ (alloc ? alloc : ACE_Allocator::instance ()),
+ len_ (0),
+ buf_len_ (0),
+ rep_ (0),
+ release_ (0)
+{
+ ACE_TRACE ("ACE_String_Base<CHAR>::ACE_String_Base");
+
+ this->resize (len, c);
+}
+
+template <class CHAR> ACE_INLINE
+ACE_String_Base<CHAR>::~ACE_String_Base (void)
+{
+ ACE_TRACE ("ACE_String_Base<CHAR>::~ACE_String_Base");
+
+ this->set (0, 0, 0);
+}
+
+template <class CHAR> ACE_INLINE void
+ACE_String_Base<CHAR>::dump (void) const
+{
+ ACE_TRACE ("ACE_String_Base<CHAR>::dump");
+}
+
+// Assignment operator (does copy memory).
+
+template <class CHAR> ACE_INLINE ACE_String_Base<CHAR> &
+ACE_String_Base<CHAR>::operator= (const ACE_String_Base<CHAR> &s)
+{
+ ACE_TRACE ("ACE_String_Base<CHAR>::operator=");
+
+ // Check for identify.
+ if (this != &s)
+ this->set (s.rep_, s.len_, 1);
+
+ return *this;
+}
+
+template <class CHAR> ACE_INLINE void
+ACE_String_Base<CHAR>::set (const CHAR *s, int release)
+{
+ size_t length;
+ if (s != 0)
+ length = ACE_OS::strlen (s);
+ else
+ length = 0;
+
+ this->set (s, length, release);
+}
+
+template <class CHAR> ACE_INLINE size_t
+ACE_String_Base<CHAR>::length (void) const
+{
+ ACE_TRACE ("ACE_String_Base<CHAR>::length");
+ return this->len_;
+}
+
+template <class CHAR> ACE_INLINE void
+ACE_String_Base<CHAR>::clear (int release)
+{
+ this->set(0, 0, release);
+}
+
+template <class CHAR> ACE_INLINE ACE_String_Base<CHAR>
+ACE_String_Base<CHAR>::substr (size_t offset,
+ ssize_t length) const
+{
+ return this->substring (offset, length);
+}
+
+// Return the <slot'th> character in the string.
+
+template <class CHAR> ACE_INLINE const CHAR &
+ACE_String_Base<CHAR>::operator[] (size_t slot) const
+{
+ ACE_TRACE ("ACE_String_Base<CHAR>::operator[]");
+ return this->rep_[slot];
+}
+
+// Return the <slot'th> character in the string by reference.
+
+template <class CHAR> ACE_INLINE CHAR &
+ACE_String_Base<CHAR>::operator[] (size_t slot)
+{
+ ACE_TRACE ("ACE_String_Base<CHAR>::operator[]");
+ return this->rep_[slot];
+}
+
+// Get a copy of the underlying representation.
+
+template <class CHAR> ACE_INLINE CHAR *
+ACE_String_Base<CHAR>::rep (void) const
+{
+ ACE_TRACE ("ACE_String_Base<CHAR>::rep");
+
+ CHAR *new_string;
+ ACE_NEW_RETURN (new_string, CHAR[this->len_ + 1], 0);
+ ACE_OS::strsncpy (new_string, this->rep_, this->len_+1);
+
+ return new_string;
+}
+
+template <class CHAR> ACE_INLINE const CHAR *
+ACE_String_Base<CHAR>::fast_rep (void) const
+{
+ return this->rep_;
+}
+
+template <class CHAR> ACE_INLINE const CHAR *
+ACE_String_Base<CHAR>::c_str (void) const
+{
+ return this->rep_;
+}
+
+// Comparison operator.
+
+template <class CHAR> ACE_INLINE int
+ACE_String_Base<CHAR>::operator== (const ACE_String_Base<CHAR> &s) const
+{
+ ACE_TRACE ("ACE_String_Base<CHAR>::operator==");
+
+ return this->len_ == s.len_
+ && ACE_OS::strncmp (this->rep_, s.rep_, this->len_) == 0;
+}
+
+// Less than comparison operator.
+
+template <class CHAR> ACE_INLINE int
+ACE_String_Base<CHAR>::operator < (const ACE_String_Base<CHAR> &s) const
+{
+ ACE_TRACE ("ACE_String_Base<CHAR>::operator <");
+
+ return (this->rep_ && s.rep_)
+ ? ACE_OS::strcmp (this->rep_, s.rep_) < 0
+ : ((s.rep_) ? 1 : 0 );
+}
+
+// Greater than comparison operator.
+
+template <class CHAR> ACE_INLINE int
+ACE_String_Base<CHAR>::operator > (const ACE_String_Base &s) const
+{
+ ACE_TRACE ("ACE_String_Base<CHAR>::operator >");
+
+ return (this->rep_ && s.rep_)
+ ? ACE_OS::strcmp (this->rep_, s.rep_) > 0
+ : ((this->rep_) ? 1 : 0 );
+}
+
+
+// Comparison operator.
+
+template <class CHAR> ACE_INLINE int
+ACE_String_Base<CHAR>::operator!= (const ACE_String_Base<CHAR> &s) const
+{
+ ACE_TRACE ("ACE_String_Base<CHAR>::operator!=");
+ return !(*this == s);
+}
+
+template <class CHAR> ACE_INLINE int
+ACE_String_Base<CHAR>::compare (const ACE_String_Base<CHAR> &s) const
+{
+ ACE_TRACE ("ACE_String_Base<CHAR>::compare");
+
+ // We can't just pass both strings to strcmp, since they are not
+ // guaranteed to be null-terminated.
+
+ // Pick smaller of the two lengths and perform the comparison.
+ int smaller_length = (this->len_ < s.len_) ? this->len_ : s.len_;
+ int result = ACE_OS::strncmp (this->rep_,
+ s.rep_,
+ smaller_length);
+
+ if (result != 0 || s.len_ == this->len_)
+ return result;
+
+ else
+ // we need to differentiate based on length
+ if (this->len_ > s.len_)
+ return (this->rep_[smaller_length] - '\0');
+
+ else
+ return ('\0' - s.rep_[smaller_length]);
+}
+
+template <class CHAR> ACE_INLINE int
+ACE_String_Base<CHAR>::find (const CHAR *s, int pos) const
+{
+ CHAR *substr = this->rep_ + pos;
+ size_t len = ACE_OS::strlen (s);
+ CHAR *pointer = ACE_OS::strnstr (substr, s, len);
+ if (pointer == 0)
+ return ACE_String_Base<CHAR>::npos;
+ else
+ return pointer - this->rep_;
+}
+
+template <class CHAR> ACE_INLINE int
+ACE_String_Base<CHAR>::find (CHAR c, int pos) const
+{
+ CHAR *substr = this->rep_ + pos;
+ CHAR *pointer = ACE_OS::strnchr (substr, c, this->len_ - pos);
+ if (pointer == 0)
+ return ACE_String_Base<CHAR>::npos;
+ else
+ return pointer - this->rep_;
+}
+
+template <class CHAR> ACE_INLINE int
+ACE_String_Base<CHAR>::find (const ACE_String_Base<CHAR> &str, int pos) const
+{
+ return this->find (str.rep_, pos);
+}
+
+template <class CHAR> ACE_INLINE int
+ACE_String_Base<CHAR>::strstr (const ACE_String_Base<CHAR> &s) const
+{
+ ACE_TRACE ("ACE_String_Base<CHAR>::strstr");
+
+ return this->find (s.rep_);
+}
+
+template <class CHAR> ACE_INLINE int
+ACE_String_Base<CHAR>::rfind (CHAR c, int pos) const
+{
+ if (pos == ACE_String_Base<CHAR>::npos)
+ pos = this->len_;
+
+ for (int i = pos - 1; i >= 0; i--)
+ if (this->rep_[i] == c)
+ return i;
+
+ return ACE_String_Base<CHAR>::npos;
+}
+
+template <class CHAR> ACE_INLINE u_long
+ACE_String_Base<CHAR>::hash (void) const
+{
+ return ACE::hash_pjw (
+ (ACE_reinterpret_cast (char *, ACE_const_cast (CHAR *,
+ this->rep_))),
+ this->len_ * sizeof (CHAR));
+}
+
+template <class CHAR> ACE_INLINE ACE_String_Base<CHAR>
+operator+ (const ACE_String_Base<CHAR> &s, const ACE_String_Base<CHAR> &t)
+{
+ ACE_String_Base<CHAR> temp (s);
+ temp += t;
+ return temp;
+}
+
+template <class CHAR> ACE_INLINE ACE_String_Base<CHAR>
+operator+ (const CHAR *s, const ACE_String_Base<CHAR> &t)
+{
+ ACE_String_Base<CHAR> temp (s);
+ temp += t;
+ return temp;
+}
+
+template <class CHAR> ACE_INLINE ACE_String_Base<CHAR>
+operator+ (const ACE_String_Base<CHAR> &s, const CHAR *t)
+{
+ ACE_String_Base<CHAR> temp (s);
+ temp += t;
+ return temp;
+}
diff --git a/ace/Utils/Test_and_Set.cpp b/ace/Utils/Test_and_Set.cpp
new file mode 100644
index 00000000000..73896eb387a
--- /dev/null
+++ b/ace/Utils/Test_and_Set.cpp
@@ -0,0 +1,49 @@
+// $Id$
+
+#ifndef ACE_TEST_AND_SET_C
+#define ACE_TEST_AND_SET_C
+
+#include "ace/Test_and_Set.h"
+#include "ace/Synch_T.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+ACE_RCSID(ace, Test_and_Set, "$Id$")
+
+template <class ACE_LOCK, class TYPE>
+ACE_Test_and_Set<ACE_LOCK, TYPE>::ACE_Test_and_Set (TYPE initial_value)
+ : is_set_ (initial_value)
+{
+}
+
+// Returns true if we are done, else false.
+template <class ACE_LOCK, class TYPE> TYPE
+ACE_Test_and_Set<ACE_LOCK, TYPE>::is_set (void) const
+{
+ ACE_GUARD_RETURN (ACE_LOCK, ace_mon, (ACE_LOCK &) this->lock_, this->is_set_);
+ return this->is_set_;
+}
+
+// Sets the <is_set_> status.
+template <class ACE_LOCK, class TYPE> TYPE
+ACE_Test_and_Set<ACE_LOCK, TYPE>::set (TYPE status)
+{
+ ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->lock_, this->is_set_);
+ TYPE o_status = this->is_set_;
+ this->is_set_ = status;
+ return o_status;
+}
+
+template <class ACE_LOCK, class TYPE> int
+ACE_Test_and_Set<ACE_LOCK, TYPE>::handle_signal (int, siginfo_t *, ucontext_t *)
+{
+ // By setting this to 1, we are "signaling" to anyone calling
+ // <is_set> or or <set> that the "test and set" object is in the
+ // "signaled" state, i.e., it's "available" to be set back to 0.
+ this->set (1);
+ return 0;
+}
+
+#endif /* ACE_TEST_AND_SET_C */
diff --git a/ace/Utils/Test_and_Set.h b/ace/Utils/Test_and_Set.h
new file mode 100644
index 00000000000..4def53af1bd
--- /dev/null
+++ b/ace/Utils/Test_and_Set.h
@@ -0,0 +1,76 @@
+
+//=============================================================================
+/**
+ * @file Test_and_Set.h
+ *
+ * $Id$
+ *
+ * @author Priyanka Gontla <pgontla@ece.uci.edu>
+ */
+//=============================================================================
+
+
+#ifndef ACE_TEST_AND_SET_H
+#define ACE_TEST_AND_SET_H
+
+#include "ace/pre.h"
+#include "ace/Event_Handler.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+/**
+ * @class ACE_Test_and_Set
+ *
+ * @brief Implements the classic ``test and set'' operation.
+ *
+ *
+ * This class keeps track of the status of <is_set_>, which can
+ * be set based on various events (such as receipt of a
+ * signal). This class is derived from <ACE_Event_Handler> so
+ * that it can be "signaled" by a Reactor when a signal occurs.
+ * We assume that <TYPE> is a data type that can be assigned the
+ * value 0 or 1.
+ */
+template <class ACE_LOCK, class TYPE>
+class ACE_Test_and_Set : public ACE_Event_Handler
+{
+public:
+ ACE_Test_and_Set (TYPE initial_value = 0);
+
+ /// Returns true if we are set, else false.
+ TYPE is_set (void) const;
+
+ /// Sets the <is_set_> status, returning the original value of
+ /// <is_set_>.
+ TYPE set (TYPE);
+
+ /// Called when object is signaled by OS (either via UNIX signals or
+ /// when a Win32 object becomes signaled).
+ virtual int handle_signal (int signum,
+ siginfo_t * = 0,
+ ucontext_t * = 0);
+
+private:
+ /// Keeps track of our state.
+ TYPE is_set_;
+
+ /// Protect the state from race conditions.
+ ACE_LOCK lock_;
+};
+
+#if defined (__ACE_INLINE__)
+#include "ace/Test_and_Set.i"
+#endif /* __ACE_INLINE__ */
+
+#if defined (ACE_TEMPLATES_REQUIRE_SOURCE)
+#include "ace/Test_and_Set.cpp"
+#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */
+
+#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA)
+#pragma implementation ("Test_and_Set.cpp")
+#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */
+
+#include "ace/post.h"
+#endif /* ACE_TEST_AND_SET_H */
diff --git a/ace/Utils/Test_and_Set.i b/ace/Utils/Test_and_Set.i
new file mode 100644
index 00000000000..cfa1da318d3
--- /dev/null
+++ b/ace/Utils/Test_and_Set.i
@@ -0,0 +1 @@
+// $Id$
diff --git a/ace/Utils/Unbounded_Queue.cpp b/ace/Utils/Unbounded_Queue.cpp
new file mode 100644
index 00000000000..c5aad55fd31
--- /dev/null
+++ b/ace/Utils/Unbounded_Queue.cpp
@@ -0,0 +1,426 @@
+// $Id$
+
+#ifndef ACE_UNBOUNDED_QUEUE_C
+#define ACE_UNBOUNDED_QUEUE_C
+
+#include "ace/Unbounded_Queue.h"
+#include "ace/Malloc_Base.h"
+#include "ace/Log_Msg.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#if !defined (__ACE_INLINE__)
+#include "ace/Unbounded_Queue.inl"
+#endif /* __ACE_INLINE__ */
+
+ACE_RCSID(ace, Unbounded_Queue, "$Id$")
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Unbounded_Queue)
+
+template <class T>
+ACE_Unbounded_Queue<T>::ACE_Unbounded_Queue (ACE_Allocator *alloc)
+ : head_ (0),
+ cur_size_ (0),
+ allocator_ (alloc)
+{
+ // ACE_TRACE ("ACE_Unbounded_Queue<T>::ACE_Unbounded_Queue (void)");
+
+ if (this->allocator_ == 0)
+ this->allocator_ = ACE_Allocator::instance ();
+
+ ACE_NEW_MALLOC (this->head_,
+ (ACE_Node<T> *) this->allocator_->malloc (sizeof (ACE_Node<T>)),
+ ACE_Node<T>);
+ // Make the list circular by pointing it back to itself.
+ this->head_->next_ = this->head_;
+}
+
+template <class T>
+ACE_Unbounded_Queue<T>::ACE_Unbounded_Queue (const ACE_Unbounded_Queue<T> &us)
+ : head_ (0),
+ cur_size_ (0),
+ allocator_ (us.allocator_)
+{
+ // ACE_TRACE ("ACE_Unbounded_Queue<T>::ACE_Unbounded_Queue");
+
+ if (this->allocator_ == 0)
+ this->allocator_ = ACE_Allocator::instance ();
+
+ ACE_NEW_MALLOC (this->head_,
+ (ACE_Node<T> *) this->allocator_->malloc (sizeof (ACE_Node<T>)),
+ ACE_Node<T>);
+ this->head_->next_ = this->head_;
+ this->copy_nodes (us);
+}
+
+template <class T> void
+ACE_Unbounded_Queue<T>::operator= (const ACE_Unbounded_Queue<T> &us)
+{
+ // ACE_TRACE ("ACE_Unbounded_Queue<T>::operator=");
+
+ if (this != &us)
+ {
+ this->delete_nodes ();
+ this->copy_nodes (us);
+ }
+}
+
+template <class T> ACE_Unbounded_Queue_Iterator<T>
+ACE_Unbounded_Queue<T>::begin (void)
+{
+ // ACE_TRACE ("ACE_Unbounded_Queue<T>::begin");
+ return ACE_Unbounded_Queue_Iterator<T> (*this);
+}
+
+template <class T> ACE_Unbounded_Queue_Iterator<T>
+ACE_Unbounded_Queue<T>::end (void)
+{
+ // ACE_TRACE ("ACE_Unbounded_Queue<T>::end");
+ return ACE_Unbounded_Queue_Iterator<T> (*this, 1);
+}
+
+template <class T> void
+ACE_Unbounded_Queue<T>::dump (void) const
+{
+ // ACE_TRACE ("ACE_Unbounded_Queue<T>::dump");
+
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\nhead_ = %u"), this->head_));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\nhead_->next_ = %u"), this->head_->next_));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\ncur_size_ = %d\n"), this->cur_size_));
+
+ T *item = 0;
+#if !defined (ACE_NLOGGING)
+ size_t count = 1;
+#endif /* ! ACE_NLOGGING */
+
+ for (ACE_Unbounded_Queue_Iterator<T> iter (*(ACE_Unbounded_Queue<T> *) this);
+ iter.next (item) != 0;
+ iter.advance ())
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("count = %d\n"), count++));
+
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+template <class T> void
+ACE_Unbounded_Queue<T>::copy_nodes (const ACE_Unbounded_Queue<T> &us)
+{
+ for (ACE_Node<T> *curr = us.head_->next_;
+ curr != us.head_;
+ curr = curr->next_)
+ if (this->enqueue_tail (curr->item_) == -1)
+ // @@ What's the right thing to do here?
+ this->delete_nodes ();
+}
+
+template <class T> void
+ACE_Unbounded_Queue<T>::delete_nodes (void)
+{
+ for (ACE_Node<T> *curr = this->head_->next_;
+ // Keep looking until we've hit the dummy node.
+ curr != this->head_;
+ )
+ {
+ ACE_Node<T> *temp = curr;
+ curr = curr->next_;
+
+ ACE_DES_FREE_TEMPLATE (temp,
+ this->allocator_->free,
+ ACE_Node,
+ <T>);
+ this->cur_size_--;
+ // @@ Doesnt make sense to have this check since
+ // this will always be true.
+ // ACE_ASSERT (this->cur_size_ >= 0);
+ }
+
+ // Reset the list to be a circular list with just a dummy node.
+ this->head_->next_ = this->head_;
+}
+
+template <class T>
+ACE_Unbounded_Queue<T>::~ACE_Unbounded_Queue (void)
+{
+ // ACE_TRACE ("ACE_Unbounded_Queue<T>::~ACE_Unbounded_Queue (void)");
+
+ this->delete_nodes ();
+ ACE_DES_FREE_TEMPLATE (head_,
+ this->allocator_->free,
+ ACE_Node,
+ <T>);
+ this->head_ = 0;
+}
+
+template <class T> int
+ACE_Unbounded_Queue<T>::enqueue_head (const T &new_item)
+{
+ // ACE_TRACE ("ACE_Unbounded_Queue<T>::enqueue_head");
+
+ ACE_Node<T> *temp;
+
+ // Create a new node that points to the original head.
+ ACE_NEW_MALLOC_RETURN (temp,
+ ACE_static_cast(ACE_Node<T> *,
+ this->allocator_->malloc (sizeof (ACE_Node<T>))),
+ ACE_Node<T> (new_item, this->head_->next_),
+ -1);
+ // Link this pointer into the front of the list. Note that the
+ // "real" head of the queue is <head_->next_>, whereas <head_> is
+ // just a pointer to the dummy node.
+ this->head_->next_ = temp;
+
+ this->cur_size_++;
+ return 0;
+}
+
+template <class T> int
+ACE_Unbounded_Queue<T>::enqueue_tail (const T &new_item)
+{
+ // ACE_TRACE ("ACE_Unbounded_Queue<T>::enqueue_tail");
+
+ // Insert <item> into the old dummy node location. Note that this
+ // isn't actually the "head" item in the queue, it's a dummy node at
+ // the "tail" of the queue...
+ this->head_->item_ = new_item;
+
+ ACE_Node<T> *temp;
+
+ // Create a new dummy node.
+ ACE_NEW_MALLOC_RETURN (temp,
+ ACE_static_cast(ACE_Node<T> *,
+ this->allocator_->malloc (sizeof (ACE_Node<T>))),
+ ACE_Node<T> (this->head_->next_),
+ -1);
+ // Link this dummy pointer into the list.
+ this->head_->next_ = temp;
+
+ // Point the head to the new dummy node.
+ this->head_ = temp;
+
+ this->cur_size_++;
+ return 0;
+}
+
+template <class T> int
+ACE_Unbounded_Queue<T>::dequeue_head (T &item)
+{
+ // ACE_TRACE ("ACE_Unbounded_Queue<T>::dequeue_head");
+
+ // Check for empty queue.
+ if (this->is_empty ())
+ return -1;
+
+ ACE_Node<T> *temp = this->head_->next_;
+
+ item = temp->item_;
+ this->head_->next_ = temp->next_;
+ ACE_DES_FREE_TEMPLATE (temp,
+ this->allocator_->free,
+ ACE_Node,
+ <T>);
+ --this->cur_size_;
+ return 0;
+}
+
+template <class T> void
+ACE_Unbounded_Queue<T>::reset (void)
+{
+ ACE_TRACE ("reset");
+
+ this->delete_nodes ();
+}
+
+template <class T> int
+ACE_Unbounded_Queue<T>::get (T *&item, size_t slot) const
+{
+ // ACE_TRACE ("ACE_Unbounded_Queue<T>::get");
+
+ ACE_Node<T> *curr = this->head_->next_;
+
+ size_t i;
+
+ for (i = 0; i < this->cur_size_; i++)
+ {
+ if (i == slot)
+ break;
+
+ curr = curr->next_;
+ }
+
+ if (i < this->cur_size_)
+ {
+ item = &curr->item_;
+ return 0;
+ }
+ else
+ return -1;
+}
+
+template <class T> int
+ACE_Unbounded_Queue<T>::set (const T &item,
+ size_t slot)
+{
+ // ACE_TRACE ("ACE_Unbounded_Queue<T>::set");
+
+ ACE_Node<T> *curr = this->head_->next_;
+
+ size_t i;
+
+ for (i = 0;
+ i < slot && i < this->cur_size_;
+ i++)
+ curr = curr->next_;
+
+ if (i < this->cur_size_)
+ {
+ // We're in range, so everything's cool.
+ curr->item_ = item;
+ return 0;
+ }
+ else
+ {
+ // We need to expand the list.
+
+ // A common case will be increasing the set size by 1.
+ // Therefore, we'll optimize for this case.
+ if (i == slot)
+ {
+ // Try to expand the size of the set by 1.
+ if (this->enqueue_tail (item) == -1)
+ return -1;
+ else
+ return 0;
+ }
+ else
+ {
+ T dummy;
+
+ // We need to expand the list by multiple (dummy) items.
+ for (; i < slot; i++)
+ {
+ // This head points to the existing dummy node, which is
+ // about to be overwritten when we add the new dummy
+ // node.
+ curr = this->head_;
+
+ // Try to expand the size of the set by 1, but don't
+ // store anything in the dummy node (yet).
+ if (this->enqueue_tail (dummy) == -1)
+ return -1;
+ }
+
+ curr->item_ = item;
+ return 0;
+ }
+ }
+}
+
+// ****************************************************************
+
+template <class T> void
+ACE_Unbounded_Queue_Const_Iterator<T>::dump (void) const
+{
+ // ACE_TRACE ("ACE_Unbounded_Queue_Const_Iterator<T>::dump");
+}
+
+template <class T>
+ACE_Unbounded_Queue_Const_Iterator<T>::ACE_Unbounded_Queue_Const_Iterator (const ACE_Unbounded_Queue<T> &q, int end)
+ : current_ (end == 0 ? q.head_->next_ : q.head_ ),
+ queue_ (q)
+{
+ // ACE_TRACE ("ACE_Unbounded_Queue_Const_Iterator<T>::ACE_Unbounded_Queue_Const_Iterator");
+}
+
+template <class T> int
+ACE_Unbounded_Queue_Const_Iterator<T>::advance (void)
+{
+ // ACE_TRACE ("ACE_Unbounded_Queue_Const_Iterator<T>::advance");
+ this->current_ = this->current_->next_;
+ return this->current_ != this->queue_.head_;
+}
+
+template <class T> int
+ACE_Unbounded_Queue_Const_Iterator<T>::first (void)
+{
+ // ACE_TRACE ("ACE_Unbounded_Queue_Const_Iterator<T>::first");
+ this->current_ = this->queue_.head_->next_;
+ return this->current_ != this->queue_.head_;
+}
+
+template <class T> int
+ACE_Unbounded_Queue_Const_Iterator<T>::done (void) const
+{
+ ACE_TRACE ("ACE_Unbounded_Queue_Const_Iterator<T>::done");
+
+ return this->current_ == this->queue_.head_;
+}
+
+template <class T> int
+ACE_Unbounded_Queue_Const_Iterator<T>::next (T *&item)
+{
+ // ACE_TRACE ("ACE_Unbounded_Queue_Const_Iterator<T>::next");
+ if (this->current_ == this->queue_.head_)
+ return 0;
+ else
+ {
+ item = &this->current_->item_;
+ return 1;
+ }
+}
+
+// ****************************************************************
+
+template <class T> void
+ACE_Unbounded_Queue_Iterator<T>::dump (void) const
+{
+ // ACE_TRACE ("ACE_Unbounded_Queue_Iterator<T>::dump");
+}
+
+template <class T>
+ACE_Unbounded_Queue_Iterator<T>::ACE_Unbounded_Queue_Iterator (ACE_Unbounded_Queue<T> &q, int end)
+ : current_ (end == 0 ? q.head_->next_ : q.head_ ),
+ queue_ (q)
+{
+ // ACE_TRACE ("ACE_Unbounded_Queue_Iterator<T>::ACE_Unbounded_Queue_Iterator");
+}
+
+template <class T> int
+ACE_Unbounded_Queue_Iterator<T>::advance (void)
+{
+ // ACE_TRACE ("ACE_Unbounded_Queue_Iterator<T>::advance");
+ this->current_ = this->current_->next_;
+ return this->current_ != this->queue_.head_;
+}
+
+template <class T> int
+ACE_Unbounded_Queue_Iterator<T>::first (void)
+{
+ // ACE_TRACE ("ACE_Unbounded_Queue_Iterator<T>::first");
+ this->current_ = this->queue_.head_->next_;
+ return this->current_ != this->queue_.head_;
+}
+
+template <class T> int
+ACE_Unbounded_Queue_Iterator<T>::done (void) const
+{
+ ACE_TRACE ("ACE_Unbounded_Queue_Iterator<T>::done");
+
+ return this->current_ == this->queue_.head_;
+}
+
+template <class T> int
+ACE_Unbounded_Queue_Iterator<T>::next (T *&item)
+{
+ // ACE_TRACE ("ACE_Unbounded_Queue_Iterator<T>::next");
+ if (this->current_ == this->queue_.head_)
+ return 0;
+ else
+ {
+ item = &this->current_->item_;
+ return 1;
+ }
+}
+
+#endif /* ACE_UNBOUNDED_QUEUE_C */
diff --git a/ace/Utils/Unbounded_Queue.h b/ace/Utils/Unbounded_Queue.h
new file mode 100644
index 00000000000..e245ecc4738
--- /dev/null
+++ b/ace/Utils/Unbounded_Queue.h
@@ -0,0 +1,234 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Unbounded_Queue.h
+ *
+ * $Id$
+ *
+ * @author Doug Schmidt
+ */
+//=============================================================================
+
+
+#ifndef ACE_UNBOUNDED_QUEUE_H
+#define ACE_UNBOUNDED_QUEUE_H
+#include "ace/pre.h"
+
+#include "ace/Node.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+// For size_t under Chorus
+#include "ace/OS_Memory.h"
+
+class ACE_Allocator;
+
+template <class T>
+class ACE_Unbounded_Queue;
+
+/**
+ * @class ACE_Unbounded_Queue_Iterator
+ *
+ * @brief Implement an iterator over an unbounded queue.
+ */
+template <class T>
+class ACE_Unbounded_Queue_Iterator
+{
+public:
+ // = Initialization method.
+ ACE_Unbounded_Queue_Iterator (ACE_Unbounded_Queue<T> &q, int end = 0);
+
+ // = Iteration methods.
+
+ /// Pass back the <next_item> that hasn't been seen in the queue.
+ /// Returns 0 when all items have been seen, else 1.
+ int next (T *&next_item);
+
+ /// Move forward by one element in the set. Returns 0 when all the
+ /// items in the queue have been seen, else 1.
+ int advance (void);
+
+ /// Move to the first element in the queue. Returns 0 if the
+ /// queue is empty, else 1.
+ int first (void);
+
+ /// Returns 1 when all items have been seen, else 0.
+ int done (void) const;
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+private:
+ /// Pointer to the current node in the iteration.
+ ACE_Node<T> *current_;
+
+ /// Pointer to the queue we're iterating over.
+ ACE_Unbounded_Queue<T> &queue_;
+};
+
+/**
+ * @class ACE_Unbounded_Queue_Const_Iterator
+ *
+ * @brief Implement an iterator over an const unbounded queue.
+ */
+template <class T>
+class ACE_Unbounded_Queue_Const_Iterator
+{
+public:
+ // = Initialization method.
+ ACE_Unbounded_Queue_Const_Iterator (const ACE_Unbounded_Queue<T> &q, int end = 0);
+
+ // = Iteration methods.
+
+ /// Pass back the <next_item> that hasn't been seen in the queue.
+ /// Returns 0 when all items have been seen, else 1.
+ int next (T *&next_item);
+
+ /// Move forward by one element in the set. Returns 0 when all the
+ /// items in the queue have been seen, else 1.
+ int advance (void);
+
+ /// Move to the first element in the queue. Returns 0 if the
+ /// queue is empty, else 1.
+ int first (void);
+
+ /// Returns 1 when all items have been seen, else 0.
+ int done (void) const;
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+private:
+ /// Pointer to the current node in the iteration.
+ ACE_Node<T> *current_;
+
+ /// Pointer to the queue we're iterating over.
+ const ACE_Unbounded_Queue<T> &queue_;
+};
+
+/**
+ * @class ACE_Unbounded_Queue
+ *
+ * @brief A Queue of "infinite" length.
+ *
+ * This implementation of an unbounded queue uses a circular
+ * linked list with a dummy node.
+ */
+template <class T>
+class ACE_Unbounded_Queue
+{
+public:
+ friend class ACE_Unbounded_Queue_Iterator<T>;
+ friend class ACE_Unbounded_Queue_Const_Iterator<T>;
+
+ // Trait definition.
+ typedef ACE_Unbounded_Queue_Iterator<T> ITERATOR;
+ typedef ACE_Unbounded_Queue_Const_Iterator<T> CONST_ITERATOR;
+
+ // = Initialization and termination methods.
+ /// construction. Use user specified allocation strategy
+ /// if specified.
+ ACE_Unbounded_Queue (ACE_Allocator *alloc = 0);
+
+ /// Copy constructor.
+ ACE_Unbounded_Queue (const ACE_Unbounded_Queue<T> &);
+
+ /// Assignment operator.
+ void operator= (const ACE_Unbounded_Queue<T> &);
+
+ /// Destructor.
+ ~ACE_Unbounded_Queue (void);
+
+ // = Check boundary conditions.
+
+ /// Returns 1 if the container is empty, otherwise returns 0.
+ int is_empty (void) const;
+
+ /// Returns 1 if the container is full, otherwise returns 0.
+ int is_full (void) const;
+
+ // = Classic queue operations.
+
+ /// Adds <new_item> to the tail of the queue. Returns 0 on success,
+ /// -1 on failure.
+ int enqueue_tail (const T &new_item);
+
+ /// Adds <new_item> to the head of the queue. Returns 0 on success,
+ /// -1 on failure.
+ int enqueue_head (const T &new_item);
+
+ /// Removes and returns the first <item> on the queue. Returns 0 on
+ /// success, -1 if the queue was empty.
+ int dequeue_head (T &item);
+
+ // = Additional utility methods.
+
+ /// Reset the <ACE_Unbounded_Queue> to be empty and release all its
+ /// dynamically allocated resources.
+ void reset (void);
+
+ /// Get the <slot>th element in the set. Returns -1 if the element
+ /// isn't in the range {0..<size> - 1}, else 0.
+ int get (T *&item, size_t slot = 0) const;
+
+ /**
+ * Set the <slot>th element in the set. Will pad out the set with
+ * empty nodes if <slot> is beyond the range {0..<size> - 1}.
+ * Returns -1 on failure, 0 if <slot> isn't initially in range, and
+ * 0 otherwise.
+ */
+ int set (const T &item, size_t slot);
+
+ /// The number of items in the queue.
+ size_t size (void) const;
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ // = STL-styled unidirectional iterator factory.
+ ACE_Unbounded_Queue_Iterator<T> begin (void);
+ ACE_Unbounded_Queue_Iterator<T> end (void);
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+protected:
+ /// Delete all the nodes in the queue.
+ void delete_nodes (void);
+
+ /// Copy nodes into this queue.
+ void copy_nodes (const ACE_Unbounded_Queue<T> &);
+
+ /// Pointer to the dummy node in the circular linked Queue.
+ ACE_Node<T> *head_;
+
+ /// Current size of the queue.
+ size_t cur_size_;
+
+ /// Allocation Strategy of the queue.
+ ACE_Allocator *allocator_;
+};
+
+#if defined (__ACE_INLINE__)
+#include "ace/Unbounded_Queue.inl"
+#endif /* __ACE_INLINE__ */
+
+#if defined (ACE_TEMPLATES_REQUIRE_SOURCE)
+#include "ace/Unbounded_Queue.cpp"
+#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */
+
+#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA)
+#pragma implementation ("Unbounded_Queue.cpp")
+#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */
+
+#include "ace/post.h"
+#endif /* ACE_UNBOUNDED_QUEUE_H */
diff --git a/ace/Utils/Unbounded_Queue.inl b/ace/Utils/Unbounded_Queue.inl
new file mode 100644
index 00000000000..ea552e7d3d8
--- /dev/null
+++ b/ace/Utils/Unbounded_Queue.inl
@@ -0,0 +1,21 @@
+// $Id$
+
+template <class T> ACE_INLINE size_t
+ACE_Unbounded_Queue<T>::size (void) const
+{
+ return this->cur_size_;
+}
+
+template <class T> ACE_INLINE int
+ACE_Unbounded_Queue<T>::is_empty (void) const
+{
+ // ACE_TRACE ("ACE_Unbounded_Queue<T>::is_empty");
+ return this->head_ == this->head_->next_;
+}
+
+template <class T> ACE_INLINE int
+ACE_Unbounded_Queue<T>::is_full (void) const
+{
+ // ACE_TRACE ("ACE_Unbounded_Queue<T>::is_full");
+ return 0; // We should implement a "node of last resort for this..."
+}
diff --git a/ace/Utils/Unbounded_Set.cpp b/ace/Utils/Unbounded_Set.cpp
new file mode 100644
index 00000000000..e1cf0708e6a
--- /dev/null
+++ b/ace/Utils/Unbounded_Set.cpp
@@ -0,0 +1,443 @@
+// $Id$
+
+#ifndef ACE_UNBOUNDED_SET_C
+#define ACE_UNBOUNDED_SET_C
+
+#include "ace/Unbounded_Set.h"
+#include "ace/Malloc_Base.h"
+#include "ace/Log_Msg.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#if !defined (__ACE_INLINE__)
+#include "ace/Unbounded_Set.inl"
+#endif /* __ACE_INLINE__ */
+
+ACE_RCSID(ace, Unbounded_Set, "$Id$")
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Unbounded_Set)
+
+ template <class T> size_t
+ACE_Unbounded_Set<T>::size (void) const
+{
+ // ACE_TRACE ("ACE_Unbounded_Set<T>::size");
+ return this->cur_size_;
+}
+
+template <class T> int
+ACE_Unbounded_Set<T>::insert_tail (const T &item)
+{
+ // ACE_TRACE ("ACE_Unbounded_Set<T>::insert_tail");
+ ACE_Node<T> *temp;
+
+ // Insert <item> into the old dummy node location.
+ this->head_->item_ = item;
+
+ // Create a new dummy node.
+ ACE_NEW_MALLOC_RETURN (temp,
+ ACE_static_cast(ACE_Node<T>*,
+ this->allocator_->malloc (sizeof (ACE_Node<T>))),
+ ACE_Node<T> (this->head_->next_),
+ -1);
+ // Link this pointer into the list.
+ this->head_->next_ = temp;
+
+ // Point the head to the new dummy node.
+ this->head_ = temp;
+
+ this->cur_size_++;
+ return 0;
+}
+
+template <class T> void
+ACE_Unbounded_Set<T>::reset (void)
+{
+ ACE_TRACE ("reset");
+
+ this->delete_nodes ();
+}
+
+template <class T> void
+ACE_Unbounded_Set<T>::dump (void) const
+{
+ ACE_TRACE ("ACE_Unbounded_Set<T>::dump");
+
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\nhead_ = %u"), this->head_));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\nhead_->next_ = %u"), this->head_->next_));
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("\ncur_size_ = %d\n"), this->cur_size_));
+
+ T *item = 0;
+#if !defined (ACE_NLOGGING)
+ size_t count = 1;
+#endif /* ! ACE_NLOGGING */
+
+ for (ACE_Unbounded_Set_Iterator<T> iter (*(ACE_Unbounded_Set<T> *) this);
+ iter.next (item) != 0;
+ iter.advance ())
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT ("count = %d\n"), count++));
+
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+template <class T> void
+ACE_Unbounded_Set<T>::copy_nodes (const ACE_Unbounded_Set<T> &us)
+{
+ for (ACE_Node<T> *curr = us.head_->next_;
+ curr != us.head_;
+ curr = curr->next_)
+ this->insert_tail (curr->item_);
+}
+
+template <class T> void
+ACE_Unbounded_Set<T>::delete_nodes (void)
+{
+ ACE_Node<T> *curr = this->head_->next_;
+
+ // Keep looking until we've hit the dummy node.
+
+ while (curr != this->head_)
+ {
+ ACE_Node<T> *temp = curr;
+ curr = curr->next_;
+ ACE_DES_FREE_TEMPLATE (temp,
+ this->allocator_->free,
+ ACE_Node,
+ <T>);
+ this->cur_size_--;
+ }
+
+ // Reset the list to be a circular list with just a dummy node.
+ this->head_->next_ = this->head_;
+}
+
+template <class T>
+ACE_Unbounded_Set<T>::~ACE_Unbounded_Set (void)
+{
+ // ACE_TRACE ("ACE_Unbounded_Set<T>::~ACE_Unbounded_Set");
+
+ this->delete_nodes ();
+
+ // Delete the dummy node.
+ ACE_DES_FREE_TEMPLATE (head_,
+ this->allocator_->free,
+ ACE_Node,
+ <T>);
+ this->head_ = 0;
+}
+
+template <class T>
+ACE_Unbounded_Set<T>::ACE_Unbounded_Set (ACE_Allocator *alloc)
+ : head_ (0),
+ cur_size_ (0),
+ allocator_ (alloc)
+{
+ // ACE_TRACE ("ACE_Unbounded_Set<T>::ACE_Unbounded_Set");
+
+ if (this->allocator_ == 0)
+ this->allocator_ = ACE_Allocator::instance ();
+
+ ACE_NEW_MALLOC (this->head_,
+ (ACE_Node<T>*) this->allocator_->malloc (sizeof (ACE_Node<T>)),
+ ACE_Node<T>);
+ // Make the list circular by pointing it back to itself.
+ this->head_->next_ = this->head_;
+}
+
+template <class T>
+ACE_Unbounded_Set<T>::ACE_Unbounded_Set (const ACE_Unbounded_Set<T> &us)
+ : head_ (0),
+ cur_size_ (0),
+ allocator_ (us.allocator_)
+{
+ ACE_TRACE ("ACE_Unbounded_Set<T>::ACE_Unbounded_Set");
+
+ if (this->allocator_ == 0)
+ this->allocator_ = ACE_Allocator::instance ();
+
+ ACE_NEW_MALLOC (this->head_,
+ (ACE_Node<T>*) this->allocator_->malloc (sizeof (ACE_Node<T>)),
+ ACE_Node<T>);
+ this->head_->next_ = this->head_;
+ this->copy_nodes (us);
+}
+
+template <class T> void
+ACE_Unbounded_Set<T>::operator= (const ACE_Unbounded_Set<T> &us)
+{
+ ACE_TRACE ("ACE_Unbounded_Set<T>::operator=");
+
+ if (this != &us)
+ {
+ this->delete_nodes ();
+ this->copy_nodes (us);
+ }
+}
+
+template <class T> int
+ACE_Unbounded_Set<T>::find (const T &item) const
+{
+ // ACE_TRACE ("ACE_Unbounded_Set<T>::find");
+ // Set <item> into the dummy node.
+ this->head_->item_ = item;
+
+ ACE_Node<T> *temp = this->head_->next_;
+
+ // Keep looping until we find the item.
+ while (!(temp->item_ == item))
+ temp = temp->next_;
+
+ // If we found the dummy node then it's not really there, otherwise,
+ // it is there.
+ return temp == this->head_ ? -1 : 0;
+}
+
+template <class T> int
+ACE_Unbounded_Set<T>::insert (const T &item)
+{
+ // ACE_TRACE ("ACE_Unbounded_Set<T>::insert");
+ if (this->find (item) == 0)
+ return 1;
+ else
+ return this->insert_tail (item);
+}
+
+template <class T> int
+ACE_Unbounded_Set<T>::remove (const T &item)
+{
+ // ACE_TRACE ("ACE_Unbounded_Set<T>::remove");
+
+ // Insert the item to be founded into the dummy node.
+ this->head_->item_ = item;
+
+ ACE_Node<T> *curr = this->head_;
+
+ while (!(curr->next_->item_ == item))
+ curr = curr->next_;
+
+ if (curr->next_ == this->head_)
+ return -1; // Item was not found.
+ else
+ {
+ ACE_Node<T> *temp = curr->next_;
+ // Skip over the node that we're deleting.
+ curr->next_ = temp->next_;
+ this->cur_size_--;
+ ACE_DES_FREE_TEMPLATE (temp,
+ this->allocator_->free,
+ ACE_Node,
+ <T>);
+ return 0;
+ }
+}
+
+template <class T> ACE_Unbounded_Set_Iterator<T>
+ACE_Unbounded_Set<T>::begin (void)
+{
+ // ACE_TRACE ("ACE_Unbounded_Set<T>::begin");
+ return ACE_Unbounded_Set_Iterator<T> (*this);
+}
+
+template <class T> ACE_Unbounded_Set_Iterator<T>
+ACE_Unbounded_Set<T>::end (void)
+{
+ // ACE_TRACE ("ACE_Unbounded_Set<T>::end");
+ return ACE_Unbounded_Set_Iterator<T> (*this, 1);
+}
+
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Unbounded_Set_Iterator)
+
+ template <class T> void
+ACE_Unbounded_Set_Iterator<T>::dump (void) const
+{
+ // ACE_TRACE ("ACE_Unbounded_Set_Iterator<T>::dump");
+}
+
+template <class T>
+ACE_Unbounded_Set_Iterator<T>::ACE_Unbounded_Set_Iterator (ACE_Unbounded_Set<T> &s, int end)
+ : current_ (end == 0 ? s.head_->next_ : s.head_ ),
+ set_ (&s)
+{
+ // ACE_TRACE ("ACE_Unbounded_Set_Iterator<T>::ACE_Unbounded_Set_Iterator");
+}
+
+template <class T> int
+ACE_Unbounded_Set_Iterator<T>::advance (void)
+{
+ // ACE_TRACE ("ACE_Unbounded_Set_Iterator<T>::advance");
+ this->current_ = this->current_->next_;
+ return this->current_ != this->set_->head_;
+}
+
+template <class T> int
+ACE_Unbounded_Set_Iterator<T>::first (void)
+{
+ // ACE_TRACE ("ACE_Unbounded_Set_Iterator<T>::first");
+ this->current_ = this->set_->head_->next_;
+ return this->current_ != this->set_->head_;
+}
+
+template <class T> int
+ACE_Unbounded_Set_Iterator<T>::done (void) const
+{
+ ACE_TRACE ("ACE_Unbounded_Set_Iterator<T>::done");
+
+ return this->current_ == this->set_->head_;
+}
+
+template <class T> int
+ACE_Unbounded_Set_Iterator<T>::next (T *&item)
+{
+ // ACE_TRACE ("ACE_Unbounded_Set_Iterator<T>::next");
+ if (this->current_ == this->set_->head_)
+ return 0;
+ else
+ {
+ item = &this->current_->item_;
+ return 1;
+ }
+}
+
+template <class T> ACE_Unbounded_Set_Iterator<T>
+ACE_Unbounded_Set_Iterator<T>::operator++ (int)
+{
+ //ACE_TRACE ("ACE_Unbounded_Set_Iterator<T>::operator++ (int)");
+ ACE_Unbounded_Set_Iterator<T> retv (*this);
+
+ // postfix operator
+
+ this->advance ();
+ return retv;
+}
+
+template <class T> ACE_Unbounded_Set_Iterator<T>&
+ACE_Unbounded_Set_Iterator<T>::operator++ (void)
+{
+ // ACE_TRACE ("ACE_Unbounded_Set_Iterator<T>::operator++ (void)");
+
+ // prefix operator
+
+ this->advance ();
+ return *this;
+}
+
+template <class T> T&
+ACE_Unbounded_Set_Iterator<T>::operator* (void)
+{
+ //ACE_TRACE ("ACE_Unbounded_Set_Iterator<T>::operator*");
+ T *retv = 0;
+
+ int result = this->next (retv);
+ ACE_ASSERT (result != 0);
+ ACE_UNUSED_ARG (result);
+
+ return *retv;
+}
+
+template <class T> int
+ACE_Unbounded_Set_Iterator<T>::operator== (const ACE_Unbounded_Set_Iterator<T> &rhs) const
+{
+ //ACE_TRACE ("ACE_Unbounded_Set_Iterator<T>::operator==");
+ return (this->set_ == rhs.set_ && this->current_ == rhs.current_);
+}
+
+template <class T> int
+ACE_Unbounded_Set_Iterator<T>::operator!= (const ACE_Unbounded_Set_Iterator<T> &rhs) const
+{
+ //ACE_TRACE ("ACE_Unbounded_Set_Iterator<T>::operator!=");
+ return (this->set_ != rhs.set_ || this->current_ != rhs.current_);
+}
+
+ACE_ALLOC_HOOK_DEFINE(ACE_Unbounded_Set_Const_Iterator)
+
+template <class T> void
+ACE_Unbounded_Set_Const_Iterator<T>::dump (void) const
+{
+ // ACE_TRACE ("ACE_Unbounded_Set_Const_Iterator<T>::dump");
+}
+
+template <class T>
+ACE_Unbounded_Set_Const_Iterator<T>::ACE_Unbounded_Set_Const_Iterator (const ACE_Unbounded_Set<T> &s, int end)
+ : current_ (end == 0 ? s.head_->next_ : s.head_ ),
+ set_ (&s)
+{
+ // ACE_TRACE ("ACE_Unbounded_Set_Const_Iterator<T>::ACE_Unbounded_Set_Const_Iterator");
+}
+
+template <class T> int
+ACE_Unbounded_Set_Const_Iterator<T>::advance (void)
+{
+ // ACE_TRACE ("ACE_Unbounded_Set_Const_Iterator<T>::advance");
+ this->current_ = this->current_->next_;
+ return this->current_ != this->set_->head_;
+}
+
+template <class T> int
+ACE_Unbounded_Set_Const_Iterator<T>::first (void)
+{
+ // ACE_TRACE ("ACE_Unbounded_Set_Const_Iterator<T>::first");
+ this->current_ = this->set_->head_->next_;
+ return this->current_ != this->set_->head_;
+}
+
+template <class T> int
+ACE_Unbounded_Set_Const_Iterator<T>::done (void) const
+{
+ ACE_TRACE ("ACE_Unbounded_Set_Const_Iterator<T>::done");
+
+ return this->current_ == this->set_->head_;
+}
+
+template <class T> int
+ACE_Unbounded_Set_Const_Iterator<T>::next (T *&item)
+{
+ // ACE_TRACE ("ACE_Unbounded_Set_Const_Iterator<T>::next");
+ if (this->current_ == this->set_->head_)
+ return 0;
+ else
+ {
+ item = &this->current_->item_;
+ return 1;
+ }
+}
+
+template <class T> ACE_Unbounded_Set_Const_Iterator<T>
+ACE_Unbounded_Set_Const_Iterator<T>::operator++ (int)
+{
+ //ACE_TRACE ("ACE_Unbounded_Set_Const_Iterator<T>::operator++ (int)");
+ ACE_Unbounded_Set_Const_Iterator<T> retv (*this);
+
+ // postfix operator
+
+ this->advance ();
+ return retv;
+}
+
+template <class T> ACE_Unbounded_Set_Const_Iterator<T>&
+ACE_Unbounded_Set_Const_Iterator<T>::operator++ (void)
+{
+ // ACE_TRACE ("ACE_Unbounded_Set_Const_Iterator<T>::operator++ (void)");
+
+ // prefix operator
+
+ this->advance ();
+ return *this;
+}
+
+template <class T> T&
+ACE_Unbounded_Set_Const_Iterator<T>::operator* (void)
+{
+ //ACE_TRACE ("ACE_Unbounded_Set_Const_Iterator<T>::operator*");
+ T *retv = 0;
+
+ int result = this->next (retv);
+ ACE_ASSERT (result != 0);
+ ACE_UNUSED_ARG (result);
+
+ return *retv;
+}
+
+#endif /* ACE_UNBOUNDED_SET_C */
diff --git a/ace/Utils/Unbounded_Set.h b/ace/Utils/Unbounded_Set.h
new file mode 100644
index 00000000000..71eb5bb300d
--- /dev/null
+++ b/ace/Utils/Unbounded_Set.h
@@ -0,0 +1,257 @@
+/* -*- C++ -*- */
+
+//=============================================================================
+/**
+ * @file Unbounded_Set.h
+ *
+ * $Id$
+ *
+ * @author Douglas C. Schmidt <schmidt@cs.wustl.edu>
+ */
+//=============================================================================
+
+#ifndef ACE_UNBOUNDED_SET_H
+#define ACE_UNBOUNDED_SET_H
+#include "ace/pre.h"
+
+#include "ace/Node.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+class ACE_Allocator;
+
+/**
+ * @class ACE_Unbounded_Set_Iterator
+ *
+ * @brief Implement an iterator over an unbounded set.
+ */
+template <class T>
+class ACE_Unbounded_Set_Iterator
+{
+public:
+ // = Initialization method.
+ ACE_Unbounded_Set_Iterator (ACE_Unbounded_Set<T> &s, int end = 0);
+
+ // = Iteration methods.
+
+ /// Pass back the <next_item> that hasn't been seen in the Set.
+ /// Returns 0 when all items have been seen, else 1.
+ int next (T *&next_item);
+
+ /// Move forward by one element in the set. Returns 0 when all the
+ /// items in the set have been seen, else 1.
+ int advance (void);
+
+ /// Move to the first element in the set. Returns 0 if the
+ /// set is empty, else 1.
+ int first (void);
+
+ /// Returns 1 when all items have been seen, else 0.
+ int done (void) const;
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ // = STL styled iteration, compare, and reference functions.
+
+ /// Postfix advance.
+ ACE_Unbounded_Set_Iterator<T> operator++ (int);
+
+ /// Prefix advance.
+ ACE_Unbounded_Set_Iterator<T>& operator++ (void);
+
+ /// Returns a reference to the internal element <this> is pointing to.
+ T& operator* (void);
+
+ /// Check if two iterators point to the same position
+ int operator== (const ACE_Unbounded_Set_Iterator<T> &) const;
+ int operator!= (const ACE_Unbounded_Set_Iterator<T> &) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+private:
+
+ /// Pointer to the current node in the iteration.
+ ACE_Node<T> *current_;
+
+ /// Pointer to the set we're iterating over.
+ ACE_Unbounded_Set<T> *set_;
+};
+
+/**
+ * @class ACE_Unbounded_Set_Const_Iterator
+ *
+ * @brief Implement an const iterator over an unbounded set.
+ */
+template <class T>
+class ACE_Unbounded_Set_Const_Iterator
+{
+public:
+ // = Initialization method.
+ ACE_Unbounded_Set_Const_Iterator (const ACE_Unbounded_Set<T> &s, int end = 0);
+
+ // = Iteration methods.
+
+ /// Pass back the <next_item> that hasn't been seen in the Set.
+ /// Returns 0 when all items have been seen, else 1.
+ int next (T *&next_item);
+
+ /// Move forward by one element in the set. Returns 0 when all the
+ /// items in the set have been seen, else 1.
+ int advance (void);
+
+ /// Move to the first element in the set. Returns 0 if the
+ /// set is empty, else 1.
+ int first (void);
+
+ /// Returns 1 when all items have been seen, else 0.
+ int done (void) const;
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ // = STL styled iteration, compare, and reference functions.
+
+ /// Postfix advance.
+ ACE_Unbounded_Set_Const_Iterator<T> operator++ (int);
+
+ /// Prefix advance.
+ ACE_Unbounded_Set_Const_Iterator<T>& operator++ (void);
+
+ /// Returns a reference to the internal element <this> is pointing to.
+ T& operator* (void);
+
+ /// Check if two iterators point to the same position
+ int operator== (const ACE_Unbounded_Set_Const_Iterator<T> &) const;
+ int operator!= (const ACE_Unbounded_Set_Const_Iterator<T> &) const;
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+private:
+
+ /// Pointer to the current node in the iteration.
+ ACE_Node<T> *current_;
+
+ /// Pointer to the set we're iterating over.
+ const ACE_Unbounded_Set<T> *set_;
+};
+
+/**
+ * @class ACE_Unbounded_Set
+ *
+ * @brief Implement a simple unordered set of <T> of unbounded size.
+ *
+ * This implementation of an unordered set uses a circular
+ * linked list with a dummy node. This implementation does not
+ * allow duplicates, but it maintains FIFO ordering of insertions.
+ */
+template <class T>
+class ACE_Unbounded_Set
+{
+public:
+ friend class ACE_Unbounded_Set_Iterator<T>;
+ friend class ACE_Unbounded_Set_Const_Iterator<T>;
+
+ // Trait definition.
+ typedef ACE_Unbounded_Set_Iterator<T> ITERATOR;
+ typedef ACE_Unbounded_Set_Iterator<T> iterator;
+ typedef ACE_Unbounded_Set_Const_Iterator<T> CONST_ITERATOR;
+ typedef ACE_Unbounded_Set_Const_Iterator<T> const_iterator;
+
+ // = Initialization and termination methods.
+ /// Constructor. Use user specified allocation strategy
+ /// if specified.
+ ACE_Unbounded_Set (ACE_Allocator *alloc = 0);
+
+ /// Copy constructor.
+ ACE_Unbounded_Set (const ACE_Unbounded_Set<T> &);
+
+ /// Assignment operator.
+ void operator= (const ACE_Unbounded_Set<T> &);
+
+ /// Destructor.
+ ~ACE_Unbounded_Set (void);
+
+ // = Check boundary conditions.
+
+ /// Returns 1 if the container is empty, otherwise returns 0.
+ int is_empty (void) const;
+
+ /// Returns 1 if the container is full, otherwise returns 0.
+ int is_full (void) const;
+
+ // = Classic unordered set operations.
+
+ /**
+ * Insert <new_item> into the set (doesn't allow duplicates).
+ * Returns -1 if failures occur, 1 if item is already present, else
+ * 0.
+ */
+ int insert (const T &new_item);
+
+ /// Insert <item> at the tail of the set (doesn't check for
+ /// duplicates).
+ int insert_tail (const T &item);
+
+ /**
+ * Remove first occurrence of <item> from the set. Returns 0 if
+ * it removes the item, -1 if it can't find the item, and -1 if a
+ * failure occurs.
+ */
+ int remove (const T &item);
+
+ /// Finds if <item> occurs in the set. Returns 0 if find succeeds,
+ /// else -1.
+ int find (const T &item) const;
+
+ /// Size of the set.
+ size_t size (void) const;
+
+ /// Dump the state of an object.
+ void dump (void) const;
+
+ /// Reset the <ACE_Unbounded_Set> to be empty.
+ void reset (void);
+
+ // = STL-styled unidirectional iterator factory.
+ ACE_Unbounded_Set_Iterator<T> begin (void);
+ ACE_Unbounded_Set_Iterator<T> end (void);
+
+ /// Declare the dynamic allocation hooks.
+ ACE_ALLOC_HOOK_DECLARE;
+
+private:
+ /// Delete all the nodes in the Set.
+ void delete_nodes (void);
+
+ /// Copy nodes into this set.
+ void copy_nodes (const ACE_Unbounded_Set<T> &);
+
+ /// Head of the linked list of Nodes.
+ ACE_Node<T> *head_;
+
+ /// Current size of the set.
+ size_t cur_size_;
+
+ /// Allocation strategy of the set.
+ ACE_Allocator *allocator_;
+};
+
+#if defined (__ACE_INLINE__)
+#include "ace/Unbounded_Set.inl"
+#endif /* __ACE_INLINE__ */
+
+#if defined (ACE_TEMPLATES_REQUIRE_SOURCE)
+#include "ace/Unbounded_Set.cpp"
+#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */
+
+#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA)
+#pragma implementation ("Unbounded_Set.cpp")
+#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */
+
+#include "ace/post.h"
+#endif /* ACE_UNBOUNDED_SET_H */
diff --git a/ace/Utils/Unbounded_Set.inl b/ace/Utils/Unbounded_Set.inl
new file mode 100644
index 00000000000..3f71cd2b498
--- /dev/null
+++ b/ace/Utils/Unbounded_Set.inl
@@ -0,0 +1,16 @@
+/* -*- C++ -*- */
+// $Id$
+
+template <class T> ACE_INLINE int
+ACE_Unbounded_Set<T>::is_empty (void) const
+{
+ ACE_TRACE ("ACE_Unbounded_Set<T>::is_empty");
+ return this->head_ == this->head_->next_;
+}
+
+template <class T> ACE_INLINE int
+ACE_Unbounded_Set<T>::is_full (void) const
+{
+ ACE_TRACE ("ACE_Unbounded_Set<T>::is_full");
+ return 0; // We should implement a "node of last resort for this..."
+}
diff --git a/ace/Utils/libACE_Utils.a b/ace/Utils/libACE_Utils.a
new file mode 100644
index 00000000000..8b277f0dd5d
--- /dev/null
+++ b/ace/Utils/libACE_Utils.a
@@ -0,0 +1 @@
+!<arch>