summaryrefslogtreecommitdiff
path: root/ACE/tests
diff options
context:
space:
mode:
Diffstat (limited to 'ACE/tests')
-rwxr-xr-xACE/tests/.cvsignore306
-rw-r--r--ACE/tests/ACE.bsp25
-rw-r--r--ACE/tests/ACE_Init_Test.cpp129
-rw-r--r--ACE/tests/ACE_Init_Test.h59
-rw-r--r--ACE/tests/ACE_Init_Test.icobin0 -> 1078 bytes
-rw-r--r--ACE/tests/ACE_Init_Test.rc169
-rw-r--r--ACE/tests/ACE_Init_Test.rc213
-rw-r--r--ACE/tests/ACE_Init_TestDlg.cpp117
-rw-r--r--ACE/tests/ACE_Init_TestDlg.h47
-rw-r--r--ACE/tests/ACE_Init_Test_Resource.h19
-rw-r--r--ACE/tests/ACE_Init_Test_StdAfx.h44
-rw-r--r--ACE/tests/ACE_Test.cpp104
-rw-r--r--ACE/tests/ARGV_Test.cpp154
-rw-r--r--ACE/tests/Aio_Platform_Test.cpp198
-rw-r--r--ACE/tests/Arg_Shifter_Test.cpp43
-rw-r--r--ACE/tests/Array_Map_Test.cpp485
-rw-r--r--ACE/tests/Atomic_Op_Test.cpp216
-rw-r--r--ACE/tests/Auto_Event_Test.cpp226
-rw-r--r--ACE/tests/Auto_IncDec_Test.cpp141
-rw-r--r--ACE/tests/Barrier_Test.cpp138
-rw-r--r--ACE/tests/Based_Pointer_Test.cpp427
-rw-r--r--ACE/tests/Based_Pointer_Test_Lib.cpp39
-rw-r--r--ACE/tests/Basic_Types_Test.cpp173
-rw-r--r--ACE/tests/Bound_Ptr_Test.cpp464
-rw-r--r--ACE/tests/Bound_Ptr_Test.h87
-rw-r--r--ACE/tests/Buffer_Stream_Test.cpp235
-rw-r--r--ACE/tests/Bug_1576_Regression_Test.cpp66
-rw-r--r--ACE/tests/Bug_1890_Regression_Test.cpp284
-rw-r--r--ACE/tests/Bug_2368_Regression_Test.cpp123
-rw-r--r--ACE/tests/Bug_2497_Regression_Test.cpp75
-rw-r--r--ACE/tests/Bug_2540_Regression_Test.cpp311
-rw-r--r--ACE/tests/CDR_Array_Test.cpp1004
-rw-r--r--ACE/tests/CDR_File_Test.cpp483
-rw-r--r--ACE/tests/CDR_Test.cpp568
-rw-r--r--ACE/tests/CE_fostream.cpp163
-rw-r--r--ACE/tests/CE_fostream.h105
-rw-r--r--ACE/tests/Cache_Map_Manager_Test.cpp598
-rw-r--r--ACE/tests/Cache_Map_Manager_Test.h38
-rw-r--r--ACE/tests/Cached_Accept_Conn_Test.cpp515
-rw-r--r--ACE/tests/Cached_Accept_Conn_Test.h137
-rw-r--r--ACE/tests/Cached_Allocator_Test.cpp276
-rw-r--r--ACE/tests/Cached_Conn_Test.cpp488
-rw-r--r--ACE/tests/Cached_Conn_Test.h35
-rw-r--r--ACE/tests/Capabilities_Test.cpp119
-rw-r--r--ACE/tests/Codecs_Test.cpp119
-rw-r--r--ACE/tests/Collection_Test.cpp184
-rw-r--r--ACE/tests/Collection_Test.h36
-rw-r--r--ACE/tests/Config_Test.cpp1514
-rw-r--r--ACE/tests/Config_Test.h77
-rw-r--r--ACE/tests/Config_Test.ini22
-rw-r--r--ACE/tests/Config_Test_Import_1.ini5
-rw-r--r--ACE/tests/Conn_Test.cpp782
-rw-r--r--ACE/tests/Conn_Test.h62
-rw-r--r--ACE/tests/DLL_Test.cpp188
-rw-r--r--ACE/tests/DLL_Test.h74
-rw-r--r--ACE/tests/DLL_Test_Impl.cpp147
-rw-r--r--ACE/tests/DLL_Test_Impl.h68
-rw-r--r--ACE/tests/DLL_Test_Parent.cpp19
-rw-r--r--ACE/tests/DLL_Test_Parent.h34
-rw-r--r--ACE/tests/DLL_Test_Parent_Export.h58
-rw-r--r--ACE/tests/DLList_Test.cpp129
-rw-r--r--ACE/tests/Date_Time_Test.cpp128
-rw-r--r--ACE/tests/Dev_Poll_Reactor_Test.cpp596
-rw-r--r--ACE/tests/Dirent_Test.cpp336
-rw-r--r--ACE/tests/Dynamic_Priority_Test.cpp796
-rw-r--r--ACE/tests/Enum_Interfaces_Test.cpp73
-rw-r--r--ACE/tests/Env_Value_Test.cpp118
-rw-r--r--ACE/tests/FIFO_Test.cpp311
-rw-r--r--ACE/tests/FlReactor_Test.cpp275
-rw-r--r--ACE/tests/Framework_Component_DLL.cpp82
-rw-r--r--ACE/tests/Framework_Component_DLL.h58
-rw-r--r--ACE/tests/Framework_Component_DLL_Export.h54
-rw-r--r--ACE/tests/Framework_Component_Test.cpp121
-rw-r--r--ACE/tests/Framework_Component_Test.h39
-rw-r--r--ACE/tests/Future_Set_Test.cpp576
-rw-r--r--ACE/tests/Future_Test.cpp606
-rw-r--r--ACE/tests/Get_Opt_Test.cpp346
-rw-r--r--ACE/tests/HTBP/HTBP_Config.conf4
-rw-r--r--ACE/tests/HTBP/Makefile.am16
-rw-r--r--ACE/tests/HTBP/README16
-rw-r--r--ACE/tests/HTBP/Reactor_Tests/.cvsignore4
-rw-r--r--ACE/tests/HTBP/Reactor_Tests/Makefile.am64
-rwxr-xr-xACE/tests/HTBP/Reactor_Tests/Reactor_Tests.mpc19
-rw-r--r--ACE/tests/HTBP/Reactor_Tests/client.cpp136
-rw-r--r--ACE/tests/HTBP/Reactor_Tests/inside.conf5
-rwxr-xr-xACE/tests/HTBP/Reactor_Tests/run_test.pl39
-rw-r--r--ACE/tests/HTBP/Reactor_Tests/server.cpp180
-rw-r--r--ACE/tests/HTBP/Reactor_Tests/test_config.h319
-rw-r--r--ACE/tests/HTBP/Send_Large_Msg/.cvsignore4
-rw-r--r--ACE/tests/HTBP/Send_Large_Msg/Makefile.am64
-rw-r--r--ACE/tests/HTBP/Send_Large_Msg/Send_Large_Msg.mpc23
-rw-r--r--ACE/tests/HTBP/Send_Large_Msg/client.cpp98
-rwxr-xr-xACE/tests/HTBP/Send_Large_Msg/run_test.pl43
-rw-r--r--ACE/tests/HTBP/Send_Large_Msg/server.cpp103
-rw-r--r--ACE/tests/HTBP/Send_Recv_Tests/.cvsignore2
-rw-r--r--ACE/tests/HTBP/Send_Recv_Tests/Makefile.am42
-rw-r--r--ACE/tests/HTBP/Send_Recv_Tests/SendRecv_Test.cpp388
-rw-r--r--ACE/tests/HTBP/Send_Recv_Tests/SendRecv_Test.mpc14
-rw-r--r--ACE/tests/HTBP/htbptest.mpb6
-rw-r--r--ACE/tests/HTBP/ping/.cvsignore4
-rw-r--r--ACE/tests/HTBP/ping/Makefile.am62
-rw-r--r--ACE/tests/HTBP/ping/client.cpp130
-rwxr-xr-xACE/tests/HTBP/ping/ping.mpc19
-rwxr-xr-xACE/tests/HTBP/ping/run_test.pl39
-rw-r--r--ACE/tests/HTBP/ping/server.cpp124
-rw-r--r--ACE/tests/Handle_Set_Test.cpp246
-rw-r--r--ACE/tests/Hash_Map_Bucket_Iterator_Test.cpp122
-rw-r--r--ACE/tests/Hash_Map_Manager_Test.cpp336
-rw-r--r--ACE/tests/High_Res_Timer_Test.cpp176
-rw-r--r--ACE/tests/INET_Addr_Test.cpp223
-rw-r--r--ACE/tests/INET_Addr_Test_IPV6.cpp167
-rw-r--r--ACE/tests/INTEGRITY.ld31
-rw-r--r--ACE/tests/IOStream_Test.cpp502
-rw-r--r--ACE/tests/Lazy_Map_Manager_Test.cpp335
-rw-r--r--ACE/tests/Log_Msg_Test.cpp607
-rw-r--r--ACE/tests/Logging_Strategy_Test.cpp514
-rw-r--r--ACE/tests/MEM_Stream_Test.cpp527
-rw-r--r--ACE/tests/MEM_Stream_Test.h57
-rw-r--r--ACE/tests/MM_Shared_Memory_Test.cpp232
-rw-r--r--ACE/tests/MT_Reactor_Timer_Test.cpp374
-rw-r--r--ACE/tests/MT_Reactor_Timer_Test.h108
-rw-r--r--ACE/tests/MT_Reactor_Upcall_Test.cpp367
-rw-r--r--ACE/tests/MT_Reference_Counted_Event_Handler_Test.cpp1424
-rw-r--r--ACE/tests/MT_Reference_Counted_Notify_Test.cpp463
-rw-r--r--ACE/tests/MT_SOCK_Test.cpp440
-rw-r--r--ACE/tests/Main.cpp30
-rw-r--r--ACE/tests/Makefile.am3004
-rw-r--r--ACE/tests/Malloc_Test.cpp437
-rw-r--r--ACE/tests/Malloc_Test.h44
-rw-r--r--ACE/tests/Manual_Event_Test.cpp205
-rw-r--r--ACE/tests/Map_Manager_Test.cpp956
-rw-r--r--ACE/tests/Map_Test.cpp369
-rw-r--r--ACE/tests/Map_Test.h151
-rw-r--r--ACE/tests/Max_Default_Port_Test.cpp292
-rw-r--r--ACE/tests/Max_Default_Port_Test.h53
-rw-r--r--ACE/tests/Max_Default_Port_Test_IPV6.cpp255
-rw-r--r--ACE/tests/Mem_Map_Test.cpp280
-rw-r--r--ACE/tests/Memcpy_Test.cpp103
-rw-r--r--ACE/tests/Message_Block_Test.cpp347
-rw-r--r--ACE/tests/Message_Queue_Notifications_Test.cpp367
-rw-r--r--ACE/tests/Message_Queue_Test.cpp688
-rw-r--r--ACE/tests/Message_Queue_Test_Ex.cpp677
-rw-r--r--ACE/tests/Message_Queue_Test_Ex.h84
-rw-r--r--ACE/tests/Multicast_Test.cpp944
-rw-r--r--ACE/tests/Multicast_Test_IPV6.cpp1004
-rw-r--r--ACE/tests/Multihomed_INET_Addr_Test.cpp470
-rw-r--r--ACE/tests/Multihomed_INET_Addr_Test_IPV6.cpp191
-rw-r--r--ACE/tests/Naming_Test.cpp288
-rw-r--r--ACE/tests/Network_Adapters_Test.cpp1174
-rw-r--r--ACE/tests/Network_Adapters_Test.h272
-rw-r--r--ACE/tests/New_Fail_Test.cpp197
-rw-r--r--ACE/tests/NonBlocking_Conn_Test.cpp319
-rw-r--r--ACE/tests/NonBlocking_Conn_Test.h54
-rw-r--r--ACE/tests/Notify_Performance_Test.cpp257
-rw-r--r--ACE/tests/OS_Test.cpp853
-rw-r--r--ACE/tests/Object_Manager_Test.cpp119
-rw-r--r--ACE/tests/Obstack_Test.cpp116
-rw-r--r--ACE/tests/OrdMultiSet_Test.cpp220
-rw-r--r--ACE/tests/Pipe_Test.cpp172
-rw-r--r--ACE/tests/Priority_Buffer_Test.cpp182
-rw-r--r--ACE/tests/Priority_Reactor_Test.cpp397
-rw-r--r--ACE/tests/Priority_Reactor_Test.h76
-rw-r--r--ACE/tests/Priority_Task_Test.cpp251
-rw-r--r--ACE/tests/Proactor_Scatter_Gather_Test.cpp1485
-rw-r--r--ACE/tests/Proactor_Test.cpp1937
-rw-r--r--ACE/tests/Proactor_Test.h142
-rw-r--r--ACE/tests/Proactor_Test_IPV6.cpp1984
-rw-r--r--ACE/tests/Proactor_Timer_Test.cpp343
-rw-r--r--ACE/tests/Process_Manager_Test.cpp320
-rw-r--r--ACE/tests/Process_Manual_Event_Test.cpp241
-rw-r--r--ACE/tests/Process_Mutex_Test.cpp218
-rw-r--r--ACE/tests/Process_Semaphore_Test.cpp230
-rw-r--r--ACE/tests/Process_Strategy_Test.cpp714
-rw-r--r--ACE/tests/Process_Strategy_Test.h141
-rw-r--r--ACE/tests/QtReactor_Test.cpp927
-rw-r--r--ACE/tests/QtReactor_Test.h23
-rw-r--r--ACE/tests/RB_Tree_Test.cpp597
-rw-r--r--ACE/tests/RB_Tree_Test.h112
-rw-r--r--ACE/tests/README82
-rw-r--r--ACE/tests/Reactor_Dispatch_Order_Test.cpp206
-rw-r--r--ACE/tests/Reactor_Exceptions_Test.cpp228
-rw-r--r--ACE/tests/Reactor_Notification_Queue_Test.cpp223
-rw-r--r--ACE/tests/Reactor_Notify_Test.cpp493
-rw-r--r--ACE/tests/Reactor_Performance_Test.cpp418
-rw-r--r--ACE/tests/Reactor_Performance_Test.h62
-rw-r--r--ACE/tests/Reactor_Registration_Test.cpp181
-rw-r--r--ACE/tests/Reactor_Timer_Test.cpp271
-rw-r--r--ACE/tests/Reactors_Test.cpp261
-rw-r--r--ACE/tests/Reader_Writer_Test.cpp293
-rw-r--r--ACE/tests/Recursive_Condition_Bug_Test.cpp191
-rw-r--r--ACE/tests/Recursive_Condition_Test.cpp308
-rw-r--r--ACE/tests/Recursive_Mutex_Test.cpp340
-rw-r--r--ACE/tests/Refcounted_Auto_Ptr_Test.cpp497
-rw-r--r--ACE/tests/Refcounted_Auto_Ptr_Test.h39
-rw-r--r--ACE/tests/Reference_Counted_Event_Handler_Test.cpp1015
-rw-r--r--ACE/tests/Reverse_Lock_Test.cpp48
-rw-r--r--ACE/tests/SOCK_Connector_Test.cpp316
-rw-r--r--ACE/tests/SOCK_Dgram_Bcast_Test.cpp256
-rw-r--r--ACE/tests/SOCK_Dgram_Test.cpp220
-rw-r--r--ACE/tests/SOCK_Netlink_Test.cpp973
-rw-r--r--ACE/tests/SOCK_SEQPACK_SCTP_Test.cpp394
-rw-r--r--ACE/tests/SOCK_Send_Recv_Test.cpp397
-rw-r--r--ACE/tests/SOCK_Send_Recv_Test_IPV6.cpp399
-rw-r--r--ACE/tests/SOCK_Test.cpp286
-rw-r--r--ACE/tests/SOCK_Test_IPv6.cpp290
-rw-r--r--ACE/tests/SPIPE_Test.cpp222
-rw-r--r--ACE/tests/SSL/Main.cpp30
-rw-r--r--ACE/tests/SSL/Makefile.am81
-rw-r--r--ACE/tests/SSL/SSL_Asynch_Stream_Test.cpp478
-rw-r--r--ACE/tests/SSL/Thread_Pool_Reactor_SSL_Test.cpp352
-rw-r--r--ACE/tests/SSL/Thread_Pool_Reactor_SSL_Test.h50
-rw-r--r--ACE/tests/SSL/acetest.mpb20
-rw-r--r--ACE/tests/SSL/dummy.pem15
-rw-r--r--ACE/tests/SSL/key.pem15
-rw-r--r--ACE/tests/SSL/tests.mpc17
-rw-r--r--ACE/tests/SString_Test.cpp336
-rw-r--r--ACE/tests/SV_Shared_Memory_Test.cpp192
-rw-r--r--ACE/tests/Semaphore_Test.cpp245
-rw-r--r--ACE/tests/Sendfile_Test.cpp317
-rw-r--r--ACE/tests/Service_Config_DLL.cpp231
-rw-r--r--ACE/tests/Service_Config_DLL.h68
-rw-r--r--ACE/tests/Service_Config_DLL_Export.h38
-rw-r--r--ACE/tests/Service_Config_Test.UTF-16.confbin0 -> 2008 bytes
-rw-r--r--ACE/tests/Service_Config_Test.UTF-16.conf.xmlbin0 -> 2874 bytes
-rw-r--r--ACE/tests/Service_Config_Test.WCHAR_T.confbin0 -> 4012 bytes
-rw-r--r--ACE/tests/Service_Config_Test.WCHAR_T.conf.xmlbin0 -> 5744 bytes
-rw-r--r--ACE/tests/Service_Config_Test.conf19
-rw-r--r--ACE/tests/Service_Config_Test.conf.xml27
-rw-r--r--ACE/tests/Service_Config_Test.cpp259
-rw-r--r--ACE/tests/Signal_Test.cpp499
-rw-r--r--ACE/tests/Sigset_Ops_Test.cpp148
-rw-r--r--ACE/tests/Simple_Message_Block_Test.cpp215
-rw-r--r--ACE/tests/Svc_Handler_Test.cpp157
-rw-r--r--ACE/tests/TP_Reactor_Test.cpp1241
-rw-r--r--ACE/tests/TP_Reactor_Test.h200
-rw-r--r--ACE/tests/TSS_Static_Test.cpp113
-rw-r--r--ACE/tests/TSS_Test.cpp309
-rw-r--r--ACE/tests/TSS_Test_Errno.h102
-rw-r--r--ACE/tests/Task_Ex_Test.cpp163
-rw-r--r--ACE/tests/Task_Ex_Test.h34
-rw-r--r--ACE/tests/Task_Test.cpp157
-rw-r--r--ACE/tests/Test_Output.cpp252
-rw-r--r--ACE/tests/Test_Output_Export.h54
-rw-r--r--ACE/tests/Thread_Manager_Test.cpp444
-rw-r--r--ACE/tests/Thread_Mutex_Test.cpp276
-rw-r--r--ACE/tests/Thread_Pool_Reactor_Resume_Test.cpp391
-rw-r--r--ACE/tests/Thread_Pool_Reactor_Resume_Test.h56
-rw-r--r--ACE/tests/Thread_Pool_Reactor_Test.cpp344
-rw-r--r--ACE/tests/Thread_Pool_Reactor_Test.h49
-rw-r--r--ACE/tests/Thread_Pool_Test.cpp459
-rw-r--r--ACE/tests/Time_Service_Test.cpp121
-rw-r--r--ACE/tests/Time_Value_Test.cpp287
-rw-r--r--ACE/tests/Timeprobe_Test.cpp124
-rw-r--r--ACE/tests/Timer_Cancellation_Test.cpp162
-rw-r--r--ACE/tests/Timer_Queue_Reference_Counting_Test.cpp676
-rw-r--r--ACE/tests/Timer_Queue_Test.cpp673
-rw-r--r--ACE/tests/TkReactor_Test.cpp316
-rw-r--r--ACE/tests/TkReactor_Test.tcl15
-rw-r--r--ACE/tests/Token_Strategy_Test.cpp245
-rw-r--r--ACE/tests/Tokens_Test.cpp330
-rw-r--r--ACE/tests/UNIXclerk.conf3
-rw-r--r--ACE/tests/UNIXserver.conf7
-rw-r--r--ACE/tests/UNIXtokens.conf5
-rw-r--r--ACE/tests/UPIPE_SAP_Test.cpp186
-rw-r--r--ACE/tests/UUIDTest.cpp89
-rw-r--r--ACE/tests/Unbounded_Set_Test.cpp135
-rw-r--r--ACE/tests/Unload_libACE.cpp259
-rw-r--r--ACE/tests/Upgradable_RW_Test.cpp491
-rw-r--r--ACE/tests/Upgradable_RW_Test.h147
-rw-r--r--ACE/tests/Vector_Test.cpp135
-rw-r--r--ACE/tests/WFMO_Reactor_Test.cpp157
-rw-r--r--ACE/tests/Win32clerk.conf3
-rw-r--r--ACE/tests/Win32server.conf10
-rw-r--r--ACE/tests/Win32tokens.conf4
-rw-r--r--ACE/tests/XtAthenaReactor_Test.cpp320
-rw-r--r--ACE/tests/XtMotifReactor_Test.cpp327
-rw-r--r--ACE/tests/acetest.mpb20
-rw-r--r--ACE/tests/dll_test_parent_lib.mpb10
-rwxr-xr-xACE/tests/log/.cvsignore1
-rwxr-xr-xACE/tests/pharlap/run_pharlap_tests.bat130
-rw-r--r--ACE/tests/rtems_init.c210
-rw-r--r--ACE/tests/run_test.lst174
-rwxr-xr-xACE/tests/run_test.pl524
-rwxr-xr-xACE/tests/run_tests.check41
-rwxr-xr-xACE/tests/run_tests_remote.sh246
-rw-r--r--ACE/tests/test_config.h174
-rw-r--r--ACE/tests/tests.mpc1358
-rw-r--r--ACE/tests/tests.mwc9
-rw-r--r--ACE/tests/tests_pharlap_msvc.lnk72
289 files changed, 77567 insertions, 0 deletions
diff --git a/ACE/tests/.cvsignore b/ACE/tests/.cvsignore
new file mode 100755
index 00000000000..052901de3e2
--- /dev/null
+++ b/ACE/tests/.cvsignore
@@ -0,0 +1,306 @@
+ACE_Init_Test
+ACE_Init_Test
+ACE_Test
+ACE_Test
+ARGV_Test
+ARGV_Test
+Aio_Platform_Test
+Aio_Platform_Test
+Arg_Shifter_Test
+Arg_Shifter_Test
+Atomic_Op_Test
+Atomic_Op_Test
+Auto_IncDec_Test
+Auto_IncDec_Test
+Barrier_Test
+Barrier_Test
+Basic_Types_Test
+Basic_Types_Test
+Bound_Ptr_Test
+Bound_Ptr_Test
+Buffer_Stream_Test
+Buffer_Stream_Test
+Bug_1576_Regression_Test
+Bug_1576_Regression_Test
+CDR_Array_Test
+CDR_Array_Test
+CDR_File_Test
+CDR_File_Test
+CDR_Test
+CDR_Test
+Cache_Map_Manager_Test
+Cache_Map_Manager_Test
+Cached_Accept_Conn_Test
+Cached_Accept_Conn_Test
+Cached_Allocator_Test
+Cached_Allocator_Test
+Cached_Conn_Test
+Cached_Conn_Test
+Capabilities_Test
+Capabilities_Test
+Codecs_Test
+Codecs_Test
+Collection_Test
+Collection_Test
+Config_Test
+Config_Test
+Conn_Test
+Conn_Test
+DLL_Test
+DLL_Test
+DLList_Test
+DLList_Test
+Date_Time_Test
+Date_Time_Test
+Dev_Poll_Reactor_Test
+Dev_Poll_Reactor_Test
+Dirent_Test
+Dirent_Test
+Dynamic_Priority_Test
+Dynamic_Priority_Test
+Enum_Interfaces_Test
+Enum_Interfaces_Test
+Env_Value_Test
+Env_Value_Test
+FIFO_Test
+FIFO_Test
+FlReactor_Test
+FlReactor_Test
+Framework_Component_Test
+Framework_Component_Test
+Future_Set_Test
+Future_Set_Test
+Future_Test
+Future_Test
+Get_Opt_Test
+Get_Opt_Test
+Handle_Set_Test
+Handle_Set_Test
+Hash_Map_Bucket_Iterator_Test
+Hash_Map_Bucket_Iterator_Test
+Hash_Map_Manager_Test
+Hash_Map_Manager_Test
+High_Res_Timer_Test
+High_Res_Timer_Test
+INET_Addr_Test
+INET_Addr_Test
+INET_Addr_Test_IPV6
+INET_Addr_Test_IPV6
+IOStream_Test
+IOStream_Test
+Lazy_Map_Manager_Test
+Lazy_Map_Manager_Test
+Log_Msg_Test
+Log_Msg_Test
+Logging_Strategy_Test
+Logging_Strategy_Test
+MEM_Stream_Test
+MEM_Stream_Test
+MM_Shared_Memory_Test
+MM_Shared_Memory_Test
+MT_Reactor_Timer_Test
+MT_Reactor_Timer_Test
+MT_Reactor_Upcall_Test
+MT_Reactor_Upcall_Test
+MT_Reference_Counted_Event_Handler_Test
+MT_Reference_Counted_Event_Handler_Test
+MT_Reference_Counted_Notify_Test
+MT_Reference_Counted_Notify_Test
+MT_SOCK_Test
+MT_SOCK_Test
+Malloc_Test
+Malloc_Test
+Map_Manager_Test
+Map_Manager_Test
+Map_Test
+Map_Test
+Max_Default_Port_Test
+Max_Default_Port_Test
+Max_Default_Port_Test_IPV6
+Max_Default_Port_Test_IPV6
+Memcpy_Test
+Mem_Map_Test
+Mem_Map_Test
+Message_Block_Test
+Message_Block_Test
+Message_Queue_Notifications_Test
+Message_Queue_Notifications_Test
+Message_Queue_Test
+Message_Queue_Test
+Message_Queue_Test_Ex
+Message_Queue_Test_Ex
+Multicast_Test
+Multicast_Test
+Multicast_Test_IPV6
+Multicast_Test_IPV6
+Multihomed_INET_Addr_Test
+Multihomed_INET_Addr_Test
+Multihomed_INET_Addr_Test_IPV6
+Multihomed_INET_Addr_Test_IPV6
+Naming_Test
+Naming_Test
+Network_Adapters_Test
+Network_Adapters_Test
+New_Fail_Test
+New_Fail_Test
+NonBlocking_Conn_Test
+NonBlocking_Conn_Test
+Notify_Performance_Test
+Notify_Performance_Test
+OS_Test
+OS_Test
+Object_Manager_Test
+Object_Manager_Test
+Obstack_Test
+Obstack_Test
+OrdMultiSet_Test
+OrdMultiSet_Test
+Pipe_Test
+Pipe_Test
+Priority_Buffer_Test
+Priority_Buffer_Test
+Priority_Reactor_Test
+Priority_Reactor_Test
+Priority_Task_Test
+Priority_Task_Test
+Proactor_Scatter_Gather_Test
+Proactor_Scatter_Gather_Test
+Proactor_Test
+Proactor_Test
+Proactor_Test_IPV6
+Proactor_Test_IPV6
+Proactor_Timer_Test
+Proactor_Timer_Test
+Process_Manager_Test
+Process_Manager_Test
+Process_Mutex_Test
+Process_Mutex_Test
+Process_Strategy_Test
+Process_Strategy_Test
+QtReactor_Test
+QtReactor_Test
+QtReactor_Test_moc.cpp
+QtReactor_Test_moc.cpp
+RB_Tree_Test
+RB_Tree_Test
+Reactor_Dispatch_Order_Test
+Reactor_Dispatch_Order_Test
+Reactor_Exceptions_Test
+Reactor_Exceptions_Test
+Reactor_Notification_Queue_Test
+Reactor_Notification_Queue_Test
+Reactor_Notify_Test
+Reactor_Notify_Test
+Reactor_Performance_Test
+Reactor_Performance_Test
+Reactor_Registration_Test
+Reactor_Registration_Test
+Reactor_Timer_Test
+Reactor_Timer_Test
+Reactors_Test
+Reactors_Test
+Reader_Writer_Test
+Reader_Writer_Test
+Recursive_Condition_Bug_Test
+Recursive_Condition_Bug_Test
+Recursive_Condition_Test
+Recursive_Condition_Test
+Recursive_Mutex_Test
+Recursive_Mutex_Test
+Refcounted_Auto_Ptr_Test
+Refcounted_Auto_Ptr_Test
+Reference_Counted_Event_Handler_Test
+Reference_Counted_Event_Handler_Test
+Reverse_Lock_Test
+Reverse_Lock_Test
+SOCK_Connector_Test
+SOCK_Connector_Test
+SOCK_Dgram_Bcast_Test
+SOCK_Dgram_Bcast_Test
+SOCK_Dgram_Test
+SOCK_Dgram_Test
+SOCK_SEQPACK_SCTP_Test
+SOCK_SEQPACK_SCTP_Test
+SOCK_Send_Recv_Test
+SOCK_Send_Recv_Test
+SOCK_Send_Recv_Test_IPV6
+SOCK_Send_Recv_Test_IPV6
+SOCK_Test
+SOCK_Test
+SOCK_Test_IPv6
+SOCK_Test_IPv6
+SPIPE_Test
+SPIPE_Test
+SString_Test
+SString_Test
+SV_Shared_Memory_Test
+SV_Shared_Memory_Test
+Semaphore_Test
+Semaphore_Test
+Service_Config_Test
+Service_Config_Test
+Signal_Test
+Signal_Test
+Sigset_Ops_Test
+Sigset_Ops_Test
+Simple_Message_Block_Test
+Simple_Message_Block_Test
+Svc_Handler_Test
+Svc_Handler_Test
+TP_Reactor_Test
+TP_Reactor_Test
+TSS_Static_Test
+TSS_Static_Test
+TSS_Test
+TSS_Test
+Task_Ex_Test
+Task_Ex_Test
+Task_Test
+Task_Test
+Thread_Manager_Test
+Thread_Manager_Test
+Thread_Mutex_Test
+Thread_Mutex_Test
+Thread_Pool_Reactor_Resume_Test
+Thread_Pool_Reactor_Resume_Test
+Thread_Pool_Reactor_Test
+Thread_Pool_Reactor_Test
+Thread_Pool_Test
+Thread_Pool_Test
+Time_Service_Test
+Time_Service_Test
+Time_Value_Test
+Time_Value_Test
+Timeprobe_Test
+Timeprobe_Test
+Timer_Cancellation_Test
+Timer_Cancellation_Test
+Timer_Queue_Reference_Counting_Test
+Timer_Queue_Reference_Counting_Test
+Timer_Queue_Test
+Timer_Queue_Test
+TkReactor_Test
+TkReactor_Test
+Token_Strategy_Test
+Token_Strategy_Test
+Tokens_Test
+Tokens_Test
+UPIPE_SAP_Test
+UPIPE_SAP_Test
+UUIDTest
+UUIDTest
+Unbounded_Set_Test
+Unbounded_Set_Test_Ex
+Unbounded_Set_Test_Ex
+Upgradable_RW_Test
+Upgradable_RW_Test
+Vector_Test
+Vector_Test
+WFMO_Reactor_Test
+WFMO_Reactor_Test
+XtAthenaReactor_Test
+XtAthenaReactor_Test
+XtMotifReactor_Test
+XtMotifReactor_Test
+XtReactor_Test
+test.reg
diff --git a/ACE/tests/ACE.bsp b/ACE/tests/ACE.bsp
new file mode 100644
index 00000000000..58959b48998
--- /dev/null
+++ b/ACE/tests/ACE.bsp
@@ -0,0 +1,25 @@
+# Target description File for the Integrate utility for use with the
+# INTEGRITY real-time operating system by Green Hills Software.
+# Before editing this file, refer to your Integrate documentation.
+
+# ACE.bsp is only appropriate for dynamic download INTEGRITY applications
+# built for use with ACE/TAO
+
+Target
+ MinimumAddress 0x0
+ MaximumAddress 0x2fffffff
+ Clock StandardTick
+ EndClock
+ Clock HighResTimer
+ EndClock
+ Clock RealTimeClock
+ EndClock
+ InitialKernelObjects 50
+ DefaultStartIt false
+ DefaultMaxPriority 255
+ DefaultPriority 127
+ DefaultWeight 255
+ DefaultMaxWeight 255
+ DefaultStackSize 0x10000
+ DefaultMemoryRegionSize 0x100000
+EndTarget
diff --git a/ACE/tests/ACE_Init_Test.cpp b/ACE/tests/ACE_Init_Test.cpp
new file mode 100644
index 00000000000..64d77320e07
--- /dev/null
+++ b/ACE/tests/ACE_Init_Test.cpp
@@ -0,0 +1,129 @@
+// $Id$
+
+// This is a Win32-only test for verifying that the ACE dll
+// initializes itself without having a nonstatic object manager
+// present by way of a console app's main function. It's a MFC dialog
+// app - it pops up a dialog and spawns a thread - the thread will
+// wait 2 seconds and programatically dismiss the dialog box. The
+// main thread waits for the other one to exit, and that's the test.
+// If the ACE DLL doesn't initialize correctly, it will go boom!
+//
+// This test program was initially generated from MSVC AppWizard, then
+// some files were renamed and moved around to fit in with the ACE
+// test directory structure.
+//
+// ACE_Init_Test.cpp : Defines the class behaviors for the application.
+
+#if !defined(ACE_HAS_MFC)
+
+#include "test_config.h"
+
+// If this is not a WIN32 platform do not even try to compile the
+// test, many of the #includes make little sense.
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("ACE_Init_Test"));
+ ACE_ERROR ((LM_INFO,
+ ACE_TEXT ("This is not a Win32 platform, test skipped\n")));
+ ACE_END_TEST;
+ return 0;
+}
+
+#else
+
+#include "ACE_Init_Test_StdAfx.h"
+#include "ACE_Init_Test.h"
+#include "ACE_Init_TestDlg.h"
+#include "test_config.h"
+#include "ace/ACE.h"
+
+#include "ace/Thread_Manager.h"
+
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+static ACE_THR_FUNC_RETURN wait_and_kill_dialog (void *pBox);
+
+/////////////////////////////////////////////////////////////////////////////
+// CACE_Init_TestApp
+
+BEGIN_MESSAGE_MAP(CACE_Init_TestApp, CWinApp)
+ //{{AFX_MSG_MAP(CACE_Init_TestApp)
+ // NOTE - the ClassWizard will add and remove mapping macros here.
+ // DO NOT EDIT what you see in these blocks of generated code!
+ //}}AFX_MSG
+ ON_COMMAND(ID_HELP, CWinApp::OnHelp)
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CACE_Init_TestApp construction
+
+CACE_Init_TestApp::CACE_Init_TestApp()
+{
+ // TODO: add construction code here,
+ // Place all significant initialization in InitInstance
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// The one and only CACE_Init_TestApp object
+
+CACE_Init_TestApp theApp;
+
+/////////////////////////////////////////////////////////////////////////////
+// CACE_Init_TestApp initialization
+
+BOOL CACE_Init_TestApp::InitInstance()
+{
+ // This is needed because there's no overridden main(int, char *[])
+ // which would normally handle the initialization. Also see the
+ // corresponding ACE::fini, below.
+ ACE::init();
+
+ ACE_START_TEST (ACE_TEXT ("ACE_Init_Test"));
+
+ CACE_Init_TestDlg dlg;
+ m_pMainWnd = &dlg;
+ ACE_Thread_Manager::instance()->spawn (wait_and_kill_dialog,
+ m_pMainWnd);
+ int nResponse = dlg.DoModal();
+ if (nResponse == IDOK)
+ {
+ // TODO: Place code here to handle when the dialog is
+ // dismissed with OK
+ }
+ else if (nResponse == IDCANCEL)
+ {
+ // TODO: Place code here to handle when the dialog is
+ // dismissed with Cancel
+ }
+
+ ACE_Thread_Manager::instance()->wait();
+
+ ACE_END_TEST;
+
+ // Since the dialog has been closed, return FALSE so that we exit the
+ // application, rather than start the application's message pump.
+ ACE::fini();
+
+ return FALSE;
+}
+
+// This function runs in a separate thread - it will wait a couple of
+// seconds and then programatically dismiss the dialog box. If ACE is
+// not properly initialized, we will have crashed before getting here.
+static ACE_THR_FUNC_RETURN
+wait_and_kill_dialog (void *pBox)
+{
+ CACE_Init_TestDlg *pDialog = reinterpret_cast<CACE_Init_TestDlg *> (pBox);
+ ACE_OS::sleep(2);
+ pDialog->EndModalLoop (IDOK);
+ return 0;
+
+}
+
+#endif /* ACE_HAS_MFC */
diff --git a/ACE/tests/ACE_Init_Test.h b/ACE/tests/ACE_Init_Test.h
new file mode 100644
index 00000000000..cd4d6d386f1
--- /dev/null
+++ b/ACE/tests/ACE_Init_Test.h
@@ -0,0 +1,59 @@
+/* -*- C++ -*- */
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// ACE_Init_Test.h
+//
+// = DESCRIPTION
+// Main header file for the ACE_INIT_TEST application.
+//
+// = AUTHOR
+// Steve Huston <shuston@cs.wustl.edu>
+//
+// ============================================================================
+
+#ifndef AFX_ACE_INIT_TEST_H__64FDC9FE_F7F9_11D2_89B6_00A024CC68DB__INCLUDED_
+#define AFX_ACE_INIT_TEST_H__64FDC9FE_F7F9_11D2_89B6_00A024CC68DB__INCLUDED_
+
+#if _MSC_VER >= 1000
+#pragma once
+#endif // _MSC_VER >= 1000
+
+#ifndef __AFXWIN_H__
+ #error include 'stdafx.h' before including this file for PCH
+#endif
+
+#include "ACE_Init_Test_Resource.h" // main symbols
+
+class CACE_Init_TestApp : public CWinApp
+{
+ // = TITLE
+ // See ACE_Init_Test.cpp for the implementation of this class
+public:
+ CACE_Init_TestApp (void);
+
+ // Overrides
+ // ClassWizard generated virtual function overrides
+ //{{AFX_VIRTUAL(CACE_Init_TestApp)
+public:
+ virtual BOOL InitInstance();
+ //}}AFX_VIRTUAL
+
+ // Implementation
+
+ //{{AFX_MSG(CACE_Init_TestApp)
+ // NOTE - the ClassWizard will add and remove member functions here.
+ // DO NOT EDIT what you see in these blocks of generated code !
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+};
+
+//{{AFX_INSERT_LOCATION}}
+// Microsoft Developer Studio will insert additional declarations immediately before the previous line.
+
+#endif /* !defined(AFX_ACE_INIT_TEST_H__64FDC9FE_F7F9_11D2_89B6_00A024CC68DB__INCLUDED_) */
diff --git a/ACE/tests/ACE_Init_Test.ico b/ACE/tests/ACE_Init_Test.ico
new file mode 100644
index 00000000000..7eef0bcbe65
--- /dev/null
+++ b/ACE/tests/ACE_Init_Test.ico
Binary files differ
diff --git a/ACE/tests/ACE_Init_Test.rc b/ACE/tests/ACE_Init_Test.rc
new file mode 100644
index 00000000000..647f04a1ba6
--- /dev/null
+++ b/ACE/tests/ACE_Init_Test.rc
@@ -0,0 +1,169 @@
+//Microsoft Developer Studio generated resource script.
+//
+#include "ACE_Init_Test_Resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "#define _AFX_NO_SPLITTER_RESOURCES\r\n"
+ "#define _AFX_NO_OLE_RESOURCES\r\n"
+ "#define _AFX_NO_TRACKER_RESOURCES\r\n"
+ "#define _AFX_NO_PROPERTY_RESOURCES\r\n"
+ "\r\n"
+ "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n"
+ "#ifdef _WIN32\r\n"
+ "LANGUAGE 9, 1\r\n"
+ "#pragma code_page(1252)\r\n"
+ "#endif\r\n"
+ "#include ""res\\ACE_Init_Test.rc2"" // non-Microsoft Visual C++ edited resources\r\n"
+ "#endif\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDR_MAINFRAME ICON DISCARDABLE "ACE_Init_Test.ico"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+#ifdef APSTUDIO_INVOKED
+IDD_ACE_INIT_TEST_DIALOG DIALOGEX 0, 0, 185, 92
+STYLE WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_APPWINDOW
+CAPTION "ACE_Init_Test"
+FONT 8, "MS Sans Serif"
+BEGIN
+ DEFPUSHBUTTON "OK",IDOK,128,7,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,128,23,50,14
+ LTEXT "This box will auto-dismiss.",IDC_STATIC,13,7,113,
+ 8
+END
+#endif // APSTUDIO_INVOKED
+
+
+#ifndef _MAC
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 1,0,0,1
+ PRODUCTVERSION 1,0,0,1
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x4L
+ FILETYPE 0x1L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904B0"
+ BEGIN
+ VALUE "CompanyName", "\0"
+ VALUE "FileDescription", "ACE_Init_Test MFC Application\0"
+ VALUE "FileVersion", "1, 0, 0, 1\0"
+ VALUE "InternalName", "ACE_Init_Test\0"
+ VALUE "LegalCopyright", "Copyright (C) 1999\0"
+ VALUE "LegalTrademarks", "\0"
+ VALUE "OriginalFilename", "ACE_Init_Test.EXE\0"
+ VALUE "ProductName", "ACE_Init_Test Application\0"
+ VALUE "ProductVersion", "1, 0, 0, 1\0"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
+
+#endif // !_MAC
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO DISCARDABLE
+BEGIN
+ IDD_ACE_INIT_TEST_DIALOG, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 178
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 85
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+#define _AFX_NO_SPLITTER_RESOURCES
+#define _AFX_NO_OLE_RESOURCES
+#define _AFX_NO_TRACKER_RESOURCES
+#define _AFX_NO_PROPERTY_RESOURCES
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE 9, 1
+#pragma code_page(1252)
+#endif
+#include "ACE_Init_Test.rc2" // non-Microsoft Visual C++ edited resources
+#endif
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/ACE/tests/ACE_Init_Test.rc2 b/ACE/tests/ACE_Init_Test.rc2
new file mode 100644
index 00000000000..91f5498d5c9
--- /dev/null
+++ b/ACE/tests/ACE_Init_Test.rc2
@@ -0,0 +1,13 @@
+//
+// ACE_INIT_TEST.RC2 - resources Microsoft Visual C++ does not edit directly
+//
+
+#ifdef APSTUDIO_INVOKED
+ #error this file is not editable by Microsoft Visual C++
+#endif //APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+// Add manually edited resources here...
+
+/////////////////////////////////////////////////////////////////////////////
diff --git a/ACE/tests/ACE_Init_TestDlg.cpp b/ACE/tests/ACE_Init_TestDlg.cpp
new file mode 100644
index 00000000000..9b10c1e0257
--- /dev/null
+++ b/ACE/tests/ACE_Init_TestDlg.cpp
@@ -0,0 +1,117 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = DESCRIPTION
+// This is a Win32-only test for verifying that the ACE dll
+// initializes itself without having a nonstatic object manager
+// present by way of a console app's main function. It's a MFC dialog
+// app - it pops up a dialog and spawns a thread - this source file is
+// the code for implementing the dialog box.
+//
+// This test program was initially generated from MSVC AppWizard, then
+// some files were renamed and moved around to fit in with the ACE
+// test directory structure.
+//
+// = AUTHOR
+// Steve Huston <shuston@riverace.com>
+//
+// ============================================================================
+
+#if defined(ACE_HAS_MFC)
+
+#include "ACE_Init_Test_StdAfx.h"
+#include "ACE_Init_Test.h"
+#include "ACE_Init_TestDlg.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// CACE_Init_TestDlg dialog
+
+CACE_Init_TestDlg::CACE_Init_TestDlg(CWnd* pParent /*=NULL*/)
+ : CDialog(CACE_Init_TestDlg::IDD, pParent)
+{
+ //{{AFX_DATA_INIT(CACE_Init_TestDlg)
+ // NOTE: the ClassWizard will add member initialization here
+ //}}AFX_DATA_INIT
+ // Note that LoadIcon does not require a subsequent DestroyIcon in Win32
+ m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
+}
+
+void CACE_Init_TestDlg::DoDataExchange(CDataExchange* pDX)
+{
+ CDialog::DoDataExchange(pDX);
+ //{{AFX_DATA_MAP(CACE_Init_TestDlg)
+ // NOTE: the ClassWizard will add DDX and DDV calls here
+ //}}AFX_DATA_MAP
+}
+
+BEGIN_MESSAGE_MAP(CACE_Init_TestDlg, CDialog)
+ //{{AFX_MSG_MAP(CACE_Init_TestDlg)
+ ON_WM_PAINT()
+ ON_WM_QUERYDRAGICON()
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CACE_Init_TestDlg message handlers
+
+BOOL CACE_Init_TestDlg::OnInitDialog()
+{
+ CDialog::OnInitDialog();
+
+ // Set the icon for this dialog. The framework does this automatically
+ // when the application's main window is not a dialog
+ SetIcon(m_hIcon, TRUE); // Set big icon
+ SetIcon(m_hIcon, FALSE); // Set small icon
+
+ // TODO: Add extra initialization here
+
+ return TRUE; // return TRUE unless you set the focus to a control
+}
+
+// If you add a minimize button to your dialog, you will need the code below
+// to draw the icon. For MFC applications using the document/view model,
+// this is automatically done for you by the framework.
+
+void CACE_Init_TestDlg::OnPaint()
+{
+ if (IsIconic())
+ {
+ CPaintDC dc(this); // device context for painting
+
+ SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);
+
+ // Center icon in client rectangle
+ int cxIcon = GetSystemMetrics(SM_CXICON);
+ int cyIcon = GetSystemMetrics(SM_CYICON);
+ CRect rect;
+ GetClientRect(&rect);
+ int x = (rect.Width() - cxIcon + 1) / 2;
+ int y = (rect.Height() - cyIcon + 1) / 2;
+
+ // Draw the icon
+ dc.DrawIcon(x, y, m_hIcon);
+ }
+ else
+ {
+ CDialog::OnPaint();
+ }
+}
+
+// The system calls this to obtain the cursor to display while the user drags
+// the minimized window.
+HCURSOR CACE_Init_TestDlg::OnQueryDragIcon()
+{
+ return (HCURSOR) m_hIcon;
+}
+
+#endif /* ACE_HAS_MFC */
diff --git a/ACE/tests/ACE_Init_TestDlg.h b/ACE/tests/ACE_Init_TestDlg.h
new file mode 100644
index 00000000000..9bab7ee331e
--- /dev/null
+++ b/ACE/tests/ACE_Init_TestDlg.h
@@ -0,0 +1,47 @@
+// $Id$
+// ACE_Init_TestDlg.h : header file
+
+#if !defined(AFX_ACE_INIT_TESTDLG_H__64FDCA00_F7F9_11D2_89B6_00A024CC68DB__INCLUDED_)
+#define AFX_ACE_INIT_TESTDLG_H__64FDCA00_F7F9_11D2_89B6_00A024CC68DB__INCLUDED_
+
+#if _MSC_VER >= 1000
+#pragma once
+#endif // _MSC_VER >= 1000
+
+// CACE_Init_TestDlg dialog
+
+class CACE_Init_TestDlg : public CDialog
+{
+// Construction
+public:
+ CACE_Init_TestDlg(CWnd* pParent = NULL); // standard constructor
+
+// Dialog Data
+ //{{AFX_DATA(CACE_Init_TestDlg)
+ enum { IDD = IDD_ACE_INIT_TEST_DIALOG };
+ // NOTE: the ClassWizard will add data members here
+ //}}AFX_DATA
+
+ // ClassWizard generated virtual function overrides
+ //{{AFX_VIRTUAL(CACE_Init_TestDlg)
+ protected:
+ virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
+ //}}AFX_VIRTUAL
+
+// Implementation
+protected:
+ HICON m_hIcon;
+
+ // Generated message map functions
+ //{{AFX_MSG(CACE_Init_TestDlg)
+ virtual BOOL OnInitDialog();
+ afx_msg void OnPaint();
+ afx_msg HCURSOR OnQueryDragIcon();
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+};
+
+//{{AFX_INSERT_LOCATION}}
+// Microsoft Developer Studio will insert additional declarations immediately before the previous line.
+
+#endif /* !defined(AFX_ACE_INIT_TESTDLG_H__64FDCA00_F7F9_11D2_89B6_00A024CC68DB__INCLUDED_) */
diff --git a/ACE/tests/ACE_Init_Test_Resource.h b/ACE/tests/ACE_Init_Test_Resource.h
new file mode 100644
index 00000000000..e32f29d5a6b
--- /dev/null
+++ b/ACE/tests/ACE_Init_Test_Resource.h
@@ -0,0 +1,19 @@
+// $Id$
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by ACE_INIT_TEST.RC
+//
+#define IDR_MAINFRAME 128
+#define IDD_ACE_INIT_TEST_DIALOG 102
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+
+#define _APS_NEXT_RESOURCE_VALUE 129
+#define _APS_NEXT_COMMAND_VALUE 32771
+#define _APS_NEXT_CONTROL_VALUE 1000
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/ACE/tests/ACE_Init_Test_StdAfx.h b/ACE/tests/ACE_Init_Test_StdAfx.h
new file mode 100644
index 00000000000..ef04442a81d
--- /dev/null
+++ b/ACE/tests/ACE_Init_Test_StdAfx.h
@@ -0,0 +1,44 @@
+/* -*- C++ -*- */
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// ACE_Init_Test_StdAfx.h
+//
+// = DESCRIPTION
+// stdafx.h : include file for standard system include files,
+// or project specific include files that are used frequently, but
+// are changed infrequently
+//
+// = AUTHOR
+// Steve Huston <shuston@cs.wustl.edu>
+//
+// ============================================================================
+
+#ifndef AFX_STDAFX_H__64FDCA02_F7F9_11D2_89B6_00A024CC68DB__INCLUDED_
+#define AFX_STDAFX_H__64FDCA02_F7F9_11D2_89B6_00A024CC68DB__INCLUDED_
+
+#if _MSC_VER >= 1000
+#pragma once
+#endif // _MSC_VER >= 1000
+
+// Exclude rarely-used stuff from Windows headers
+#define VC_EXTRALEAN
+
+// MFC core and standard components
+#include <afxwin.h>
+// MFC extensions
+#include <afxext.h>
+#ifndef _AFX_NO_AFXCMN_SUPPORT
+// MFC support for Windows Common Controls
+#include <afxcmn.h>
+#endif /* _AFX_NO_AFXCMN_SUPPORT */
+
+//{{AFX_INSERT_LOCATION}} Microsoft Developer Studio will insert
+//additional declarations immediately before the previous line.
+
+#endif /* !defined(AFX_STDAFX_H__64FDCA02_F7F9_11D2_89B6_00A024CC68DB__INCLUDED_) */
diff --git a/ACE/tests/ACE_Test.cpp b/ACE/tests/ACE_Test.cpp
new file mode 100644
index 00000000000..86749cc3a0c
--- /dev/null
+++ b/ACE/tests/ACE_Test.cpp
@@ -0,0 +1,104 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = DESCRIPTION
+// This simple test exercises and illustrates use of ACE value-added
+// functions.
+//
+// = AUTHOR
+// Steve Huston <shuston@riverace.com>
+//
+// ============================================================================
+
+#include "test_config.h"
+
+#include "ace/ACE.h"
+
+ACE_RCSID(tests, ACE_Test, "$Id$")
+
+int
+log2_test (void)
+{
+ u_long values[] = {1, 2, 4, 8, 1048576};
+ u_long results[] = {0, 1, 2, 3, 20};
+ u_long result = 0;
+ int error_count = 0;
+
+ for (size_t i = 0 ; i < sizeof (values) / sizeof (u_long) ; i++)
+ {
+ result = ACE::log2(values [i]);
+ if (result != results [i])
+ {
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("Log2 error: input %d, output %d, expected %d\n"), values [i], result, results [i]));
+ error_count++;
+ }
+ }
+
+ return error_count;
+}
+
+// Test ACE::execname to be sure it finds .exe without regard to case.
+int
+execname_test (void)
+{
+ int error_count = 0;
+
+ // This test is only interesting on Win32
+#if defined (ACE_WIN32)
+ const ACE_TCHAR *newname;
+ const ACE_TCHAR *prog1 = ACE_TEXT ("myprog.exe");
+ const ACE_TCHAR *prog2 = ACE_TEXT ("myprog.EXE");
+ const ACE_TCHAR *prog3 = ACE_TEXT ("myprog");
+
+ newname = ACE::execname (prog1);
+ if (newname != prog1) // Didn't find .exe correctly
+ {
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("Name %s, not %s\n"), newname, prog1));
+ delete [] const_cast<ACE_TCHAR *> (newname);
+ ++error_count;
+ }
+
+ newname = ACE::execname (prog2);
+ if (newname != prog2) // Didn't find .exe correctly
+ {
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("Name %s, not %s\n"), newname, prog2));
+ delete [] const_cast<ACE_TCHAR *> (newname);
+ ++error_count;
+ }
+
+ newname = ACE::execname (prog3);
+ if (newname == prog3) // Thought the name didn't need .exe
+ {
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("Says .exe not needed for %s\n"),
+ newname));
+ ++error_count;
+ }
+ else
+ delete [] const_cast<ACE_TCHAR *> (newname);
+#endif /* ACE_WIN32 */
+
+ return error_count;
+}
+
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("ACE_Test"));
+
+ int status = 0;
+ int result;
+
+ if ((result = execname_test ()) != 0)
+ status = result;
+
+ if ((result = log2_test ()) != 0)
+ status = result;
+
+ ACE_END_TEST;
+ return status;
+}
diff --git a/ACE/tests/ARGV_Test.cpp b/ACE/tests/ARGV_Test.cpp
new file mode 100644
index 00000000000..bb06c6b8d31
--- /dev/null
+++ b/ACE/tests/ARGV_Test.cpp
@@ -0,0 +1,154 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = DESCRIPTION
+// This simple test illustrates how to use advanced features of
+// <ACE_ARGV>.
+//
+// = AUTHOR
+// Suresh Kannan <kannan@uav.ae.gatech.edu> and
+// Duane Binder <duane.binder@veritas.com>
+
+// ============================================================================
+
+#include "ace/ARGV.h"
+#include "ace/Arg_Shifter.h"
+#include "ace/OS_NS_string.h"
+#include "ace/Argv_Type_Converter.h"
+#include "test_config.h"
+
+ACE_RCSID(tests, ARGV_Test, "$Id$")
+
+static void
+consume_arg (int &argc, ACE_TCHAR *argv[])
+{
+ ACE_Arg_Shifter arg_shifter (argc, argv);
+
+ if (arg_shifter.is_anything_left ())
+ arg_shifter.consume_arg (1);
+ // Once we initialize an arg_shifter, we must iterate through it all!
+ while ((arg_shifter.is_anything_left ()))
+ arg_shifter.ignore_arg (1);
+}
+
+static int
+test_argv_type_converter (void)
+{
+ char *argv[20];
+ argv[0] = ACE_OS_String::strdup ("one");
+ argv[1] = ACE_OS_String::strdup ("two");
+ argv[2] = ACE_OS_String::strdup ("three");
+ argv[3] = ACE_OS_String::strdup ("four");
+ argv[4] = 0;
+
+ char *save_argv[20];
+ ACE_OS_String::memcpy (save_argv, argv, sizeof (argv));
+
+ int argc = 4;
+
+ {
+ ACE_Argv_Type_Converter ct2 (argc, argv);
+ }
+
+ {
+ ACE_Argv_Type_Converter ct (argc, argv);
+ ct.get_argc (); ct.get_TCHAR_argv ();
+ consume_arg ( ct.get_argc (), ct.get_TCHAR_argv ());
+ }
+ {
+ ACE_Argv_Type_Converter ct3 (argc, argv);
+ ct3.get_argc (); ct3.get_ASCII_argv ();
+ consume_arg ( ct3.get_argc (), ct3.get_TCHAR_argv ());
+ }
+
+ {
+ for (size_t i = 0; i < 4; i++)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT (" (%d) %s\n"),
+ i,
+ ACE_TEXT_CHAR_TO_TCHAR (argv[i])));
+ }
+
+ for (size_t i = 0; save_argv[i]; ++i)
+ ACE_OS_Memory::free (save_argv[i]);
+
+ return 0;
+}
+
+static int
+test_argv_type_converter2 (void)
+{
+ ACE_TCHAR *argv[20];
+ argv[0] = ACE_OS_String::strdup (ACE_TEXT ("one"));
+ argv[1] = ACE_OS_String::strdup (ACE_TEXT ("two"));
+ argv[2] = ACE_OS_String::strdup (ACE_TEXT ("three"));
+ argv[3] = ACE_OS_String::strdup (ACE_TEXT ("four"));
+ argv[4] = 0;
+
+ ACE_TCHAR *save_argv[20];
+ ACE_OS_String::memcpy (save_argv, argv, sizeof (argv));
+
+ int argc = 4;
+
+ {
+ ACE_Argv_Type_Converter ct (argc, argv);
+ ct.get_argc (); ct.get_TCHAR_argv ();
+ consume_arg ( ct.get_argc (), ct.get_TCHAR_argv ());
+ }
+
+ consume_arg ( argc, argv);
+
+ {
+ for (size_t i = 0; i < 4; i++)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT (" (%d) %s\n"),
+ i,
+ argv[i]));
+ }
+
+ for (size_t i = 0; save_argv[i]; ++i)
+ ACE_OS_Memory::free (save_argv[i]);
+
+ return 0;
+}
+
+int
+run_main (int, ACE_TCHAR *argv[])
+{
+ ACE_START_TEST (ACE_TEXT ("ARGV_Test"));
+
+ // From command line.
+ ACE_ARGV cl (argv);
+
+ // My own stuff.
+ ACE_ARGV my;
+
+ // Add to my stuff.
+ my.add (ACE_TEXT ("-ORBEndpoint iiop://localhost:12345"));
+
+ // Combine the two (see the ace/ARGV.h constructors documentation).
+ ACE_ARGV a (cl.argv (),
+ my.argv ());
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("argc = %d\n"),
+ a.argc ()));
+
+ // Print the contents of the combined <ACE_ARGV>.
+ for (int i = 0; i < a.argc (); i++)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT (" (%d) %s\n"),
+ i,
+ a.argv ()[i]));
+
+ test_argv_type_converter2 ();
+ test_argv_type_converter ();
+
+ ACE_END_TEST;
+ return 0;
+}
+
diff --git a/ACE/tests/Aio_Platform_Test.cpp b/ACE/tests/Aio_Platform_Test.cpp
new file mode 100644
index 00000000000..22c13223e06
--- /dev/null
+++ b/ACE/tests/Aio_Platform_Test.cpp
@@ -0,0 +1,198 @@
+// $Id$
+
+// ============================================================================
+//
+// = FILENAME
+// aio_platform_test.cpp
+//
+// = DESCRITPTION
+// Testing the platform for POSIX Asynchronous I/O. Basically
+// prints the predefined constants and also checks for their run
+// time values. If this test succeeds further tests at
+// $ACE_ROOT/examples/Reactor/Proactor can be used to test the
+// features further.
+//
+// = AUTHOR
+// Programming for the Real World. Bill O. GallMeister. Modified
+// by Alexander Babu Arulanthu <alex@cs.wustl.edu>
+//
+// =====================================================================
+
+#include "test_config.h"
+#include "ace/OS_NS_unistd.h"
+
+ACE_RCSID(tests, Aio_Platform_Test, "$Id$")
+
+#if defined (_POSIX_ASYNCHRONOUS_IO)
+static int do_sysconf (void)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ "Doing <sysconf> calls to know the run-time values of POSIX feature limits\n"));
+
+ // Call sysconf to find out runtime values.
+ errno = 0;
+#if defined (_SC_LISTIO_AIO_MAX)
+ ACE_DEBUG ((LM_DEBUG,
+ "Runtime value of LISTIO_AIO_MAX is %d, errno = %d, Minimum is 2\n",
+ ACE_OS::sysconf (_SC_LISTIO_AIO_MAX),
+ errno));
+#elif defined (_SC_AIO_LISTIO_MAX)
+ ACE_DEBUG ((LM_DEBUG,
+ "Runtime value of AIO_LISTIO_MAX is %d, errno = %d, Minimum is 2\n",
+ ACE_OS::sysconf (_SC_AIO_LISTIO_MAX),
+ errno));
+#else
+ ACE_ERROR ((LM_ERROR,
+ "_SC_LISTIO_AIO_MAX or _SC_AIO_LISTIO_MAX"
+ " do not exist on this platform\n"));
+#endif /* _SC_LISTIO_AIO_MAX */
+
+#if defined (_SC_AIO_MAX)
+ errno = 0;
+ ACE_DEBUG ((LM_DEBUG,
+ "Runtime value of AIO_MAX is %d, errno = %d, Minimum is 1\n",
+ ACE_OS::sysconf (_SC_AIO_MAX),
+ errno));
+#else
+ ACE_ERROR ((LM_ERROR,
+ "_SC_AIO_MAX does not exist on this platform\n"));
+#endif /* _SC_AIO_MAX */
+
+#if defined (_SC_ASYNCHRONOUS_IO)
+ errno = 0;
+ ACE_DEBUG ((LM_DEBUG,
+ "Runtime value of _POSIX_ASYNCHRONOUS_IO is %d, errno = %d\n",
+ ACE_OS::sysconf (_SC_ASYNCHRONOUS_IO),
+ errno));
+#else /* Not _SC_ASYNCHRONOUS_IO */
+ ACE_ERROR ((LM_ERROR,
+ "_SC_ASYNCHRONOUS_IO does not exist on this platform\n"));
+#endif /* _SC_ASYNCHRONOUS_IO */
+
+#if defined (_SC_REALTIME_SIGNALS)
+ errno = 0;
+ ACE_DEBUG ((LM_DEBUG,
+ "Runtime value of _POSIX_REALTIME_SIGNALS is %d, errno = %d\n",
+ ACE_OS::sysconf (_SC_REALTIME_SIGNALS),
+ errno));
+#else /* Not _SC_REALTIME_SIGNALS */
+ ACE_ERROR ((LM_ERROR,
+ "_SC_REALTIME_SIGNALS does not exist on this platform\n"));
+#endif /* _SC_REALTIME_SIGNALS */
+
+
+#if defined (_SC_RTSIG_MAX)
+ errno = 0;
+ ACE_DEBUG ((LM_DEBUG,
+ "Runtime value of RTSIG_MAX %d, Errno = %d, Minimum is 8\n",
+ ACE_OS::sysconf (_SC_RTSIG_MAX),
+ errno));
+#else /* Not _SC_RTSIG_MAX */
+ ACE_ERROR ((LM_ERROR,
+ "_SC_RTSIG_MAX does not exist on this platform\n"));
+#endif /* _SC_RTSIG_MAX */
+
+#if defined (_SC_SIGQUEUE_MAX)
+ errno = 0;
+ ACE_DEBUG ((LM_DEBUG,
+ "Runtime value of SIGQUEUE_MAX %d, Errno = %d, Minimum is 32\n",
+ ACE_OS::sysconf (_SC_SIGQUEUE_MAX),
+ errno));
+#else /* Not _SC_SIGQUEUE_MAX */
+ ACE_ERROR ((LM_ERROR,
+ "_SC_SIGQUEUE_MAX does not exist on this platform\n"));
+#endif /* _SC_SIGQUEUE_MAX */
+ return 0;
+}
+#endif /* _POSIX_ASYNCHRONOUS_IO */
+
+static int
+have_asynchio (void)
+{
+#if defined (_POSIX_ASYNCHRONOUS_IO)
+#if defined (_POSIX_ASYNC_IO)
+#if _POSIX_ASYNC_IO == -1
+ ACE_DEBUG ((LM_DEBUG,
+ "_POSIX_ASYNC_IO = -1.. ASYNCH IO NOT supported at all\n"));
+ return -1;
+#else /* Not _POSIX_ASYNC_IO == -1 */
+ ACE_DEBUG ((LM_DEBUG,
+ "_POSIX_ASYNC_IO = %d\n ASYNCH IO is supported FULLY\n",
+ _POSIX_ASYNC_IO));
+#endif /* _POSIX_ASYNC_IO == -1 */
+
+#else /* Not defined _POSIX_ASYNC_IO */
+ ACE_ERROR ((LM_DEBUG,
+ "_POSIX_ASYNC_IO is not defined.\n"));
+ ACE_DEBUG ((LM_DEBUG,
+ "AIO might *not* be supported on all the paths\n"));
+#endif /* _POSIX_ASYNC_IO */
+
+ // System defined POSIX Values.
+ ACE_DEBUG ((LM_DEBUG,
+ "System claims to have POSIX_ASYNCHRONOUS_IO\n"));
+
+#if defined(_POSIX_AIO_LISTIO_MAX)
+ ACE_DEBUG ((LM_DEBUG,
+ "Number of operations in one listio: "
+ "Minimum value is 2: "
+ "_POSIX_AIO_LISTIO_MAX = %d\n",
+ _POSIX_AIO_LISTIO_MAX));
+#else
+ ACE_DEBUG ((LM_DEBUG,
+ "No value for _POSIX_AIO_LISTIO_MAX\n"));
+#endif
+
+#if defined(_POSIX_AIO_MAX)
+ ACE_DEBUG ((LM_DEBUG,
+ "Number of simultaneous asynchronous I/Os: "
+ "Minimum is 1: "
+ "_POSIX_AIO_MAX = %d\n",
+ _POSIX_AIO_MAX));
+#else
+ ACE_DEBUG ((LM_DEBUG,
+ "No value for _POSIX_AIO_MAX\n"));
+#endif
+
+ // @@ Debugging.
+ ACE_DEBUG ((LM_DEBUG,
+ "Before do_sysconf : Errno %d\n",
+ errno));
+
+ // Check and print the run time values.
+ do_sysconf ();
+
+ // @@ Debugging.
+ ACE_DEBUG ((LM_DEBUG,
+ "After do_sysconf: Errno : %d\n", errno));
+
+ return 0;
+
+#else /* Not _POSIX_ASYNCHRONOUS_IO */
+ ACE_DEBUG ((LM_DEBUG,
+ "No support._POSIX_ASYNCHRONOUS_IO itself is not defined\n"));
+ return -1;
+#endif /* _POSIX_ASYNCHRONOUS_IO */
+}
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("Aio_Platform_Test"));
+
+ // Test the #defined and constants and runtime values.
+ errno = 0;
+ if (have_asynchio () == 0)
+ ACE_DEBUG ((LM_DEBUG,
+ "Basic test successful"
+ "Check the run time values of the predefined constants\n"
+ "ACE_HAS_AIO_CALLS can be defined for this platform\n"
+ "Further tests at $ACE_ROOT/examples/Reactor/Proactor\n"));
+ else
+ ACE_ERROR ((LM_INFO,
+ "AIO not supported on this platform\n"));
+
+ ACE_END_TEST;
+
+ return 0;
+}
diff --git a/ACE/tests/Arg_Shifter_Test.cpp b/ACE/tests/Arg_Shifter_Test.cpp
new file mode 100644
index 00000000000..649f8054f46
--- /dev/null
+++ b/ACE/tests/Arg_Shifter_Test.cpp
@@ -0,0 +1,43 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = DESCRIPTION
+// This program exercises the ACE_Arg_Shifter class.
+//
+// = AUTHOR
+// Steve Huston <shuston@riverace.com>
+//
+// ============================================================================
+
+#include "ace/Arg_Shifter.h"
+#include "test_config.h"
+
+ACE_RCSID(tests, Arg_Shifter_Test, "$Id$")
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("Arg_Shifter_Test"));
+
+ const int test_argc_size = 5;
+ int argl (test_argc_size);
+ const ACE_TCHAR *args[test_argc_size] = {
+ ACE_TEXT ("-known"),
+ ACE_TEXT ("-huh"),
+ ACE_TEXT ("-arg"),
+ ACE_TEXT ("-what"),
+ ACE_TEXT ("arg")
+ };
+
+ ACE_Arg_Shifter shifter (argl, args);
+
+ if (!shifter.is_anything_left ())
+ ACE_ERROR ((LM_ERROR, "is_anything_left() returned 0 at start.\n"));
+
+ ACE_END_TEST;
+ return 0;
+}
diff --git a/ACE/tests/Array_Map_Test.cpp b/ACE/tests/Array_Map_Test.cpp
new file mode 100644
index 00000000000..9f5deeee3bd
--- /dev/null
+++ b/ACE/tests/Array_Map_Test.cpp
@@ -0,0 +1,485 @@
+//=============================================================================
+/**
+ * @file Array_Map_Test.cpp
+ *
+ * $Id$
+ *
+ * Regression test for ACE_Array_Map.
+ *
+ * @author Ossama Othman
+ */
+//=============================================================================
+
+
+#include "test_config.h"
+
+#include "ace/SString.h"
+#include "ace/Array_Map.h"
+
+#include <algorithm>
+//#include <map> /* For STL portability testing. */
+
+
+ACE_RCSID (tests,
+ Array_Map_Test,
+ "$Id$")
+
+
+static char const letters[] =
+ { 'A', 'C', 'E', ' ', 'r', 'u', 'l', 'e', 'z', '!' };
+
+static ACE_TString const words[] =
+ {
+ ACE_TEXT ("alpha"), // A
+ ACE_TEXT ("charlie"), // C
+ ACE_TEXT ("echo"), // E
+ ACE_TEXT (" "), //
+ ACE_TEXT ("romeo"), // r
+ ACE_TEXT ("uniform"), // u
+ ACE_TEXT ("lima"), // l
+ ACE_TEXT ("echo"), // e
+ ACE_TEXT ("zulu"), // z
+ ACE_TEXT ("!") // !
+ };
+
+static size_t const letters_len = sizeof (letters) / sizeof (letters[0]);
+static size_t const words_len = sizeof (words) / sizeof (words[0]);
+
+// --------------------------------------------------------------
+
+bool
+insertion_removal_test (void)
+{
+ // Instantiate the map.
+ typedef ACE_Array_Map<char, ACE_TString> Map;
+ Map phonetic[2];
+
+ ACE_ASSERT (phonetic[0] == phonetic[1]); // Sanity check.
+
+ static size_t const phonetic_len =
+ sizeof (phonetic) / sizeof (phonetic[0]);
+
+ unsigned int count = 1;
+
+ // Test map insertion.
+ for (Map * m = phonetic;
+ m != phonetic + phonetic_len;
+ ++m, ++count)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("------------- Populating map %u -------------\n"),
+ count));
+
+
+ ACE_TString const * word = words;
+ for (char const * i = letters;
+ i != letters + letters_len;
+ ++i, ++word)
+ {
+ std::pair<Map::iterator, bool> const result =
+ m->insert (std::make_pair (*i, *word));
+
+ if (result.second)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Inserted \"%c | %s\"\n"),
+ *i,
+ word->c_str ()));
+ else
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("Insertion of \"%c | %s\" failed.\n"),
+ *i,
+ word->c_str ()),
+ false);
+ }
+
+ ACE_ASSERT (m->size () == letters_len);
+ }
+
+ // Test equality of identically populated maps.
+ if (!(phonetic[0] == phonetic[1]))
+ {
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("Equality comparison of two identical ")
+ ACE_TEXT ("maps failed.\n")),
+ false);
+ }
+ else if (phonetic[0] < phonetic[1])
+ {
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("Relational comparison of two identical ")
+ ACE_TEXT ("maps incorrectly passed.\n")),
+ false);
+ }
+
+ ACE_ASSERT (!phonetic[0].is_empty ()); // Sanity check.
+
+ Map foo (phonetic[0]); // Copy construction
+ Map bar = foo; // Assignment
+
+ if (!(foo == bar))
+ {
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("Second equality comparison of two ")
+ ACE_TEXT ("identical maps failed.\n")),
+ false);
+ }
+
+ Map::value_type values[letters_len];
+ size_t const values_len = sizeof (values) / sizeof (values[0]);
+
+ ACE_TString const * word = words;
+ char const * letter = letters;
+
+ for (Map::value_type * v = values;
+ v != values + values_len;
+ ++v, ++letter, ++word)
+ {
+ *v = std::make_pair (*letter, *word);
+ }
+
+ Map A (values, values + values_len);
+
+ if (!(A == bar))
+ {
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("Third equality comparison of two ")
+ ACE_TEXT ("identical maps failed.\n")),
+ false);
+ }
+
+ Map B;
+ B.insert (values, values + values_len);
+
+ if (!(A == B))
+ {
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("Fourth equality comparison of two ")
+ ACE_TEXT ("identical maps failed.\n")),
+ false);
+ }
+
+ // ==== Removal tests ====
+
+ // Remove two elements from map.
+ Map::iterator letter_A = A.find ('A');
+ ACE_ASSERT (letter_A == A.begin ()); // Should be first map element.
+ ACE_ASSERT (A.count ('A') == 1); // Should only be one letter 'A'.
+
+ A.erase (letter_A);
+ if (A.find ('A') != A.end ()
+ || A.count ('A') != 0)
+ {
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("Letter '%c' not removed from map\n"),
+ (*letter_A).first),
+ false);
+ }
+
+ static char const z = 'z';
+ if (A.erase (z) != 1
+ || A.count (z) != 0
+ || A.find (z) != A.end ())
+ {
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("Letter '%c' not removed from map\n"),
+ z),
+ false);
+ }
+
+
+ // Remove range of letters from map.
+ static size_t const removed_len = 3;
+ Map::iterator const first = B.begin () + 2;
+ Map::iterator const last = first + removed_len;
+
+ ACE_ASSERT (static_cast<Map::size_type> (last - first) < B.size ());
+ ACE_ASSERT (last < B.end ());
+
+ Map::value_type removed[removed_len];
+ size_t rcount = 0;
+ for (Map::iterator x = first; x != last; ++x)
+ {
+ removed[rcount++] = *x;
+ }
+
+ B.erase (first, last);
+
+ for (size_t s = 0; s < removed_len ; ++s)
+ {
+ Map::key_type const key = removed[s].first;
+
+ if (B.count (key) != 0
+ || B.find (key) != B.end ())
+ {
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("Letter '%c' from range of letters ")
+ ACE_TEXT ("not removed from map\n"),
+ key),
+ false);
+ }
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Insertion/removal test passed.\n")));
+
+ return true;
+}
+
+// --------------------------------------------------------------
+
+bool
+index_operator_test (void)
+{
+ // Instantiate the map.
+ typedef ACE_Array_Map<char, ACE_TString> Map;
+ Map phonetic;
+
+ ACE_ASSERT (phonetic.size () == 0 && phonetic.is_empty ());
+ ACE_ASSERT (phonetic.max_size () > 1);
+
+ // Run the same test twice, clearing the contents of the map between
+ // the iterations. The goal is to verify that the constant time
+ // clear() method performs as advertised.
+ for (unsigned int count = 1; count < 3; ++count)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("----- Index operator test ")
+ ACE_TEXT ("iteration %u -----\n"),
+ count));
+
+ // Test map insertion through the index operator.
+ ACE_TString const * word = words;
+ for (char const * i = letters;
+ i != letters + letters_len;
+ ++i, ++word)
+ {
+ phonetic[*i] = *word;
+ }
+
+ ACE_ASSERT (phonetic.size () == letters_len);
+
+ typedef Map::const_iterator const_iterator;
+
+ // Access the elements that were inserted into the map.
+ char const * letter = letters;
+ word = words;
+ const_iterator const last = phonetic.end ();
+ for (const_iterator n = phonetic.begin ();
+ n != last;
+ ++n, ++letter, ++word)
+ {
+ if ((*n).first != *letter || (*n).second != *word)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("Key/Datum mismatch:\n")
+ ACE_TEXT (" key \"%c\" should be \"%c\"\n")
+ ACE_TEXT (" datum \"%s\" should be \"%s\"\n"),
+ (*n).first,
+ *letter,
+ (*n).second.c_str (),
+ word->c_str ()),
+ false);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\t%c\t%s\n"),
+ (*n).first,
+ (*n).second.c_str ()));
+ }
+
+ // Now run the same test in reverse.
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("... in reverse ...\n")));
+
+ typedef Map::const_reverse_iterator const_reverse_iterator;
+
+ letter = letters + letters_len - 1;
+ word = words + words_len - 1;
+
+ // Work around compiler / STL implementations that cannot
+ // handle implicit conversions from iterator to const_iterator
+ // (e.g. due to missing template constructor.)
+ //
+ // We don't strictly need a const Map for this test but having
+ // one allows us to exercise const iterators.
+ Map const & const_phonetic = phonetic;
+
+ const_reverse_iterator const rlast = const_phonetic.rend ();
+ for (const_reverse_iterator r = const_phonetic.rbegin ();
+ !(r == rlast); // Sun C++ Forte doesn't support operator!=
+ ++r, --letter, --word)
+ {
+ if ((*r).first != *letter || (*r).second != *word)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("Key/Datum mismatch:\n")
+ ACE_TEXT (" key \"%c\" should be \"%c\"\n")
+ ACE_TEXT (" datum \"%s\" should be \"%s\"\n"),
+ (*r).first,
+ *letter,
+ (*r).second.c_str (),
+ word->c_str ()),
+ false);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\t%c\t%s\n"),
+ (*r).first,
+ (*r).second.c_str ()));
+ }
+
+ // The size should not have changed.
+ ACE_ASSERT (phonetic.size () == letters_len);
+
+ // Empty the map of its contents wholesale.
+ phonetic.clear ();
+
+ ACE_ASSERT (phonetic.size () == 0 && phonetic.is_empty ());
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Index operator test passed.\n")));
+
+ return true;
+}
+
+// --------------------------------------------------------------
+
+class RefCounted
+{
+public:
+
+ RefCounted (void)
+ : refcount_ (0)
+ {
+ }
+
+ RefCounted (unsigned int * count)
+ : refcount_ (count)
+ {
+ }
+
+ ~RefCounted (void)
+ {
+ if (this->refcount_)
+ --(*this->refcount_);
+ }
+
+ RefCounted (RefCounted const & r)
+ : refcount_ (r.refcount_ptr ())
+ {
+ if (this->refcount_)
+ ++(*this->refcount_);
+ }
+
+ RefCounted &
+ operator= (RefCounted const & r)
+ {
+ RefCounted tmp (r);
+ std::swap (this->refcount_, tmp.refcount_);
+
+ return *this;
+ }
+
+ unsigned int *
+ refcount_ptr (void) const
+ {
+ return this->refcount_;
+ }
+
+ unsigned int
+ refcount (void) const
+ {
+ return *this->refcount_;
+ }
+
+private:
+
+ unsigned int * refcount_;
+
+};
+
+// --------
+
+bool
+reference_count_test (void)
+{
+ typedef ACE_Array_Map<ACE_TString, RefCounted> Map;
+
+ static Map::size_type const CAPACITY = 30;
+
+ unsigned int ref_count = 1;
+
+ RefCounted counted (&ref_count);
+
+ ACE_ASSERT (counted.refcount () == 1);
+
+ {
+ Map map (CAPACITY); // Preallocate storage for a number of
+ // elements even if they are not used to test
+ // some internals.
+
+ map[ACE_TEXT("One")] = counted;
+
+ ACE_ASSERT (counted.refcount () == 2);
+
+
+ std::pair<Map::iterator, bool> result;
+
+ {
+ // Enter a new scope block to assure destruction of temporaries
+ // on systems like Solaris / Sun C++.
+
+ result = map.insert (std::make_pair (ACE_TString (ACE_TEXT ("Two")),
+ counted));
+
+ ACE_ASSERT (result.second);
+ }
+
+ ACE_ASSERT (counted.refcount () == 3);
+
+ {
+ // Enter a new scope block to assure destruction of temporaries
+ // on systems like Solaris / Sun C++.
+
+ result = map.insert (std::make_pair (ACE_TString (ACE_TEXT ("Three")),
+ counted));
+
+ ACE_ASSERT (result.second);
+ }
+
+
+ ACE_ASSERT (counted.refcount () == 4);
+
+ Map::size_type const erased = map.erase (ACE_TEXT ("One"));
+
+ ACE_ASSERT (erased == 1);
+ ACE_ASSERT (counted.refcount () == 3);
+ }
+
+ // Map instance no longer contains any references to the "counted"
+ // object so the reference count should be back to one.
+
+ ACE_ASSERT (counted.refcount () == 1);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Reference count test passed.\n")));
+
+ return true;
+}
+
+// --------------------------------------------------------------
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("Array_Map_Test"));
+
+ ACE_ASSERT (::letters_len == ::words_len);
+
+ bool const success =
+ ::insertion_removal_test ()
+ && ::index_operator_test ()
+ && ::reference_count_test ();
+
+ ACE_END_TEST;
+
+ return (success ? 0 : -1);
+}
+
diff --git a/ACE/tests/Atomic_Op_Test.cpp b/ACE/tests/Atomic_Op_Test.cpp
new file mode 100644
index 00000000000..310c12aa89e
--- /dev/null
+++ b/ACE/tests/Atomic_Op_Test.cpp
@@ -0,0 +1,216 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Atomic_Op_Test.cpp
+//
+// = DESCRIPTION
+// This is a simple test of the Atomic Operations Class in ACE.
+// On platforms like Win32, ACE uses template specialization to
+// use native implementations provided by the OS to accelarate
+// these operations.
+//
+// = AUTHOR
+// Irfan Pyarali <irfan@cs.wustl.edu>
+//
+// ============================================================================
+
+#include "tests/test_config.h"
+
+ACE_RCSID(tests, Atomic_Op_Test, "$Id$")
+
+#if defined (ACE_HAS_THREADS)
+
+#include "ace/Atomic_Op.h"
+
+enum { TEST_ITERATIONS = 1000000 };
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("Atomic_Op_Test"));
+
+ ACE_Atomic_Op <ACE_Thread_Mutex, long> foo (5);
+
+ ACE_ASSERT (foo == 5);
+
+ long result = ++foo;
+ ACE_ASSERT (foo == 6);
+ ACE_ASSERT (result == 6);
+
+ result = --foo;
+ ACE_ASSERT (foo == 5);
+ ACE_ASSERT (result == 5);
+
+ result = foo++;
+ ACE_ASSERT (foo == 6);
+ ACE_ASSERT (result == 5);
+
+ result = foo--;
+ ACE_ASSERT (foo == 5);
+ ACE_ASSERT (result == 6);
+
+ result = foo += 10;
+ ACE_ASSERT (foo == 15);
+ ACE_ASSERT (result == 15);
+
+ result = foo -= 10;
+ ACE_ASSERT (foo == 5);
+ ACE_ASSERT (result == 5);
+
+ foo = 7;
+ ACE_ASSERT (foo == 7);
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Starting <long> assignment %D\n")));
+ int i;
+ for (i = 0; i < TEST_ITERATIONS; ++i)
+ {
+ foo = 1;
+ foo = 2;
+ foo = 3;
+ foo = 4;
+ }
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Ending <long> assignment %D\n")));
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Starting <long> increment %D\n")));
+ for (i = 0; i < TEST_ITERATIONS; ++i)
+ {
+ ++foo;
+ ++foo;
+ ++foo;
+ ++foo;
+ }
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Ending <long> increment %D\n")));
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Starting <long> decrement %D\n")));
+ for (i = 0; i < TEST_ITERATIONS; ++i)
+ {
+ --foo;
+ --foo;
+ --foo;
+ --foo;
+ }
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Ending <long> decrement %D\n")));
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Starting <long> addition %D\n")));
+ for (i = 0; i < TEST_ITERATIONS; ++i)
+ {
+ foo += 5;
+ foo += 5;
+ foo += 5;
+ foo += 5;
+ }
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Ending <long> addition %D\n")));
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Starting <long> subtraction %D\n")));
+ for (i = 0; i < TEST_ITERATIONS; ++i)
+ {
+ foo -= 5;
+ foo -= 5;
+ foo -= 5;
+ foo -= 5;
+ }
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Ending <long> subtraction %D\n")));
+
+ ACE_Atomic_Op <ACE_Thread_Mutex, int> bar (5);
+
+ ACE_ASSERT (bar == 5);
+
+ result = ++bar;
+ ACE_ASSERT (bar == 6);
+ ACE_ASSERT (result == 6);
+
+ result = --bar;
+ ACE_ASSERT (bar == 5);
+ ACE_ASSERT (result == 5);
+
+ result = bar++;
+ ACE_ASSERT (bar == 6);
+ ACE_ASSERT (result == 5);
+
+ result = bar--;
+ ACE_ASSERT (bar == 5);
+ ACE_ASSERT (result == 6);
+
+ result = bar += 10;
+ ACE_ASSERT (bar == 15);
+ ACE_ASSERT (result == 15);
+
+ result = bar -= 10;
+ ACE_ASSERT (bar == 5);
+ ACE_ASSERT (result == 5);
+
+ bar = 5L;
+ ACE_ASSERT (bar == 5);
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Starting <int> assignment %D\n")));
+ for (i = 0; i < TEST_ITERATIONS; ++i)
+ {
+ bar = 1;
+ bar = 2;
+ bar = 3;
+ bar = 4;
+ }
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Ending <int> assignment %D\n")));
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Starting <int> increment %D\n")));
+ for (i = 0; i < TEST_ITERATIONS; ++i)
+ {
+ ++bar;
+ ++bar;
+ ++bar;
+ ++bar;
+ }
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Ending <int> increment %D\n")));
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Starting <int> decrement %D\n")));
+ for (i = 0; i < TEST_ITERATIONS; ++i)
+ {
+ --bar;
+ --bar;
+ --bar;
+ --bar;
+ }
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Ending <int> decrement %D\n")));
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Starting <int> addition %D\n")));
+ for (i = 0; i < TEST_ITERATIONS; ++i)
+ {
+ bar += 5;
+ bar += 5;
+ bar += 5;
+ bar += 5;
+ }
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Ending <int> addition %D\n")));
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Starting <int> subtraction %D\n")));
+ for (i = 0; i < TEST_ITERATIONS; ++i)
+ {
+ bar -= 5;
+ bar -= 5;
+ bar -= 5;
+ bar -= 5;
+ }
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Ending <int> subtraction %D\n")));
+
+ ACE_END_TEST;
+ return 0;
+}
+
+#else
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("Atomic_Op_Test"));
+
+ ACE_ERROR ((LM_INFO,
+ ACE_TEXT ("threads not supported on this platform\n")));
+
+ ACE_END_TEST;
+ return 0;
+}
+#endif /* ACE_HAS_THREADS */
diff --git a/ACE/tests/Auto_Event_Test.cpp b/ACE/tests/Auto_Event_Test.cpp
new file mode 100644
index 00000000000..a31b8a9f6a1
--- /dev/null
+++ b/ACE/tests/Auto_Event_Test.cpp
@@ -0,0 +1,226 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Auto_Event Test
+//
+// = DESCRIPTION
+// This test verifies the functionality of the <ACE_Auto_Event>
+// implementation.
+//
+// = AUTHOR
+// Martin Corino <mcorino@remedy.nl>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/Auto_Event.h"
+#include "ace/Thread.h"
+#include "ace/Thread_Manager.h"
+#include "ace/Get_Opt.h"
+#include "ace/OS_NS_sys_time.h"
+#include "ace/OS_NS_time.h"
+#include "ace/OS_NS_unistd.h"
+
+ACE_RCSID(tests, Auto_Event_Test, "$Id$")
+
+// msec that times are allowed to differ before test fails.
+#if defined (ACE_HAS_HI_RES_TIMER) || defined (ACE_HAS_AIX_HI_RES_TIMER) || \
+ defined (ACE_HAS_PENTIUM) || defined (ACE_HAS_ALPHA_TIMER) || \
+ defined (ACE_HAS_POWERPC_TIMER)
+# define ACE_ALLOWED_SLACK 100
+#else /* don't have a high-res timer */
+# define ACE_ALLOWED_SLACK 1100
+#endif /* don't have a high-res timer */
+
+// Test results, 'success' is 0
+static int test_result = 0;
+
+#if defined (ACE_HAS_THREADS)
+
+// Event used in the tests. Start it "unsignalled" (i.e., its initial
+// state is 0).
+static ACE_Auto_Event evt ((unsigned int) 0);
+
+// Default number of iterations.
+static int n_iterations = 10;
+
+// Number of worker threads.
+static size_t n_workers = 10;
+
+// Number of timeouts.
+static size_t timeouts = 0;
+
+// Number of times to call test_timeout ().
+static size_t test_timeout_count = 3;
+
+// Tests the amount of time spent in a timed wait.
+static int
+test_timeout (void)
+{
+ int status = 0;
+
+ // milliseconds...
+ long msecs_expected;
+ long msecs_waited;
+ long msecs_diff;
+
+ // Wait a little longer each time
+ static long wait_secs = 3;
+
+ ACE_Time_Value wait = ACE_OS::gettimeofday ();
+
+ ACE_Time_Value begin = wait;
+
+ wait.sec (wait.sec () + wait_secs);
+
+ if (evt.wait (&wait) == -1)
+ ACE_ASSERT (errno == ETIME);
+
+ ACE_Time_Value wait_diff = ACE_OS::gettimeofday () - begin;
+
+ msecs_waited = wait_diff.msec ();
+ msecs_expected = wait_secs * 1000;
+ msecs_diff = labs (msecs_expected - msecs_waited);
+
+ if (msecs_diff > ACE_ALLOWED_SLACK)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Timed wait fails length test\n")));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Value: %d ms, actual %d ms\n"),
+ msecs_expected,
+ msecs_waited));
+ status = -1;
+ }
+
+ ++wait_secs;
+ return status;
+}
+
+// Explain usage and exit.
+static void
+print_usage_and_die (void)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("usage: %n [-w n_workers] [-n iteration_count]\n")));
+ ACE_OS::exit (1);
+}
+
+static void
+parse_args (int argc, ACE_TCHAR *argv[])
+{
+ ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("w:n:"));
+
+ int c;
+
+ while ((c = get_opt ()) != -1)
+ switch (c)
+ {
+ case 'w':
+ n_workers = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'n':
+ n_iterations = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ default:
+ print_usage_and_die ();
+ break;
+ }
+}
+
+// Worker tries to acquire the semaphore, hold it for a while, and
+// then releases it.
+
+static void *
+worker (void *)
+{
+ for (int iterations = 1;
+ iterations <= n_iterations;
+ iterations++)
+ {
+ ACE_Time_Value wait (0,
+ iterations * 1000 * 100); // Wait 'iter' msec
+ ACE_Time_Value tv = ACE_OS::gettimeofday () + wait;
+ if (evt.wait (&tv) == -1)
+ {
+ // verify that we have ETIME
+ ACE_ASSERT(ACE_OS::last_error() == ETIME);
+ ++timeouts;
+ ACE_Time_Value diff = ACE_OS::gettimeofday ();
+ diff = diff - tv; // tv should have been reset to time acquired
+ long diff_msec = diff.msec ();
+
+ if (diff_msec > ACE_ALLOWED_SLACK)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Acquire fails time reset test\n")));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Diff btw now and returned time: %d ms\n"),
+ diff.msec ()));
+ test_result = 1;
+ }
+ // Hold the lock for a while.
+ ACE_OS::sleep (ACE_Time_Value (0,
+ (ACE_OS::rand () % 1000) * 1000));
+ evt.signal ();
+ }
+
+ ACE_Thread::yield ();
+ }
+
+ return 0;
+}
+
+#endif /* ACE_HAS_THREADS */
+
+// Test event functionality.
+
+int run_main (int argc, ACE_TCHAR *argv[])
+{
+ ACE_START_TEST (ACE_TEXT ("Auto_Event_Test"));
+
+#if defined (ACE_HAS_THREADS)
+ parse_args (argc, argv);
+ ACE_OS::srand (ACE_OS::time (0L));
+
+ //Test timed waits.
+ for (size_t i = 0; i < test_timeout_count; i++)
+ if (test_timeout () != 0)
+ test_result = 1;
+
+ if (ACE_Thread_Manager::instance ()->spawn_n
+ (static_cast<size_t> (n_workers),
+ ACE_THR_FUNC (worker),
+ 0,
+ THR_NEW_LWP) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("spawn_n")),
+ 1);
+
+ // Release the first worker.
+ evt.signal ();
+
+ ACE_Thread_Manager::instance ()->wait ();
+
+ size_t percent = (timeouts * 100) / (n_workers * n_iterations);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Worker threads timed out %d percent of the time\n"),
+ percent));
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Auto_Event Test successful\n")));
+#else
+ ACE_UNUSED_ARG (argc);
+ ACE_UNUSED_ARG (argv);
+ ACE_ERROR ((LM_INFO,
+ ACE_TEXT ("Threads not supported on this platform\n")));
+#endif /* ACE_HAS_THREADS */
+ ACE_END_TEST;
+ return test_result;
+}
diff --git a/ACE/tests/Auto_IncDec_Test.cpp b/ACE/tests/Auto_IncDec_Test.cpp
new file mode 100644
index 00000000000..3308a35445b
--- /dev/null
+++ b/ACE/tests/Auto_IncDec_Test.cpp
@@ -0,0 +1,141 @@
+// $Id$
+
+//============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Auto_IncDec_Test.cpp
+//
+// = DESCRIPTION
+// This is a simple test of the Auto Increment/Decrement Class in
+// ACE.
+//
+// = AUTHOR
+// Edan Ayal <EdanA@cti2.com>
+//
+//============================================================================
+
+#include "tests/test_config.h"
+#include "ace/Auto_IncDec_T.h"
+#include "ace/Thread_Manager.h"
+#include "ace/Atomic_Op.h"
+#include "ace/OS_NS_unistd.h"
+
+ACE_RCSID(tests, Auto_IncDec_Test, "Auto_IncDec_Test.cpp, by Edan Ayal")
+
+#if defined (ACE_HAS_THREADS)
+
+// Default number of threads.
+static size_t n_threads = 15;
+
+typedef ACE_Atomic_Op<ACE_Thread_Mutex, int> INTERLOCKED_INT;
+static INTERLOCKED_INT current_threads_in_first_section;
+static INTERLOCKED_INT current_threads_in_second_section;
+
+static void *
+worker (void *)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT (" (%t) worker starting\n")));
+
+ { // First section.
+ ACE_Auto_IncDec<INTERLOCKED_INT> threads_in_section_auto_inc_dec
+ (current_threads_in_first_section);
+
+ // Wait according to the number of threads...
+ ACE_Time_Value pause (current_threads_in_first_section.value (),
+ 0);
+ ACE_OS::sleep (pause);
+ }
+
+ { // Second section.
+ ACE_Auto_IncDec<INTERLOCKED_INT> threads_in_section_auto_inc_dec
+ (current_threads_in_second_section);
+
+ // Wait according to the number of threads inside the previous
+ // section...
+ ACE_Time_Value pause (current_threads_in_first_section.value (),
+ 0);
+ ACE_OS::sleep (pause);
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT (" (%t) worker exiting\n")));
+ return 0;
+}
+
+#endif /* ACE_HAS_THREADS */
+
+// Spawn off threads.
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("Auto_IncDec_Test"));
+
+#if defined (ACE_HAS_THREADS)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT (" (%t) main thread starting\n")));
+
+ current_threads_in_first_section = 0;
+ current_threads_in_second_section = 0;
+
+ if (ACE_Thread_Manager::instance ()->spawn_n
+ (n_threads,
+ ACE_THR_FUNC (worker),
+ 0,
+ THR_NEW_LWP) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("spawn_n")),
+ -1);
+ // Make sure at least one thread is started...
+ ACE_Thread::yield ();
+
+ while (ACE_Thread_Manager::instance ()->count_threads ())
+ {
+ // wait according to the number of threads...
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT (" %d in first section, %d in second section, %d total\n"),
+ current_threads_in_first_section.value (),
+ current_threads_in_second_section.value (),
+ ACE_Thread_Manager::instance ()->count_threads ()));
+
+ ACE_Time_Value pause (1, 0);
+ ACE_OS::sleep (pause);
+ }
+
+ ACE_Thread_Manager::instance ()->wait ();
+
+ ACE_ASSERT (current_threads_in_first_section.value () == 0
+ && current_threads_in_second_section.value () == 0);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT (" (%t) exiting main thread\n")));
+#else
+ int counter = 0;
+ {
+ ACE_Auto_IncDec<int> Auto_IncDec1 (counter);
+ ACE_ASSERT (counter == 1);
+
+ ACE_Auto_IncDec<int> Auto_IncDec2 (counter);
+ ACE_ASSERT (counter == 2);
+
+ {
+ ACE_ASSERT (counter == 2);
+ ACE_Auto_IncDec<int> Auto_IncDec3 (counter);
+ ACE_ASSERT (counter == 3);
+ }
+
+ ACE_ASSERT (counter == 2);
+ }
+
+ ACE_ASSERT (counter == 0);
+
+#endif /* ACE_HAS_THREADS */
+
+ ACE_END_TEST;
+ return 0;
+}
diff --git a/ACE/tests/Barrier_Test.cpp b/ACE/tests/Barrier_Test.cpp
new file mode 100644
index 00000000000..2af15dfb66d
--- /dev/null
+++ b/ACE/tests/Barrier_Test.cpp
@@ -0,0 +1,138 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Barrier_Test.cpp
+//
+// = DESCRIPTION
+// This program illustrates how the ACE barrier synchronization
+// mechanisms work.
+//
+// = AUTHOR
+// Prashant Jain <pjain@cs.wustl.edu> and Doug Schmidt <schmidt@cs.wustl.edu>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/Barrier.h"
+#include "ace/Thread_Manager.h"
+
+ACE_RCSID(tests, Barrier_Test, "$Id$")
+
+#if defined (ACE_HAS_THREADS)
+
+struct Tester_Args
+ // = TITLE
+ // These arguments are passed into each test thread.
+{
+ Tester_Args (ACE_Barrier &tb, int i)
+ : tester_barrier_ (tb),
+ n_iterations_ (i) {}
+
+ ACE_Barrier &tester_barrier_;
+ // Reference to the tester barrier. This controls each miteration
+ // of the tester function running in every thread.
+
+ int n_iterations_;
+ // Number of iterations to run.
+};
+
+// Iterate <n_iterations> time printing off a message and "waiting"
+// for all other threads to complete this iteration.
+
+static void *
+wait_tester (Tester_Args *args)
+{
+ for (int iterations = 1;
+ iterations <= args->n_iterations_;
+ iterations++)
+ {
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) in iteration %d\n"),
+ iterations));
+
+ // Block until all other threads have waited, then continue.
+ if (args->tester_barrier_.wait () != 0)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%t) %p\n"),
+ ACE_TEXT ("wait failed")));
+ }
+
+ return 0;
+}
+
+// Wait on the barrier, expecting it to be shut down before completing
+// the wait.
+
+static void *
+shut_tester (Tester_Args *args)
+{
+ if (args->tester_barrier_.wait () == 0)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%t) wait succeeded, should have shut down\n")));
+ else if (errno != ESHUTDOWN)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%t) wait failed, expecting ESHUTDOWN, %p\n"),
+ ACE_TEXT ("got")));
+ return 0;
+}
+
+#endif /* ACE_HAS_THREADS */
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("Barrier_Test"));
+
+#if defined (ACE_HAS_THREADS)
+ int n_threads = ACE_MAX_THREADS;
+ int n_iterations = ACE_MAX_ITERATIONS;
+
+ ACE_Barrier tester_barrier (n_threads);
+
+ Tester_Args args (tester_barrier, n_iterations);
+
+ for (size_t iteration_count = 0;
+ iteration_count < ACE_MAX_ITERATIONS;
+ iteration_count++)
+ {
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("starting iteration %d\n"),
+ iteration_count));
+
+ if (ACE_Thread_Manager::instance ()->spawn_n
+ (n_threads,
+ (ACE_THR_FUNC) wait_tester,
+ (void *) &args,
+ THR_NEW_LWP | THR_JOINABLE) == -1)
+
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"),
+ ACE_TEXT ("spawn_n")), 1);
+
+ ACE_Thread_Manager::instance ()->wait ();
+ }
+
+ // Now test ACE_Barrier shutdown. Set up a barrier for n_threads, and start
+ // n_threads - 1 threads to wait, then shut the barrier down.
+ ACE_Barrier shut_barrier (n_threads);
+ Tester_Args shut_args (shut_barrier, 1);
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Starting shutdown test threads\n")));
+ if (ACE_Thread_Manager::instance ()->spawn_n
+ (n_threads - 1,
+ (ACE_THR_FUNC) shut_tester,
+ (void *) &shut_args,
+ THR_NEW_LWP | THR_JOINABLE) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("spawn_n")), 1);
+
+ shut_barrier.shutdown ();
+ ACE_Thread_Manager::instance ()->wait ();
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("test done\n")));
+#else
+ ACE_ERROR ((LM_INFO,
+ ACE_TEXT ("threads not supported on this platform\n")));
+#endif /* ACE_HAS_THREADS */
+ ACE_END_TEST;
+ return 0;
+}
diff --git a/ACE/tests/Based_Pointer_Test.cpp b/ACE/tests/Based_Pointer_Test.cpp
new file mode 100644
index 00000000000..03a853e9b95
--- /dev/null
+++ b/ACE/tests/Based_Pointer_Test.cpp
@@ -0,0 +1,427 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Based_Pointer_Test.cpp
+//
+// = DESCRIPTION
+// This test check the Based_Pointer and Based_Pointer_repository classes.
+//
+// = AUTHOR
+// Steve Williams <steve@telxio>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/DLL.h"
+#include "ace/ACE.h"
+#include "ace/OS.h"
+#ifdef ACE_HAS_POSITION_INDEPENDENT_POINTERS
+#include "ace/Based_Pointer_Repository.h"
+#endif /* ACE_HAS_POSITION_INDEPENDENT_POINTERS */
+#include "ace/Malloc_T.h"
+#include "ace/MMAP_Memory_Pool.h"
+#include "ace/PI_Malloc.h"
+#include "ace/Null_Mutex.h"
+
+ACE_RCSID (tests,
+ Based_Pointer_Repository_Test,
+ "$Id$")
+
+#ifdef ACE_HAS_POSITION_INDEPENDENT_POINTERS
+
+#if defined (ACE_WIN32) && defined (_MSC_VER) && defined (_DEBUG)
+# define OBJ_SUFFIX ACE_TEXT ("d") ACE_DLL_SUFFIX
+#elif defined (ACE_WIN32) && defined (__BORLANDC__)
+# define OBJ_SUFFIX ACE_LD_DECORATOR_STR ACE_DLL_SUFFIX
+#else
+# define OBJ_SUFFIX ACE_DLL_SUFFIX
+#endif /* ACE_WIN32 && && _MSC_VER && _DEBUG */
+
+#if defined (ACE_WIN32) || defined (ACE_OPENVMS)
+# define OBJ_PREFIX ACE_DLL_PREFIX
+#else
+# define OBJ_PREFIX ACE_TEXT("./") ACE_DLL_PREFIX
+#endif /* ACE_WIN32 */
+
+// Declare the type of the DLL symbol:
+typedef void *(*Get_Bp_Repository_Inst)(void);
+
+// Declare an allocator based MMAP_Memory_Pool
+typedef ACE_Malloc_T< ACE_MMAP_MEMORY_POOL, ACE_Null_Mutex, ACE_PI_Control_Block
+ > MMAP_Allocator;
+
+
+// Check that the ACE_Based_Pointer_Repository can be accessed
+// from a Windows DLL
+// (see http://deuce.doc.wustl.edu/bugzilla/show_bug.cgi?id=1991)
+int singleton_test (void)
+{
+ void* baddr1 = ACE_BASED_POINTER_REPOSITORY::instance();
+ void* baddr2 = ACE_BASED_POINTER_REPOSITORY::instance();
+
+ if (baddr1 != baddr2)
+ {
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("ACE_Based_Pointer_Repository is not a singleton\n")),
+ -1);
+ }
+
+// Protection against this test being run on platforms not supporting Dlls.
+#if defined(ACE_HAS_DYNAMIC_LINKING)
+
+ ACE_DLL dll;
+
+ // If DLL causes multiple instances of singleton
+ // then the ACE_Cleanup object registered
+ // with the ACE_Object_manager will no longer be valid,
+ // at exit time if the library is unloaded. Override
+ // the default close on destruct.
+ int retval = dll.open (OBJ_PREFIX
+ ACE_TEXT ("Based_Pointer_Test_Lib")
+ OBJ_SUFFIX,
+ ACE_DEFAULT_SHLIB_MODE,
+ 0);
+
+ if (retval != 0)
+ {
+ ACE_TCHAR *dll_error = dll.error ();
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("Error in DLL Open: %s\n"),
+ dll_error ? dll_error : ACE_TEXT ("unknown error")),
+ -1);
+ }
+
+#if defined (ACE_OPENVMS)
+ // with OPENVMS symbol names > 31 cause us trouble with dlsym()
+ void* foo = dll.symbol (ACE_TEXT ("get_based_pointer_repo_inst"));
+#else
+ void* foo = dll.symbol (ACE_TEXT ("get_based_pointer_repository_instance"));
+#endif
+
+ // Cast the void* to function* with a long as intermediate.
+ ptrdiff_t tmp = reinterpret_cast<ptrdiff_t> (foo);
+ Get_Bp_Repository_Inst get_bp_repository_inst =
+ reinterpret_cast<Get_Bp_Repository_Inst> (tmp);
+ if (get_bp_repository_inst == 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ dll.error ()),
+ -1);
+
+ void* baddr_dll = get_bp_repository_inst ();
+
+ dll.close ();
+
+ if (baddr_dll != baddr1)
+ {
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("ACE_Based_Pointer_Repository is not a singleton in DLL %x %x\n"), baddr_dll, baddr1),
+ -1);
+ }
+
+#endif /* ACE_HAS_DYNAMIC_LINKING */
+
+ return 0;
+}
+
+// Check that MMAP memory blocks are correctly mapped
+// into the Based_Pointer_Repository
+int
+mmap_map_test(void)
+{
+ MMAP_Allocator* alloc = 0;
+
+ ACE_OS::unlink("foo");
+ {
+ // The 'options' are only here to quiet MSVC 6. It can be removed
+ // when MSVC 6 support is removed.
+ MMAP_Allocator::MEMORY_POOL_OPTIONS *options = 0;
+ ACE_NEW_RETURN
+ (alloc,
+ MMAP_Allocator (ACE_TEXT ("foo"), ACE_TEXT ("foo"), options),
+ -1);
+
+ void* addr = alloc->base_addr();
+ if(addr == 0)
+ {
+ ACE_ERROR((LM_ERROR,
+ ACE_TEXT ("Unable to get base to MMAP Memory Pool\n")));
+ alloc->remove();
+ delete alloc;
+ return -1;
+ }
+
+ // Check a base address mapping was added to the Repository
+ // when the pool was created
+ void* ba = 0;
+ if(ACE_BASED_POINTER_REPOSITORY::instance()->find(addr, ba) == -1)
+ {
+ ACE_ERROR((LM_ERROR,
+ ACE_TEXT ("Unable to access repository\n")));
+ alloc->remove();
+ delete alloc;
+ return -1;
+ }
+
+ alloc->remove();
+ delete alloc;
+
+ if(ba != addr)
+ {
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT (
+ "MMAP pool mapping not present\n")),
+ -1);
+ }
+
+ // Check Mapping is removed when object is deleted
+ if(ACE_BASED_POINTER_REPOSITORY::instance()->find(addr, ba) == -1)
+ {
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("Unable to access repository\n")),
+ -1);
+ }
+ if(ba != 0)
+ {
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("MMAP pool mapping not removed\n")),
+ -1);
+ }
+ }
+ return 0;
+}
+
+// Check that persistent MMAP memory blocks are correctly remapped
+// into the Based_Pointer_Repository
+// (i.e. maps based on backing stores that are already
+// present in the filesystem)
+// (see http://deuce.doc.wustl.edu/bugzilla/show_bug.cgi?id=2216)
+int
+mmap_persistent_map_test(void)
+{
+ MMAP_Allocator* alloc = 0;
+
+ // The 'options' are only here to quiet MSVC 6. It can be removed
+ // when MSVC 6 support is removed.
+ MMAP_Allocator::MEMORY_POOL_OPTIONS *options = 0;
+ ACE_OS::unlink("foo");
+ {
+ ACE_NEW_RETURN
+ (alloc,
+ MMAP_Allocator (ACE_TEXT ("foo"), ACE_TEXT ("foo"), options),
+ -1);
+ alloc->sync();
+
+ // Delete Malloc and the memory pool, but do not remove
+ // the backing store
+ alloc->memory_pool().release(0);
+ delete alloc;
+ }
+ //
+ // Recreate segment with existing backing store
+ //
+ ACE_NEW_RETURN
+ (alloc,
+ MMAP_Allocator (ACE_TEXT ("foo"), ACE_TEXT("foo"), options),
+ -1);
+
+ void* addr = alloc->base_addr();
+ if(addr == 0)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Unable to get base to persistent MMAP Memory Pool\n")));
+ alloc->remove();
+ delete alloc;
+ return -1;
+ }
+ void* ba = 0;
+ if(ACE_BASED_POINTER_REPOSITORY::instance()->find(addr, ba) == -1)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Unable to find base address after map of persistent segment\n")));
+ alloc->remove();
+ delete alloc;
+ return -1;
+ }
+ if(ba == 0)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Persistent MMAP Memory Pool not mapped\n")));
+ alloc->remove();
+ delete alloc;
+ return -1;
+ }
+
+ alloc->remove();
+ delete alloc;
+ return 0;
+}
+
+// Check that MMAP memory blocks are correctly remapped
+// into the Based_Pointer_Repository
+// (i.e. when a segment is resized it may move its base address
+// because the OS cannot fit the new segment size at the same
+// base address, in this case the Repository must be updated)
+// (see http://deuce.doc.wustl.edu/bugzilla/show_bug.cgi?id=2218)
+int
+mmap_remap_test(void)
+{
+ // Use a Position Independent memory segment
+ // because this one is going to move
+
+ MMAP_Allocator *alloc[ 3 ]= {0, 0, 0};
+ void *pool_base[ 3 ]= {0, 0, 0};
+
+ // Make sure the Pool options are set to allow
+ // the segment to move
+ ACE_MMAP_Memory_Pool_Options data_opts(
+ 0,
+ ACE_MMAP_Memory_Pool_Options::NEVER_FIXED );
+ int i;
+
+ for (i= 0; i<3; ++i)
+ {
+ ACE_TCHAR store[ MAXPATHLEN + 1 ];
+ ACE_OS::sprintf( store, ACE_TEXT("foo%d"), i );
+ ACE_OS::unlink( store );
+
+ ACE_NEW_RETURN (alloc[ i ],
+ MMAP_Allocator (store, store, &data_opts),
+ -1);
+ pool_base[ i ]= alloc[ i ]->base_addr();
+ }
+
+ // sort pools into base address order
+ for (i= 0; i<2; ++i)
+ {
+ if (pool_base[ i ] < pool_base[ i+1 ])
+ {
+ void *tmp1= pool_base[ i ];
+ MMAP_Allocator *tmp2= alloc[ i ];
+ pool_base[ i ]= pool_base[ i+1 ];
+ alloc[ i ]= alloc[ i+1 ];
+ pool_base[ i+1 ]= tmp1;
+ alloc[ i+1 ]= tmp2;
+ i= -1;
+ }
+ }
+
+ // alloc[1] is now bounded, whether memory grows up or
+ // down, it will hit either alloc[0] or alloc[2] and have
+ // to be remapped.
+ //
+ // Calculate maximum space between base addresses
+
+ size_t size= (char *) pool_base[ 0 ] - (char *) pool_base[ 1 ];
+ size_t tmpsize= (char *) pool_base[ 1 ] - (char *) pool_base[ 2 ];
+ size= (size < tmpsize) ? tmpsize : size;
+
+ // force pool to move
+ ++size;
+
+ (void)alloc[ 1 ]->malloc(size);
+ void *nba= alloc[ 1 ]->base_addr();
+
+ if (pool_base[ 1 ] == nba)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("MMAP Pool did not move base address as expected\n")));
+ for (i= 0; i<3; ++i)
+ {
+ alloc[ i ]->remove();
+ delete alloc[ i ];
+ }
+ return -1;
+ }
+
+ void *ba= 0;
+ if (ACE_BASED_POINTER_REPOSITORY::instance()->find(nba, ba) == -1)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Unable to find base address after remap of segment\n")));
+ for (i= 0; i<3; ++i)
+ {
+ alloc[ i ]->remove();
+ delete alloc[ i ];
+ }
+ return -1;
+ }
+
+ if (ba != nba)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("New base address not mapped after MMAP remap\n")));
+ for (i= 0; i<3; ++i)
+ {
+ alloc[ i ]->remove();
+ delete alloc[ i ];
+ }
+ return -1;
+ }
+
+ // Check old base address has been removed
+ // from the repository
+ if (ACE_BASED_POINTER_REPOSITORY::instance()->find( pool_base[ 1 ], ba ) == -1)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Unable to find base address after remap of segment\n")));
+ for (i= 0; i<3; ++i)
+ {
+ alloc[ i ]->remove();
+ delete alloc[ i ];
+ }
+ return -1;
+ }
+
+ if (ba == pool_base[ 1 ])
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Old base address not removed after MMAP remap\n")));
+ for (i= 0; i<3; ++i)
+ {
+ alloc[ i ]->remove();
+ delete alloc[ i ];
+ }
+ return -1;
+ }
+
+ for (i= 0; i<3; ++i)
+ {
+ alloc[ i ]->remove();
+ delete alloc[ i ];
+ }
+ return 0;
+}
+
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("Based_Pointer_Test"));
+
+ int retval = 0;
+
+ retval += singleton_test ();
+ retval += mmap_map_test();
+ retval += mmap_persistent_map_test();
+ retval += mmap_remap_test();
+
+ ACE_END_TEST;
+ return retval == 0 ? 0 : 1;
+}
+
+#else /* ! ACE_HAS_POSITION_INDEPENDENT_POINTERS */
+// Nothing to test !
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("Based_Pointer_Test"));
+ ACE_END_TEST;
+ return 0;
+}
+#endif /* ACE_HAS_POSITION_INDEPENDENT_POINTERS */
diff --git a/ACE/tests/Based_Pointer_Test_Lib.cpp b/ACE/tests/Based_Pointer_Test_Lib.cpp
new file mode 100644
index 00000000000..e7047b70fa3
--- /dev/null
+++ b/ACE/tests/Based_Pointer_Test_Lib.cpp
@@ -0,0 +1,39 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Based_Pointer_Test_Lib.cpp
+//
+// = DESCRIPTION
+// This test confirms the function of the Based_Pointer_Repository
+//
+// = AUTHOR
+// Steve Williams <steve@telxio>
+//
+// ============================================================================
+
+#include "ace/ACE.h"
+#include "ace/svc_export.h"
+#include "ace/Based_Pointer_Repository.h"
+
+ACE_RCSID (tests,
+ Based_Pointer_Repository_DLL_Test,
+ "$Id$")
+
+#if defined (ACE_OPENVMS)
+ // with OPENVMS symbol names > 31 cause us trouble with dlsym()
+extern "C" ACE_Svc_Export void *
+get_based_pointer_repo_inst (void)
+#else
+extern "C" ACE_Svc_Export void *
+get_based_pointer_repository_instance (void)
+#endif
+{
+ void* baddr = ACE_BASED_POINTER_REPOSITORY::instance();
+ return baddr;
+}
+
diff --git a/ACE/tests/Basic_Types_Test.cpp b/ACE/tests/Basic_Types_Test.cpp
new file mode 100644
index 00000000000..90fbf04a991
--- /dev/null
+++ b/ACE/tests/Basic_Types_Test.cpp
@@ -0,0 +1,173 @@
+// $Id$
+//
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Basic_Types_Test.cpp
+//
+// = DESCRIPTION
+// Checks the #defines in ace/Basic_Types.h, and a few other basics.
+//
+// = AUTHOR
+// David L. Levine <levine@cs.wustl.edu>
+//
+// ============================================================================
+
+#include "ace/config-all.h"
+// Don't use the ACE version accessors in class ACE, so that we can
+// support this test cleanly with the OS component, only.
+#include "ace/Version.h"
+
+#if defined (ACE_HAS_MINIMAL_ACE_OS)
+ // Redefine these macros to allow the test to print out useful info.
+# undef ACE_DEBUG
+# define ACE_DEBUG(x) ACE_OS::fprintf x
+# define LM_DEBUG stdout
+# undef ACE_ERROR
+# define ACE_ERROR(x) ACE_OS::fprintf x
+# define LM_ERROR stderr
+# define ACE_START_TEST(x) ACE_OS::printf (x ACE_TEXT ("\n"))
+# define ACE_END_TEST
+#else /* ! ACE_HAS_MINIMAL_ACE_OS */
+# include "test_config.h"
+#endif /* ! ACE_HAS_MINIMAL_ACE_OS */
+
+#include "ace/Basic_Types.h"
+#include "ace/OS_NS_unistd.h"
+
+ACE_RCSID(tests, Basic_Types_Test, "$Id$")
+
+typedef void* (*a_function_pointer) (void*);
+
+static
+u_int
+check (const ACE_TCHAR *message, u_int i, u_int j)
+{
+ if (i == j)
+ {
+ ACE_DEBUG ((LM_DEBUG, message, j, ACE_TEXT ("\n")));
+ return 0;
+ }
+ else
+ {
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("assertion failed \"%s\": %u != %u\n"),
+ message, i, j));
+ return 1;
+ }
+}
+
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("Basic_Types_Test"));
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("This is ACE Version %u.%u.%u\n\n"),
+ ACE_MAJOR_VERSION,
+ ACE_MINOR_VERSION,
+ ACE_BETA_VERSION));
+
+ u_int errors = 0;
+
+ errors += check (ACE_TEXT ("ACE_SIZEOF_CHAR: %u%s"),
+ sizeof (char), ACE_SIZEOF_CHAR);
+#if defined (ACE_HAS_WCHAR)
+ errors += check (ACE_TEXT ("ACE_SIZEOF_WCHAR: %u%s"),
+ sizeof (wchar_t), ACE_SIZEOF_WCHAR);
+#endif /* ACE_HAS_WCHAR */
+ errors += check (ACE_TEXT ("ACE_SIZEOF_SHORT: %u%s"),
+ sizeof (short), ACE_SIZEOF_SHORT);
+ errors += check (ACE_TEXT ("ACE_SIZEOF_INT: %u%s"),
+ sizeof (int), ACE_SIZEOF_INT);
+ errors += check (ACE_TEXT ("ACE_SIZEOF_LONG: %u%s"),
+ sizeof (long), ACE_SIZEOF_LONG);
+ errors += check (ACE_TEXT ("ACE_SIZEOF_LONG_LONG: %u%s"),
+#if defined (ACE_LACKS_LONGLONG_T)
+ sizeof (ACE_U_LongLong),
+#elif defined (ACE_WIN32)
+ sizeof (unsigned __int64),
+#else /* ! ACE_WIN32 && ! ACE_LACKS_LONGLONG_T */
+ sizeof (long long),
+#endif /* ! ACE_WIN32 && ! ACE_LACKS_LONGLONG_T */
+ ACE_SIZEOF_LONG_LONG);
+ errors += check (ACE_TEXT ("sizeof 64-bit literal: %u%s"),
+ sizeof ACE_UINT64_LITERAL (1),
+ 8);
+ errors += check (ACE_TEXT ("ACE_SIZEOF_VOID_P: %u%s"),
+ sizeof (void *), ACE_SIZEOF_VOID_P);
+ errors += check (ACE_TEXT ("ACE_SIZEOF_FLOAT: %u%s"),
+ sizeof (float), ACE_SIZEOF_FLOAT);
+ errors += check (ACE_TEXT ("ACE_SIZEOF_DOUBLE: %u%s"),
+ sizeof (double), ACE_SIZEOF_DOUBLE);
+ errors += check (ACE_TEXT ("ACE_SIZEOF_LONG_DOUBLE: %u%s"),
+ sizeof (long double), ACE_SIZEOF_LONG_DOUBLE);
+
+// Crays don't have 16-bit quantities, so don't even test for 16-bit values
+#if !defined(_UNICOS)
+ errors += check (ACE_TEXT ("sizeof (ACE_INT16) is %u%s"),
+ sizeof (ACE_INT16), 2);
+ errors += check (ACE_TEXT ("sizeof (ACE_UINT16) is %u%s"),
+ sizeof (ACE_INT16), 2);
+#else /* ! _UNICOS */
+ errors += check (ACE_TEXT ("sizeof (ACE_INT16) is %u%s"),
+ sizeof (ACE_INT16), 8);
+ errors += check (ACE_TEXT ("sizeof (ACE_UINT16) is %u%s"),
+ sizeof (ACE_INT16), 8);
+#endif /* ! _UNICOS */
+
+// MPP Crays do have 32-bit quantities (short), though vector Crays don't
+#if !defined(_UNICOS) || defined(_CRAYMPP)
+ errors += check (ACE_TEXT ("sizeof (ACE_INT32) is %u%s"),
+ sizeof (ACE_INT32), 4);
+ errors += check (ACE_TEXT ("sizeof (ACE_UINT32) is %u%s"),
+ sizeof (ACE_INT32), 4);
+#else /* ! _UNICOS */
+ errors += check (ACE_TEXT ("sizeof (ACE_INT32) is %u%s"),
+ sizeof (ACE_INT32), 8);
+ errors += check (ACE_TEXT ("sizeof (ACE_UINT32) is %u%s"),
+ sizeof (ACE_INT32), 8);
+#endif /* ! _UNICOS */
+ errors += check (ACE_TEXT ("sizeof (ACE_UINT64) is %u%s"),
+ sizeof (ACE_UINT64), 8);
+
+ // ACE assumes sizeof (ptrdiff_t) == sizeof (void*)
+ if (sizeof (ptrdiff_t) == sizeof (void *))
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("sizeof (ptrdiff_t) == sizeof (void*)\n")));
+ else
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("sizeof (ptrdiff_t) != sizeof (void*)\n")));
+
+ // ACE assumes sizeof (ptrdiff_t) >= sizeof (a_function_pointer)
+ if (sizeof (ptrdiff_t) >= sizeof (a_function_pointer))
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("sizeof (ptrdiff_t) >= sizeof (a_function_pointer)\n")));
+ else
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("sizeof (ptrdiff_t) < sizeof (a_function_pointer)\n")));
+
+#if defined (ACE_LITTLE_ENDIAN)
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("little endian\n")));
+#elif defined (ACE_BIG_ENDIAN)
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("big endian\n")));
+#else
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("assertion failed: no ACE_*_ENDIAN definition!\n")));
+#endif /* ACE_LITTLE_ENDIAN */
+
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("OS page size: %u\n"),
+ ACE_OS::getpagesize ()));
+
+#if defined (_SC_PAGESIZE)
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("sysconf page size: %d\n"),
+ (int) ACE_OS::sysconf (_SC_PAGESIZE)));
+#endif /* _SC_PAGESIZE */
+#if defined (_SC_CLK_TCK)
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("clock ticks/sec = %d\n"),
+ (int) ACE_OS::sysconf (_SC_CLK_TCK)));
+#endif /* _SC_CLK_TCK */
+
+
+ ACE_END_TEST;
+ return errors == 0 ? 0 : 1;
+}
diff --git a/ACE/tests/Bound_Ptr_Test.cpp b/ACE/tests/Bound_Ptr_Test.cpp
new file mode 100644
index 00000000000..fa449f67a37
--- /dev/null
+++ b/ACE/tests/Bound_Ptr_Test.cpp
@@ -0,0 +1,464 @@
+// $Id$
+
+//=============================================================================
+/**
+ * @file Bound_Ptr_Test.cpp
+ *
+ * $Id$
+ *
+ * This example tests the <ACE_Strong_Bound_Ptr> and
+ * <ACE_Weak_Bound_Ptr> and illustrates how they may be dispersed
+ * between multiple threads using an implementation of the Active
+ * Object pattern, which is available in the POSA2 book
+ * <http://www.cs.wustl.edu/~schmidt/POSA>.
+ *
+ * @author Christopher Kohlhoff <chris@kohlhoff.com>
+ */
+//=============================================================================
+
+#include "test_config.h"
+#include "ace/Null_Mutex.h"
+#include "ace/Method_Request.h"
+#include "Bound_Ptr_Test.h"
+
+ACE_RCSID (tests, Bound_Ptr_Test, "Bound_Ptr_Test.cpp,v 4.8 2000/04/23 04:43:58 brunsch Exp")
+
+// The following Parent and Child classes illustrate how you might use the
+// ACE_Strong_Bound_Ptr and ACE_Weak_Bound_Ptr together in cyclic
+// relationships.
+
+struct Child_Base
+{
+ virtual ~Child_Base (void);
+
+ // Perform some operation.
+ virtual void do_something (void) = 0;
+};
+
+
+// This class should only be created on the heap. Normally it would be an
+// abstract class, and the implementation would be elsewhere.
+struct Parent
+{
+ Parent (void);
+ ~Parent (void);
+
+ // Weak pointer to this object used to hand out new references. Must be
+ // weak since it can't own itself!
+ ACE_Weak_Bound_Ptr<Parent, ACE_Null_Mutex> weak_self_;
+
+ // The parent owns the child. When the parent is destroyed the child will
+ // be automatically deleted.
+ ACE_Strong_Bound_Ptr<Child_Base, ACE_Null_Mutex> child_;
+
+ // Called by the child to perform some operation.
+ void do_something (void);
+
+ static size_t instance_count_;
+};
+
+// This class should only be created on the heap. Normally it would be an
+// abstract class, and the implementation would be elsewhere.
+struct Child : public Child_Base
+{
+ Child (ACE_Weak_Bound_Ptr<Parent, ACE_Null_Mutex> parent);
+ virtual ~Child (void);
+
+ // Back pointer to the parent. The child does not own the parent so has no
+ // effect on its lifetime.
+ ACE_Weak_Bound_Ptr<Parent, ACE_Null_Mutex> parent_;
+
+ // Perform some operation. Delegates the work to the parent.
+ virtual void do_something (void);
+
+ static size_t instance_count_;
+};
+
+Child_Base::~Child_Base (void)
+{
+}
+
+
+size_t Parent::instance_count_ = 0;
+
+Parent::Parent (void)
+ : weak_self_(this),
+ child_(new Child(weak_self_))
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Creating Parent object\n")));
+ ++Parent::instance_count_;
+}
+
+Parent::~Parent (void)
+{
+ --Parent::instance_count_;
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Deleting Parent object\n")));
+}
+
+void Parent::do_something (void)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Parent doing something\n")));
+}
+
+size_t Child::instance_count_ = 0;
+
+Child::Child (ACE_Weak_Bound_Ptr<Parent, ACE_Null_Mutex> parent)
+ : parent_(parent)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Creating Child object\n")));
+ ++Child::instance_count_;
+}
+
+Child::~Child (void)
+{
+ --Child::instance_count_;
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Deleting Child object\n")));
+}
+
+void Child::do_something (void)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Child doing something\n")));
+
+ // Using operator-> on a weak pointer will automatically create a strong
+ // pointer as a temporary. This ensures that the object exists for the
+ // lifetime of the call (although it does not check for null).
+ parent_->do_something ();
+
+ // In cases where we may need to call operations on the weak pointer
+ // many times, we can reduce the overhead by explicitly converting to a
+ // strong pointer first.
+ ACE_Strong_Bound_Ptr<Parent, ACE_Null_Mutex> strong_parent (parent_);
+
+ // You can check for null to see if the parent object still exists (in this
+ // case it is not strictly necessary since the child will only exist if the
+ // parent still exists).
+ if (strong_parent == 0)
+ return;
+
+ for (int i = 0; i < 5; ++i)
+ strong_parent->do_something ();
+}
+
+size_t Printer::instance_count_ = 0;
+
+Printer::Printer (const char *message)
+ : message_ (message)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Creating Printer object\n")));
+ ++Printer::instance_count_;
+}
+
+Printer::~Printer (void)
+{
+ --Printer::instance_count_;
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Deleting Printer object\n")));
+}
+
+void
+Printer::print (void)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) %s\n"),
+ ACE_TEXT_CHAR_TO_TCHAR(this->message_)));
+}
+
+#if defined (ACE_HAS_THREADS)
+
+/**
+ * @class Method_Request_print
+ *
+ * @brief Reification of the <print> method.
+ */
+class Method_Request_print : public ACE_Method_Request
+{
+public:
+ Method_Request_print (Scheduler *,
+ Printer_var &printer);
+ virtual ~Method_Request_print (void);
+
+ /// This is the entry point into the Active Object method.
+ virtual int call (void);
+
+private:
+ Scheduler *scheduler_;
+ Printer_var printer_;
+};
+
+Method_Request_print::Method_Request_print (Scheduler *new_scheduler,
+ Printer_var &printer)
+ : scheduler_ (new_scheduler),
+ printer_ (printer)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Method_Request_print created\n")));
+}
+
+Method_Request_print::~Method_Request_print (void)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Method_Request_print will be deleted.\n")));
+}
+
+int
+Method_Request_print::call (void)
+{
+ // Dispatch the Servant's operation and store the result into the
+ // Future.
+ Printer_var temp = printer_;
+
+ temp->print ();
+
+ return 0;
+}
+
+/**
+ * @class Method_Request_end
+ *
+ * @brief Reification of the <end> method.
+ */
+class Method_Request_end : public ACE_Method_Request
+{
+public:
+ Method_Request_end (Scheduler *new_Prime_Scheduler);
+ virtual ~Method_Request_end (void);
+ virtual int call (void);
+
+private:
+ Scheduler *scheduler_;
+};
+
+Method_Request_end::Method_Request_end (Scheduler *scheduler)
+ : scheduler_ (scheduler)
+{
+}
+
+Method_Request_end::~Method_Request_end (void)
+{
+}
+
+int
+Method_Request_end::call (void)
+{
+ // Shut down the scheduler by deactivating the activation queue's
+ // underlying message queue - should pop all worker threads off their
+ // wait and they'll exit.
+ this->scheduler_->msg_queue ()->deactivate ();
+ return -1;
+}
+
+// Constructor
+// Associates the activation queue with this task's message queue,
+// allowing easy access to the message queue for shutting it down
+// when it's time to stop this object's service threads.
+Scheduler::Scheduler (Scheduler *new_scheduler)
+ : activation_queue_ (msg_queue ()), scheduler_ (new_scheduler)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Scheduler created\n")));
+}
+
+// Destructor
+
+Scheduler::~Scheduler (void)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Scheduler will be destroyed\n")));
+}
+
+// open
+
+int
+Scheduler::open (void *)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Scheduler open\n")));
+ // Become an Active Object.
+ int num_threads = 3;
+ return this->activate (THR_BOUND | THR_JOINABLE, num_threads);
+}
+
+// close
+
+int
+Scheduler::close (u_long)
+{
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) rundown\n")));
+ return 0;
+}
+
+// Service..
+
+int
+Scheduler::svc (void)
+{
+ for (;;)
+ {
+ // Dequeue the next method request (we use an strong pointer in
+ // case an exception is thrown in the <call>).
+ ACE_Strong_Bound_Ptr<ACE_Method_Request, ACE_Null_Mutex> mo (this->activation_queue_.dequeue ());
+ if (mo == 0)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) activation queue shut down\n")));
+ break;
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) calling method request\n")));
+ // Call it.
+ if (mo->call () == -1)
+ break;
+
+ // Destructor automatically deletes it.
+ }
+
+ return 0;
+}
+
+void
+Scheduler::end (void)
+{
+ this->activation_queue_.enqueue (new Method_Request_end (this));
+}
+
+// Here's where the work takes place.
+
+void
+Scheduler::print (Printer_var &printer)
+{
+ this->activation_queue_.enqueue
+ (new Method_Request_print (this,
+ printer));
+}
+
+// Total number of loops.
+static int n_loops = 10;
+
+#endif /* ACE_HAS_THREADS */
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("Bound_Ptr_Test"));
+
+
+ // =========================================================================
+ // The following test uses the ACE_Strong_Bound_Ptr in a single
+ // thread of control, hence we use the ACE_Null_Mutex
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) performing synchronous test...\n")));
+
+ Parent *parent1 = 0;
+ ACE_NEW_RETURN (parent1,
+ Parent,
+ -1);
+ ACE_Weak_Bound_Ptr<Parent, ACE_Null_Mutex> p8;
+ {
+ // Must get the pointer from the parent object's weak_self_ member.
+ ACE_Strong_Bound_Ptr<Parent, ACE_Null_Mutex> p(parent1->weak_self_);
+ ACE_Strong_Bound_Ptr<Parent, ACE_Null_Mutex> p1(p);
+ ACE_Strong_Bound_Ptr<Parent, ACE_Null_Mutex> p2(p);
+ ACE_Weak_Bound_Ptr<Parent, ACE_Null_Mutex> p3(p);
+ ACE_Strong_Bound_Ptr<Parent, ACE_Null_Mutex> p4(p);
+ ACE_Strong_Bound_Ptr<Parent, ACE_Null_Mutex> p5 = p2;
+ ACE_Strong_Bound_Ptr<Parent, ACE_Null_Mutex> p6 = p3;
+ ACE_Weak_Bound_Ptr<Parent, ACE_Null_Mutex> p7(p1);
+ p8 = p2;
+ p->child_->do_something ();
+ }
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Parent instance count is %d, expecting 0\n"),
+ Parent::instance_count_));
+ ACE_ASSERT (Parent::instance_count_ == 0);
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Child instance count is %d, expecting 0\n"),
+ Child::instance_count_));
+ ACE_ASSERT (Child::instance_count_ == 0);
+ // Weak pointer should now be set to null.
+ ACE_ASSERT (p8.null ());
+
+ Printer *printer1 = 0;
+ ACE_NEW_RETURN (printer1,
+ Printer ("I am printer 1"),
+ -1);
+ ACE_Weak_Bound_Ptr<Printer, ACE_Null_Mutex> r9;
+ {
+ ACE_Strong_Bound_Ptr<Printer, ACE_Null_Mutex> r(printer1);
+ ACE_Strong_Bound_Ptr<Printer, ACE_Null_Mutex> r1(r);
+ ACE_Strong_Bound_Ptr<Printer, ACE_Null_Mutex> r2(r);
+ ACE_Strong_Bound_Ptr<Printer, ACE_Null_Mutex> r3(r);
+ ACE_Strong_Bound_Ptr<Printer, ACE_Null_Mutex> r4(r);
+ ACE_Strong_Bound_Ptr<Printer, ACE_Null_Mutex> r5 = r2;
+ ACE_Strong_Bound_Ptr<Printer, ACE_Null_Mutex> r6 = r1;
+ ACE_Weak_Bound_Ptr<Printer, ACE_Null_Mutex> r7(r1);
+ ACE_Weak_Bound_Ptr<Printer, ACE_Null_Mutex> r8 = r2;
+ r9 = r3;
+ r9->print ();
+ }
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Printer instance count is %d, expecting 0\n"),
+ Printer::instance_count_));
+ ACE_ASSERT (Printer::instance_count_ == 0);
+ // Weak pointer should now be set to null.
+ ACE_ASSERT (r9.null ());
+
+#if defined (ACE_HAS_THREADS)
+
+ // =========================================================================
+ // The following test uses the ACE_Strong_Bound_Ptr in multiple
+ // threads of control.
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) performing asynchronous test...\n")));
+
+ Scheduler *scheduler_ptr;
+
+ // Create active objects..
+ ACE_NEW_RETURN (scheduler_ptr,
+ Scheduler (),
+ -1);
+
+ ACE_Strong_Bound_Ptr<Scheduler, ACE_Null_Mutex> scheduler(scheduler_ptr);
+
+ ACE_ASSERT (scheduler->open () != -1);
+
+ {
+ Printer *printer2;
+ ACE_NEW_RETURN (printer2,
+ Printer ("I am printer 2"),
+ -1);
+
+ // Ownership is transferred from the auto_ptr to the strong pointer.
+ auto_ptr<Printer> a (printer2);
+ Printer_var r (a);
+
+ for (int i = 0; i < n_loops; i++)
+ // Spawn off the methods, which run in a separate thread as
+ // active object invocations.
+ scheduler->print (r);
+ }
+
+ // Close things down.
+ scheduler->end ();
+
+ scheduler->wait ();
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Printer instance count is %d, expecting 0\n"),
+ Printer::instance_count_));
+ ACE_ASSERT (Printer::instance_count_ == 0);
+
+#endif /* ACE_HAS_THREADS */
+ ACE_END_TEST;
+
+ return 0;
+}
diff --git a/ACE/tests/Bound_Ptr_Test.h b/ACE/tests/Bound_Ptr_Test.h
new file mode 100644
index 00000000000..9b72c7863d1
--- /dev/null
+++ b/ACE/tests/Bound_Ptr_Test.h
@@ -0,0 +1,87 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Bound_Ptr_Test.h
+//
+// = DESCRIPTION
+// Define class needed for generating templates. IBM C++ requires this to
+// be in its own file for auto template instantiation.
+//
+// = AUTHOR
+// @author Christopher Kohlhoff <chris@kohlhoff.com>
+//
+// ============================================================================
+
+#ifndef ACE_TESTS_BOUND_PTR_TEST_H
+#define ACE_TESTS_BOUND_PTR_TEST_H
+
+#include "ace/Activation_Queue.h"
+#include "ace/Bound_Ptr.h"
+#include "ace/Task.h"
+#include "ace/Thread_Mutex.h"
+
+struct Printer
+{
+ Printer (const char *message);
+ ~Printer (void) ;
+
+ void print (void);
+
+ const char *message_;
+ static size_t instance_count_;
+};
+
+#if defined (ACE_HAS_THREADS)
+
+typedef ACE_Strong_Bound_Ptr<Printer, ACE_Thread_Mutex> Printer_var;
+
+/**
+ * @class Scheduler
+ *
+ * @brief The scheduler for the Active Object.
+ *
+ * This class also plays the role of the Proxy and the Servant
+ * in the Active Object pattern. Naturally, these roles could
+ * be split apart from the Scheduler.
+ */
+class Scheduler : public ACE_Task<ACE_SYNCH>
+{
+
+ friend class Method_Request_print;
+ friend class Method_Request_end;
+public:
+ // = Initialization and termination methods.
+ /// Constructor.
+ Scheduler (Scheduler * = 0);
+
+ /// Initializer.
+ virtual int open (void *args = 0);
+
+ /// Terminator.
+ virtual int close (u_long flags = 0);
+
+ /// Destructor.
+ virtual ~Scheduler (void);
+
+ // = These methods are part of the Active Object Proxy interface.
+ void print (Printer_var &printer);
+ void end (void);
+
+protected:
+ /// Runs the Scheduler's event loop, which dequeues <Method_Requests>
+ /// and dispatches them.
+ virtual int svc (void);
+
+private:
+ // = These are the <Scheduler> implementation details.
+ ACE_Activation_Queue activation_queue_;
+ Scheduler *scheduler_;
+};
+
+#endif /* ACE_HAS_THREADS */
+#endif /* ACE_TESTS_BOUND_PTR_TEST_H */
diff --git a/ACE/tests/Buffer_Stream_Test.cpp b/ACE/tests/Buffer_Stream_Test.cpp
new file mode 100644
index 00000000000..dde6d876f4c
--- /dev/null
+++ b/ACE/tests/Buffer_Stream_Test.cpp
@@ -0,0 +1,235 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Buffer_Stream_Test.cpp
+//
+// = DESCRIPTION
+// This program illustrates an implementation of the classic
+// "bounded buffer" program using an ASX STREAM containing two
+// Modules. Each ACE_Module contains two Tasks. Each ACE_Task
+// contains a ACE_Message_Queue and a pointer to a
+// ACE_Thread_Manager. Note how the use of these reusable
+// components reduces the reliance on global variables.
+//
+// = AUTHOR
+// Prashant Jain <pjain@cs.wustl.edu> and Doug Schmidt <schmidt@cs.wustl.edu>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/Stream.h"
+#include "ace/Module.h"
+#include "ace/Task.h"
+#include "ace/OS_NS_string.h"
+#include "ace/OS_NS_time.h"
+
+ACE_RCSID(tests, Buffer_Stream_Test, "$Id$")
+
+#if defined (ACE_HAS_THREADS)
+
+static const char ACE_ALPHABET[] = "abcdefghijklmnopqrstuvwxyz";
+
+typedef ACE_Stream<ACE_MT_SYNCH> MT_Stream;
+typedef ACE_Module<ACE_MT_SYNCH> MT_Module;
+typedef ACE_Task<ACE_MT_SYNCH> MT_Task;
+
+class Common_Task : public MT_Task
+ // = TITLE
+ // Methods that are common to the Supplier and consumer.
+{
+public:
+ Common_Task (void) {}
+
+ // = ACE_Task hooks.
+ virtual int open (void * = 0);
+ virtual int close (u_long = 0);
+};
+
+class Supplier : public Common_Task
+// = TITLE
+// Define the Supplier interface.
+{
+public:
+ Supplier (void) {}
+
+ virtual int svc (void);
+ // Read data from stdin and pass to consumer.
+};
+
+class Consumer : public Common_Task
+ // = TITLE
+ // Define the Consumer interface.
+{
+public:
+ Consumer (void) {}
+
+ virtual int put (ACE_Message_Block *mb, ACE_Time_Value *tv = 0);
+ // Enqueue the message on the ACE_Message_Queue for subsequent
+ // handling in the svc() method.
+
+ virtual int svc (void);
+ // Receive message from Supplier and print to stdout.
+private:
+
+ ACE_Time_Value timeout_;
+ // Amount of time to wait for a timeout.
+};
+
+// Spawn off a new thread.
+
+int
+Common_Task::open (void *)
+{
+ if (this->activate (THR_NEW_LWP | THR_DETACHED) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("spawn")), -1);
+ return 0;
+}
+
+int
+Common_Task::close (u_long exit_status)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) thread is exiting with status %d in module %s\n"),
+ exit_status,
+ this->name ()));
+
+ // Can do anything here that is required when a thread exits, e.g.,
+ // storing thread-specific information in some other storage
+ // location, etc.
+ return 0;
+}
+
+// The Supplier reads data from the stdin stream, creates a message,
+// and then queues the message in the message list, where it is
+// removed by the consumer thread. A 0-sized message is enqueued when
+// there is no more data to read. The consumer uses this as a flag to
+// know when to exit.
+
+int
+Supplier::svc (void)
+{
+ ACE_Message_Block *mb = 0;
+
+ // Send one message for each letter of the alphabet, then send an empty
+ // message to mark the end.
+ for (const char *c = ACE_ALPHABET; *c != '\0'; c++)
+ {
+ // Allocate a new message.
+ char d[2];
+ d[0] = *c;
+ d[1] = '\0';
+
+ ACE_NEW_RETURN (mb,
+ ACE_Message_Block (2),
+ -1);
+ ACE_OS::strcpy (mb->wr_ptr (), d);
+
+ mb->wr_ptr (2);
+
+ if (this->put_next (mb) == -1)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%t) %p\n"),
+ ACE_TEXT ("put_next")));
+ }
+
+ ACE_NEW_RETURN(mb, ACE_Message_Block, -1);
+ if (this->put_next (mb) == -1)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%t) %p\n"), ACE_TEXT ("put_next")));
+
+ return 0;
+}
+
+int
+Consumer::put (ACE_Message_Block *mb, ACE_Time_Value *tv)
+{
+ // Simply enqueue the Message_Block into the end of the queue.
+ return this->putq (mb, tv);
+}
+
+// The consumer dequeues a message from the ACE_Message_Queue, writes
+// the message to the stderr stream, and deletes the message. The
+// Consumer sends a 0-sized message to inform the consumer to stop
+// reading and exit.
+
+int
+Consumer::svc (void)
+{
+ ACE_Message_Block *mb = 0;
+ int result;
+ const char *c = ACE_ALPHABET;
+ char *output = 0;
+
+ // Keep looping, reading a message out of the queue, until we
+ // timeout or get a message with a length == 0, which signals us to
+ // quit.
+
+ for (;;)
+ {
+ this->timeout_.set (ACE_OS::time (0) + 4, 0); // Wait for upto 4 seconds
+
+ result = this->getq (mb, &this->timeout_);
+
+ if (result == -1)
+ break;
+
+ size_t const length = mb->length ();
+
+ if (length > 0)
+ {
+ output = mb->rd_ptr ();
+ ACE_ASSERT (*c == output[0]);
+ c++;
+ }
+ mb->release ();
+
+ if (length == 0)
+ break;
+ }
+
+#if !defined (ACE_HAS_WINCE)
+ ACE_ASSERT (result == 0 || errno == EWOULDBLOCK);
+#endif /* ! ACE_HAS_WINCE */
+ return 0;
+}
+
+#endif /* ACE_HAS_THREADS */
+
+// Main driver function.
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("Buffer_Stream_Test"));
+
+#if defined (ACE_HAS_THREADS)
+ // Control hierachically-related active objects.
+ MT_Stream stream;
+ MT_Module *cm = 0;
+ MT_Module *sm = 0;
+
+ // Allocate the Consumer and Supplier modules.
+ ACE_NEW_RETURN (cm, MT_Module (ACE_TEXT ("Consumer"), new Consumer), -1);
+ ACE_NEW_RETURN (sm, MT_Module (ACE_TEXT ("Supplier"), new Supplier), -1);
+
+ // Create Supplier and Consumer Modules and push them onto the
+ // Stream. All processing is performed in the Stream.
+
+ if (stream.push (cm) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("push")), 1);
+ else if (stream.push (sm) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("push")), 1);
+
+ // Barrier synchronization: wait for the threads to exit, then exit
+ // ourselves.
+ ACE_Thread_Manager::instance ()->wait ();
+#else
+ ACE_ERROR ((LM_INFO,
+ ACE_TEXT ("threads not supported on this platform\n")));
+#endif /* ACE_HAS_THREADS */
+ ACE_END_TEST;
+ return 0;
+}
diff --git a/ACE/tests/Bug_1576_Regression_Test.cpp b/ACE/tests/Bug_1576_Regression_Test.cpp
new file mode 100644
index 00000000000..e0986fe9fa9
--- /dev/null
+++ b/ACE/tests/Bug_1576_Regression_Test.cpp
@@ -0,0 +1,66 @@
+/**
+ * @file Bug_1576_Regression_Test.cpp
+ *
+ * $Id$
+ *
+ * Reproduces the problems reported in bug 1576:
+ * http://deuce.doc.wustl.edu/bugzilla/show_bug.cgi?id=1576
+ *
+ * @author Carlos O'Ryan <coryan@atdesk.com>
+ */
+
+#include "test_config.h"
+#include "ace/DLL.h"
+
+ACE_RCSID (tests,
+ Bug_1576_Regression_Test,
+ "$Id$")
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("Bug_1576_Regression_Test"));
+
+ ACE_DLL dll;
+
+ const ACE_TCHAR * dll_name = ACE_TEXT ("NOT_A_DLL") ACE_DLL_SUFFIX;
+
+ // Normally applications should check the return value, but if they
+ // ignore it...
+ int result = dll.open (dll_name);
+
+ if(result == -1)
+ {
+ // Use dll.error() is you want to get the error text, but we don't this in
+ // this test because else the error is shown on the scoreboard
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Load failed, as expected\n")));
+ }
+ else
+ {
+ ACE_ERROR((LM_ERROR,
+ ACE_TEXT ("Success loading %s ? It should have failed!\n"),
+ dll_name));
+ }
+
+ // ... and then use the DLL library, the program crashes (instead of
+ // just getting an error ...
+ void * symbol = dll.symbol (ACE_TEXT ("SHOULD_CRASH"));
+
+ if(symbol == 0)
+ {
+ // Use dll.error() is you want to get the error text, but we don't this in
+ // this test because else the error is shown on the scoreboard
+ ACE_DEBUG((LM_DEBUG,
+ ACE_TEXT ("Symbol lookup failed, as expected\n")));
+ }
+ else
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Found symbol ? It should have failed!\n")));
+ }
+
+ ACE_END_TEST;
+
+ return 0;
+}
diff --git a/ACE/tests/Bug_1890_Regression_Test.cpp b/ACE/tests/Bug_1890_Regression_Test.cpp
new file mode 100644
index 00000000000..a28c8302b77
--- /dev/null
+++ b/ACE/tests/Bug_1890_Regression_Test.cpp
@@ -0,0 +1,284 @@
+/**
+ * @file Bug_1890_Regression_Test.cpp
+ *
+ * $Id$
+ *
+ * Reproduces the problems reported in bug 1890
+ * http://deuce.doc.wustl.edu/bugzilla/show_bug.cgi?id=1890
+ *
+ * @author Carlos O'Ryan <coryan@atdesk.com>
+ * Based on a test provided by "Vadim" (no further details available)
+ */
+
+#include "test_config.h"
+
+#include "ace/Pipe.h"
+#include "ace/Event_Handler.h"
+#include "ace/Reactor.h"
+
+ACE_RCSID (tests,
+ Bug_1890_Regression_Test,
+ "$Id$")
+
+int const nhandlers = 3;
+
+/**
+ * This class is used to create real I/O in the test. To keep the I/O under
+ * control and keep the test to a single process we use ACE_Pipe. This class
+ * is known to work with the Reactor, in fact, that is its main function.
+ *
+ * Handler counts how many calls to handle_input() has the reactor performed.
+ * When bug 1890 is triggered the Reactor continues to call the timers, but it
+ * stops calling select() and the handle_input() functions.
+ */
+class Handler : public ACE_Event_Handler
+{
+public:
+ Handler();
+
+ /// Initialize the pipe and register with the reactor
+ int open(ACE_Reactor * reactor);
+
+ /// Return the current count
+ size_t handle_input_count() const;
+
+ /// Write some data
+ void send_dummy_data();
+
+ /// Reactor callback
+ virtual ACE_HANDLE get_handle() const;
+ virtual int handle_input(ACE_HANDLE);
+
+private:
+ size_t handle_input_count_;
+
+ ACE_Pipe the_pipe_;
+
+ ACE_HANDLE handles_[2];
+};
+
+/**
+ * This is the main driver for the test. This timer is called by the reactor
+ * in a repeating interval. On the first @c initial_iterations the Timer
+ * writes data through all of its handlers. On iteration @c initial_iteration
+ * it triggers bug 1890 by removing all the handlers from the reactor, and
+ * then re-adding one handler.
+ *
+ */
+class Timer : public ACE_Event_Handler
+{
+public:
+ Timer();
+
+ int open(ACE_Reactor * reactor);
+ void close();
+ bool check_expected_results() const;
+
+ virtual int handle_timeout(ACE_Time_Value const &, void const*);
+
+private:
+ void send_data_through_handlers();
+ void remove_some_handlers();
+
+ Handler & special_handler();
+ Handler const & special_handler() const;
+
+private:
+ Handler handler_[nhandlers];
+ int iteration_;
+
+ size_t recorded_count_;
+};
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("Bug_1890_Regression_Test"));
+
+ ACE_Reactor * reactor = ACE_Reactor::instance();
+
+ // Create the timer, this is the main driver for the test
+ Timer * timer = new Timer;
+
+ // Initialize the timer and register with the reactor
+ if (-1 == timer->open(reactor))
+ {
+ ACE_ERROR_RETURN ((LM_ERROR, "Cannot initialize timer\n"), -1);
+ }
+
+ reactor->run_reactor_event_loop();
+
+ // Verify that the results are what we expect
+ if (!timer->check_expected_results())
+ {
+ ACE_ERROR_RETURN ((LM_ERROR, "Test failed\n"), -1);
+ }
+
+ // Cleanup
+ timer->close();
+
+ ACE_END_TEST;
+
+ return 0;
+}
+
+Handler::Handler()
+ : handle_input_count_(0)
+ , the_pipe_()
+{
+}
+
+int Handler::
+open(ACE_Reactor * r)
+{
+ if(-1 == the_pipe_.open(handles_))
+ {
+ return -1;
+ }
+ if(-1 == r->register_handler(this, ACE_Event_Handler::READ_MASK))
+ {
+ return -1;
+ }
+ return 0;
+}
+
+size_t Handler::handle_input_count() const
+{
+ return handle_input_count_;
+}
+
+void Handler::send_dummy_data()
+{
+ char buf[] = "dummy";
+ (void) the_pipe_.send(buf, sizeof(buf));
+}
+
+ACE_HANDLE Handler::get_handle() const
+{
+ return the_pipe_.read_handle();
+}
+
+int Handler::handle_input(ACE_HANDLE)
+{
+ ++handle_input_count_;
+ // ACE_DEBUG((LM_DEBUG, "Handler::handle_input called for %d\n", h));
+ return 0;
+}
+
+int const initial_iterations = 5;
+int const total_iterations = 10;
+
+int const special_handler_index = nhandlers - 1;
+
+Timer::Timer()
+ : iteration_(0)
+ , recorded_count_(0)
+{
+}
+
+int Timer::open(ACE_Reactor * r)
+{
+ this->reactor(r);
+
+ // Initialize both handles and register them with the reactor for reading.
+ for(int i = 0; i != nhandlers; ++i)
+ {
+ if (-1 == handler_[i].open(r))
+ {
+ ACE_ERROR_RETURN ((LM_ERROR, "Could not open dummy handler %d\n", i), -1);
+ }
+ }
+
+ ACE_Time_Value const interval(0, ACE_ONE_SECOND_IN_USECS / 10);
+ ACE_Time_Value const startup (0, ACE_ONE_SECOND_IN_USECS / 20);
+
+ if ( -1 == r->schedule_timer(
+ this, 0, startup, interval))
+ {
+ ACE_ERROR_RETURN((LM_ERROR, "Could not schedule timer\n"), -1);
+ }
+
+ return 0;
+}
+
+void Timer::close()
+{
+ for(int i = 0; i != nhandlers; ++i)
+ {
+ reactor()->remove_handler(&handler_[i], ACE_Event_Handler::ALL_EVENTS_MASK);
+ }
+ reactor()->cancel_timer(this);
+}
+
+bool Timer::check_expected_results() const
+{
+ if(recorded_count_ < special_handler().handle_input_count())
+ {
+ return true;
+ }
+ return false;
+}
+
+int Timer::handle_timeout(ACE_Time_Value const &, void const *)
+{
+ if (iteration_ == 0)
+ {
+ send_data_through_handlers();
+ }
+
+ ++iteration_;
+ if (iteration_ < initial_iterations)
+ {
+ return 0;
+ }
+
+ if (iteration_ == initial_iterations)
+ {
+ remove_some_handlers();
+ recorded_count_ = special_handler().handle_input_count();
+ return 0;
+ }
+
+ if (iteration_ < total_iterations)
+ {
+ return 0;
+ }
+
+ reactor()->end_event_loop();
+
+ return 0;
+}
+
+void Timer::send_data_through_handlers()
+{
+ for(int i = 0; i != nhandlers; ++i)
+ {
+ handler_[i].send_dummy_data();
+ }
+}
+
+void Timer::remove_some_handlers()
+{
+ for(int i = 0; i != nhandlers; ++i)
+ {
+ if (-1 == reactor()->remove_handler(&handler_[i], ACE_Event_Handler::ALL_EVENTS_MASK))
+ {
+ ACE_ERROR((LM_ERROR, "Cannot remove handler %d in timeout\n", i));
+ }
+ }
+
+ if (-1 == reactor()->register_handler(&special_handler(), ACE_Event_Handler::ALL_EVENTS_MASK))
+ {
+ ACE_ERROR((LM_ERROR, "Cannot add back special handler in timeout\n"));
+ }
+}
+
+Handler & Timer::special_handler()
+{
+ return handler_[special_handler_index];
+}
+
+Handler const & Timer::special_handler() const
+{
+ return handler_[special_handler_index];
+}
diff --git a/ACE/tests/Bug_2368_Regression_Test.cpp b/ACE/tests/Bug_2368_Regression_Test.cpp
new file mode 100644
index 00000000000..8441abe346f
--- /dev/null
+++ b/ACE/tests/Bug_2368_Regression_Test.cpp
@@ -0,0 +1,123 @@
+/**
+ * @file Bug_2368_Regression_Test.cpp
+ *
+ * $Id$
+ *
+ * Reproduces the problems reported in bug 2368:
+ * http://deuce.doc.wustl.edu/bugzilla/show_bug.cgi?id=2368
+ *
+ * @author Johnny Willemsen <jwillemsen@remedy.nl>
+ */
+
+#include "test_config.h"
+#include "ace/Service_Config.h"
+#include "ace/Reactor.h"
+#include "ace/Log_Msg.h"
+#include "ace/Signal.h"
+
+ACE_RCSID (tests,
+ Bug_2368_Regression_Test,
+ "$Id$")
+
+static bool handleA_close_called = false;
+static bool handleB_close_called = false;
+
+class My_HandlerA : public ACE_Event_Handler
+{
+public:
+ virtual int handle_close (ACE_HANDLE,
+ ACE_Reactor_Mask)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ "Handle close called\n"));
+ handleA_close_called = true;
+
+ return 0;
+ }
+
+ virtual int handle_signal (int,
+ siginfo_t *,
+ ucontext_t *)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ "Handle signal called\n"));
+
+ return 0;
+ }
+};
+
+class My_HandlerB : public ACE_Event_Handler
+{
+public:
+ virtual int handle_close (ACE_HANDLE,
+ ACE_Reactor_Mask)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ "Handle close called\n"));
+ handleB_close_called = true;
+
+ return 0;
+ }
+
+ virtual int handle_signal (int,
+ siginfo_t *,
+ ucontext_t *)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ "Handle signal called\n"));
+
+ return 0;
+ }
+};
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("Bug_2368_Regression_Test"));
+
+ My_HandlerA my_handlerA;
+ My_HandlerB my_handlerB;
+
+ // Set up an ACE signal handler.
+ if (ACE_Reactor::instance ()->register_handler
+ (SIGINT,
+ &my_handlerA) == -1)
+ ACE_ERROR_RETURN ((LM_DEBUG,
+ "%p\n",
+ "register_handlerA"),
+ -1);
+
+ if (ACE_Reactor::instance ()->register_handler
+ (SIGINT,
+ &my_handlerB) == -1)
+ ACE_ERROR_RETURN ((LM_DEBUG,
+ "%p\n",
+ "register_handlerB"),
+ -1);
+
+ ACE_Sig_Action *new_disp = 0;
+ if (ACE_Reactor::instance ()->remove_handler
+ (SIGINT,
+ new_disp) == -1)
+ ACE_ERROR_RETURN ((LM_DEBUG,
+ "%p\n",
+ "remove_handlerB"),
+ -1);
+
+ if (ACE_Reactor::instance ()->close () == -1)
+ ACE_ERROR ((LM_ERROR,
+ "%p\n",
+ "close"));
+
+ if (!handleA_close_called)
+ ACE_ERROR ((LM_ERROR,
+ "Handle close hasn't been called for A\n"));
+
+ if (!handleB_close_called)
+ ACE_ERROR ((LM_ERROR,
+ "Handle close hasn't been called for B\n"));
+
+ ACE_END_TEST;
+
+ return 0;
+}
diff --git a/ACE/tests/Bug_2497_Regression_Test.cpp b/ACE/tests/Bug_2497_Regression_Test.cpp
new file mode 100644
index 00000000000..2cd1a92e66c
--- /dev/null
+++ b/ACE/tests/Bug_2497_Regression_Test.cpp
@@ -0,0 +1,75 @@
+/**
+ * @file Bug_2497_Regression_Test.cpp
+ *
+ * $Id$
+ *
+ * Reproduces the problems reported in bug 2497
+ * http://deuce.doc.wustl.edu/bugzilla/show_bug.cgi?id=2497
+ *
+ * @author sergant128@mail.ru
+ */
+
+#include "test_config.h"
+#include "ace/Module.h"
+#include "ace/Task.h"
+#include "ace/Stream.h"
+
+ACE_RCSID (tests,
+ Bug_2497_Regression_Test,
+ "$Id$")
+
+class Test_Task : public ACE_Task<ACE_SYNCH>
+{
+public:
+ Test_Task( void ) :
+ _destructorCalled(0)
+ {
+ }
+
+ virtual ~Test_Task( void )
+ {
+ ++_destructorCalled;
+ if (_destructorCalled > 1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Test_Task::~Test_Task() should be called once!!!\n")));
+ }
+
+private:
+ int _destructorCalled;
+};
+
+
+class Test_Module : public ACE_Module<ACE_SYNCH>
+{
+public:
+ Test_Module( void )
+ {
+ this->open( ACE_TEXT("Test module"),
+ &_writerTask,
+ &_readerTask,
+ NULL,
+ M_DELETE_NONE );
+ }
+
+private:
+ Test_Task _writerTask, _readerTask;
+};
+
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("Bug_2497_Regression_Test"));
+
+ ACE_Stream<ACE_SYNCH> stream;
+
+ if (stream.push(new Test_Module()) == -1)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Error: push failed\n")));
+ }
+
+ ACE_END_TEST;
+
+ return 0;
+}
diff --git a/ACE/tests/Bug_2540_Regression_Test.cpp b/ACE/tests/Bug_2540_Regression_Test.cpp
new file mode 100644
index 00000000000..72cd831cd8f
--- /dev/null
+++ b/ACE/tests/Bug_2540_Regression_Test.cpp
@@ -0,0 +1,311 @@
+/**
+ * @file Bug_2540_Regression_Test.cpp
+ *
+ * $Id$
+ *
+ * Reproduces the problems reported in bug 2540
+ * http://deuce.doc.wustl.edu/bugzilla/show_bug.cgi?id=2540
+ *
+ * @author Carlos O'Ryan <coryan@atdesk.com>
+ * Based on Bug_1890_Regression_Test
+ */
+
+#include "test_config.h"
+
+#include "ace/Pipe.h"
+#include "ace/Event_Handler.h"
+#include "ace/Reactor.h"
+
+ACE_RCSID (tests,
+ Bug_2540_Regression_Test,
+ "$Id$")
+
+int const nhandlers = 3;
+
+/**
+ * This class is used to create real I/O in the test. To keep the I/O under
+ * control and keep the test to a single process we use ACE_Pipe. This class
+ * is known to work with the Reactor, in fact, that is its main function.
+ *
+ * Handler counts how many calls to handle_input() has the reactor performed.
+ * When bug 2540 is triggered the Reactor continues to call the timers, but it
+ * stops calling select() and the handle_input() functions.
+ */
+class Handler : public ACE_Event_Handler
+{
+public:
+ Handler();
+
+ /// Initialize the pipe and register with the reactor
+ int open(ACE_Reactor * reactor);
+
+ /// Return the current count
+ size_t handle_input_count() const;
+
+ /// Write some data
+ void send_dummy_data();
+
+ /// Removes itself from the reactor on the next call to handle_input()
+ void simulate_socket_closure();
+
+ /// Reactor callback
+ virtual ACE_HANDLE get_handle() const;
+ virtual int handle_input(ACE_HANDLE);
+
+private:
+ bool auto_remove_flag_;
+
+ size_t handle_input_count_;
+
+ ACE_Pipe the_pipe_;
+
+ ACE_HANDLE handles_[2];
+};
+
+/**
+ * This is the main driver for the test. This timer is called by the reactor
+ * in a repeating interval. On the first @c initial_iterations the Timer
+ * writes data through all of its handlers. On iteration @c initial_iteration
+ * it triggers bug 2540 by removing two handlers from the reactor.
+ *
+ */
+class Timer : public ACE_Event_Handler
+{
+public:
+ Timer();
+
+ int open(ACE_Reactor * reactor);
+ void close();
+ bool check_expected_results() const;
+
+ virtual int handle_timeout(ACE_Time_Value const &, void const*);
+
+private:
+ void send_data_through_handlers();
+ void remove_some_handlers();
+
+ Handler & special_handler();
+ Handler const & special_handler() const;
+
+private:
+ Handler handler_[nhandlers];
+ int iteration_;
+
+ size_t recorded_count_;
+};
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("Bug_2540_Regression_Test"));
+
+ ACE_Reactor * reactor = ACE_Reactor::instance();
+
+ // Create the timer, this is the main driver for the test
+ Timer * timer = new Timer;
+
+ // Initialize the timer and register with the reactor
+ if (-1 == timer->open(reactor))
+ {
+ ACE_ERROR_RETURN ((LM_ERROR, "Cannot initialize timer\n"), -1);
+ }
+
+ reactor->run_reactor_event_loop();
+
+ // Verify that the results are what we expect
+ if (!timer->check_expected_results())
+ {
+ ACE_ERROR_RETURN ((LM_ERROR, "Test failed\n"), -1);
+ }
+
+ // Cleanup
+ timer->close();
+
+ ACE_END_TEST;
+
+ return 0;
+}
+
+Handler::Handler()
+ : auto_remove_flag_(false)
+ , handle_input_count_(0)
+ , the_pipe_()
+{
+}
+
+int Handler::
+open(ACE_Reactor * r)
+{
+ if(-1 == the_pipe_.open(handles_))
+ {
+ return -1;
+ }
+ if(-1 == r->register_handler(this, ACE_Event_Handler::READ_MASK))
+ {
+ return -1;
+ }
+ return 0;
+}
+
+size_t Handler::handle_input_count() const
+{
+ return handle_input_count_;
+}
+
+void Handler::send_dummy_data()
+{
+ char buf[] = "dummy";
+ (void) the_pipe_.send(buf, sizeof(buf));
+}
+
+void Handler::simulate_socket_closure()
+{
+ auto_remove_flag_ = true;
+}
+
+ACE_HANDLE Handler::get_handle() const
+{
+ return the_pipe_.read_handle();
+}
+
+int Handler::handle_input(ACE_HANDLE /* h */)
+{
+
+ ++handle_input_count_;
+ // ACE_DEBUG((LM_DEBUG, "Handler::handle_input called for %d\n", h));
+
+ if(auto_remove_flag_)
+ {
+ auto_remove_flag_ = false;
+ return -1;
+ }
+
+ return 0;
+}
+
+int const initial_iterations = 5;
+int const total_iterations = 10;
+
+int const special_handler_index = nhandlers - 1;
+
+Timer::Timer()
+ : iteration_(0)
+ , recorded_count_(0)
+{
+}
+
+int Timer::open(ACE_Reactor * r)
+{
+ this->reactor(r);
+
+ // Initialize both handles and register them with the reactor for reading.
+ for(int i = 0; i != nhandlers; ++i)
+ {
+ if (-1 == handler_[i].open(r))
+ {
+ ACE_ERROR_RETURN ((LM_ERROR, "Could not open dummy handler %d\n", i), -1);
+ }
+ }
+
+ ACE_Time_Value const interval(0, ACE_ONE_SECOND_IN_USECS / 10);
+ ACE_Time_Value const startup (0, ACE_ONE_SECOND_IN_USECS / 20);
+
+ if ( -1 == r->schedule_timer(
+ this, 0, startup, interval))
+ {
+ ACE_ERROR_RETURN((LM_ERROR, "Could not schedule timer\n"), -1);
+ }
+
+ return 0;
+}
+
+void Timer::close()
+{
+ for(int i = 0; i != nhandlers; ++i)
+ {
+ reactor()->remove_handler(&handler_[i], ACE_Event_Handler::ALL_EVENTS_MASK);
+ }
+ reactor()->cancel_timer(this);
+}
+
+bool Timer::check_expected_results() const
+{
+ // We expect at least one more call after the other handlers are removed.
+ if(recorded_count_ + 1 < special_handler().handle_input_count() )
+ {
+ return true;
+ }
+ return false;
+}
+
+int Timer::handle_timeout(ACE_Time_Value const &, void const *)
+{
+ if (iteration_ == 0)
+ {
+ // Sending data on the first iteration makes the handles always
+ // "ready" for reading because the Handler::handle_input() function
+ // never consumes the data.
+ send_data_through_handlers();
+ }
+
+ ++iteration_;
+ if (iteration_ < initial_iterations)
+ {
+ // The first iterations are there just to prime things.
+ return 0;
+ }
+
+ if (iteration_ == initial_iterations)
+ {
+ // We expect the special_handler() to work normally after this
+ // iteration, i.e., more calls to handle_input() should be delivered
+ // to it.
+ recorded_count_ = special_handler().handle_input_count();
+
+ // Remove the handlers the next time the loop runs
+ remove_some_handlers();
+
+ // Run the event loop, this causes the handlers to be removed from the
+ // reactor, except for special_handler()
+ ACE_Time_Value interval(0, ACE_ONE_SECOND_IN_USECS / 50);
+ reactor()->handle_events(&interval);
+
+ return 0;
+ }
+
+ if (iteration_ < total_iterations)
+ {
+ // Run a while more to make sure the special_handler() is used.
+ return 0;
+ }
+
+ reactor()->end_event_loop();
+
+ return 0;
+}
+
+void Timer::send_data_through_handlers()
+{
+ for(int i = 0; i != nhandlers; ++i)
+ {
+ handler_[i].send_dummy_data();
+ }
+}
+
+void Timer::remove_some_handlers()
+{
+ for(int i = 0; i != nhandlers - 1; ++i)
+ {
+ handler_[i].simulate_socket_closure();
+ }
+}
+
+Handler & Timer::special_handler()
+{
+ return handler_[special_handler_index];
+}
+
+Handler const & Timer::special_handler() const
+{
+ return handler_[special_handler_index];
+}
diff --git a/ACE/tests/CDR_Array_Test.cpp b/ACE/tests/CDR_Array_Test.cpp
new file mode 100644
index 00000000000..5bb5a01c3eb
--- /dev/null
+++ b/ACE/tests/CDR_Array_Test.cpp
@@ -0,0 +1,1004 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// CDR_Array_Test.cpp
+//
+// = DESCRIPTION
+// Checks ACE_OutputCDR::write_XX_array.
+// Checks ACE_InputCDR::read_XX_array.
+// Checks operator<< and operator>> for CDR Streams in
+// each of the basic CDR types.
+// Gives a measure of the speed of the ACE CDR streams wrt those
+// operations.
+//
+// = AUTHORS
+// Cristian Ferretti <cristian_ferretti@yahoo.com>
+//
+// ============================================================================
+
+// For measuring time, choose your method:
+// Define:
+//
+// * USE_GETRUSAGE for using ACE_OS::getrusage.
+// Ticks only when process is running.
+//
+// * USE_CLOCK for using clock(2).
+// You're on your own, no ACE_OS:: support.
+// Ticks only when process is running.
+//
+// * None of the above for using ACE_High_Res_Timer.
+// Ticks independent of running state of process.
+
+// #define USE_CLOCK
+// #define USE_GETRUSAGE
+
+#if defined(USE_CLOCK)
+#include <time.h>
+#endif
+
+#include "test_config.h"
+#include "ace/OS_Memory.h"
+#include "ace/OS_NS_stdlib.h"
+#include "ace/Get_Opt.h"
+#include "ace/CDR_Stream.h"
+#include "ace/High_Res_Timer.h"
+#include "ace/ACE.h"
+
+#if defined(USE_GETRUSAGE) && !defined(ACE_HAS_GETRUSAGE)
+#error "Can't define USE_GETRUSAGE on this platform."
+#endif
+
+ACE_RCSID(tests, CDR_Array_Test, "$Id$")
+
+// Default number of elements for check buffer, for each tested CDR type.
+// Be aware that time will be affected by the buffer fitting/not fitting
+// in the cache (ie, if default_total*sizeof(T) bytes fit in the cache).
+// Also, you want that your time measuring method has a resolution
+// compatible with this buffer size, if not you will end up measuring 0.
+// You can change this value with -t option.
+static const int default_total = 32*1024;
+
+// Repeat this many times for each tested CDR type.
+// We then take the average time that took for each type and report that.
+// You can change this value with -n option.
+static const int default_niter = 10;
+
+//
+// A simple cronometer in seconds, that encapsulates our time
+// measuring method.
+//
+class Crono {
+public:
+ Crono() {}
+ ~Crono() {}
+ void start ()
+ {
+#if defined(USE_CLOCK)
+ start_ = clock ();
+#elif defined(USE_GETRUSAGE)
+ ACE_OS::getrusage (RUSAGE_SELF, &start_);
+#else
+ timer.start ();
+#endif
+ }
+ void stop ()
+ {
+#if defined(USE_CLOCK)
+ end_ = clock ();
+#elif defined(USE_GETRUSAGE)
+ ACE_OS::getrusage (RUSAGE_SELF, &end_);
+#else
+ timer.stop ();
+#endif
+ }
+ double read_seconds ()
+ {
+#if defined(USE_CLOCK)
+ return (end_ - start_) / (double) CLOCKS_PER_SEC;
+#elif defined(USE_GETRUSAGE)
+ timeval diff;
+ diff.tv_sec = end_.ru_utime.tv_sec - start_.ru_utime.tv_sec;
+ diff.tv_usec = end_.ru_utime.tv_usec - start_.ru_utime.tv_usec;
+ while (diff.tv_usec < 0)
+ {
+ --diff.tv_sec;
+ diff.tv_usec += ACE_ONE_SECOND_IN_USECS;
+ }
+
+ return diff.tv_sec + diff.tv_usec / double(ACE_ONE_SECOND_IN_USECS);
+#else
+ ACE_Time_Value tv;
+ timer.elapsed_time(tv);
+ return tv.usec () / 1000000.0;
+#endif
+ }
+private:
+#if defined(USE_CLOCK)
+ clock_t start_;
+ clock_t end_;
+#elif defined(USE_GETRUSAGE)
+ ACE_Rusage start_;
+ ACE_Rusage end_;
+#else
+ ACE_High_Res_Timer timer;
+#endif
+};
+
+//
+// Our test, performed in the constructor.
+// T is one of the CDR types.
+// H is a helper class (described later).
+//
+// All this stuff is in a class and not in template functions
+// to avoid having to deal with potential template function
+// instantiations problems.
+//
+template<class T, class H> class CDR_Test
+{
+public:
+ CDR_Test (int total, int niter, int use_array);
+ static void do_test (int total, int niter, int use_array,
+ char* srcbuf, char* dstbuf,
+ int src_offset = 0, int dst_offset = 0);
+ ~CDR_Test ();
+
+ static void ttoh (const T& t, char* s);
+ static T checkval(int i);
+
+private:
+ CDR_Test (const CDR_Test<T, H>&);
+ CDR_Test<T, H>& operator= (const CDR_Test<T, H>&);
+};
+
+static ACE_UINT32 seal = 0xdeadbeef;
+
+void
+zero (char* p, size_t k)
+{
+ char* end = p + k;
+ while (p < end)
+ {
+ *p++ = '\0';
+ }
+}
+
+inline int
+mymax (int a, int b)
+{
+ return (a >= b) ? a : b;
+}
+
+void
+memabort ()
+{
+ ACE_ERROR((LM_ERROR,
+ ACE_TEXT ("new failed, aborting\n")));
+ ACE_OS::exit (1);
+}
+
+template<class T, class H>
+CDR_Test<T, H>::CDR_Test (int total, int niter, int use_array)
+{
+ if (total <= 0)
+ {
+ return ;
+ }
+
+ char* srcbuf;
+ char* dstbuf;
+ {
+ const size_t stotal =
+ (total + 10) * H::size () + sizeof(ACE_UINT32) + ACE_CDR::MAX_ALIGNMENT;
+
+ ACE_NEW(srcbuf, char[stotal]);
+ if (srcbuf == 0)
+ {
+ memabort ();
+ }
+ zero(srcbuf, stotal);
+
+ ACE_NEW(dstbuf, char[stotal]);
+ if (dstbuf == 0)
+ {
+ memabort ();
+ }
+ zero(dstbuf, stotal);
+ }
+
+ if (use_array)
+ {
+ // We want to test all the possible loop unrolling deltas.
+ int t;
+ for (t = total - 3; t <= total; t++)
+ {
+ int delta;
+ if (sizeof(long) <= H::size ())
+ {
+ delta = 1;
+ }
+ else
+ {
+ delta = (int) (sizeof(long) / H::size ());
+ }
+
+ // We want to test all the posible source/destination buffer
+ // alignment combinations.
+ int sk;
+ for (sk = 0; sk < delta; sk++)
+ {
+ int dk;
+ for (dk = 0; dk < delta; dk++)
+ {
+ int tdelta = t - mymax(sk, dk);
+
+ CDR_Test<T, H>::do_test(tdelta, niter, 1,
+ srcbuf, dstbuf,
+ sk, dk);
+
+ }
+ }
+ }
+ }
+ else
+ {
+ do_test(total, niter, use_array, srcbuf, dstbuf);
+ }
+
+ delete[] srcbuf;
+ delete[] dstbuf;
+}
+
+// Generate an ``interesting'' value for testing at pos >i<.
+template<class T, class H> T
+CDR_Test<T, H>::checkval (int i)
+{
+ if (!H::integral ())
+ {
+ // If T is not an integral type, we don't want to risk
+ // getting an invalid bit pattern for a T value.
+ return T(i);
+ }
+ else
+ {
+ T v;
+ unsigned char* s = reinterpret_cast<unsigned char*> ((&v));
+ unsigned int j;
+ for (j = 0; j < H::size (); j++)
+ {
+ s[j] = (unsigned char) ((j + i * H::size ()) % 256);
+ }
+
+ return v;
+ }
+}
+
+//
+// Returns in s an hex representation of T's memory.
+// (differences in byte order will be noticed in s).
+//
+// If T = int,
+// t = 0xaabbccdd,
+// => s = "aabbccdd" for big endian machines,
+// s = "ddccbbaa" for little endian machines.
+//
+template<class T, class H> void
+CDR_Test<T, H>::ttoh (const T& t, char* s)
+{
+ const unsigned char *const p =
+ reinterpret_cast<const unsigned char*> (&t);
+
+ static char digits[16] = {
+ '0', '1', '2', '3',
+ '4', '5', '6', '7',
+ '8', '9', 'a', 'b',
+ 'c', 'd', 'e', 'f'
+ };
+
+ const unsigned char* q;
+ for (q = p; q < p + H::size (); ++q)
+ {
+ int k = *q;
+ *s++ = digits[ k >> 4 ];
+ *s++ = digits[ k & 15 ];
+ }
+
+ *s = 0;
+}
+
+void
+do_seal (char* pos)
+{
+ char* ps = reinterpret_cast<char*> (&seal);
+ pos[0] = ps[0];
+ pos[1] = ps[1];
+ pos[2] = ps[2];
+ pos[3] = ps[3];
+}
+
+int
+check_seal (char* pos)
+{
+ char* ps = reinterpret_cast<char*> (&seal);
+ return (pos[0] == ps[0]
+ && pos[1] == ps[1]
+ && pos[2] == ps[2]
+ && pos[3] == ps[3]);
+}
+
+//
+// returns the alignment of ptr, wrt ACE_CDR::MAX_ALIGNMENT.
+//
+int
+tellalign (const char* const ptr)
+{
+ int align = ACE_CDR::MAX_ALIGNMENT;
+ while (ptr != ACE_ptr_align_binary(ptr, align))
+ {
+ align = align >> 1;
+ }
+
+ return align;
+}
+
+template<class T, class H> void
+CDR_Test<T, H>::do_test (int total, int niter, int use_array,
+ char* srcbuf, char* dstbuf,
+ int src_offset, int dst_offset)
+{
+ if (!use_array)
+ {
+ dst_offset = src_offset = 0;
+ }
+
+ ACE_DEBUG((LM_DEBUG,
+ ACE_TEXT( "Starting Test for %s: %d elements " )
+ ACE_TEXT( "%susing arrays.\n" ),
+ H::name (),
+ total,
+ ((use_array) ? ACE_TEXT( "" ) : ACE_TEXT( "not " ))));
+
+
+ if (!use_array && (total % 4) != 0)
+ {
+ int lasttotal = total;
+ total -= (total % 4);
+ ACE_DEBUG((LM_DEBUG,
+ ACE_TEXT( "Rounding from %d to %d elements.\n" ),
+ lasttotal,
+ total));
+ }
+
+ char* src = ACE_ptr_align_binary(srcbuf, H::size ());
+ T* idata = reinterpret_cast<T*> (src);
+ idata += src_offset;
+ src = reinterpret_cast<char*> (idata);
+
+ {
+ int i;
+ for (i = 0; i < total; i++)
+ {
+ idata[i] = CDR_Test<T, H>::checkval (i);
+ }
+ }
+
+ ACE_DEBUG((LM_DEBUG,
+ ACE_TEXT( "Writing data...\n" )));
+
+ char* toread = 0;
+ {
+ ACE_ASSERT(use_array || total % 4 == 0);
+
+ double totalsecs = 0.0;
+ int n;
+ for (n = 0; n < niter; n++)
+ {
+ size_t size = H::size () * (dst_offset + total) +
+ ACE_CDR::MAX_ALIGNMENT;
+ ACE_OutputCDR os (dstbuf, size);
+
+ // This is intrusive...
+ char* const end = os.begin ()->wr_ptr() + size;
+
+ do_seal (end);
+
+ double secs = 0.0;
+ if (use_array)
+ {
+ {
+ int i;
+ for (i = 0; i < dst_offset; i++)
+ {
+ os << T(0);
+ }
+ }
+
+ if (n == 0)
+ {
+ ACE_DEBUG((LM_DEBUG,
+ ACE_TEXT ("* src align = %d, dst align = %d\n"),
+ tellalign (src),
+ tellalign (os.begin ()->wr_ptr ())));
+ }
+
+ Crono crono;
+ crono.start ();
+ H::write_array (os, idata, total);
+ crono.stop ();
+ secs = crono.read_seconds ();
+ }
+ else
+ {
+ int i = 0;
+ for (; i < dst_offset; i++)
+ {
+ os << T(0);
+ }
+ i = 0;
+
+ Crono crono;
+ crono.start();
+ while (i < total)
+ {
+ os << idata[i++];
+ os << idata[i++];
+ os << idata[i++];
+ os << idata[i++];
+ // static char rs[32 + 1];
+ // CDR_Test<T,H>::ttoh (idata[i], rs);
+ // ACE_DEBUG ((LM_DEBUG, "Write idata[%d] = %s\n", i, rs));
+ // os << idata[i];
+ // i++;
+ }
+ crono.stop ();
+ secs = crono.read_seconds ();
+ }
+
+ if (!check_seal(end))
+ {
+ ACE_ERROR((LM_ERROR,
+ ACE_TEXT( "Broken seal, aborting.\n" )));
+ ACE_OS::exit(1);
+ }
+
+ totalsecs += secs;
+
+ if (n == niter - 1)
+ {
+ toread = os.begin ()->rd_ptr ();
+ }
+ }
+
+ totalsecs = totalsecs / niter;
+
+ ACE_DEBUG((LM_DEBUG,
+ ACE_TEXT ("Writing to stream %d %s values: %f seconds.\n"),
+ total,
+ H::name (),
+ totalsecs));
+ }
+
+ {
+ int i;
+ for (i = 0; i < total; i++)
+ {
+ idata[i] = 0;
+ }
+ }
+
+ ACE_DEBUG((LM_DEBUG,
+ ACE_TEXT( "Reading them back in opposing byte order...\n" )));
+
+ const int opposite_byte_order = 1 - ACE_CDR_BYTE_ORDER;
+
+ {
+ double totalsecs = 0.0;
+ int n;
+ for (n = 0; n < niter; n++)
+ {
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("====== Read iteration %d\n"), n));
+
+ size_t size = (total + dst_offset) * H::size ();
+ ACE_InputCDR is (toread, size, opposite_byte_order);
+
+ // This is intrusive...
+ char* const end = is.rd_ptr () + size;
+
+ do_seal (end);
+
+ double secs = 0.0;
+ if (use_array)
+ {
+ {
+ int i;
+ for (i = 0; i < dst_offset; i++)
+ {
+ T v;
+ is >> v;
+ }
+ }
+
+ if (n == 0)
+ {
+ ACE_DEBUG((LM_DEBUG,
+ ACE_TEXT ("* src align = %d, dst align = %d\n"),
+ tellalign (is.rd_ptr ()),
+ tellalign (src)));
+ }
+
+ Crono crono;
+ crono.start ();
+ H::read_array (is, idata, total);
+ crono.stop ();
+ secs = crono.read_seconds ();
+
+ // Testing for good bit value. Try reading atleast 10
+ // times the size of total. It should fail with good bit
+ // set to 0.
+ H::read_array (is, idata, 10 * total);
+
+ if (is.good_bit () != 0)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Test for good bit failed in %s Array_test \n"),
+ H::name ()));
+ }
+ }
+ else
+ {
+ int i = 0;
+ Crono crono;
+ crono.start ();
+ while (i < total)
+ {
+#if 0
+ T v;
+ is >> v;
+ static char rs[32 + 1];
+ CDR_Test<T,H>::ttoh (v, rs);
+ ACE_DEBUG ((LM_DEBUG, "Read idata[%d] = %s\n", i, rs));
+ idata[i] = v;
+ i++;
+#else
+ is >> idata[i++];
+ is >> idata[i++];
+ is >> idata[i++];
+ is >> idata[i++];
+#endif /* 0 */
+ }
+ crono.stop ();
+ secs = crono.read_seconds ();
+ }
+ totalsecs += secs;
+
+ if (!check_seal (end))
+ {
+ ACE_ERROR((LM_ERROR,
+ ACE_TEXT( "Broken seal, aborting.\n" )));
+ ACE_OS::exit(1);
+ }
+ }
+
+ totalsecs = totalsecs / niter;
+
+ ACE_DEBUG((LM_DEBUG,
+ ACE_TEXT ("Reading from stream %d %s values")
+ ACE_TEXT (" (byte swapping): %f seconds.\n"),
+ total,
+ H::name (),
+ totalsecs));
+ }
+
+ ACE_DEBUG((LM_DEBUG,
+ ACE_TEXT ("Now checking data...\n") ));
+
+ int errors = 0;
+ const int maxerrors = 6;
+
+ {
+ int i;
+ for (i = 0; i < total; i++)
+ {
+ T rv;
+
+ const char* src = reinterpret_cast<const char*> ((idata + i));
+ char* dst = reinterpret_cast<char*> ((&rv));
+
+ H::swap(src, dst);
+
+ T cv = CDR_Test<T, H>::checkval (i);
+ if (rv != cv)
+ {
+ static char rs[32 + 1];
+ static char cs[32 + 1];
+ CDR_Test<T, H>::ttoh (rv, rs);
+ CDR_Test<T, H>::ttoh (cv, cs);
+ ACE_ERROR((LM_ERROR,
+ ACE_TEXT ( "Wrong value at pos %d:" )
+ ACE_TEXT ( " '%s' should be '%s'.\n" ),
+ i, rs, cs));
+ errors++;
+ if (errors == maxerrors)
+ {
+ ACE_ERROR((LM_ERROR,
+ ACE_TEXT ( "%d errors found, ")
+ ACE_TEXT ( "interrupting check.\n" ),
+ errors));
+ break;
+ }
+ }
+ }
+ }
+
+ if (errors != 0)
+ {
+ ACE_ERROR((LM_ERROR,
+ ACE_TEXT (" assertion failed: Inconsistencies found (%d), ")
+ ACE_TEXT ("aborting.\n"), errors));
+ ACE_OS::exit(1);
+ }
+
+ ACE_DEBUG((LM_DEBUG,
+ ACE_TEXT ("Data OK, test %s completed.\n"),
+ H::name ()));
+}
+
+template <class T, class N>
+CDR_Test<T, N>::~CDR_Test ()
+{
+}
+
+//
+// Helper Clases for the second template parameter of CDR_Test.
+// One for each tested CDR type.
+//
+
+struct DoubleHelper
+{
+ static const ACE_TCHAR* name ()
+ {
+ return ACE_TEXT ("CDR::Double");
+ }
+ static int integral ()
+ {
+ return 0;
+ }
+ static void read_array (ACE_InputCDR& is,
+ ACE_CDR::Double* x,
+ ACE_UINT32 n)
+ {
+ is.read_double_array (x, n);
+ }
+ static void write_array (ACE_OutputCDR& os,
+ ACE_CDR::Double* x,
+ ACE_UINT32 n)
+ {
+ os.write_double_array (x, n);
+ }
+ static void swap (const char *src, char *dst)
+ {
+ ACE_CDR::swap_8 (src, dst);
+ }
+ static size_t size ()
+ {
+ return sizeof(ACE_CDR::Double);
+ }
+};
+
+struct FloatHelper
+{
+ static const ACE_TCHAR* name ()
+ {
+ return ACE_TEXT ("CDR::Float");
+ }
+ static int integral ()
+ {
+ return 0;
+ }
+ static void read_array (ACE_InputCDR& is,
+ ACE_CDR::Float* x,
+ ACE_UINT32 n)
+ {
+ is.read_float_array (x, n);
+ }
+ static void write_array (ACE_OutputCDR& os,
+ ACE_CDR::Float* x,
+ ACE_UINT32 n)
+ {
+ os.write_float_array (x, n);
+ }
+ static void swap (const char *src, char *dst)
+ {
+ ACE_CDR::swap_4 (src, dst);
+ }
+ static size_t size ()
+ {
+ return sizeof(ACE_CDR::Float);
+ }
+};
+
+struct ShortHelper
+{
+ static const ACE_TCHAR* name ()
+ {
+ return ACE_TEXT ("CDR::Short");
+ }
+ static int integral ()
+ {
+ return 1;
+ }
+ static void read_array (ACE_InputCDR& is,
+ ACE_CDR::Short* x,
+ ACE_UINT32 n)
+ {
+ is.read_short_array (x, n);
+ }
+ static void write_array (ACE_OutputCDR& os,
+ ACE_CDR::Short* x,
+ ACE_UINT32 n)
+ {
+ os.write_short_array (x, n);
+ }
+ static void swap (const char *src, char *dst)
+ {
+ ACE_CDR::swap_2 (src, dst);
+ }
+ static size_t size ()
+ {
+ return sizeof(ACE_CDR::Short);
+ }
+};
+
+struct LongHelper
+{
+ static const ACE_TCHAR* name ()
+ {
+ return ACE_TEXT ("CDR::Long");
+ }
+ static int integral ()
+ {
+ return 1;
+ }
+ static void read_array (ACE_InputCDR& is,
+ ACE_CDR::Long* x,
+ ACE_UINT32 n)
+ {
+ is.read_long_array (x, n);
+ }
+ static void write_array (ACE_OutputCDR& os,
+ ACE_CDR::Long* x,
+ ACE_UINT32 n)
+ {
+ os.write_long_array (x, n);
+ }
+ static void swap (const char *src, char *dst)
+ {
+ ACE_CDR::swap_4 (src, dst);
+ }
+ static size_t size ()
+ {
+ return sizeof(ACE_CDR::Long);
+ }
+};
+
+#if !defined (ACE_LACKS_LONGLONG_T)
+struct LongLongHelper
+{
+ static const ACE_TCHAR* name ()
+ {
+ return ACE_TEXT ("CDR::LongLong");
+ }
+ static int integral ()
+ {
+ return 1;
+ }
+ static void read_array (ACE_InputCDR& is,
+ ACE_CDR::LongLong* x,
+ ACE_UINT32 n)
+ {
+ is.read_longlong_array (x, n);
+ }
+ static void write_array (ACE_OutputCDR& os,
+ ACE_CDR::LongLong* x,
+ ACE_UINT32 n)
+ {
+ os.write_longlong_array (x, n);
+ }
+
+ static void swap (const char *src, char *dst)
+ {
+ ACE_CDR::swap_8 (src, dst);
+ }
+ static size_t size ()
+ {
+ return sizeof(ACE_CDR::LongLong);
+ }
+};
+#endif /* ! ACE_LACKS_LONGLONG_T */
+
+struct CharHelper
+{
+ static const ACE_TCHAR* name ()
+ {
+ return ACE_TEXT ("CDR::Char");
+ }
+ static int integral ()
+ {
+ return 1;
+ }
+ static void read_array (ACE_InputCDR& is,
+ ACE_CDR::Char* x,
+ ACE_UINT32 n)
+ {
+ is.read_char_array (x, n);
+ }
+ static void write_array (ACE_OutputCDR& os,
+ ACE_CDR::Char* x,
+ ACE_UINT32 n)
+ {
+ os.write_char_array (x, n);
+ }
+ static void swap (const char *src, char *dst)
+ {
+ *dst = *src;
+ }
+ static size_t size ()
+ {
+ return sizeof(ACE_CDR::Char);
+ }
+};
+
+void usage (const ACE_TCHAR* cmd)
+{
+ ACE_ERROR((LM_ERROR,
+ ACE_TEXT ("Usage: %s ")
+ ACE_TEXT ("[-n n] " )
+ ACE_TEXT ("[[-d n|-f n|-q n|-w n|-h n|-c n|-t n] | [-t n]]\n")
+ ACE_TEXT (" -n n: average time for n iterations.\n")
+ ACE_TEXT (" -d n: n double precision floating point\n")
+ ACE_TEXT (" -f n: n single precision floating point\n")
+ ACE_TEXT (" -q n: n quadwords (int64).\n")
+ ACE_TEXT (" -w n: n words (int32).\n")
+ ACE_TEXT (" -h n: n halfwords (int16).\n")
+ ACE_TEXT (" -c n: n chars.\n")
+ ACE_TEXT (" -t n: n iterations for every type.\n")
+ ACE_TEXT (" n must be >= 16 for dfqwhct.\n")
+ ACE_TEXT (" If you provide one of dfqwhc, then only the\n")
+ ACE_TEXT (" test for the corresponding type ")
+ ACE_TEXT ("will be performed.\n"),
+ cmd));
+ ACE_OS::exit(1);
+}
+
+int
+validtotal (int n)
+{
+ return n >= 16;
+}
+
+int
+validiters (int n)
+{
+ return n > 0;
+}
+
+int
+run_main (int argc, ACE_TCHAR *argv[])
+{
+ ACE_START_TEST (ACE_TEXT ("CDR_Array_Test"));
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("This is ACE Version %u.%u.%u\n\n"),
+ ACE::major_version (),
+ ACE::minor_version(),
+ ACE::beta_version()));
+
+ ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("d:f:q:w:h:c:t:n:"));
+ int dtotal = 0;
+ int ftotal = 0;
+ int qtotal = 0;
+ int wtotal = 0;
+ int htotal = 0;
+ int ctotal = 0;
+ int total = 0;
+ int niter = 0;
+
+ struct { int c; int *v; int (*checkf)(int); } opts[] = {
+ { 'd', &dtotal, validtotal },
+ { 'f', &ftotal, validtotal },
+ { 'q', &qtotal, validtotal },
+ { 'w', &wtotal, validtotal },
+ { 'h', &htotal, validtotal },
+ { 'c', &ctotal, validtotal },
+ { 't', &total, validtotal },
+ { 'n', &niter, validiters },
+ };
+
+ int n = sizeof(opts)/sizeof(opts[0]);
+
+ int opt;
+ while ((opt = get_opt ()) != EOF)
+ {
+ int got = 0;
+ int i;
+ for (i = 0; i < n; i++)
+ {
+ if (opts[i].c == opt)
+ {
+ int v = ACE_OS::atoi (get_opt.opt_arg ());
+ if (!(opts[i].checkf) (v))
+ {
+ usage(ACE_TEXT("CDR_Array_Test"));
+ }
+
+ *(opts[i].v) = v;
+ got = 1;
+ break;
+ }
+ }
+
+ if (!got)
+ {
+ usage(ACE_TEXT("CDR_Array_Test"));
+ }
+ }
+
+ if (total == 0)
+ {
+ total = default_total;
+ }
+
+ if (niter == 0)
+ {
+ niter = default_niter;
+ }
+
+ if (dtotal == 0
+ && ftotal == 0
+ && qtotal == 0
+ && wtotal == 0
+ && htotal == 0
+ && ctotal == 0)
+ {
+ dtotal = ftotal = qtotal = wtotal = htotal = ctotal = total;
+ }
+
+ int use_array;
+ for (use_array = 0; use_array < 2; use_array++)
+ {
+ {
+ CDR_Test<ACE_CDR::Double, DoubleHelper>
+ test (dtotal, niter, use_array);
+ }
+ {
+ CDR_Test<ACE_CDR::Float, FloatHelper>
+ test (ftotal, niter, use_array);
+ }
+#if !defined (ACE_LACKS_LONGLONG_T)
+ {
+ CDR_Test<ACE_CDR::LongLong, LongLongHelper>
+ test (qtotal, niter, use_array);
+ }
+#endif /* ! ACE_LACKS_LONGLONG_T */
+ {
+ CDR_Test<ACE_CDR::Long, LongHelper>
+ test (wtotal, niter, use_array);
+ }
+ {
+ CDR_Test<ACE_CDR::Short, ShortHelper>
+ test (htotal, niter, use_array);
+ }
+ {
+ CDR_Test<ACE_CDR::Char, CharHelper>
+ test (ctotal, niter, use_array);
+ }
+ }
+
+ ACE_END_TEST;
+ return 0;
+}
+
diff --git a/ACE/tests/CDR_File_Test.cpp b/ACE/tests/CDR_File_Test.cpp
new file mode 100644
index 00000000000..4b698128acb
--- /dev/null
+++ b/ACE/tests/CDR_File_Test.cpp
@@ -0,0 +1,483 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// CDR_File_Test.cpp
+//
+// = DESCRIPTION
+// Checks the functionality of the ACE CDR streams used for file
+// I/O.
+//
+// = AUTHORS
+// Giga Giguashvili <gregoryg@ParadigmGeo.com> and
+// Douglas C. Schmidt <schmidt@cs.wustl.edu>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/OS_Memory.h"
+#include "ace/OS_NS_stdlib.h"
+#include "ace/OS_NS_string.h"
+#include "ace/CDR_Stream.h"
+#include "ace/FILE_Connector.h"
+#include "ace/Auto_Ptr.h"
+#include "ace/Get_Opt.h"
+#include "ace/ACE.h"
+
+// FUZZ: disable check_for_streams_include
+#include "ace/streams.h"
+
+ACE_RCSID(tests, CDR_File_Test, "$Id$")
+
+#if !defined (ACE_LACKS_IOSTREAM_TOTALLY) | defined (ACE_HAS_WINCE)
+
+#if defined (ACE_HAS_WINCE)
+#include "CE_fostream.h"
+#endif // ACE_HAS_WINCE
+
+class CDR_Test
+{
+ // = TITLE
+ // Simple class that's used to read and write CDR streams.
+
+ friend ostream& operator << (ostream &os, const CDR_Test &t);
+ // Output the state of a <CDR_Test> object to the <ostream>.
+
+ friend void operator << (ACE_OutputCDR &os, const CDR_Test &t);
+ // Convert the state of this object into an <ACE_OutputCDR>.
+
+ friend void operator >> (ACE_InputCDR &is, CDR_Test &);
+ // Convert the <ACE_InputCDR> into the state of this object.
+
+public:
+ CDR_Test (void);
+ // Default constructor.
+
+ CDR_Test (ACE_CDR::Char o,
+ ACE_CDR::Short s,
+ ACE_CDR::Long w,
+ ACE_CDR::ULongLong lw,
+ ACE_CDR::Float f,
+ ACE_CDR::Double d);
+ // Constructor.
+
+ bool operator == (const CDR_Test &rhs) const;
+ // Compare <rhs> for equality with <this>.
+
+private:
+ ACE_CDR::Char char_;
+ ACE_CDR::Short word2_;
+ ACE_CDR::Long word4_;
+ ACE_CDR::ULongLong word8_;
+ ACE_CDR::Float fpoint_;
+ ACE_CDR::Double dprec_;
+};
+
+ostream &
+operator << (ostream &os,
+ const CDR_Test &t)
+{
+#if defined (ACE_OPENVMS)
+ // to circumvent some obscure bug with OpenVMS iostreams digit conversions
+ // combined with shared libraries????
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\n"
+ "Char: %c\n"
+ "Short: %u\n"
+ "Long: %d\n"),
+ t.char_, t.word2_, t.word4_));
+
+ ACE_CDR::ULongLong hi = (t.word8_ >> 32);
+ ACE_CDR::ULongLong lo = (t.word8_ & 0xffffffff);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\n"
+ "ULongLong 1st half: %x\n"
+ "ULongLong 2nd half: %x\n"
+ "Float: %f\n"
+ "Double: %f\n"),
+ ACE_U64_TO_U32(hi),
+ ACE_U64_TO_U32(lo),
+ t.fpoint_, t.dprec_));
+#else
+ os << "Char: " << t.char_ << endl
+ << "Short: " << t.word2_ << endl
+ << "Long: " << t.word4_ << endl;
+
+ ACE_CDR::ULongLong hi = (t.word8_ >> 32);
+ ACE_CDR::ULongLong lo = (t.word8_ & 0xffffffff);
+
+ os << "ULongLong 1st half: "
+ << hex
+ << ACE_U64_TO_U32 (hi)
+ << dec << endl
+ << "ULongLong 2nd half: "
+ << hex
+ << ACE_U64_TO_U32 (lo)
+ << dec << endl
+ << "Float: " << t.fpoint_ << endl
+ << "Double: " << t.dprec_ << endl;
+#endif
+ return os;
+}
+
+CDR_Test::CDR_Test (void)
+ : char_ (0),
+ word2_ (0),
+ word4_ (0),
+ word8_ (0),
+ fpoint_ (0.0),
+ dprec_ (0.0)
+{
+}
+
+CDR_Test::CDR_Test (ACE_CDR::Char o,
+ ACE_CDR::Short s,
+ ACE_CDR::Long w,
+ ACE_CDR::ULongLong lw,
+ ACE_CDR::Float f,
+ ACE_CDR::Double d)
+ : char_ (o),
+ word2_ (s),
+ word4_ (w),
+ word8_ (lw),
+ fpoint_ (f),
+ dprec_ (d)
+{
+}
+
+void
+operator << (ACE_OutputCDR &os, const CDR_Test &t)
+{
+ os << t.char_;
+ os << t.word2_;
+ os << t.word4_;
+ os << t.word8_;
+ os << t.fpoint_;
+ os << t.dprec_;
+}
+
+void
+operator >> (ACE_InputCDR &is, CDR_Test &t)
+{
+ is >> t.char_;
+ is >> t.word2_;
+ is >> t.word4_;
+ is >> t.word8_;
+ is >> t.fpoint_;
+ is >> t.dprec_;
+}
+
+bool
+CDR_Test::operator == (const CDR_Test &rhs) const
+{
+ // @@ Workaround bug in egcs-1.1.1 using a single && expression
+ // results in UMR errors in purify.
+ if (this->char_ != rhs.char_)
+ return false;
+ if (this->word2_ != rhs.word2_)
+ return false;
+ if (this->word4_ != rhs.word4_)
+ return false;
+ if (this->word8_ != rhs.word8_)
+ return false;
+ if (this->fpoint_ != rhs.fpoint_)
+ return false;
+ if (this->dprec_ != rhs.dprec_)
+ return false;
+ return true;
+}
+
+static int
+run_test (int write_file,
+ ACE_FILE_IO &file,
+ const ACE_TCHAR *filename,
+ CDR_Test &cdr_test)
+{
+ if (write_file)
+ {
+ char byte_order = ACE_CDR_BYTE_ORDER;
+ size_t n = file.send (&byte_order, 1);
+ if (n != 1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("send failed on %p\n"),
+ filename),
+ -1);
+
+ ACE_OutputCDR output_cdr (0,
+ ACE_CDR_BYTE_ORDER,
+ 0,
+ 0,
+ 0,
+ ACE_DEFAULT_CDR_MEMCPY_TRADEOFF,
+ ACE_CDR_GIOP_MAJOR_VERSION,
+ ACE_CDR_GIOP_MINOR_VERSION);
+ // Marshal the <CDR_Test> object data to the output CDR stream.
+ output_cdr << cdr_test;
+
+ // Output the data to cout.
+#if defined (ACE_HAS_WINCE) && defined (ACE_LACKS_IOSTREAM_TOTALLY)
+ // Since CE does not have ostream, ace_file_stream and output_file() cannot
+ // be used. Just use 'hard-coded' file name here.
+ (*ACE_CE_OSTREAM::instance()).open(ACE_TEXT("\\Log\\CDR_File_Test.txt"));
+ (*ACE_CE_OSTREAM::instance()) << cdr_test;
+#else
+ *ace_file_stream::instance ()->output_file () << cdr_test;
+#endif // ACE_HAS_WINCE
+
+ // Save the data.
+ const ACE_Message_Block *output_mb =
+ output_cdr.begin ();
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Writing file %s in %s endian format...\n"),
+ filename,
+ ACE_CDR_BYTE_ORDER ? ACE_TEXT("little") : ACE_TEXT("big")));
+
+ n = file.send (output_mb->rd_ptr (),
+ output_mb->length ());
+ if (n != (size_t) output_mb->length ())
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("send failed on %p\n"),
+ filename),
+ -1);
+ }
+ else // We're reading from the file.
+ {
+ ACE_FILE_Info info;
+ if (file.get_info (info) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("get_info failed on %p\n"),
+ filename),
+ -1);
+
+ ACE_LOFF_T msgsize = info.size_ - 1;
+
+ // Allocate the input buffer
+ char *buffer = 0;
+ ACE_NEW_RETURN (buffer,
+ char[msgsize],
+ -1);
+#if defined (ACE_INITIALIZE_MEMORY_BEFORE_USE)
+ ACE_OS::memset(buffer, 0, sizeof (buffer));
+#endif /* ACE_INITIALIZE_MEMORY_BEFORE_USE */
+
+ // Make sure <buffer> is released automagically.
+ ACE_Auto_Basic_Array_Ptr<char> b (buffer);
+
+ // Move the file pointer back to the beginning of the file.
+ if (file.seek (0,
+ SEEK_SET) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ filename),
+ -1);
+
+ char byte_order;
+ size_t size = file.recv (&byte_order, 1);
+ if (size != 1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("Read %d bytes, rather than expected ")
+ ACE_TEXT ("1 bytes\n"),
+ size),
+ -1);
+
+ // Read the cdr data from the file into the buffer.
+ size = file.recv (buffer, msgsize);
+ if (size != msgsize)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("Read %d bytes, rather than expected ")
+ ACE_TEXT ("%d bytes\n"),
+ size,
+ msgsize),
+ -1);
+
+ // Create message block for the whole file. Ensure that it is
+ // aligned to properly handle the double.
+ ACE_Message_Block mb (ACE_CDR::MAX_ALIGNMENT + msgsize);
+ ACE_CDR::mb_align (&mb);
+
+ mb.copy (buffer, msgsize);
+
+ // Create CDR input stream from the message block.
+
+ ACE_InputCDR input_cdr (&mb);
+ input_cdr.reset_byte_order ((int) byte_order);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Reading file %s in %s endian format...\n"),
+ filename,
+ ACE_CDR_BYTE_ORDER ? ACE_TEXT("little") : ACE_TEXT("big")));
+
+ CDR_Test temp;
+
+ // Demarshal the data from the input CDR stream into the
+ // <CDR_Test> object.
+ input_cdr >> temp;
+
+#if defined (ACE_HAS_WINCE) && defined (ACE_LACKS_IOSTREAM_TOTALLY)
+ (*ACE_CE_OSTREAM::instance()) << temp;
+#else
+ *ace_file_stream::instance ()->output_file () << temp;
+#endif // ACE_HAS_WINCE
+
+ ACE_ASSERT (temp == cdr_test);
+ }
+
+ return 0;
+}
+
+static void
+usage (const ACE_TCHAR *cmd)
+{
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Usage: %s ")
+ ACE_TEXT ("[-f filename [-w|-r]]"),
+ cmd));
+ ACE_OS::exit (1);
+}
+
+// Main function
+
+int
+run_main (int argc, ACE_TCHAR *argv[])
+{
+ ACE_START_TEST (ACE_TEXT ("CDR_File_Test"));
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("This is ACE Version %u.%u.%u\n\n"),
+ ACE::major_version (),
+ ACE::minor_version (),
+ ACE::beta_version ()));
+
+ ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("f:rw"));
+ int opt;
+ int reading = 1;
+ int writing = 1;
+ ACE_TCHAR* fn = 0;
+ while ((opt = get_opt ()) != EOF)
+ {
+ switch (opt)
+ {
+ case 'f':
+ fn = get_opt.opt_arg ();
+ break;
+ case 'r':
+ writing = 0;
+ break;
+ case 'w':
+ reading = 0;
+ break;
+ case '?':
+ default:
+ usage (ACE_TEXT("CDR_File_Test"));
+ }
+ }
+
+ if ((!reading || !writing) && fn == 0)
+ usage (ACE_TEXT("CDR_File_Test"));
+
+ if (!reading && !writing)
+ usage (ACE_TEXT("CDR_File_Test"));
+
+ // Create a temporary filename.
+ ACE_FILE_Addr filename (ACE_sap_any_cast (ACE_FILE_Addr &));
+ if (fn != 0)
+ filename.set (fn);
+
+
+ ACE_FILE_Connector connector;
+ ACE_FILE_IO file;
+
+ // Open up the file.
+ if (connector.connect (file,
+ filename,
+ 0,
+ ACE_Addr::sap_any,
+ 0,
+ ((writing) ? (O_RDWR | O_CREAT) : O_RDONLY),
+ ACE_DEFAULT_FILE_PERMS) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("connect failed for %p\n"),
+ filename.get_path_name ()),
+ 1);
+
+#if (!defined (ACE_WIN32) \
+ || (defined (ACE_HAS_WINNT4) && ACE_HAS_WINNT4 == 1)) && \
+ !defined (VXWORKS)
+# define TEST_CAN_UNLINK_IN_ADVANCE
+#endif
+
+#if defined (TEST_CAN_UNLINK_IN_ADVANCE)
+ if (fn == 0)
+ {
+ // Unlink this file right away so that it is automatically removed
+ // when the process exits.
+ if (file.unlink () == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("unlink failed for %p\n"),
+ filename.get_path_name ()),
+ 1);
+ }
+#endif
+
+ CDR_Test cdr_test ('a',
+ 0x00ff,
+ 0xaabbccdd,
+ 0x01234567,
+ 1.54321f,
+ 1.12345);
+
+ if (writing)
+ {
+ // write the file.
+ run_test (1,
+ file,
+ filename.get_path_name (),
+ cdr_test);
+ }
+
+ if (reading)
+ {
+ // read the file.
+ run_test (0,
+ file,
+ filename.get_path_name (),
+ cdr_test);
+ }
+
+#if !defined (TEST_CAN_UNLINK_IN_ADVANCE)
+ if (fn == 0)
+ {
+ file.close ();
+ if (file.unlink () == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("unlink failed for %p\n"),
+ filename.get_path_name ()),
+ 1);
+ }
+#endif
+
+ ACE_END_TEST;
+ return 0;
+}
+
+#else /* ! ACE_LACKS_IOSTREAM_TOTALLY */
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("CDR_File_Test"));
+
+ ACE_ERROR ((LM_INFO,
+ ACE_TEXT ("iostreams not supported on this platform\n")));
+
+ ACE_END_TEST;
+ return 0;
+}
+
+#endif /* ! ACE_LACKS_IOSTREAM_TOTALLY */
diff --git a/ACE/tests/CDR_Test.cpp b/ACE/tests/CDR_Test.cpp
new file mode 100644
index 00000000000..ca61076c4ed
--- /dev/null
+++ b/ACE/tests/CDR_Test.cpp
@@ -0,0 +1,568 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// CDR_Test.cpp
+//
+// = DESCRIPTION
+// Checks the functionality of the ACE CDR streams.
+//
+// = AUTHORS
+// Istvan Buki <istvan.buki@euronet.be> and
+// Jeff Parsons <parsons@cs.wustl.edu> and
+// Carlos O'Ryan <coryan@cs.wustl.edu>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/Get_Opt.h"
+#include "ace/Auto_Ptr.h"
+#include "ace/CDR_Stream.h"
+#include "ace/CDR_Size.h"
+#include "ace/SString.h"
+#include "ace/ACE.h"
+#include "ace/OS_NS_stdlib.h"
+#include "ace/OS_NS_string.h"
+#include "ace/OS_NS_wchar.h"
+
+ACE_RCSID(tests, CDR_Test, "$Id$")
+
+static int n = 4096;
+static int nloops = 100;
+
+struct CDR_Test_Types
+{
+ CDR_Test_Types (void);
+
+ ACE_CDR::Octet o;
+ ACE_CDR::Short s;
+ ACE_CDR::Long l;
+ const ACE_CDR::Char *str;
+ const ACE_CDR::WChar *wstr;
+ ACE_CDR::Double d;
+
+ int test_put (ACE_OutputCDR& cdr);
+ int test_get (ACE_InputCDR& cdr) const;
+
+ enum
+ {
+ ARRAY_SIZE = 10
+ };
+
+ ACE_CDR::Short a[ARRAY_SIZE];
+};
+
+CDR_Test_Types::CDR_Test_Types (void)
+ : o (1),
+ s (2),
+ l (4),
+ str ("abc"),
+ wstr (0),
+ d (8)
+{
+ for (int i = 0;
+ i < CDR_Test_Types::ARRAY_SIZE;
+ ++i)
+ a[i] = i;
+}
+
+static int
+short_stream (void)
+{
+ // counter
+ u_int i;
+
+ // Build an output stream
+ ACE_OutputCDR os;
+ ACE_SizeCDR ss;
+
+ // Basic types for output
+ ACE_CDR::Char ch = 'A';
+ ACE_CDR::Char wchtmp[] = {'\xF3'};
+ ACE_CDR::WChar wch = *wchtmp;
+ ACE_CDR::WChar wchar2[] = {'\x00'}; // empty wide string
+ ACE_CDR::WChar *wstr = wchar2;
+ ACE_CString str ("Test String");
+ ACE_CDR::Short s = -123;
+ ACE_CDR::UShort us = 123;
+ ACE_CDR::Long l = -65800L;
+ ACE_CDR::ULong ul = 65800UL;
+ ACE_CDR::Float f = 1.23f;
+ ACE_CDR::Double d = 123.456789;
+
+ // Arrays for output
+ ACE_CDR::Short s_array[3] = { -1, 0, 1 };
+ ACE_CDR::Long l_array[3] = { -345678, 0, 345678 };
+ ACE_CDR::Float f_array[3] = { -1.23f, 0.0f, 1.23f };
+ ACE_CDR::Double d_array[3] = { -123.456789, 0.0, 123.456789 };
+
+ ACE_OutputCDR::from_char fc (ch);
+ ACE_OutputCDR::from_wchar fwc (wch);
+ os << fc;
+ os << fwc;
+ os << str;
+ os << wstr;
+ os << s;
+ os << us;
+ os << l;
+ os << ul;
+ os << f;
+ os << d;
+ os.write_short_array (s_array, 3);
+ os.write_long_array (l_array, 3);
+ os.write_float_array (f_array, 3);
+ os.write_double_array (d_array, 3);
+
+ // Do the same for size stream.
+ ss << fc;
+ ss << fwc;
+ ss << str;
+ ss << wstr;
+ ss << s;
+ ss << us;
+ ss << l;
+ ss << ul;
+ ss << f;
+ ss << d;
+ ss.write_short_array (s_array, 3);
+ ss.write_long_array (l_array, 3);
+ ss.write_float_array (f_array, 3);
+ ss.write_double_array (d_array, 3);
+
+ // Check the size.
+ if (ss.total_length () != os.total_length ())
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("representation length does not match")),
+ 1);
+
+ const ACE_Message_Block *out_mb = os.begin ();
+ size_t len = out_mb->length ();
+
+ // Create an input stream (copy constructor)
+ ACE_InputCDR is (os);
+ const ACE_Message_Block *in_mb = is.start ();
+
+ if (in_mb->length () != len)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("buffer length not preserved")),
+ 1);
+
+ for (i = 0; i < len; i++)
+ {
+ unsigned long const in_chunk =
+ static_cast<unsigned long> (* (in_mb->rd_ptr () + i));
+
+ unsigned long const out_chunk =
+ static_cast<unsigned long> (* (out_mb->rd_ptr () + i));
+
+ if (in_chunk != out_chunk)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("buffer contents not preserved")),
+ 1);
+ }
+
+ // Basic types for input
+ ACE_CDR::Char ch1 = '\0';
+ ACE_CDR::WChar wch1 = '\x00';
+ ACE_CDR::WChar *wstr1 = 0;
+ ACE_CString str1;
+ ACE_CDR::Short s1 = 0;
+ ACE_CDR::UShort us1 = 0;
+ ACE_CDR::Long l1 = 0L;
+ ACE_CDR::ULong ul1 = 0UL;
+ ACE_CDR::Float f1 = 0.0f;
+ ACE_CDR::Double d1 = 0.0;
+
+ // Arrays for input
+ ACE_CDR::Short s_array1[3];
+ ACE_CDR::Long l_array1[3];
+ ACE_CDR::Float f_array1[3];
+ ACE_CDR::Double d_array1[3];
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Checking operators and arrays\n\n")));
+
+ ACE_InputCDR::to_char tc (ch1);
+ is >> tc;
+ ACE_InputCDR::to_wchar twc (wch1);
+ is >> twc;
+ is >> str1;
+ ACE_InputCDR::to_wstring twstr (wstr1, 0);
+ is >> twstr;
+ // @todo Lose the ACE_Auto_Array_Ptr. We should be using a
+ // std::string, or the like.
+ ACE_Auto_Array_Ptr<ACE_CDR::WChar> safe_wstr (wstr1);
+ is >> s1;
+ is >> us1;
+ is >> l1;
+ is >> ul1;
+ is >> f1;
+ is >> d1;
+ is.read_short_array (s_array1, 3);
+ is.read_long_array (l_array1, 3);
+ is.read_float_array (f_array1, 3);
+ is.read_double_array (d_array1, 3);
+
+ if (ch1 != ch)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("char transfer error")),
+ 1);
+
+ if (wch1 != wch)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("wchar transfer error")),
+ 1);
+
+ if (str1 != str)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("string transfer error")),
+ 1);
+
+ if (ACE_OS::wscmp (wstr1, wstr))
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("wide string transfer error")),
+ 1);
+
+
+ if (s1 != s)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("short transfer error")),
+ 1);
+
+ if (us1 != us)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("ushort transfer error")),
+ 1);
+
+ if (l1 != l)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("long transfer error")),
+ 1);
+
+ if (ul1 != ul)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("ulong transfer error")),
+ 1);
+
+ if (f1 != f)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("float transfer error")),
+ 1);
+
+ if (d1 != d)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("double transfer error")),
+ 1);
+
+ for (i = 0 ; i < 3; i++)
+ if (s_array1[i] != s_array[i])
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("short array transfer error")),
+ 1);
+
+ for (i = 0 ; i < 3; i++)
+ if (l_array1[i] != l_array[i])
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("long array transfer error")),
+ 1);
+
+ for (i = 0 ; i < 3; i++)
+ if (f_array1[i] != f_array[i])
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("float array transfer error")),
+ 1);
+
+ for (i = 0 ; i < 3; i++)
+ if (d_array1[i] != d_array[i])
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("double array transfer error")),
+ 1);
+
+ return 0;
+}
+
+int
+CDR_Test_Types::test_put (ACE_OutputCDR &cdr)
+{
+ for (int i = 0; i < n; ++i)
+ {
+ if (cdr.write_octet (this->o) == 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("write_octet[%d] failed\n"),
+ i),
+ 1);
+ if (cdr.write_short (this->s) == 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("write_short[%d] failed\n"),
+ i),
+ 1);
+ if (cdr.write_octet (this->o) == 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("write_octet-2[%d] failed\n"),
+ i),
+ 1);
+ if (cdr.write_long (this->l) == 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("write_long[%d] failed\n"),
+ i),
+ 1);
+ if (cdr.write_long (this->l) == 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("write_long-2[%d] failed\n"),
+ i),
+ 1);
+
+ if (cdr.write_string (this->str) == 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("write_string[%d] failed\n"),
+ i),
+ 1);
+
+ if (cdr.write_wstring (this->wstr) == 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("write_wstring[%d] failed\n"),
+ i),
+ 1);
+
+ }
+
+ return 0;
+}
+
+int
+CDR_Test_Types::test_get (ACE_InputCDR &cdr) const
+{
+ ACE_CDR::Octet xo;
+ ACE_CDR::Short xs;
+ ACE_CDR::Long xl;
+
+ for (int i = 0; i < n; ++i)
+ {
+ if (cdr.read_octet (xo) == 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("read_octet[%d] failed\n"),
+ i),
+ 1);
+ if (xo != this->o)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("octet[%d] differs\n"),
+ i),
+ 1);
+ if (cdr.read_short (xs) == 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("read_short[%d] failed\n"),
+ i), 1);
+ if (xs != this->s)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("short[%d] differs\n"),
+ i),
+ 1);
+ if (cdr.read_octet (xo) == 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("read_octet-2[%d] failed\n"),
+ i),
+ 1);
+ if (xo != this->o)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("octet-2[%d] differs\n"),
+ i),
+ 1);
+ if (cdr.read_long (xl) == 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("read_long[%d] failed\n"),
+ i),
+ 1);
+ if (xl != this->l)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("long[%d] differs\n"),
+ i),
+ 1);
+ if (cdr.read_long (xl) == 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("read_long-2[%d] failed\n"),
+ i),
+ 1);
+ if (xl != this->l)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("long-2[%d] differs\n"),
+ i),
+ 1);
+
+ ACE_CDR::Char *xstr;
+ if (cdr.read_string (xstr) == 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("read_string2[%d] failed\n"),
+ i),
+ 1);
+ ACE_Auto_Basic_Array_Ptr<ACE_CDR::Char> auto_xstr (xstr);
+ if (ACE_OS::strcmp (auto_xstr.get (), this->str) != 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("string[%d] differs\n"),
+ i),
+ 1);
+
+ ACE_CDR::WChar *wstr1;
+ if (cdr.read_wstring (wstr1) == 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("read_wstring2[%d] failed\n"),
+ i),
+ 1);
+ // zero length
+ ACE_Auto_Basic_Array_Ptr<ACE_CDR::WChar> auto_xwstr (wstr1);
+ if (ACE_OS::wslen(auto_xwstr.get () ))
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("wstring[%d] differs\n"),
+ i),
+ 1);
+ }
+ return 0;
+}
+
+int
+run_main (int argc, ACE_TCHAR *argv[])
+{
+ ACE_START_TEST (ACE_TEXT ("CDR_Test"));
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("This is ACE Version %u.%u.%u\n\n"),
+ ACE::major_version (),
+ ACE::minor_version(),
+ ACE::beta_version()));
+
+ ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("dn:l:"));
+ int opt;
+ int debug = 0;
+
+ while ((opt = get_opt ()) != EOF)
+ {
+ switch (opt)
+ {
+ case 'd':
+ debug++;
+ break;
+ case 'n':
+ n = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'l':
+ nloops = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case '?':
+ default:
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Usage: %s ")
+ ACE_TEXT ("-d debug")
+ ACE_TEXT ("-n <num> ")
+ ACE_TEXT ("-l <loops> ")
+ ACE_TEXT ("\n"),
+ ACE_TEXT ("CDR_Test")));
+ return -1;
+ }
+ }
+
+ // Sanity checks.
+ ACE_ASSERT (sizeof (ACE_CDR::Boolean) >= 1);
+ ACE_ASSERT (sizeof (ACE_CDR::Octet) == 1);
+ ACE_ASSERT (sizeof (ACE_CDR::WChar) >= 2);
+ ACE_ASSERT (sizeof (ACE_CDR::Short) == 2);
+ ACE_ASSERT (sizeof (ACE_CDR::Long) == 4);
+ ACE_ASSERT (sizeof (ACE_CDR::LongLong) == 8);
+ ACE_ASSERT (sizeof (ACE_CDR::Float) == 4);
+ ACE_ASSERT (sizeof (ACE_CDR::Double) == 8);
+ ACE_ASSERT (sizeof (ACE_CDR::LongDouble) == 16);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Testing ACE CDR functions - short stream\n\n")));
+
+ if (short_stream () != 0 )
+ return 1;
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Short stream - no errors\n\n")
+ ACE_TEXT ("Testing basic types - long stream\n\n")));
+
+ for (int i = 0; i < nloops; ++i)
+ {
+ ACE_OutputCDR output;
+ CDR_Test_Types test_types;
+
+ if (test_types.test_put (output) != 0)
+ return 1;
+
+ ACE_InputCDR input (output);
+ if (debug > 0)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Output CDR: \n")));
+ ACE_HEX_DUMP ((LM_DEBUG,
+ input.rd_ptr(),
+ 64));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Input CDR: \n")));
+ ACE_HEX_DUMP ((LM_DEBUG,
+ input.rd_ptr(),
+ 64));
+ }
+
+ if (test_types.test_get (input) != 0)
+ return 1;
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Long stream - no errors\n\n")
+ ACE_TEXT ("Testing basic types - long stream[2]\n\n")));
+
+ for (int j = 0; j < nloops; ++j)
+ {
+ ACE_OutputCDR output;
+ CDR_Test_Types test_types;
+
+ if (test_types.test_put (output) != 0)
+ return 1;
+
+ ACE_InputCDR input (output.begin ());
+ if (debug > 0)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Output CDR: \n")));
+ ACE_HEX_DUMP ((LM_DEBUG,
+ input.rd_ptr(),
+ 64));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Input CDR: \n")));
+ ACE_HEX_DUMP ((LM_DEBUG,
+ input.rd_ptr(),
+ 64));
+ }
+
+ if (test_types.test_get (input) != 0)
+ return 1;
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Long stream[2] - no errors\n\n")));
+
+ ACE_END_TEST;
+ return 0;
+}
+
diff --git a/ACE/tests/CE_fostream.cpp b/ACE/tests/CE_fostream.cpp
new file mode 100644
index 00000000000..a57c9d7199e
--- /dev/null
+++ b/ACE/tests/CE_fostream.cpp
@@ -0,0 +1,163 @@
+//=============================================================================
+/**
+ * @file CE_fostream.cpp
+ *
+ * $Id$
+ *
+ * @author Si Mong Park <spark@ociweb.com>
+ *
+ * This is a helper class to simulate basic functions of fostream for
+ * Windows CE since WinCE does not have IO stream.
+ *
+ * Note that the numeric base conversion does not work and will be displayed
+ * as received.
+ */
+// ============================================================================
+
+#include "CE_fostream.h"
+
+// This is CE only, prior to availability of iostreams (VC 8).
+#if defined (ACE_HAS_WINCE) && defined (ACE_LACKS_IOSTREAM_TOTALLY)
+
+ACE_CE_fostream* ACE_CE_fostream::instance_ = 0;
+
+
+ACE_CE_fostream* ACE_CE_fostream::instance (void)
+{
+ if (instance_ == 0) {
+ instance_ = new ACE_CE_fostream();
+ }
+
+ return instance_;
+}
+
+
+ACE_CE_fostream::ACE_CE_fostream()
+: ostream_(0)
+, displayMode_(dec)
+{
+}
+
+
+ACE_CE_fostream::~ACE_CE_fostream()
+{
+ fclose(ostream_);
+}
+
+
+FILE* ACE_CE_fostream::open(const ACE_TCHAR *prog_name)
+{
+ ostream_ = _wfopen(prog_name, ACE_TEXT("a+"));
+
+ return ostream_;
+}
+
+
+ACE_CE_fostream& ACE_CE_fostream::operator << (NUM_TYPE num_type)
+{
+ displayMode_ = num_type;
+ return *this;
+}
+
+
+ACE_CE_fostream& ACE_CE_fostream::operator << (const ACE_ANTI_TCHAR* c)
+{
+ fprintf(ostream_, "%s", c);
+ return *this;
+}
+
+
+ACE_CE_fostream& ACE_CE_fostream::operator << (ACE_ANTI_TCHAR c)
+{
+ fprintf(ostream_, "%c", c);
+ return *this;
+}
+
+
+ACE_CE_fostream& ACE_CE_fostream::operator << (const ACE_TCHAR* c)
+{
+ fwprintf(ostream_, ACE_TEXT("%s"), c);
+ return *this;
+}
+
+
+ACE_CE_fostream& ACE_CE_fostream::operator << (ACE_TCHAR c)
+{
+ fwprintf(ostream_, ACE_TEXT("%c"), c);
+ return *this;
+}
+
+
+ACE_CE_fostream& ACE_CE_fostream::operator << (short s)
+{
+ if (displayMode_ == oct) {
+ const NUM_BITS = ACE_SIZEOF_SHORT * 8;
+ short currentMax = 16384;
+
+ for (int i = 0; i < NUM_BITS; ++i) {
+ }
+ }
+ else if (displayMode_ == hex) {
+ }
+
+ fwprintf(ostream_, ACE_TEXT("%d"), s);
+ return *this;
+}
+
+
+ACE_CE_fostream& ACE_CE_fostream::operator << (int i)
+{
+ fwprintf(ostream_, ACE_TEXT("%d"), i);
+ return *this;
+}
+
+
+ACE_CE_fostream& ACE_CE_fostream::operator << (unsigned int i)
+{
+ fwprintf(ostream_, ACE_TEXT("%d"), i);
+ return *this;
+}
+
+
+ACE_CE_fostream& ACE_CE_fostream::operator << (long l)
+{
+ fwprintf(ostream_, ACE_TEXT("%f"), l);
+ return *this;
+}
+
+
+ACE_CE_fostream& ACE_CE_fostream::operator << (unsigned long l)
+{
+ fwprintf(ostream_, ACE_TEXT("%f"), l);
+ return *this;
+}
+
+
+ACE_CE_fostream& ACE_CE_fostream::operator << (float f)
+{
+ fwprintf(ostream_, ACE_TEXT("%f"), f);
+ return *this;
+}
+
+
+ACE_CE_fostream& ACE_CE_fostream::operator << (double d)
+{
+ fwprintf(ostream_, ACE_TEXT("%f"), d);
+ return *this;
+}
+
+
+ACE_CE_fostream& ACE_CE_fostream::operator << (long double d)
+{
+ fwprintf(ostream_, ACE_TEXT("%f"), d);
+ return *this;
+}
+
+
+ACE_CE_fostream& ACE_CE_fostream::operator << (const void* v)
+{
+ fwprintf(ostream_, ACE_TEXT("%d"), v);
+ return *this;
+}
+
+#endif /* ACE_HAS_WINCE && ACE_LACKS_IOSTREAMS_TOTALLY */
diff --git a/ACE/tests/CE_fostream.h b/ACE/tests/CE_fostream.h
new file mode 100644
index 00000000000..9d84d7fc2be
--- /dev/null
+++ b/ACE/tests/CE_fostream.h
@@ -0,0 +1,105 @@
+// -*- C++ -*-
+
+//=============================================================================
+/**
+ * @file CE_fostream.h
+ *
+ * $Id$
+ *
+ * @author Si Mong Park <spark@ociweb.com>
+ *
+ * This is a helper class to simulate basic functions of fostream for
+ * Windows CE since WinCE does not have IO stream.
+ *
+ * Note that the numeric base conversion does not work and will be displayed
+ * as received.
+ */
+// ============================================================================
+
+#ifndef ACE_CE_fostream_h
+#define ACE_CE_fostream_h
+
+#include "ace/config-all.h"
+
+#if defined (ACE_HAS_WINCE) && defined (ACE_LACKS_IOSTREAM_TOTALLY)
+
+#include "ace/Null_Mutex.h"
+#include "ace/Singleton.h"
+
+#ifdef ostream
+#undef ostream
+#endif
+
+#ifdef OFSTREAM
+#undef OFSTREAM
+#endif // OFSTREAM
+
+#define ostream ACE_CE_fostream
+#define OFSTREAM ACE_CE_fostream
+#define dec ACE_CE_fostream::dec
+#define oct ACE_CE_fostream::oct
+#define hex ACE_CE_fostream::hex
+#define endl ACE_TEXT("\n")
+
+class ACE_CE_fostream
+{
+public:
+ friend class ACE_Singleton<ACE_CE_fostream, ACE_Null_Mutex>;
+
+ enum NUM_TYPE {
+ // These numbers are not really meaningful for this class; set same as defined in ios.
+ // Also, base formatting works only for the integer types.
+ dec = 0x0010,
+ oct = 0x0020,
+ hex = 0x0040
+ };
+
+ static ACE_CE_fostream* instance (void);
+
+ FILE* open(const ACE_TCHAR *prog_name);
+
+ ACE_CE_fostream& operator << (NUM_TYPE);
+
+ ACE_CE_fostream& operator << (unsigned char);
+
+ ACE_CE_fostream& operator << (const ACE_ANTI_TCHAR *);
+ ACE_CE_fostream& operator << (ACE_ANTI_TCHAR);
+
+ ACE_CE_fostream& operator << (const ACE_TCHAR*);
+ ACE_CE_fostream& operator << (ACE_TCHAR);
+
+ ACE_CE_fostream& operator << (short);
+
+ ACE_CE_fostream& operator << (int);
+ ACE_CE_fostream& operator << (unsigned int);
+
+ ACE_CE_fostream& operator << (long);
+ ACE_CE_fostream& operator << (unsigned long);
+ ACE_CE_fostream& operator << (float);
+ ACE_CE_fostream& operator << (double);
+ ACE_CE_fostream& operator << (long double);
+
+ ACE_CE_fostream& operator << (const void *);
+
+private:
+ ACE_CE_fostream();
+
+ ~ACE_CE_fostream();
+
+ /**
+ * The ostream where logging messages can be written.
+ */
+ ACE_OSTREAM_TYPE *ostream_;
+
+ /**
+ * Currently set numeric base.
+ */
+ NUM_TYPE displayMode_;
+
+ static ACE_CE_fostream* instance_;
+};
+
+typedef ACE_Singleton<ACE_CE_fostream, ACE_Null_Mutex> ACE_CE_OSTREAM;
+
+#endif /* ACE_HAS_WINCE && ACE_LACKS_IOSTREAM_TOTALLY */
+#endif /* ACE_CE_fostream_h */
diff --git a/ACE/tests/Cache_Map_Manager_Test.cpp b/ACE/tests/Cache_Map_Manager_Test.cpp
new file mode 100644
index 00000000000..400235216e0
--- /dev/null
+++ b/ACE/tests/Cache_Map_Manager_Test.cpp
@@ -0,0 +1,598 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Cache_Map_Manager_Test.cpp
+//
+// = DESCRIPTION
+// This is a test of the <ACE_Cache_Map_Manager> and
+// <ACE_Hash_Cache_Map_Manager> that illustrates how to use the
+// forward and reverse iterators, as well as the purging and
+// caching features.
+//
+// = AUTHOR
+// Kirthika Parameswaran <kirthika@cs.wustl.edu>
+//
+// ============================================================================
+
+#include "ace/OS_NS_string.h"
+
+#include "ace/OS_Memory.h"
+#include "ace/OS_NS_stdlib.h"
+#include "ace/OS_NS_time.h"
+#include "test_config.h"
+#include "ace/Hash_Cache_Map_Manager_T.h"
+#include "ace/Map_Manager.h"
+#include "ace/Caching_Strategies_T.h"
+#include "ace/Functor.h"
+#include "ace/Pair_T.h"
+#include "ace/Get_Opt.h"
+#include "Cache_Map_Manager_Test.h" // Hash_Key class defined in here
+
+typedef size_t KEY;
+typedef size_t VALUE;
+typedef int ATTR;
+typedef ACE_Pair<VALUE, ATTR> CACHE_VALUE;
+typedef ACE_Equal_To<KEY> COMPARE_KEYS;
+
+typedef ACE_Hash_Map_Manager_Ex<KEY, CACHE_VALUE, Hash_Key, ACE_Equal_To<KEY>, ACE_Null_Mutex>
+ HASH_MAP_MANAGER;
+typedef ACE_Hash_Map_Iterator_Ex<KEY, CACHE_VALUE, Hash_Key, ACE_Equal_To<KEY>, ACE_Null_Mutex>
+ HASH_MAP_ITERATOR;
+typedef ACE_Hash_Map_Reverse_Iterator_Ex<KEY, CACHE_VALUE, Hash_Key, ACE_Equal_To<KEY>, ACE_Null_Mutex>
+ HASH_MAP_REVERSE_ITERATOR;
+
+typedef ACE_Map_Manager<KEY, CACHE_VALUE, ACE_Null_Mutex>
+ MAP_MANAGER;
+typedef ACE_Map_Iterator<KEY, CACHE_VALUE, ACE_Null_Mutex>
+ MAP_ITERATOR;
+typedef ACE_Map_Reverse_Iterator<KEY, CACHE_VALUE, ACE_Null_Mutex>
+ MAP_REVERSE_ITERATOR;
+
+typedef ACE_Cleanup_Strategy<KEY, CACHE_VALUE, HASH_MAP_MANAGER>
+ HASH_MAP_CLEANUP;
+
+typedef ACE_Cleanup_Strategy<KEY, CACHE_VALUE, MAP_MANAGER>
+ MAP_CLEANUP;
+
+typedef ACE_Pair_Caching_Utility<KEY, CACHE_VALUE, HASH_MAP_MANAGER, HASH_MAP_ITERATOR, ATTR>
+ HASH_MAP_CACHING_UTILITY;
+
+typedef ACE_Pair_Caching_Utility<KEY, CACHE_VALUE, MAP_MANAGER, MAP_ITERATOR, ATTR>
+ MAP_CACHING_UTILITY;
+
+// = Hash_Map_Manager related
+typedef ACE_Caching_Strategy<ATTR, HASH_MAP_CACHING_UTILITY>
+ HASH_MAP_CACHING_STRATEGY;
+typedef ACE_LRU_Caching_Strategy<ATTR, HASH_MAP_CACHING_UTILITY>
+ HASH_MAP_LRU;
+typedef ACE_LFU_Caching_Strategy<ATTR, HASH_MAP_CACHING_UTILITY>
+ HASH_MAP_LFU;
+typedef ACE_FIFO_Caching_Strategy<ATTR, HASH_MAP_CACHING_UTILITY>
+ HASH_MAP_FIFO;
+typedef ACE_Null_Caching_Strategy<ATTR, HASH_MAP_CACHING_UTILITY>
+ HASH_MAP_NULL;
+typedef ACE_Caching_Strategy_Adapter<ATTR, HASH_MAP_CACHING_UTILITY, HASH_MAP_LRU>
+ HASH_MAP_LRU_ADAPTER;
+typedef ACE_Caching_Strategy_Adapter<ATTR, HASH_MAP_CACHING_UTILITY, HASH_MAP_LFU>
+ HASH_MAP_LFU_ADAPTER;
+typedef ACE_Caching_Strategy_Adapter<ATTR, HASH_MAP_CACHING_UTILITY, HASH_MAP_FIFO>
+ HASH_MAP_FIFO_ADAPTER;
+typedef ACE_Caching_Strategy_Adapter<ATTR, HASH_MAP_CACHING_UTILITY, HASH_MAP_NULL>
+ HASH_MAP_NULL_ADAPTER;
+
+// = Map_Manager related
+typedef ACE_Caching_Strategy<ATTR, MAP_CACHING_UTILITY>
+ MAP_CACHING_STRATEGY;
+typedef ACE_LRU_Caching_Strategy<ATTR, MAP_CACHING_UTILITY>
+ MAP_LRU;
+typedef ACE_LFU_Caching_Strategy<ATTR, MAP_CACHING_UTILITY>
+ MAP_LFU;
+typedef ACE_FIFO_Caching_Strategy<ATTR, MAP_CACHING_UTILITY>
+ MAP_FIFO;
+typedef ACE_Null_Caching_Strategy<ATTR, MAP_CACHING_UTILITY>
+ MAP_NULL;
+typedef ACE_Caching_Strategy_Adapter<ATTR, MAP_CACHING_UTILITY, MAP_LRU>
+ MAP_LRU_ADAPTER;
+typedef ACE_Caching_Strategy_Adapter<ATTR, MAP_CACHING_UTILITY, MAP_LFU>
+ MAP_LFU_ADAPTER;
+typedef ACE_Caching_Strategy_Adapter<ATTR, MAP_CACHING_UTILITY, MAP_FIFO>
+ MAP_FIFO_ADAPTER;
+typedef ACE_Caching_Strategy_Adapter<ATTR, MAP_CACHING_UTILITY, MAP_NULL>
+ MAP_NULL_ADAPTER;
+
+typedef ACE_Hash_Cache_Map_Manager<KEY, VALUE, Hash_Key, ACE_Equal_To<KEY>, HASH_MAP_CACHING_STRATEGY, ATTR>
+ HASH_MAP_CACHE;
+typedef ACE_Cache_Map_Manager<KEY, VALUE, MAP_MANAGER, MAP_ITERATOR, MAP_REVERSE_ITERATOR, MAP_CACHING_STRATEGY, ATTR>
+ MAP_CACHE;
+
+enum Caching_Strategy_Type
+{
+ ACE_LFU,
+ ACE_FIFO,
+ ACE_LRU,
+ ACE_NULL,
+ ACE_ALL
+};
+
+static size_t iterations = ACE_MAX_ITERATIONS;
+static size_t no_of_lookups = iterations / 2;
+static int randomize_lookups = 1;
+static int purge_percent = 10;
+static int debug = 0;
+static Caching_Strategy_Type caching_strategy_type = ACE_ALL;
+static KEY *lookup_array = 0;
+
+static void
+run_iterator_cache (MAP_CACHE &cache)
+{
+ size_t iterations = cache.current_size ();
+ size_t counter = 0;
+ MAP_CACHE::iterator end = cache.end ();
+
+ for (MAP_CACHE::iterator iter = cache.begin ();
+ iter != end;
+ ++iter)
+ {
+ // Debugging info.
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%d|%d)"),
+ (*iter).first (),
+ (*iter).second ()));
+
+ ACE_ASSERT ((*iter).first () == (*iter).second ());
+ ++counter;
+ }
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\n")));
+
+ ACE_UNUSED_ARG (iterations);
+ ACE_ASSERT (counter == iterations);
+}
+
+static void
+run_iterator_hash_cache (HASH_MAP_CACHE &cache)
+{
+ size_t iterations = cache.current_size ();
+ size_t counter = 0;
+ HASH_MAP_CACHE::iterator end = cache.end ();
+
+ for (HASH_MAP_CACHE::iterator iter = cache.begin ();
+ iter != end;
+ ++iter)
+ {
+ // Debugging info.
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%d|%d)"),
+ (*iter).first (),
+ (*iter).second ()));
+
+ ACE_ASSERT ((*iter).first () == (*iter).second ());
+ ++counter;
+ }
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\n")));
+
+ ACE_UNUSED_ARG (iterations);
+ ACE_ASSERT (counter == iterations);
+}
+
+static void
+run_reverse_iterator_cache (MAP_CACHE &cache)
+{
+ size_t counter = cache.current_size ();
+ MAP_CACHE::reverse_iterator rend = cache.rend ();
+
+ for (MAP_CACHE::reverse_iterator iter = cache.rbegin ();
+ iter != rend;
+ ++iter)
+ {
+ ACE_ASSERT ((*iter).first () == (*iter).second ());
+
+ // Debugging info.
+ if (debug)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%d|%d)"),
+ (*iter).first (),
+ (*iter).second ()));
+ --counter;
+ }
+
+ if (debug)
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\n")));
+
+ ACE_ASSERT (counter == 0);
+}
+
+static void
+run_reverse_iterator_hash_cache (HASH_MAP_CACHE &cache)
+{
+ size_t counter = cache.current_size ();
+ HASH_MAP_CACHE::reverse_iterator rend = cache.rend ();
+
+ for (HASH_MAP_CACHE::reverse_iterator iter = cache.rbegin ();
+ iter != rend;
+ ++iter)
+ {
+ ACE_ASSERT ((*iter).first () == (*iter).second ());
+
+ // Debugging info.
+ if (debug)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%d|%d)"),
+ (*iter).first (),
+ (*iter).second ()));
+ --counter;
+ }
+
+ if (debug)
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\n")));
+
+ ACE_ASSERT (counter == 0);
+}
+
+static void
+find_test_cache (MAP_CACHE &cache)
+{
+ for (size_t i = 0; i < no_of_lookups; ++i)
+ {
+ VALUE j = 0;
+ int result = cache.find (lookup_array[i], j);
+
+ ACE_ASSERT (result != -1);
+ ACE_ASSERT (j == lookup_array[i]);
+
+ if (debug)
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("%d "), j));
+
+ ACE_UNUSED_ARG (result);
+ }
+
+ if (debug)
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\n")));
+}
+
+static void
+find_test_hash_cache (HASH_MAP_CACHE &cache)
+{
+ for (size_t i = 0; i < no_of_lookups; ++i)
+ {
+ VALUE j = 0;
+ int result = cache.find (lookup_array[i], j);
+
+ ACE_ASSERT (result != -1);
+ ACE_ASSERT (j == lookup_array[i]);
+
+ if (debug)
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("%d "), j));
+
+ ACE_UNUSED_ARG (result);
+ }
+
+ if (debug)
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\n")));
+}
+
+static void
+purge_test_cache (MAP_CACHE &cache)
+{
+ // Get the number of entries in the container.
+ size_t current_map_size = cache.current_size ();
+
+ // Find the number of entries which will get purged.
+ size_t entries_to_remove = size_t ((double (purge_percent) / 100 * current_map_size) + 0.5);
+
+ // Tell the caching strategy how much to purge.
+ cache.caching_strategy ().purge_percent (purge_percent);
+
+ // Purge from cache.
+ int result = cache.purge ();
+ ACE_ASSERT (result != -1);
+ ACE_UNUSED_ARG (result);
+
+ size_t resultant_size = 0;
+ if (caching_strategy_type == ACE_NULL)
+ resultant_size = current_map_size;
+ else
+ resultant_size = current_map_size - entries_to_remove;
+
+ // Make sure the purge took out the appropriate number of entries.
+ ACE_ASSERT (cache.current_size () == resultant_size);
+ ACE_UNUSED_ARG (resultant_size);
+}
+
+static void
+purge_test_hash_cache (HASH_MAP_CACHE &cache)
+{
+ // Get the number of entries in the container.
+ size_t current_map_size = cache.current_size ();
+
+ // Find the number of entries which will get purged.
+ size_t entries_to_remove = size_t ((double (purge_percent) / 100 * current_map_size) + 0.5);
+
+ // Tell the caching strategy how much to purge.
+ cache.caching_strategy ().purge_percent (purge_percent);
+
+ // Purge from cache.
+ int result = cache.purge ();
+ ACE_ASSERT (result != -1);
+ ACE_UNUSED_ARG (result);
+
+ size_t resultant_size = 0;
+ if (caching_strategy_type == ACE_NULL)
+ resultant_size = current_map_size;
+ else
+ resultant_size = current_map_size - entries_to_remove;
+
+ // Make sure the purge took out the appropriate number of entries.
+ ACE_ASSERT (cache.current_size () == resultant_size);
+ ACE_UNUSED_ARG (resultant_size);
+}
+
+static void
+functionality_test_cache (MAP_CACHING_STRATEGY &caching_strategy)
+{
+ MAP_CACHE cache (caching_strategy);
+ KEY i = 0;
+ VALUE j = 0;
+
+ // Add it to the map now.
+ for (size_t counter = 0;
+ i < iterations;
+ ++i, ++j)
+ {
+ int result = cache.bind (i, j);
+ ACE_ASSERT (result == 0);
+ ACE_UNUSED_ARG (result);
+
+ if (debug)
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("keys[%d]=%d value=[%d]=%d\n"),
+ i, i, j, j));
+ ++counter;
+ ACE_ASSERT (cache.current_size () == counter);
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Number of entries in cache before purging: %d\n"),
+ cache.current_size ()));
+
+ run_iterator_cache (cache);
+ run_reverse_iterator_cache (cache);
+
+ find_test_cache (cache);
+
+ purge_test_cache (cache);
+
+ run_iterator_cache (cache);
+ run_reverse_iterator_cache (cache);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Number of entries in cache after purging: %d\n"),
+ cache.current_size ()));
+}
+
+static void
+functionality_test_hash_cache (HASH_MAP_CACHING_STRATEGY &caching_strategy)
+{
+ HASH_MAP_CACHE cache (caching_strategy);
+ KEY i = 0;
+ VALUE j = 0;
+
+ // Add it to the map now.
+ for (size_t counter = 0;
+ i < iterations;
+ ++i, ++j)
+ {
+ int result = cache.bind (i, j);
+ ACE_ASSERT (result == 0);
+ ACE_UNUSED_ARG (result);
+
+ if (debug)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("keys[%d]=%d value=[%d]=%d\n"),
+ i, i, j, j));
+ ++counter;
+ ACE_ASSERT (cache.current_size () == counter);
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Number of entries in cache before purging: %d\n"),
+ cache.current_size ()));
+
+ run_iterator_hash_cache (cache);
+ run_reverse_iterator_hash_cache (cache);
+
+ find_test_hash_cache (cache);
+
+ purge_test_hash_cache (cache);
+
+ run_iterator_hash_cache (cache);
+ run_reverse_iterator_hash_cache (cache);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Number of entries in cache after purging: %d\n"),
+ cache.current_size ()));
+}
+
+void
+test_caching_strategy_type (void)
+{
+ HASH_MAP_CACHING_STRATEGY *hash_map_caching_strategy = 0;
+ MAP_CACHING_STRATEGY *map_caching_strategy = 0;
+
+ switch (caching_strategy_type)
+ {
+ case ACE_NULL:
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\nNull_Caching_Strategy\n\n")));
+ ACE_NEW (map_caching_strategy,
+ MAP_NULL_ADAPTER);
+ ACE_NEW (hash_map_caching_strategy,
+ HASH_MAP_NULL_ADAPTER);
+ break;
+
+ case ACE_LRU:
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\nLRU_Caching_Strategy\n\n")));
+ ACE_NEW (map_caching_strategy,
+ MAP_LRU_ADAPTER);
+ ACE_NEW (hash_map_caching_strategy,
+ HASH_MAP_LRU_ADAPTER);
+ break;
+
+ case ACE_LFU:
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\nLFU_Caching_Strategy\n\n")));
+ ACE_NEW (map_caching_strategy,
+ MAP_LFU_ADAPTER);
+ ACE_NEW (hash_map_caching_strategy,
+ HASH_MAP_LFU_ADAPTER);
+ break;
+
+ case ACE_FIFO:
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\nFIFO_Caching_Strategy\n\n")));
+ ACE_NEW (map_caching_strategy,
+ MAP_FIFO_ADAPTER);
+ ACE_NEW (hash_map_caching_strategy,
+ HASH_MAP_FIFO_ADAPTER);
+ break;
+
+ case ACE_ALL: // Just to remove warnings!
+ break;
+ }
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("map cache\n")));
+ functionality_test_cache (*map_caching_strategy);
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\nhash map cache\n")));
+ functionality_test_hash_cache (*hash_map_caching_strategy);
+
+ delete map_caching_strategy;
+ delete hash_map_caching_strategy;
+}
+
+static int
+parse_args (int argc, ACE_TCHAR *argv[])
+{
+ ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("c:i:r:f:p:d"));
+
+ int cc;
+ while ((cc = get_opt ()) != -1)
+ {
+ switch (cc)
+ {
+ case 'c':
+ if (ACE_OS::strcmp (get_opt.opt_arg (), ACE_TEXT ("null")) == 0)
+ caching_strategy_type = ACE_NULL;
+ if (ACE_OS::strcmp (get_opt.opt_arg (), ACE_TEXT ("lru")) == 0)
+ caching_strategy_type = ACE_LRU;
+ if (ACE_OS::strcmp (get_opt.opt_arg (), ACE_TEXT ("lfu")) == 0)
+ caching_strategy_type = ACE_LFU;
+ if (ACE_OS::strcmp (get_opt.opt_arg (), ACE_TEXT ("fifo")) == 0)
+ caching_strategy_type = ACE_FIFO;
+ break;
+ case 'i':
+ iterations = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'f':
+ no_of_lookups = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'r':
+ randomize_lookups = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'p':
+ purge_percent = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'd':
+ debug = 1;
+ break;
+ case '?':
+ case 'h':
+ default:
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("usage: %s ")
+ ACE_TEXT ("[-c (caching strategy: lru / lfu / fifo / null [default = all])] ")
+ ACE_TEXT ("[-r (randomize lookups)] ")
+ ACE_TEXT ("[-i (iterations)] ")
+ ACE_TEXT ("[-d (debug, i.e., addition printouts)] ")
+ ACE_TEXT ("[-p (purge percent)] ")
+ ACE_TEXT ("[-f (number of lookups)] \n"),
+ ACE_TEXT ("Cache_Map_Manager_Test")));
+ return -1;
+ }
+ }
+ return 0;
+}
+
+int
+run_main (int argc, ACE_TCHAR *argv[])
+{
+ // Validate options.
+ int result = parse_args (argc, argv);
+ if (result != 0)
+ return result;
+
+ // Start the test only if options are valid.
+ ACE_START_TEST (ACE_TEXT ("Cache_Map_Manager_Test"));
+
+ // Remove the extra debugging attributes from Log_Msg output.
+ ACE_LOG_MSG->clr_flags (ACE_Log_Msg::VERBOSE_LITE);
+
+ // Providing random a unique seed.
+ ACE_OS::srand (static_cast<u_int> (ACE_OS::time (0)));
+
+ // Create the lookup array.
+ ACE_NEW_RETURN (lookup_array,
+ KEY[no_of_lookups],
+ -1);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\nLookup sequence: ")));
+
+ // Initialize the lookup array.
+ for (size_t k = 0;
+ k < no_of_lookups;
+ ++k)
+ {
+ if (randomize_lookups != 0)
+ lookup_array[k] = ACE_OS::rand () % iterations;
+ else
+ lookup_array[k] = k % iterations;
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%d "),
+ lookup_array[k]));
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\n\n")));
+
+ // Do we need to test all the strategies.
+ if (caching_strategy_type == ACE_ALL)
+ {
+ caching_strategy_type = ACE_NULL;
+ test_caching_strategy_type ();
+
+ caching_strategy_type = ACE_LRU;
+ test_caching_strategy_type ();
+
+ caching_strategy_type = ACE_LFU;
+ test_caching_strategy_type ();
+
+ caching_strategy_type = ACE_FIFO;
+ test_caching_strategy_type ();
+ }
+ else
+ {
+ test_caching_strategy_type ();
+ }
+
+ delete[] lookup_array;
+
+ ACE_LOG_MSG->set_flags (ACE_Log_Msg::VERBOSE_LITE);
+ ACE_END_TEST;
+
+ return 0;
+}
+
diff --git a/ACE/tests/Cache_Map_Manager_Test.h b/ACE/tests/Cache_Map_Manager_Test.h
new file mode 100644
index 00000000000..6ca91ddf4de
--- /dev/null
+++ b/ACE/tests/Cache_Map_Manager_Test.h
@@ -0,0 +1,38 @@
+/* -*- C++ -*- */
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Cache_Map_Manager_Test.h
+//
+// = DESCRIPTION
+// Define class needed for generating templates. IBM C++ requires this to
+// be in its own file for auto template instantiation.
+//
+// = AUTHOR
+// Kirthika Parameswaran <kirthika@cs.wustl.edu>
+//
+// ============================================================================
+
+#ifndef __ACE_CACHE_MAP_MANAGER_TEST_H
+#define __ACE_CACHE_MAP_MANAGER_TEST_H
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+class Hash_Key
+{
+public:
+ u_long operator () (size_t t) const
+ {
+ // Simply returns t
+ return static_cast<u_long> (t);
+ }
+};
+
+#endif /* __ACE_CACHE_MAP_MANAGER_TEST_T */
diff --git a/ACE/tests/Cached_Accept_Conn_Test.cpp b/ACE/tests/Cached_Accept_Conn_Test.cpp
new file mode 100644
index 00000000000..64717629458
--- /dev/null
+++ b/ACE/tests/Cached_Accept_Conn_Test.cpp
@@ -0,0 +1,515 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Cached_Accept_Conn_Test.cpp
+//
+// = DESCRIPTION
+// The test illustrates how the <ACE_Strategy_Connector> works by
+// showing how you can cache connections on the client using
+// different caching strategies. Also how connections can be purged
+// explicitly and implicitly if needed from the connection cache
+// maintained by the connector. The <ACE_Strategy_Acceptor> can also
+// explicitly purge connections from the process CONNECTION CACHE on
+// demand.
+//
+// = AUTHOR
+// Kirthika Parameswaran <kirthika@cs.wustl.edu>
+//
+// ============================================================================
+
+#ifndef CACHED_ACCEPT_CONNECTION_TEST
+#define CACHED_ACCEPT_CONNECTION_TEST
+
+#include "test_config.h"
+
+// IBM C Set++ just can't grok the templates in here for auto template
+// instantiation. It ends up overwriting a tempinc/*.C file and mashes
+// its contents.
+#if !defined (__xlC__) || (__xlC__ > 0x0301)
+
+#include "Cached_Accept_Conn_Test.h"
+
+#include "ace/OS_NS_string.h"
+#include "ace/Get_Opt.h"
+
+#if defined(_MSC_VER)
+#pragma warning(disable:4503)
+#endif /* _MSC_VER */
+
+ACE_RCSID(tests, Cached_Accept_Conn_Test, "$Id$")
+
+// Note: To keep both sunCC5.0 without debugging symbols and gcc2.7.3
+// happy, it was necessary to have the definitions of the methods of
+// the Accept_Strategy before the instantiations.
+
+// HPUX doesn't accept these declaration after their usage.
+
+// For some strange reason this must *not* be static since otherwise
+// certain versions of SunC++ will not link properly.
+int connection_accepted = 0;
+
+// For some strange reason this must *not* be static since otherwise
+// certain versions of SunC++ will not link properly.
+int debug = 0;
+
+template <class SVC_HANDLER, ACE_PEER_ACCEPTOR_1>
+Accept_Strategy<SVC_HANDLER, ACE_PEER_ACCEPTOR_2>::Accept_Strategy (CACHED_CONNECT_STRATEGY &caching_connect_strategy)
+ : caching_connect_strategy_ (caching_connect_strategy)
+{
+}
+
+template <class SVC_HANDLER, ACE_PEER_ACCEPTOR_1> int
+Accept_Strategy<SVC_HANDLER, ACE_PEER_ACCEPTOR_2>::open (const ACE_PEER_ACCEPTOR_ADDR &local_addr,
+ int restart)
+{
+ int result = ACCEPT_STRATEGY_BASE::open (local_addr,
+ restart);
+
+ if (result == 0)
+ return result;
+
+ // If the error occured due to the fact that the file descriptor
+ // limit was exhausted, then purge the connection cache of some
+ // entries.
+ result = this->out_of_sockets_handler ();
+ if (result == -1)
+ return -1;
+
+ // If we are able to purge, try again.
+ return ACCEPT_STRATEGY_BASE::open (local_addr, restart);
+}
+
+template <class SVC_HANDLER, ACE_PEER_ACCEPTOR_1> int
+Accept_Strategy<SVC_HANDLER, ACE_PEER_ACCEPTOR_2>::accept_svc_handler (SVC_HANDLER *svc_handler)
+{
+ // Stop the event loop.
+ connection_accepted = 1;
+
+ // 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 = this->reactor_->uses_event_associations ();
+
+ int result = this->acceptor ().accept (svc_handler->peer (), // stream
+ 0, // remote address
+ 0, // timeout
+ 1, // restart
+ reset_new_handle // reset new handler
+ );
+ if (result == 0)
+ {
+ if (debug)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Accept succeeded with handle %d\n"),
+ svc_handler->get_handle ()));
+ return result;
+ }
+
+ // If the error occured due to teh fact that the file descriptor
+ // limit was exhausted, then purge the connection cache of some
+ // entries.
+ result = this->out_of_sockets_handler ();
+ ACE_ASSERT (result == 0);
+
+ // Close down handler to avoid memory leaks.
+ svc_handler->close (0);
+ return -1;
+}
+
+template <class SVC_HANDLER, ACE_PEER_ACCEPTOR_1> int
+Accept_Strategy<SVC_HANDLER, ACE_PEER_ACCEPTOR_2>::out_of_sockets_handler (void)
+{
+ if (ACE::out_of_handles (errno))
+ {
+ // Close connections which are cached by explicitly purging the
+ // connection cache maintained by the connector.
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Purging connections from Connection Cache...\n")));
+
+ return this->caching_connect_strategy_.purge_connections ();
+ }
+
+ return -1;
+}
+
+typedef Accept_Strategy<Server_Svc_Handler, ACE_SOCK_ACCEPTOR>
+ ACCEPT_STRATEGY;
+
+Client_Svc_Handler::Client_Svc_Handler (ACE_Thread_Manager *t)
+ : ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH> (t)
+{
+}
+
+int
+Client_Svc_Handler::open (void *)
+{
+ if (debug)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("opening Client_Svc_Handler %@ with handle %d\n"),
+ this,
+ this->peer ().get_handle ()));
+ return 0;
+}
+
+int
+Client_Svc_Handler::close (u_long flags)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Closing Client_Svc_Handler %@ with handle %d\n"),
+ this,
+ this->peer ().get_handle ()));
+ return ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH>::close (flags);
+}
+
+
+Server_Svc_Handler::Server_Svc_Handler (ACE_Thread_Manager *t)
+ : ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH> (t)
+{
+}
+
+int
+Server_Svc_Handler::open (void *)
+{
+ if (debug)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("opening Server_Svc_Handler %@ with handle %d\n"),
+ this,
+ this->peer ().get_handle ()));
+
+ return this->close ();
+}
+
+enum Caching_Strategy_Type
+{
+ ACE_LFU,
+ ACE_FIFO,
+ ACE_LRU,
+ ACE_NULL,
+ ACE_ALL
+};
+
+// Default number of clients/servers.
+static int listen_once = 1;
+static int user_has_specified_iterations = 0;
+static size_t keep_handles_available = 100;
+static double purge_percentage = 20;
+static Caching_Strategy_Type caching_strategy_type = ACE_ALL;
+
+// On Win32, the handle gobbling doesn't work. Therefore, we need
+// more iterations to get to the handle limit.
+#if defined (ACE_WIN32)
+static int iterations = 2000;
+#else
+static int iterations = 200;
+#endif /* ACE_WIN32 */
+
+
+static int
+cached_connect (STRATEGY_CONNECTOR &con,
+ const ACE_INET_Addr &server_addr)
+{
+ // This will make sure we get the host information correct.
+ ACE_INET_Addr remote_addr (server_addr.get_port_number (),
+ ACE_LOCALHOST);
+
+ // Perform a blocking connect to the server using the Strategy
+ // Connector with a connection caching strategy.
+ Client_Svc_Handler *svc_handler = 0;
+ int result = con.connect (svc_handler,
+ remote_addr);
+ if (result == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("connection failed")),
+ -1);
+ else
+ if (debug)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Connection successful to server at port %d!\n"),
+ remote_addr.get_port_number ()));
+
+ // Reset Svc_Handler state.
+ svc_handler->recycle_state (ACE_RECYCLABLE_PURGABLE_BUT_NOT_IDLE);
+
+ return 0;
+}
+
+static void
+server (void)
+{
+ int result = 1;
+
+ while (connection_accepted == 0)
+ result = ACE_Reactor::instance ()->handle_events ();
+
+ connection_accepted = 0;
+
+ ACE_UNUSED_ARG (result);
+}
+
+static void
+test_connection_management (CACHING_STRATEGY &caching_strategy)
+{
+ // Configure the Strategy Connector with a strategy that caches
+ // connection.
+ CACHED_CONNECT_STRATEGY caching_connect_strategy (caching_strategy);
+
+ NULL_CREATION_STRATEGY creation_strategy;
+ NULL_ACTIVATION_STRATEGY activation_strategy;
+
+ STRATEGY_CONNECTOR strategy_connector (0,
+ &creation_strategy,
+ &caching_connect_strategy,
+ &activation_strategy);
+
+ // Connect strategy is required by the <out_of_sockets_handler>.
+ ACCEPT_STRATEGY listen_one_time_accept_strategy (caching_connect_strategy);
+
+ // If <listen_once> is true, only one Acceptor is used for the test.
+ ACCEPTOR listen_one_time_acceptor;
+ ACE_INET_Addr server_addr;
+
+ int result =
+ listen_one_time_acceptor.open (ACE_sap_any_cast (const ACE_INET_Addr &),
+ ACE_Reactor::instance (),
+ 0,
+ &listen_one_time_accept_strategy);
+ ACE_ASSERT (result == 0);
+
+ result = listen_one_time_acceptor.acceptor ().get_local_addr (server_addr);
+ ACE_ASSERT (result == 0);
+
+ for (int i = 1; i <= iterations; ++i)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("iteration %d\n"),
+ i));
+
+ // Connect strategy is required by the <out_of_sockets_handler>.
+ ACCEPT_STRATEGY listen_multiple_times_accept_strategy (caching_connect_strategy);
+
+ // If <listen_once> is false, one Acceptor is used for every
+ // iteration.
+ ACCEPTOR listen_multiple_times_acceptor;
+
+ if (!listen_once)
+ {
+ // Bind acceptor to any port and then find out what the port
+ // was.
+ if (listen_multiple_times_acceptor.open (ACE_sap_any_cast (const ACE_INET_Addr &),
+ ACE_Reactor::instance (),
+ 0,
+ &listen_multiple_times_accept_strategy) == -1)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("open")));
+ ACE_ASSERT (0);
+ }
+
+ if (listen_multiple_times_acceptor.acceptor ().get_local_addr (server_addr) == -1)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("get_local_addr")));
+ ACE_ASSERT (0);
+ }
+
+ }
+
+ if (debug)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("starting server at port %d\n"),
+ server_addr.get_port_number ()));
+
+ // Run the cached blocking test.
+ int result = cached_connect (strategy_connector,
+ server_addr);
+ ACE_ASSERT (result != -1);
+
+ server ();
+ }
+}
+
+void
+test_caching_strategy_type (void)
+{
+ CACHING_STRATEGY *caching_strategy = 0;
+
+ switch (caching_strategy_type)
+ {
+ case ACE_NULL:
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\nNull_Caching_Strategy\n\n")));
+ ACE_NEW (caching_strategy,
+ NULL_CACHING_STRATEGY_ADAPTER);
+ break;
+
+ case ACE_LRU:
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\nLRU_Caching_Strategy\n\n")));
+ ACE_NEW (caching_strategy,
+ LRU_CACHING_STRATEGY_ADAPTER);
+ break;
+
+ case ACE_LFU:
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\nLFU_Caching_Strategy\n\n")));
+ ACE_NEW (caching_strategy,
+ LFU_CACHING_STRATEGY_ADAPTER);
+ break;
+
+ case ACE_FIFO:
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\nFIFO_Caching_Strategy\n\n")));
+ ACE_NEW (caching_strategy,
+ FIFO_CACHING_STRATEGY_ADAPTER);
+ break;
+
+ case ACE_ALL: // Just to remove warnings!
+ break;
+ }
+
+ caching_strategy->purge_percent (purge_percentage);
+ test_connection_management (*caching_strategy);
+ delete caching_strategy;
+}
+
+int
+parse_args (int argc, ACE_TCHAR *argv[])
+{
+ ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("l:i:p:c:a:d"));
+
+ int cc;
+
+ while ((cc = get_opt ()) != -1)
+ switch (cc)
+ {
+ case 'd':
+ debug = 1;
+ break;
+ case 'l':
+ listen_once = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'i':
+ iterations = ACE_OS::atoi (get_opt.opt_arg ());
+ user_has_specified_iterations = 1;
+ break;
+ case 'p':
+ purge_percentage = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'c':
+ // Note that if null caching strategy is used then this test
+ // will fail if the number of servers exceed number of open
+ // files allowed for the process.
+ if (ACE_OS::strcmp (get_opt.opt_arg (), ACE_TEXT ("null")) == 0)
+ caching_strategy_type = ACE_NULL;
+ if (ACE_OS::strcmp (get_opt.opt_arg (), ACE_TEXT ("lru")) == 0)
+ caching_strategy_type = ACE_LRU;
+ if (ACE_OS::strcmp (get_opt.opt_arg (), ACE_TEXT ("lfu")) == 0)
+ caching_strategy_type = ACE_LFU;
+ if (ACE_OS::strcmp (get_opt.opt_arg (), ACE_TEXT ("fifo")) == 0)
+ caching_strategy_type = ACE_FIFO;
+ break;
+ case 'a':
+ keep_handles_available = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case '?':
+ case 'h':
+ default:
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("usage: %s ")
+ ACE_TEXT ("[-t (timeout)] ")
+ ACE_TEXT ("[-c (caching strategy: lru / lfu / fifo / null [default = all])] ")
+ ACE_TEXT ("[-i (iterations)] ")
+ ACE_TEXT ("[-l (listen once)] ")
+ ACE_TEXT ("[-d (addition debugging output)] ")
+ ACE_TEXT ("[-p (purge percent)] ")
+ ACE_TEXT ("[-a (keep handles available)] "),
+ ACE_TEXT ("Cached_Accept_Conn_Test")));
+ return -1;
+ }
+
+ return 0;
+}
+
+int
+run_main (int argc, ACE_TCHAR *argv[])
+{
+ // Validate options.
+ int result = parse_args (argc, argv);
+ if (result != 0)
+ return result;
+
+#if defined (ACE_WIN32)
+ // Somehow, on Win32, the <listen once> option allows us to create
+ // more handles.
+ if (!user_has_specified_iterations &&
+ listen_once)
+ iterations *= 2;
+#endif /* ACE_WIN32 */
+
+ // Start the test only if options are valid.
+ ACE_START_TEST (ACE_TEXT ("Cached_Accept_Conn_Test"));
+
+ // Remove the extra debugging attributes from Log_Msg output.
+ ACE_LOG_MSG->clr_flags (ACE_Log_Msg::VERBOSE_LITE);
+
+ // The reactor's constructor changes the handle limit for the
+ // process.
+ ACE_Reactor::instance ();
+
+ // Consume all handles in the process, leaving us
+ // <keep_handles_available> to play with.
+ ACE_Handle_Gobbler handle_gobbler;
+ result = handle_gobbler.consume_handles (keep_handles_available);
+ ACE_ASSERT (result == 0);
+
+ // Do we need to test all the strategies. Note, that the less
+ // useful null strategy is ignored in this case.
+ if (caching_strategy_type == ACE_ALL)
+ {
+ caching_strategy_type = ACE_LRU;
+ test_caching_strategy_type ();
+
+ // Default iterations are too many; if the user hasn't specified
+ // otherwise, we'll shrink the iterations for LFU and FIFO.
+ if (!user_has_specified_iterations)
+ iterations /= 100;
+
+ caching_strategy_type = ACE_LFU;
+ test_caching_strategy_type ();
+
+ caching_strategy_type = ACE_FIFO;
+ test_caching_strategy_type ();
+ }
+ else
+ {
+ test_caching_strategy_type ();
+ }
+
+ ACE_LOG_MSG->set_flags (ACE_Log_Msg::VERBOSE_LITE);
+
+#else /* Do this for C Set++ 3.1 */
+
+int
+run_main (int argc, ACE_TCHAR *argv[])
+{
+ ACE_UNUSED_ARG (argc);
+ ACE_UNUSED_ARG (argv);
+
+ ACE_START_TEST (ACE_TEXT ("Cached_Accept_Conn_Test"));
+ ACE_ERROR ((LM_INFO,
+ ACE_TEXT ("C Set++ won't build this test correctly\n")));
+
+#endif /* !__xlC__ || __xlC > 0x0301 */
+
+ ACE_END_TEST;
+ return 0;
+}
+
+
+#endif /* CACHED_ACCEPT_CONNECTION_TEST */
diff --git a/ACE/tests/Cached_Accept_Conn_Test.h b/ACE/tests/Cached_Accept_Conn_Test.h
new file mode 100644
index 00000000000..6b8b3e8f46a
--- /dev/null
+++ b/ACE/tests/Cached_Accept_Conn_Test.h
@@ -0,0 +1,137 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Cache_Accept_Conn_Test.h
+//
+// = DESCRIPTION
+// Define class needed for generating templates. IBM C++ requires this to
+// be in its own file for auto template instantiation.
+//
+// = AUTHOR
+// Kirthika Parameswaran <kirthika@cs.wustl.edu>
+//
+// ============================================================================
+
+#ifndef ACE_TESTS_CACHED_ACCEPT_CONN_TEST_H
+#define ACE_TESTS_CACHED_ACCEPT_CONN_TEST_H
+
+#include "ace/SOCK_Connector.h"
+#include "ace/SOCK_Acceptor.h"
+#include "ace/SOCK_Stream.h"
+#include "ace/INET_Addr.h"
+#include "ace/Acceptor.h"
+#include "ace/Connector.h"
+#include "ace/Svc_Handler.h"
+#include "ace/Caching_Utility_T.h"
+#include "ace/Cached_Connect_Strategy_T.h"
+#include "ace/Handle_Gobbler.h"
+
+class Client_Svc_Handler : public ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH>
+{
+public:
+
+ Client_Svc_Handler (ACE_Thread_Manager *t = 0);
+ int open (void *v = 0);
+ int close (u_long flags = 0);
+};
+
+class Server_Svc_Handler : public ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH>
+{
+public:
+
+ Server_Svc_Handler (ACE_Thread_Manager *t = 0);
+ int open (void *v = 0);
+};
+
+typedef size_t ATTRIBUTES;
+typedef ACE_Pair<Client_Svc_Handler *, ATTRIBUTES>
+ CACHED_HANDLER;
+typedef ACE_Refcounted_Hash_Recyclable<ACE_INET_Addr>
+ ACE_ADDR;
+typedef ACE_Hash<ACE_ADDR> H_KEY;
+typedef ACE_Equal_To<ACE_ADDR> C_KEYS;
+
+typedef ACE_Hash_Map_Manager_Ex<ACE_ADDR, CACHED_HANDLER, H_KEY, C_KEYS, ACE_Null_Mutex>
+ HASH_MAP;
+typedef ACE_Hash_Map_Iterator_Ex<ACE_ADDR, CACHED_HANDLER, H_KEY, C_KEYS, ACE_Null_Mutex>
+ HASH_MAP_ITERATOR;
+typedef ACE_Hash_Map_Reverse_Iterator_Ex<ACE_ADDR, CACHED_HANDLER, H_KEY, C_KEYS, ACE_Null_Mutex>
+ HASH_MAP_REVERSE_ITERATOR;
+
+typedef ACE_Recyclable_Handler_Cleanup_Strategy<ACE_ADDR, CACHED_HANDLER, HASH_MAP>
+ CLEANUP_STRATEGY;
+typedef ACE_Recyclable_Handler_Caching_Utility<ACE_ADDR, CACHED_HANDLER, HASH_MAP, HASH_MAP_ITERATOR, ATTRIBUTES>
+ CACHING_UTILITY;
+
+typedef ACE_LRU_Caching_Strategy<ATTRIBUTES, CACHING_UTILITY>
+ LRU_CACHING_STRATEGY;
+
+typedef ACE_LFU_Caching_Strategy<ATTRIBUTES, CACHING_UTILITY>
+ LFU_CACHING_STRATEGY;
+typedef ACE_FIFO_Caching_Strategy<ATTRIBUTES, CACHING_UTILITY>
+ FIFO_CACHING_STRATEGY;
+typedef ACE_Null_Caching_Strategy<ATTRIBUTES, CACHING_UTILITY>
+ NULL_CACHING_STRATEGY;
+typedef ACE_Caching_Strategy_Adapter<ATTRIBUTES, CACHING_UTILITY, LRU_CACHING_STRATEGY>
+ LRU_CACHING_STRATEGY_ADAPTER;
+typedef ACE_Caching_Strategy_Adapter<ATTRIBUTES, CACHING_UTILITY, LFU_CACHING_STRATEGY>
+ LFU_CACHING_STRATEGY_ADAPTER;
+typedef ACE_Caching_Strategy_Adapter<ATTRIBUTES, CACHING_UTILITY, FIFO_CACHING_STRATEGY>
+ FIFO_CACHING_STRATEGY_ADAPTER;
+typedef ACE_Caching_Strategy_Adapter<ATTRIBUTES, CACHING_UTILITY, NULL_CACHING_STRATEGY>
+ NULL_CACHING_STRATEGY_ADAPTER;
+typedef ACE_Caching_Strategy<ATTRIBUTES, CACHING_UTILITY>
+ CACHING_STRATEGY;
+
+typedef ACE_Strategy_Acceptor<Server_Svc_Handler, ACE_SOCK_ACCEPTOR>
+ ACCEPTOR;
+
+typedef ACE_Strategy_Connector<Client_Svc_Handler, ACE_SOCK_CONNECTOR>
+ STRATEGY_CONNECTOR;
+
+typedef ACE_NOOP_Creation_Strategy<Client_Svc_Handler>
+ NULL_CREATION_STRATEGY;
+
+typedef ACE_NOOP_Concurrency_Strategy<Client_Svc_Handler>
+ NULL_ACTIVATION_STRATEGY;
+
+typedef ACE_Cached_Connect_Strategy_Ex<Client_Svc_Handler, ACE_SOCK_CONNECTOR, CACHING_STRATEGY, ATTRIBUTES, ACE_SYNCH_NULL_MUTEX>
+ CACHED_CONNECT_STRATEGY;
+
+
+template <class SVC_HANDLER, ACE_PEER_ACCEPTOR_1>
+class Accept_Strategy : public ACE_Accept_Strategy<SVC_HANDLER, ACE_PEER_ACCEPTOR_2>
+{
+public:
+
+ Accept_Strategy (CACHED_CONNECT_STRATEGY &caching_connect_strategy);
+ // Constructor.
+
+ int open (const ACE_PEER_ACCEPTOR_ADDR &local_addr,
+ int restart = 0);
+ // Initialize the <peer_acceptor_> with <local_addr>. If the
+ // process runs out of descriptors, the unsed svc_handlers from the
+ // CONNECTION CACHE are removed.
+
+ int accept_svc_handler (SVC_HANDLER *svc_handler);
+ // The default behavior delegates to the <accept> method of the
+ // PEER_ACCEPTOR. A check is made here for the process running out
+ // of file descriptors. If so, the CONNECTION CACHE is purged of
+ // some idle svc_handlers.
+
+protected:
+
+ typedef ACE_Accept_Strategy<SVC_HANDLER, ACE_PEER_ACCEPTOR_2> ACCEPT_STRATEGY_BASE;
+
+ int out_of_sockets_handler (void);
+ // Handler for removing cached connections.
+
+ CACHED_CONNECT_STRATEGY &caching_connect_strategy_;
+};
+
+#endif /* ACE_TESTS_CACHED_ACCEPT_CONN_TEST_H */
diff --git a/ACE/tests/Cached_Allocator_Test.cpp b/ACE/tests/Cached_Allocator_Test.cpp
new file mode 100644
index 00000000000..c348398e7a9
--- /dev/null
+++ b/ACE/tests/Cached_Allocator_Test.cpp
@@ -0,0 +1,276 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Cached_Allocator_Test.cpp
+//
+// = DESCRIPTION
+// Simple test of ACE_Dynamic_Cached_Allocator and ACE_Cached_Allocator.
+//
+// = AUTHOR
+// Jaroslaw Nozderko <jareknz@polbox.com>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/OS_NS_string.h"
+#include "ace/Malloc_T.h"
+#include "ace/High_Res_Timer.h"
+
+ACE_RCSID(tests, Cached_Allocator_Test, "$Id$")
+
+#include "ace/Synch_Traits.h"
+#include "ace/Null_Mutex.h"
+
+typedef ACE_Dynamic_Cached_Allocator<ACE_SYNCH_NULL_MUTEX> DYNAMIC_ALLOCATOR;
+
+static int
+speed_test (ACE_UINT32 loops)
+{
+#ifndef ACE_LACKS_FLOATING_POINT
+ double tt = 0.0,
+ ut = 0.0,
+ utus = 0.0,
+ speed = 0.0;
+#endif /* ACE_LACKS_FLOATING_POINT */
+
+ ACE_Time_Value tc;
+ void *ptr = 0;
+ ACE_UINT32 i = loops;
+ size_t n_chunks = 10;
+ size_t chunk_size = 8;
+
+ ACE_DEBUG ((LM_INFO,
+ ACE_TEXT (" (%t) ACE_Dynamic_Cached_Allocator ")
+ ACE_TEXT ("speed test...\n")));
+
+ DYNAMIC_ALLOCATOR allocator (n_chunks, chunk_size);
+
+ ACE_High_Res_Timer timer;
+ timer.reset ();
+
+ timer.start ();
+
+ while (i--)
+ {
+ ptr = allocator.malloc (chunk_size);
+ allocator.free (ptr);
+ }
+
+ timer.stop ();
+
+ timer.elapsed_time (tc);
+
+ ACE_DEBUG ((LM_INFO, ACE_TEXT (" (%t) Iterations : %d\n"), loops));
+#ifdef ACE_LACKS_FLOATING_POINT
+ ACE_DEBUG ((LM_INFO, ACE_TEXT (" (%t) Total time : %d s, %d us\n"),
+ tc.sec (), tc.usec ()));
+#elif !defined ACE_LACKS_FLOATING_POINT
+ tt = tc.sec () + tc.usec ()*1.0e-6;
+ ut = tt/loops;
+ utus = ut*1.0e6;
+ speed = loops/tt;
+
+ ACE_DEBUG ((LM_INFO, ACE_TEXT (" (%t) Total time : %.6g [s]\n"), tt));
+ ACE_DEBUG ((LM_INFO, ACE_TEXT (" (%t) Unit time : %.6g [us]\n"), utus));
+ ACE_DEBUG ((LM_INFO, ACE_TEXT (" (%t) Speed : %.6g [1/s]\n"), speed));
+
+#endif /* !defined ACE_LACKS_FLOATING_POINT */
+
+ return 0;
+}
+
+typedef char MEMBLOCK[8];
+typedef ACE_Cached_Allocator<MEMBLOCK, ACE_SYNCH_NULL_MUTEX> STATIC_ALLOCATOR;
+
+static int
+stdspeed_test (ACE_UINT32 loops)
+{
+
+#ifndef ACE_LACKS_FLOATING_POINT
+ double tt = 0.0,
+ ut = 0.0,
+ utus = 0.0,
+ speed = 0.0;
+#endif /* ACE_LACKS_FLOATING_POINT */
+
+ ACE_Time_Value tc;
+ void *ptr = 0;
+ ACE_UINT32 i = loops;
+ size_t n_chunks = 10,
+ chunk_size = 8;
+
+ ACE_DEBUG ((LM_INFO, ACE_TEXT (" (%t) ACE_Cached_Allocator ")
+ ACE_TEXT ("speed test...\n")));
+
+ STATIC_ALLOCATOR allocator (n_chunks);
+
+ ACE_High_Res_Timer timer;
+ timer.reset ();
+
+ timer.start ();
+ while (i--)
+ {
+ ptr = allocator.malloc (chunk_size);
+ allocator.free (ptr);
+ }
+ timer.stop ();
+
+ timer.elapsed_time (tc);
+
+ ACE_DEBUG ((LM_INFO, ACE_TEXT (" (%t) Iterations : %d\n"), loops));
+#ifdef ACE_LACKS_FLOATING_POINT
+ ACE_DEBUG ((LM_INFO, ACE_TEXT (" (%t) Total time : %d s, %d us\n"),
+ tc.sec (), tc.usec ()));
+#elif !defined ACE_LACKS_FLOATING_POINT
+ tt = tc.sec () + tc.usec ()*1.0e-6;
+ ut = tt/loops;
+ utus = ut*1.0e6;
+ speed = loops/tt;
+
+ ACE_DEBUG ((LM_INFO, ACE_TEXT (" (%t) Total time : %.6g [s]\n"), tt));
+ ACE_DEBUG ((LM_INFO, ACE_TEXT (" (%t) Unit time : %.6g [us]\n"), utus));
+ ACE_DEBUG ((LM_INFO, ACE_TEXT (" (%t) Speed : %.6g [1/s]\n"), speed));
+
+#endif /* !defined ACE_LACKS_FLOATING_POINT */
+
+ return 0;
+}
+
+int
+run_main (int argc, ACE_TCHAR *argv[])
+{
+ ACE_START_TEST (ACE_TEXT ("Cached_Allocator_Test"));
+
+ size_t chunk_size = 0;
+ size_t n_chunks = 0;
+ size_t requested_size = 0;
+ size_t depth = 0;
+ char *ptr1 = 0;
+ char *ptr2 = 0;
+ char *ptr3 = 0;
+ char *ptr4 = 0;
+ ACE_UINT32 loops = 0;
+
+ const char *str1 = "12345678";
+ const char *str3 = "ABCDEFGH";
+
+ if (argc < 2)
+ loops = 10000000;
+ else
+ loops = ACE_OS::atoi (argv[1]);
+
+ chunk_size = 8;
+ n_chunks = 2;
+
+ ACE_DEBUG ((LM_INFO,
+ ACE_TEXT (" (%t) Creating allocator: ")
+ ACE_TEXT ("%d chunks, %d bytes each\n"),
+ n_chunks,
+ chunk_size));
+
+ DYNAMIC_ALLOCATOR allocator (n_chunks, chunk_size);
+
+ if ((depth = allocator.pool_depth ()) != n_chunks)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Expected pool depth ") ACE_SIZE_T_FORMAT_SPECIFIER
+ ACE_TEXT (" but reported ") ACE_SIZE_T_FORMAT_SPECIFIER
+ ACE_TEXT ("\n"),
+ n_chunks, depth));
+ requested_size = chunk_size;
+ ACE_DEBUG ((LM_INFO,
+ ACE_TEXT (" (%t) Allocating chunk 1: %d bytes, should succeed...\n"),
+ requested_size));
+
+ ptr1 = (char *) allocator.malloc (requested_size);
+ if (!ptr1)
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT (" (%t) Failed, exiting.\n")), -1);
+
+ ACE_DEBUG ((LM_INFO, ACE_TEXT (" (%t) OK, succeeded.\n")));
+ if ((depth = allocator.pool_depth ()) != (n_chunks - 1))
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Expected pool depth ") ACE_SIZE_T_FORMAT_SPECIFIER
+ ACE_TEXT (" but reported ") ACE_SIZE_T_FORMAT_SPECIFIER
+ ACE_TEXT ("\n"),
+ n_chunks - 1, depth));
+
+ requested_size = chunk_size + 1;
+ ACE_DEBUG ((LM_INFO,
+ ACE_TEXT (" (%t) Allocating chunk 2: %d bytes, too big, should fail...\n"),
+ requested_size));
+
+ ptr2 = (char *) allocator.malloc (requested_size);
+ if (!ptr2)
+ ACE_DEBUG ((LM_INFO, ACE_TEXT (" (%t) OK, failed.\n")));
+ else
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT (" (%t) Something is wrong...\n")), -1);
+
+ requested_size = chunk_size - 1;
+ ACE_DEBUG ((LM_INFO,
+ ACE_TEXT (" (%t) Allocating chunk 3: %d bytes, ")
+ ACE_TEXT ("should succeed...\n"),
+ requested_size));
+ ptr3 = (char *) allocator.malloc (requested_size);
+ if (!ptr3)
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT (" (%t) Failed, exiting.\n")), -1);
+
+ ACE_DEBUG ((LM_INFO, ACE_TEXT (" (%t) OK, succeeded.\n")));
+
+ // One chunk too far...
+ if ((depth = allocator.pool_depth ()) != 0)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Expected pool depth 0")
+ ACE_TEXT (" but reported ") ACE_SIZE_T_FORMAT_SPECIFIER
+ ACE_TEXT ("\n"),
+ depth));
+ requested_size = chunk_size;
+ ACE_DEBUG ((LM_INFO,
+ ACE_TEXT (" (%t) Allocating chunk 4: %d bytes, no free chunks,")
+ ACE_TEXT (" should fail...\n"),
+ requested_size));
+
+ ptr4 = (char *) allocator.malloc (requested_size);
+ if (!ptr4)
+ ACE_DEBUG ((LM_INFO, ACE_TEXT (" (%t) OK, failed.\n")));
+ else
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT (" (%t) Something is wrong\n")), -1);
+
+ ACE_DEBUG ((LM_INFO, ACE_TEXT (" (%t) Writing to chunk 1: %s\n"), str1));
+ ACE_OS::memcpy (ptr1, str1, chunk_size);
+ ptr1[chunk_size - 1] = '\0';
+ ACE_DEBUG ((LM_INFO, ACE_TEXT (" (%t) Reading from chunk 1: %s\n"), ptr1));
+
+ ACE_DEBUG ((LM_INFO, ACE_TEXT (" (%t) Writing to chunk 3: %s\n"), str3));
+ ACE_OS::memcpy (ptr3, str3, chunk_size);
+ ptr3[chunk_size - 1] = '\0';
+ ACE_DEBUG ((LM_INFO, ACE_TEXT (" (%t) Reading from chunk 3: %s\n"), ptr3));
+
+ ACE_DEBUG ((LM_INFO, ACE_TEXT (" (%t) Deallocating chunk 1\n")));
+ allocator.free (ptr1);
+
+ requested_size = chunk_size;
+ ACE_DEBUG ((LM_INFO, ACE_TEXT (" (%t) Allocating chunk: %d bytes, ")
+ ACE_TEXT ("should succeed...\n"),
+ requested_size));
+ ptr1 = (char *) allocator.malloc (requested_size);
+ if (!ptr1)
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT (" (%t) Failed, exiting.\n")), -1);
+
+ ACE_DEBUG ((LM_INFO, ACE_TEXT (" (%t) OK, succeeded.\n")));
+
+ ACE_DEBUG ((LM_INFO, ACE_TEXT (" (%t) Deallocating chunk 1\n")));
+ allocator.free (ptr1);
+ ACE_DEBUG ((LM_INFO, ACE_TEXT (" (%t) Deallocating chunk 3\n")));
+ allocator.free (ptr3);
+
+ speed_test (loops);
+ stdspeed_test (loops);
+
+ ACE_END_TEST;
+ return 0;
+}
+
diff --git a/ACE/tests/Cached_Conn_Test.cpp b/ACE/tests/Cached_Conn_Test.cpp
new file mode 100644
index 00000000000..d67d84a5988
--- /dev/null
+++ b/ACE/tests/Cached_Conn_Test.cpp
@@ -0,0 +1,488 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Cached_Conn_Test.cpp
+//
+// = DESCRIPTION
+// The test illustrates how the <ACE_Strategy_Connector> works by
+// showing how you can cache connections on the client using
+// different caching strategies. Also how connections can be purged
+// explicitly and implicitly if needed from the connection cache
+// maintained by the connector.
+//
+// = AUTHOR
+// Kirthika Parameswaran <kirthika@cs.wustl.edu>
+//
+// ============================================================================
+
+#ifndef CACHED_CONNECT_TEST
+#define CACHED_CONNECT_TEST
+
+#include "test_config.h"
+
+// IBM C Set++ just can't grok the templates in here for auto template
+// instantiation. It ends up overwriting a tempinc/*.C file and mashes
+// its contents.
+#if !defined (__xlC__) || (__xlC__ > 0x0301)
+
+#include "Cached_Conn_Test.h"
+
+#include "ace/OS_NS_string.h"
+#include "ace/INET_Addr.h"
+#include "ace/SOCK_Connector.h"
+#include "ace/SOCK_Acceptor.h"
+#include "ace/Svc_Handler.h"
+#include "ace/SOCK_Stream.h"
+#include "ace/Acceptor.h"
+#include "ace/Connector.h"
+#include "ace/Get_Opt.h"
+#include "ace/Caching_Utility_T.h"
+#include "ace/Cached_Connect_Strategy_T.h"
+#include "ace/Handle_Gobbler.h"
+
+#if defined(_MSC_VER)
+#pragma warning(disable:4503)
+#endif /* _MSC_VER */
+
+ACE_RCSID(tests, Cached_Conn_Test, "$Id$")
+
+typedef size_t ATTRIBUTES;
+typedef ACE_Pair<Svc_Handler *, ATTRIBUTES>
+ CACHED_HANDLER;
+typedef ACE_Refcounted_Hash_Recyclable<ACE_INET_Addr>
+ ACE_ADDR;
+typedef ACE_Hash<ACE_ADDR> H_KEY;
+typedef ACE_Equal_To<ACE_ADDR> C_KEYS;
+
+typedef ACE_Hash_Map_Manager_Ex<ACE_ADDR, CACHED_HANDLER, H_KEY, C_KEYS, ACE_Null_Mutex>
+ HASH_MAP;
+typedef ACE_Hash_Map_Iterator_Ex<ACE_ADDR, CACHED_HANDLER, H_KEY, C_KEYS, ACE_Null_Mutex>
+ HASH_MAP_ITERATOR;
+typedef ACE_Hash_Map_Reverse_Iterator_Ex<ACE_ADDR, CACHED_HANDLER, H_KEY, C_KEYS, ACE_Null_Mutex>
+ HASH_MAP_REVERSE_ITERATOR;
+
+typedef ACE_Recyclable_Handler_Cleanup_Strategy<ACE_ADDR, CACHED_HANDLER, HASH_MAP>
+ CLEANUP_STRATEGY;
+typedef ACE_Recyclable_Handler_Caching_Utility<ACE_ADDR, CACHED_HANDLER, HASH_MAP, HASH_MAP_ITERATOR, ATTRIBUTES>
+ CACHING_UTILITY;
+
+typedef ACE_LRU_Caching_Strategy<ATTRIBUTES, CACHING_UTILITY>
+ LRU_CACHING_STRATEGY;
+
+typedef ACE_LFU_Caching_Strategy<ATTRIBUTES, CACHING_UTILITY>
+ LFU_CACHING_STRATEGY;
+typedef ACE_FIFO_Caching_Strategy<ATTRIBUTES, CACHING_UTILITY>
+ FIFO_CACHING_STRATEGY;
+typedef ACE_Null_Caching_Strategy<ATTRIBUTES, CACHING_UTILITY>
+ NULL_CACHING_STRATEGY;
+typedef ACE_Caching_Strategy_Adapter<ATTRIBUTES, CACHING_UTILITY, LRU_CACHING_STRATEGY>
+ LRU_CACHING_STRATEGY_ADAPTER;
+typedef ACE_Caching_Strategy_Adapter<ATTRIBUTES, CACHING_UTILITY, LFU_CACHING_STRATEGY>
+ LFU_CACHING_STRATEGY_ADAPTER;
+typedef ACE_Caching_Strategy_Adapter<ATTRIBUTES, CACHING_UTILITY, FIFO_CACHING_STRATEGY>
+ FIFO_CACHING_STRATEGY_ADAPTER;
+typedef ACE_Caching_Strategy_Adapter<ATTRIBUTES, CACHING_UTILITY, NULL_CACHING_STRATEGY>
+ NULL_CACHING_STRATEGY_ADAPTER;
+typedef ACE_Caching_Strategy<ATTRIBUTES, CACHING_UTILITY>
+ CACHING_STRATEGY;
+
+typedef ACE_Oneshot_Acceptor<Svc_Handler, ACE_SOCK_ACCEPTOR>
+ ACCEPTOR;
+
+typedef ACE_Strategy_Connector<Svc_Handler, ACE_SOCK_CONNECTOR>
+ STRATEGY_CONNECTOR;
+
+typedef ACE_NOOP_Creation_Strategy<Svc_Handler>
+ NULL_CREATION_STRATEGY;
+
+typedef ACE_NOOP_Concurrency_Strategy<Svc_Handler>
+ NULL_ACTIVATION_STRATEGY;
+
+typedef ACE_Cached_Connect_Strategy_Ex<Svc_Handler, ACE_SOCK_CONNECTOR, CACHING_STRATEGY, ATTRIBUTES, ACE_SYNCH_NULL_MUTEX>
+ CACHED_CONNECT_STRATEGY;
+
+#endif /* CACHED_CONNECT_TEST */
+
+static int debug = 0;
+
+Svc_Handler::Svc_Handler (ACE_Thread_Manager *t)
+ : ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH> (t)
+{
+}
+
+int
+Svc_Handler::open (void *)
+{
+ if (debug)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("opening Svc_Handler %@ with handle %d\n"),
+ this,
+ this->peer ().get_handle ()));
+
+ return 0;
+}
+
+int
+Svc_Handler::close (u_long flags)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Closing Svc_Handler %@ with handle %d\n"),
+ this,
+ this->peer ().get_handle ()));
+ return ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH>::close (flags);
+}
+
+enum Caching_Strategy_Type
+{
+ ACE_LFU,
+ ACE_FIFO,
+ ACE_LRU,
+ ACE_NULL,
+ ACE_ALL
+};
+
+// Default number of clients/servers.
+static int listen_once = 1;
+static int user_has_specified_iterations = 0;
+static size_t keep_handles_available = 100;
+static double purge_percentage = 20;
+static Caching_Strategy_Type caching_strategy_type = ACE_ALL;
+static CACHED_CONNECT_STRATEGY *connect_strategy = 0;
+
+// On Win32, the handle gobbling doesn't work. Therefore, we need
+// more iterations to get to the handle limit.
+#if defined (ACE_WIN32)
+static int iterations = 2000;
+#elif defined (__Lynx__)
+static int iterations = 134;
+#else
+static int iterations = 200;
+#endif /* ACE_WIN32 */
+
+//====================================================================
+
+static void
+out_of_sockets_handler (void)
+{
+ if (ACE::out_of_handles (errno))
+ {
+ // Close connections which are cached by explicitly purging the
+ // connection cache maintained by the connector.
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Purging connections from Connection Cache...\n")));
+
+ int retval = connect_strategy->purge_connections ();
+ ACE_ASSERT (retval != -1);
+ }
+ else
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("out_of_sockets_handler failed!")));
+ // This shouldn't happen!
+ ACE_ASSERT (0);
+ }
+}
+
+static int
+cached_connect (STRATEGY_CONNECTOR &con,
+ const ACE_INET_Addr &server_addr)
+{
+ // This will make sure we get the host information correct.
+ ACE_INET_Addr remote_addr (server_addr.get_port_number (),
+ ACE_LOCALHOST);
+
+ // Perform a blocking connect to the server using the Strategy
+ // Connector with a connection caching strategy.
+ Svc_Handler *svc_handler = 0;
+ int result = con.connect (svc_handler,
+ remote_addr);
+ if (result == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("connection failed")),
+ -1);
+
+ // Reset Svc_Handler state.
+ svc_handler->recycle_state (ACE_RECYCLABLE_PURGABLE_BUT_NOT_IDLE);
+
+ return 0;
+}
+
+static int
+server (ACCEPTOR *acceptor)
+{
+ ACE_INET_Addr cli_addr;
+
+ // Create a new <Svc_Handler> to consume the data.
+ Svc_Handler svc_handler;
+
+ int result = acceptor->accept (&svc_handler,
+ &cli_addr);
+ if (result == -1)
+ return -1;
+
+ if (debug)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("client %s connected from %d\n"),
+ cli_addr.get_host_name (),
+ cli_addr.get_port_number ()));
+
+ //
+ // Svc_Handler dies here, closing the server side socket.
+ //
+ return 0;
+}
+
+static void
+test_connection_management (CACHING_STRATEGY &caching_strategy)
+{
+ // Configure the Strategy Connector with a strategy that caches
+ // connection.
+ CACHED_CONNECT_STRATEGY caching_connect_strategy (caching_strategy);
+
+ // This is required by the <out_of_sockets_handler>.
+ connect_strategy = &caching_connect_strategy;
+
+ NULL_CREATION_STRATEGY creation_strategy;
+ NULL_ACTIVATION_STRATEGY activation_strategy;
+
+ STRATEGY_CONNECTOR strategy_connector (0,
+ &creation_strategy,
+ &caching_connect_strategy,
+ &activation_strategy);
+
+ // If <listen_once> is true, only one Acceptor is used for the test.
+ ACCEPTOR listen_one_time_acceptor;
+ ACE_INET_Addr server_addr;
+
+ int result = listen_one_time_acceptor.open (ACE_sap_any_cast (const ACE_INET_Addr &));
+ ACE_ASSERT (result == 0);
+
+ result = listen_one_time_acceptor.acceptor ().get_local_addr (server_addr);
+ ACE_ASSERT (result == 0);
+
+ for (int i = 1; i <= iterations; ++i)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("iteration %d\n"),
+ i));
+
+ // If <listen_once> is false, one Acceptor is used for every
+ // iteration.
+ ACCEPTOR listen_multiple_times_acceptor;
+
+ ACCEPTOR &acceptor = listen_once ?
+ listen_one_time_acceptor :
+ listen_multiple_times_acceptor;
+
+ if (!listen_once)
+ {
+ // Bind acceptor to any port and then find out what the port
+ // was.
+ if (acceptor.open (ACE_sap_any_cast (const ACE_INET_Addr &)) == -1)
+ {
+ out_of_sockets_handler ();
+ continue;
+ }
+
+ if (acceptor.acceptor ().get_local_addr (server_addr) == -1)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("get_local_addr")));
+ ACE_ASSERT (0);
+ }
+
+ if (debug)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("starting server at port %d\n"),
+ server_addr.get_port_number ()));
+ }
+
+ // Run the cached blocking test.
+ int result = cached_connect (strategy_connector,
+ server_addr);
+ ACE_ASSERT (result != -1);
+
+ result = server (&acceptor);
+ if (result == -1)
+ out_of_sockets_handler ();
+ }
+}
+
+void
+test_caching_strategy_type (void)
+{
+ CACHING_STRATEGY *caching_strategy = 0;
+
+ switch (caching_strategy_type)
+ {
+ case ACE_NULL:
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\nNull_Caching_Strategy\n\n")));
+ ACE_NEW (caching_strategy,
+ NULL_CACHING_STRATEGY_ADAPTER);
+ break;
+
+ case ACE_LRU:
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\nLRU_Caching_Strategy\n\n")));
+ ACE_NEW (caching_strategy,
+ LRU_CACHING_STRATEGY_ADAPTER);
+ break;
+
+ case ACE_LFU:
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\nLFU_Caching_Strategy\n\n")));
+ ACE_NEW (caching_strategy,
+ LFU_CACHING_STRATEGY_ADAPTER);
+ break;
+
+ case ACE_FIFO:
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\nFIFO_Caching_Strategy\n\n")));
+ ACE_NEW (caching_strategy,
+ FIFO_CACHING_STRATEGY_ADAPTER);
+ break;
+
+ case ACE_ALL: // Just to remove warnings!
+ break;
+ }
+
+ caching_strategy->purge_percent (purge_percentage);
+ test_connection_management (*caching_strategy);
+ delete caching_strategy;
+}
+
+int
+parse_args (int argc, ACE_TCHAR *argv[])
+{
+ ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("l:i:p:c:a:d"));
+
+ int cc;
+
+ while ((cc = get_opt ()) != -1)
+ switch (cc)
+ {
+ case 'd':
+ debug = 1;
+ break;
+ case 'l':
+ listen_once = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'i':
+ iterations = ACE_OS::atoi (get_opt.opt_arg ());
+ user_has_specified_iterations = 1;
+ break;
+ case 'p':
+ purge_percentage = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'c':
+ // Note that if null caching strategy is used then this test
+ // will fail if the number of servers exceed number of open
+ // files allowed for the process.
+ if (ACE_OS::strcmp (get_opt.opt_arg (), ACE_TEXT ("null")) == 0)
+ caching_strategy_type = ACE_NULL;
+ if (ACE_OS::strcmp (get_opt.opt_arg (), ACE_TEXT ("lru")) == 0)
+ caching_strategy_type = ACE_LRU;
+ if (ACE_OS::strcmp (get_opt.opt_arg (), ACE_TEXT ("lfu")) == 0)
+ caching_strategy_type = ACE_LFU;
+ if (ACE_OS::strcmp (get_opt.opt_arg (), ACE_TEXT ("fifo")) == 0)
+ caching_strategy_type = ACE_FIFO;
+ break;
+ case 'a':
+ keep_handles_available = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case '?':
+ case 'h':
+ default:
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("usage: %s ")
+ ACE_TEXT ("[-c (caching strategy: lru / lfu / fifo / null [default = all])] ")
+ ACE_TEXT ("[-i (iterations)] ")
+ ACE_TEXT ("[-l (listen once)] ")
+ ACE_TEXT ("[-d (addition debugging output)] ")
+ ACE_TEXT ("[-p (purge percent)] ")
+ ACE_TEXT ("[-a (keep handles available)] "),
+ ACE_TEXT ("Cached_Conn_Test")));
+ return -1;
+ }
+
+ return 0;
+}
+
+int
+run_main (int argc, ACE_TCHAR *argv[])
+{
+ // Validate options.
+ int result = parse_args (argc, argv);
+ if (result != 0)
+ return result;
+
+#if defined (ACE_WIN32)
+ // Somehow, on Win32, the <listen once> option allows us to create
+ // more handles.
+ if (!user_has_specified_iterations &&
+ listen_once)
+ iterations *= 2;
+#endif /* ACE_WIN32 */
+
+ // Start the test only if options are valid.
+ ACE_START_TEST (ACE_TEXT ("Cached_Conn_Test"));
+
+ // Remove the extra debugging attributes from Log_Msg output.
+ ACE_LOG_MSG->clr_flags (ACE_Log_Msg::VERBOSE_LITE);
+
+ // The reactor's constructor changes the handle limit for the
+ // process.
+ ACE_Reactor::instance ();
+
+ // Consume all handles in the process, leaving us
+ // <keep_handles_available> to play with.
+ ACE_Handle_Gobbler handle_gobbler;
+ result = handle_gobbler.consume_handles (keep_handles_available);
+ ACE_ASSERT (result == 0);
+
+ // Do we need to test all the strategies. Note, that the less
+ // useful null strategy is ignored in this case.
+ if (caching_strategy_type == ACE_ALL)
+ {
+ caching_strategy_type = ACE_LRU;
+ test_caching_strategy_type ();
+
+ // Default iterations are too many; if the user hasn't specified
+ // otherwise, we'll shrink the iterations for LFU and FIFO.
+ if (!user_has_specified_iterations)
+ iterations /= 100;
+
+ caching_strategy_type = ACE_LFU;
+ test_caching_strategy_type ();
+
+ caching_strategy_type = ACE_FIFO;
+ test_caching_strategy_type ();
+ }
+ else
+ {
+ test_caching_strategy_type ();
+ }
+
+ ACE_LOG_MSG->set_flags (ACE_Log_Msg::VERBOSE_LITE);
+
+#else /* Do this for C Set++ 3.1 */
+
+int
+run_main (int argc, ACE_TCHAR *argv[])
+{
+ ACE_UNUSED_ARG (argc);
+ ACE_UNUSED_ARG (argv);
+
+ ACE_START_TEST (ACE_TEXT ("Cached_Conn_Test"));
+ ACE_ERROR ((LM_INFO,
+ ACE_TEXT ("C Set++ won't build this test correctly\n")));
+
+#endif /* !__xlC__ || __xlC > 0x0301 */
+
+ ACE_END_TEST;
+ return 0;
+}
diff --git a/ACE/tests/Cached_Conn_Test.h b/ACE/tests/Cached_Conn_Test.h
new file mode 100644
index 00000000000..4e7cfa4673e
--- /dev/null
+++ b/ACE/tests/Cached_Conn_Test.h
@@ -0,0 +1,35 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Cache_Conn_Test.h
+//
+// = DESCRIPTION
+// Define class needed for generating templates. IBM C++ requires this to
+// be in its own file for auto template instantiation.
+//
+// = AUTHOR
+// Kirthika Parameswaran <kirthika@cs.wustl.edu>
+//
+// ============================================================================
+
+#ifndef ACE_TESTS_CACHED_CONN_TEST_H
+#define ACE_TESTS_CACHED_CONN_TEST_H
+
+#include "ace/SOCK_Stream.h"
+#include "ace/Svc_Handler.h"
+
+class Svc_Handler : public ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH>
+{
+public:
+
+ Svc_Handler (ACE_Thread_Manager *t = 0);
+ int open (void *v = 0);
+ int close (u_long flags = 0);
+};
+
+#endif /* ACE_TESTS_CACHED_ACCEPT_CONN_TEST_H */
diff --git a/ACE/tests/Capabilities_Test.cpp b/ACE/tests/Capabilities_Test.cpp
new file mode 100644
index 00000000000..6bfbc6d9e60
--- /dev/null
+++ b/ACE/tests/Capabilities_Test.cpp
@@ -0,0 +1,119 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Capabilities_Test.cpp
+//
+// = DESCRIPTION
+// This is a test that makes sure the <ACE_Capabililties> class
+// works correctly.
+//
+// = AUTHOR
+// Arturo Montes <mitosys@colomsat.net.co>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/OS_NS_fcntl.h"
+#include "ace/OS_NS_unistd.h"
+#include "ace/Capabilities.h"
+
+ACE_RCSID(tests, Capabilities_Test, "$Id$")
+
+static const ACE_TCHAR config[] = ACE_TEXT ("Capabilities_Test.cfg");
+
+static int
+load_config (void)
+{
+ ACE_Capabilities caps;
+ if (caps.getent (config, ACE_TEXT ("Config")) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("Can't read %s\n"),
+ config),
+ 1);
+
+ int b = 0;
+ caps.getval (ACE_TEXT ("bool"), b);
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("bool = %d\n"),
+ b));
+
+ int n = 0;
+ caps.getval (ACE_TEXT ("integer"), n);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("integer = %d\n"),
+ n));
+
+ ACE_TString s;
+ caps.getval (ACE_TEXT ("string"), s);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("string = %s\n"),
+ s.c_str ()));
+ return 0;
+}
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("Capabilities_Test"));
+
+
+ // --------------------------------------------------------
+ // Create config file
+ // --------------------------------------------------------
+
+ // A config file is created within the test so that the test is
+ // completely self contained.
+
+ const char file_contents[] =
+ "Config|Esta entrada reservada para la configuracion,\n"
+ " bool,\n"
+ " integer#2,\n"
+ " string=000030,\n\n";
+
+ ACE_HANDLE fd = ACE_OS::open (config,
+ O_RDWR | O_CREAT | O_TRUNC,
+ ACE_DEFAULT_FILE_PERMS);
+
+ if (fd == ACE_INVALID_HANDLE)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("ACE_OS::open")),
+ -1);
+
+
+ if (ACE_OS::write (fd, file_contents, sizeof(file_contents)) !=
+ sizeof(file_contents))
+ {
+ ACE_OS::unlink (config);
+ ACE_OS::close (fd);
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("ACE_OS::write")),
+ -1);
+ }
+
+ if (ACE_OS::close (fd) != 0)
+ {
+ ACE_OS::unlink (config);
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("ACE_OS::close")),
+ -1);
+ }
+ // --------------------------------------------------------
+
+
+ int result = load_config ();
+
+ ACE_OS::unlink (config);
+
+ ACE_END_TEST;
+ return result;
+}
diff --git a/ACE/tests/Codecs_Test.cpp b/ACE/tests/Codecs_Test.cpp
new file mode 100644
index 00000000000..165ed9bfb8e
--- /dev/null
+++ b/ACE/tests/Codecs_Test.cpp
@@ -0,0 +1,119 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Codecs_Test.cpp
+//
+// = DESCRIPTION
+// Checks the functionality of the ACE Codecs class.
+//
+// = AUTHORS
+// Krishnakumar B <kitty@cs.wustl.edu>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/Codecs.h"
+#include "ace/Auto_Ptr.h"
+#include "ace/ACE.h"
+
+ACE_RCSID(tests, Codecs_Test, "$Id$")
+
+// Don't change the strings thinking that they are typos
+
+const ACE_Byte normal_stream[] = "This is a sample test stream, to test simple Base64 encoding";
+
+const ACE_Byte one_padded_stream[] = "This stream is different from the above in that, it results in one padding character to be adde";
+
+const ACE_Byte two_padded_stream[] = "This stream is different from the above in that, it results in two padding characters to be addedddd";
+
+int
+encode_decode_stream (const ACE_Byte* stream, size_t length)
+{
+ size_t encode_len = 0;
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Input stream = %s\n"),
+ stream));
+
+ ACE_Byte* encodeBuf = ACE_Base64::encode (stream, length,
+ &encode_len);
+ if (encodeBuf == 0)
+ {
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("Error in encoding stream\n")));
+ return -1;
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Base64 encoded stream = %s\n"),
+ encodeBuf));
+
+
+ ACE_Auto_Basic_Array_Ptr<ACE_Byte> cleanup_encodeBuf (encodeBuf);
+
+ size_t decode_len = 0;
+ ACE_Byte* decodeBuf = ACE_Base64::decode (encodeBuf, &decode_len);
+
+ if (decodeBuf == 0)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Error in decoding encoded stream\n")));
+ return -1;
+ }
+
+ ACE_Auto_Basic_Array_Ptr<ACE_Byte> cleanup_decodeBuf (decodeBuf);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Decoded Base64 encoded stream = %s\n"),
+ decodeBuf));
+
+ for (size_t i = 0; i < length; ++i)
+ if (decodeBuf[i] != stream[i])
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Encoded->Decoded stream differs from original stream\n")));
+ return -1;
+ }
+ return 0;
+}
+
+int
+run_main (int argc, ACE_TCHAR *argv[])
+{
+ ACE_UNUSED_ARG (argc);
+ ACE_UNUSED_ARG (argv);
+
+ ACE_START_TEST (ACE_TEXT ("Codecs_Test"));
+ int status = 0;
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("This is ACE Version %u.%u.%u\n\n"),
+ ACE::major_version (),
+ ACE::minor_version(),
+ ACE::beta_version()));
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Testing ACE Base64 - normal stream\n\n")));
+
+ status = encode_decode_stream (normal_stream, sizeof (normal_stream) - 1);
+
+ if (status == 0) {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Testing ACE Base64 - one padded stream\n\n")));
+ status = encode_decode_stream (one_padded_stream,
+ sizeof (one_padded_stream) - 1);
+ }
+ if (status == 0) {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Testing ACE Base64 - two padded stream\n\n")));
+ status = encode_decode_stream (two_padded_stream,
+ sizeof (two_padded_stream) - 1);
+ }
+ ACE_END_TEST;
+ return status;
+}
+
diff --git a/ACE/tests/Collection_Test.cpp b/ACE/tests/Collection_Test.cpp
new file mode 100644
index 00000000000..cf8e124de77
--- /dev/null
+++ b/ACE/tests/Collection_Test.cpp
@@ -0,0 +1,184 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Collection_Test.cpp
+//
+// = DESCRIPTION
+// This is a simple test of the ACE collection classes and its
+// iterators.
+//
+// = AUTHOR
+// Irfan Pyarali <irfan@cs.wustl.edu>
+//
+// ============================================================================
+
+#include "test_config.h"
+
+ACE_RCSID(tests, Collection_Test, "$Id$")
+
+#include "ace/Containers.h"
+#include "Collection_Test.h"
+
+UglyThing::UglyThing (void* alloc, deletion_func dfunc)
+ : alloc_ (alloc)
+ , dfunc_ (dfunc)
+{
+}
+
+bool
+UglyThing::operator== (const UglyThing& r) const
+{
+ return this->alloc_ == r.alloc_;
+}
+
+typedef UglyThing DATA;
+typedef ACE_Unbounded_Set<DATA> UNBOUNDED_SET;
+typedef ACE_Unbounded_Set_Iterator<DATA> UNBOUNDED_SET_ITERATOR;
+typedef ACE_Unbounded_Set_Const_Iterator<DATA> UNBOUNDED_SET_CONST_ITERATOR;
+
+typedef int ARRAY_DATA;
+typedef ACE_Array<ARRAY_DATA> ARRAY;
+typedef ACE_Array_Iterator<ARRAY_DATA> ARRAY_ITERATOR;
+
+void iterate_const(const UNBOUNDED_SET& set)
+{
+ {
+ UNBOUNDED_SET_CONST_ITERATOR iterator (set);
+ while (!iterator.done ())
+ {
+ DATA *data = 0;
+ iterator.next (data);
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("%x,%x\n"),
+ data->alloc_, data->dfunc_));
+
+ DATA data_second = *iterator;
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("%x,%x\n"),
+ data_second.alloc_, data_second.dfunc_));
+
+ iterator.advance ();
+ }
+ }
+}
+
+struct DummyFunctor
+{
+ int operator() (void) { return 0; }
+};
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("Collection_Test"));
+
+ deletion_func NO_DFUNC = (deletion_func)0;
+ DummyFunctor dummyfunc;
+
+ {
+ UNBOUNDED_SET unbounded_set;
+
+ unbounded_set.insert (UglyThing ((void*)&unbounded_set, NO_DFUNC));
+ unbounded_set.insert (UglyThing ((void*)&dummyfunc, NO_DFUNC));
+
+ {
+ for (UNBOUNDED_SET::iterator iterator = unbounded_set.begin ();
+ iterator != unbounded_set.end ();
+ ++iterator)
+ {
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("%x,%x\n"),
+ (*iterator).alloc_, (*iterator).dfunc_));
+ }
+ }
+
+ unbounded_set.insert (UglyThing (0, NO_DFUNC));
+ unbounded_set.remove (UglyThing ((void*)&dummyfunc, NO_DFUNC));
+
+ {
+ UNBOUNDED_SET_ITERATOR iterator (unbounded_set);
+ while (!iterator.done ())
+ {
+ DATA *data = 0;
+ iterator.next (data);
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("%x,%x\n"),
+ data->alloc_, data->dfunc_));
+ iterator.advance ();
+ }
+ }
+ iterate_const (unbounded_set);
+
+ unbounded_set.reset ();
+
+ {
+ DATA *data;
+ UNBOUNDED_SET_ITERATOR i (unbounded_set);
+
+ while (i.next (data) != 0)
+ {
+ ACE_DEBUG ((LM_DEBUG, "%x,%x\n", data->alloc_, data->dfunc_));
+ i.advance ();
+ }
+ }
+ iterate_const (unbounded_set);
+ }
+
+ {
+ ARRAY array;
+ }
+
+ {
+ ARRAY array (0);
+ }
+
+ {
+ ARRAY array1;
+ array1.size (2);
+ array1[0] = 4;
+ array1[1] = 4;
+
+ ARRAY array2 (2, 4);
+
+ ARRAY array3 (array2);
+
+ ARRAY array4;
+ array4 = array2;
+
+ ACE_ASSERT (array1 == array2);
+ ACE_ASSERT (array1 == array3);
+ ACE_ASSERT (array1 == array4);
+
+ {
+ for (size_t i = 0;
+ i != array1.size ();
+ ++i)
+ {
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("%d\n"),
+ array1[i]));
+ ACE_ASSERT (array1[i] == 4);
+ }
+ }
+
+ {
+ ARRAY_ITERATOR iterator (array1);
+ while (!iterator.done ())
+ {
+ ARRAY_DATA *data = 0;
+ iterator.next (data);
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("%d\n"),
+ (*data)));
+ ACE_ASSERT (*data == 4);
+ iterator.advance ();
+ }
+ }
+ }
+
+
+ ACE_END_TEST;
+
+ return 0;
+}
+
diff --git a/ACE/tests/Collection_Test.h b/ACE/tests/Collection_Test.h
new file mode 100644
index 00000000000..249c9dd281d
--- /dev/null
+++ b/ACE/tests/Collection_Test.h
@@ -0,0 +1,36 @@
+// -*- C++ -*-
+
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Collection_Test.h
+//
+// = DESCRIPTION
+// Define class needed for generating templates. IBM C++ requires this to
+// be in its own file for auto template instantiation.
+//
+// = AUTHOR
+// Irfan Pyarali <irfan@cs.wustl.edu>
+//
+// ============================================================================
+
+#ifndef ACE_TESTS_COLLECTION_TEST_H
+#define ACE_TESTS_COLLECTION_TEST_H
+
+typedef void (*deletion_func)(void* p);
+
+struct UglyThing
+{
+ void *alloc_;
+ deletion_func dfunc_;
+
+ UglyThing (void* alloc = 0, deletion_func dfunc = 0);
+ bool operator== (const UglyThing& r) const;
+};
+
+#endif /* ACE_TESTS_COLLECTION_TEST_H */
diff --git a/ACE/tests/Config_Test.cpp b/ACE/tests/Config_Test.cpp
new file mode 100644
index 00000000000..01bc3bf97bf
--- /dev/null
+++ b/ACE/tests/Config_Test.cpp
@@ -0,0 +1,1514 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Config_Test.cpp
+//
+// = DESCRIPTION
+// This is a test that makes sure various classes in
+// <ACE_Configuration> work correctly.
+//
+// = AUTHOR
+// Michael Searles <msearles@base16.com>,
+// Chris Hafey <chafey@stentor.com>, and
+// Jerry D. Odenwelder Jr. <jerry.o@mindspring.com>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "Config_Test.h"
+#include "ace/Configuration_Import_Export.h"
+#include "ace/OS_NS_ctype.h"
+#include "ace/OS_NS_errno.h"
+#include "ace/OS_NS_stdio.h"
+#include "ace/OS_NS_string.h"
+#include "ace/OS_NS_unistd.h"
+
+ACE_RCSID(tests, Config_Test, "$Id$")
+
+static int
+test (ACE_Configuration *config,
+ ACE_Configuration_Section_Key &testsection)
+{
+ ACE_TString stvalue;
+
+ // Set some values.
+ if (config->set_string_value (testsection,
+ ACE_TEXT ("stvalue"),
+ ACE_TEXT ("stvaluetest")))
+ return -3;
+
+ else if (config->remove_value (testsection,
+ ACE_TEXT ("stvalue")))
+ return -4;
+ // Make sure it's really gone
+ else if (0 == config->get_string_value (testsection,
+ ACE_TEXT ("stvalue"),
+ stvalue))
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("test:remove_value didn't remove\n")),
+ -4);
+
+ else if (config->set_string_value (testsection,
+ ACE_TEXT ("stvalue"),
+ ACE_TEXT ("stvaluetest")))
+ return -3;
+ else if (config->set_string_value (testsection,
+ ACE_TEXT ("stvalue"),
+ ACE_TEXT ("second stvaluetest")))
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("test:set_string_value twice failed\n")),
+ -3);
+
+ else if (config->set_integer_value (testsection,
+ ACE_TEXT ("intvalue"),
+ 77))
+ return -4;
+ // Reset to the value we test for below
+ else if (config->set_integer_value (testsection,
+ ACE_TEXT ("intvalue"),
+ 42))
+ return -4;
+
+ u_char data[80];
+
+ for (int i = 0; i < 80; i++)
+ data[i] = i + 128;
+
+ if (config->set_binary_value (testsection,
+ ACE_TEXT ("binvalue"),
+ data,
+ 80))
+ return -5;
+
+ // Get the values and compare
+ if (config->get_string_value (testsection,
+ ACE_TEXT ("stvalue"),
+ stvalue))
+ return -6;
+ else if (stvalue != ACE_TEXT ("second stvaluetest"))
+ return -7;
+
+ u_int intvalue;
+
+ if (config->get_integer_value (testsection,
+ ACE_TEXT ("intvalue"),
+ intvalue))
+ return -8;
+ else if (intvalue != 42)
+ return -9;
+
+ u_char *data_out = 0;
+ size_t length = 0;
+
+ if (config->get_binary_value (testsection,
+ ACE_TEXT ("binvalue"),
+ (void*&) data_out,
+ length))
+ return -10;
+
+ // compare em
+ for (int j = 0; j < 80; j++)
+ if (data_out[j] != data[j])
+ return -11;
+
+ delete [] data_out;
+
+ // Test iteration.
+ ACE_TString name;
+ ACE_Configuration::VALUETYPE type;
+ u_int index = 0;
+ int found[3] = { 0, 0, 0 }; // One for each expected value
+
+ while (!config->enumerate_values (testsection,
+ index,
+ name,
+ type))
+ {
+ if (name == ACE_TEXT ("stvalue"))
+ {
+ if (type != ACE_Configuration::STRING)
+ return -12;
+ if (found[0] != 0)
+ return -12;
+ found[0] = 1;
+ }
+ else if (name == ACE_TEXT ("intvalue"))
+ {
+ if (type != ACE_Configuration::INTEGER)
+ return -13;
+ if (found[1] != 0)
+ return -13;
+ found[1] = 1;
+ }
+ else if (name == ACE_TEXT ("binvalue"))
+ {
+ if (type != ACE_Configuration::BINARY)
+ return -14;
+ if (found[2] != 0)
+ return -14;
+ found[2] = 1;
+ }
+ index++;
+ }
+
+ // Make sure we got three values.
+ if (index != 3 || !found[0] || !found[1] || !found[2])
+ return -15;
+
+ {
+ // Add some subsections. This part is a separate scope to be sure
+ // the test2, test3, test4 keys are closed before further
+ // manipulating/deleting the sections further down in the test.
+ ACE_Configuration_Section_Key test2;
+ ACE_Configuration_Section_Key test3;
+ ACE_Configuration_Section_Key test4;
+
+ if (config->open_section (testsection,
+ ACE_TEXT ("test2"),
+ 1,
+ test2))
+ return -16;
+ else if (config->open_section (testsection,
+ ACE_TEXT ("test3"),
+ 1,
+ test3))
+ return -17;
+ else if (config->open_section (testsection,
+ ACE_TEXT ("test4"),
+ 1,
+ test4))
+ return -18;
+ }
+
+ // Test enumerate sections.
+ index = 0;
+ found[0] = found[1] = found[2] = 0;
+ while (!config->enumerate_sections (testsection,
+ index,
+ name))
+ {
+ if (name == ACE_TEXT ("test2"))
+ {
+ if (found[0] != 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("enumerate_sections, dupl test2\n")),
+ -19);
+ found[0] = 1;
+ }
+ else if (name == ACE_TEXT ("test3"))
+ {
+ if (found[1] != 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("enumerate_sections, dupl test3\n")),
+ -19);
+ found[1] = 1;
+ }
+ else if (name == ACE_TEXT ("test4"))
+ {
+ if (found[2] != 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("enumerate_sections, dupl test4\n")),
+ -19);
+ found[2] = 1;
+ }
+ index++;
+ }
+
+ if (index != 3 || !found[0] || !found[1] || !found[2])
+ return -19;
+
+ // Remove a subsection
+ if (config->remove_section (testsection,
+ ACE_TEXT ("test2"),
+ 0))
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p (%d)\n"),
+ ACE_TEXT ("remove_section test2"),
+ ACE_OS::last_error ()),
+ -20);
+
+ // Try to remove it again
+ if (!config->remove_section (testsection,
+ ACE_TEXT ("test2"),
+ 0))
+ return -21;
+
+ return 0;
+}
+
+static int
+test (ACE_Configuration *config)
+{
+ const ACE_Configuration_Section_Key& root =
+ config->root_section ();
+
+ {
+ // Scope this so the testsection key is closed before trying to
+ // remove the "test" section.
+ ACE_Configuration_Section_Key testsection;
+
+ if (config->open_section (root,
+ ACE_TEXT ("test"),
+ 1,
+ testsection))
+ return -2;
+
+ int ret_val = test (config, testsection);
+ if (ret_val)
+ return ret_val;
+ }
+
+ // Try to remove the testsection root, it should fail since it still
+ // has subkeys
+ if (!config->remove_section (root,
+ ACE_TEXT ("test"),
+ 0))
+ return -22;
+
+ {
+ // Test find section, and be sure the key is closed before testing the
+ // remove, below.
+ ACE_Configuration_Section_Key result;
+
+ if (config->open_section (root,
+ ACE_TEXT ("test"),
+ 0,
+ result))
+ return -23;
+ }
+
+ // Now test the recursive remove.
+ if (config->remove_section (root,
+ ACE_TEXT ("test"),
+ 1))
+ return -24;
+
+ // Make sure its not there
+ ACE_Configuration_Section_Key testsectiongone;
+ if (!config->open_section (root,
+ ACE_TEXT ("test"),
+ 0,
+ testsectiongone))
+ return -25;
+
+ return 0;
+}
+
+static int
+test_subkey_path (ACE_Configuration* config)
+{
+ ACE_Configuration_Section_Key root =
+ config->root_section ();
+
+ ACE_Configuration_Section_Key testsection;
+
+ if (config->open_section (root,
+ ACE_TEXT ("Software\\ACE\\test"),
+ 1,
+ testsection))
+ return -26;
+
+ int ret_val = test (config, testsection);
+ if (ret_val)
+ return ret_val;
+
+ if (config->open_section (root,
+ ACE_TEXT ("Software"),
+ 0,
+ testsection))
+ return -27;
+
+ if (config->remove_section (testsection,
+ ACE_TEXT ("ACE"),
+ 1))
+ return -28;
+
+ return 0;
+}
+
+static int
+run_tests (void)
+{
+ int status;
+
+ {
+ // Test import of a legit INI format from a previously-existing file.
+ ACE_Configuration_Heap cf;
+ if ((status = cf.open ()) != 0)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("ACE_Configuration_Heap::open returned %d\n"),
+ status));
+ ACE_Ini_ImpExp import (cf);
+ // This one should work...
+ status = import.import_config (ACE_TEXT ("Config_Test_Import_1.ini"));
+ if (status != 0) {
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"),
+ ACE_TEXT ("Config_Test_Import_1.ini failed")));
+ }
+ else {
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Config_Test_Import_1.ini imported\n")));
+
+ // Imported clean; verify content. See ini file for expected content.
+ // Verify the expected sections are there, but no others. Verify the
+ // expected keys are there, but no others.
+ int section1_seen = 0, section2_seen = 0;
+ int somekey_seen = 0, someotherkey_seen = 0;
+ int index;
+ ACE_TString sect_name;
+ const ACE_Configuration_Section_Key &root = cf.root_section ();
+ for (index = 0;
+ (status = cf.enumerate_sections (root, index, sect_name)) == 0;
+ ++index) {
+ if (index > 1) // There are only two sections.
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Enumerated %d sections; expected 2\n"),
+ index + 1));
+ else {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Enumerated to section %s\n"),
+ sect_name.c_str ()));
+ if (sect_name == ACE_TEXT ("SectionOne")) {
+ if (section1_seen)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("Saw %s multiple times!\n"),
+ sect_name.c_str ()));
+ section1_seen = 1;
+ // Check for values in this section.
+ ACE_Configuration_Section_Key sect1;
+ if (cf.open_section (root, sect_name.c_str (), 0, sect1) != 0)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("Failed to open section: %s\n"),
+ sect_name.c_str ()));
+ else {
+ int val_index = 0, val_status;
+ ACE_TString val_name, value;
+ ACE_Configuration::VALUETYPE val_type;
+ while ((val_status =
+ cf.enumerate_values
+ (sect1, val_index, val_name, val_type)) == 0) {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Enumerated %s, type %d\n"),
+ val_name.c_str (),
+ val_type));
+ if (val_type != ACE_Configuration::STRING)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Expected %s to be STRING, but %d\n"),
+ val_name.c_str (),
+ val_type));
+ if (val_name == ACE_TEXT ("SomeKey")) {
+ if (somekey_seen)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Saw %s more than once\n"),
+ val_name.c_str ()));
+ somekey_seen = 1;
+ }
+ else
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("Unexpected key %s\n"),
+ val_name.c_str ()));
+ if ((val_status = cf.get_string_value
+ (sect1, val_name.c_str (), value)) != 0)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("Can't get value of %s\n"),
+ val_name.c_str ()));
+ else {
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("%s value: %s\n"),
+ val_name.c_str (), value.c_str ()));
+ if (value != ACE_TEXT ("SomeValue")) {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("SomeKey: %s; expected SomeValue\n")));
+ }
+ }
+ ++val_index;
+ }
+ if (val_status == 1) {
+ if (val_index != 1) // Should have only seen 1
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Expected 1 value; saw %d\n"),
+ index));
+ }
+ else
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Error enumerating %s; status %d\n"),
+ sect_name.c_str (), val_status));
+ }
+ }
+ else if (sect_name == ACE_TEXT ("SectionTwo")) {
+ if (section2_seen)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Saw %s multiple times!\n"),
+ sect_name.c_str ()));
+ section2_seen = 1;
+ // Check for values in this section.
+ ACE_Configuration_Section_Key sect2;
+ if (cf.open_section (root, sect_name.c_str (), 0, sect2) != 0)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Failed to open section: %s\n"),
+ sect_name.c_str ()));
+ else {
+ int val_index = 0, val_status;
+ ACE_TString val_name, value;
+ ACE_Configuration::VALUETYPE val_type;
+ while ((val_status = cf.enumerate_values
+ (sect2, val_index, val_name, val_type)) == 0) {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Enumerated %s, type %d\n"),
+ val_name.c_str (),
+ val_type));
+ if (val_type != ACE_Configuration::STRING)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Expected %s to be STRING, but %d\n"),
+ val_name.c_str (), val_type));
+ if (val_name == ACE_TEXT ("SomeOtherKey")) {
+ if (someotherkey_seen)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("Saw %s more than once\n"),
+ val_name.c_str ()));
+ someotherkey_seen = 1;
+ }
+ else
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("Unexpected key %s\n"),
+ val_name.c_str ()));
+ if ((val_status = cf.get_string_value
+ (sect2, val_name.c_str (), value)) != 0)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("Can't get value of %s\n"),
+ val_name.c_str ()));
+ else {
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("%s value: %s\n"),
+ val_name.c_str (), value.c_str ()));
+ if (value != ACE_TEXT ("SomeOtherValue")) {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("SomeOtherKey: %s; expected SomeOtherValue\n")));
+ }
+ }
+ ++val_index;
+ }
+ if (val_status == 1) {
+ if (val_index != 1) // Should have only seen 1
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Expected 1 value; saw %d\n"),
+ index));
+ }
+ else
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Error enumerating %s; status %d\n"),
+ sect_name.c_str (), val_status));
+ }
+ }
+ else {
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("Saw unexpected section: %s\n"),
+ sect_name.c_str ()));
+ }
+ }
+ }
+ if (status == 1) { // Ran out of sections
+ if (index != 2)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("Saw %d sections; expected 2\n"),
+ index));
+ }
+ else
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Error enumerating sections; status %d\n"),
+ status));
+ }
+ }
+
+#if defined (ACE_WIN32)
+ {
+ ACE_Configuration_Win32Registry RegConfig (HKEY_LOCAL_MACHINE);
+ int result = test_subkey_path (&RegConfig);
+ if (result)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("Win32Registry test HKEY_LOCAL_MACHINE")
+ ACE_TEXT (" failed (%d)\n"), result),
+ -1);
+ }
+ // test win32 registry implementation.
+ HKEY root =
+ ACE_Configuration_Win32Registry::resolve_key (HKEY_LOCAL_MACHINE,
+ ACE_TEXT ("Software\\ACE\\test"));
+ if (!root)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("resolve_key is broken\n")), -2);
+
+ // test resolving of forward slashes
+ HKEY root_fs =
+ ACE_Configuration_Win32Registry::resolve_key (HKEY_LOCAL_MACHINE,
+ ACE_TEXT ("Software/ACE/test"), 0);
+ if (!root_fs)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("resolve_key resolving slashes is broken\n")),
+ -2);
+
+ ACE_Configuration_Win32Registry RegConfig (root);
+ {
+ int result = test (&RegConfig);
+ if (result)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("Win32 registry test root failed (%d)\n"),
+ result),
+ -1);
+ }
+
+#endif /* ACE_WIN32 */
+ // Test Heap version
+ ACE_Configuration_Heap heap_config;
+
+ if (heap_config.open ())
+ return 0;
+ {
+ int result = test_subkey_path (&heap_config);
+ if (result)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("Heap Config subkey test failed (%d)\n"),
+ result),
+ -1);
+ }
+
+ {
+ int result = test (&heap_config);
+ if (result)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("Heap Configuration test failed (%d)\n"),
+ result),
+ -1);
+ }
+
+ // Test persistent heap version
+ ACE_OS::unlink (ACE_TEXT ("test.reg"));
+ ACE_Configuration_Heap pers_config;
+
+ if (pers_config.open (ACE_TEXT ("test.reg")))
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("Cannot open test.reg\n")),
+ -1);
+
+ {
+ int result = test (&pers_config);
+ if (result)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("Persistent Heap Config test failed (%d)\n"),
+ result),
+ -1);
+ }
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Test passed\n")));
+ return 0;
+}
+
+static int
+build_config_object (ACE_Configuration& cfg)
+{
+ ACE_Configuration_Section_Key root = cfg.root_section ();
+ ACE_Configuration_Section_Key NetworkSection;
+ ACE_Configuration_Section_Key LoggerSection;
+ ACE_Configuration_Section_Key BinarySection;
+
+ if (cfg.open_section (root,
+ ACE_TEXT ("network"),
+ 1,
+ NetworkSection))
+ return -1;
+
+ if (cfg.set_integer_value (NetworkSection,
+ ACE_TEXT ("TimeToLive"),
+ 100))
+ return -2;
+ else if (cfg.set_string_value (NetworkSection,
+ ACE_TEXT ("Delay"),
+ ACE_TString (ACE_TEXT ("FALSE"))))
+ return -3;
+ else if (cfg.set_string_value (NetworkSection,
+ ACE_TEXT ("DestIPAddress"),
+ ACE_TString (ACE_TEXT ("localhost"))))
+ return -4;
+ else if (cfg.set_integer_value (NetworkSection,
+ ACE_TEXT ("DestPort"),
+ 12670))
+ return -5;
+ else if (cfg.set_integer_value (NetworkSection,
+ ACE_TEXT ("ReconnectInterval"),
+ 3))
+ return -6;
+
+ if (cfg.open_section (root,
+ ACE_TEXT ("logger"),
+ 1,
+ LoggerSection))
+ return -7;
+
+ if (cfg.set_string_value (LoggerSection,
+ ACE_TEXT ("Heading"),
+ ACE_TString (ACE_TEXT ("ACE - Adaptive Communication Environment"))))
+ return -8;
+ else if (cfg.set_integer_value (LoggerSection,
+ ACE_TEXT ("SeekIndex"),
+ 14))
+ return -9;
+ else if (cfg.set_integer_value (LoggerSection,
+ ACE_TEXT ("TraceLevel"),
+ 6))
+ return -10;
+ else if (cfg.set_string_value (LoggerSection,
+ ACE_TEXT ("Justification"),
+ ACE_TString (ACE_TEXT ("left_justified"))))
+ return -11;
+ else if (cfg.set_string_value (LoggerSection,
+ ACE_TEXT ("LogFilePath"),
+ ACE_TString (ACE_TEXT ("log/"))))
+ return -12;
+ else if (cfg.set_string_value (LoggerSection,
+ ACE_TEXT ("TransactionFilePath"),
+ ACE_TString (ACE_TEXT ("data/"))))
+ return -13;
+
+ if (cfg.open_section (root,
+ ACE_TEXT ("binary"),
+ 1,
+ BinarySection))
+ return -14;
+
+ u_char data[80];
+
+ for (int i = 0; i < 80; i++)
+ data[i] = i + 128;
+
+ if (cfg.set_binary_value (BinarySection,
+ ACE_TEXT ("data"),
+ data,
+ 80))
+ return -15;
+
+ ACE_TString string((ACE_TCHAR*) 0);// = '0';
+ // Try to set the unnamed, default value.
+ if (cfg.set_string_value (LoggerSection,
+ 0,//string.c_str (),//0, //ACE_TEXT ("x"),
+ ACE_TString (ACE_TEXT ("some string"))))
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("could not set value with null name\n")),
+ -16);
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("here\n")));
+ //return 0;
+ //ACE_TString string;
+ ACE_TString name ((ACE_TCHAR*)0);
+ if (cfg.get_string_value (LoggerSection,
+ name.c_str (), //0, //ACE_TEXT ("x"),
+ string))
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("error using ACE_TString::c_str() == %d, len == %d\n"),
+ name.c_str(), name.length ()),
+ -17);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("the value for the unnamed var=(%s)\n"),
+ string.c_str ()));
+
+ return 0;
+}
+
+/*
+ * Test ACE_Configuration::operator==
+ */
+int
+Config_Test::testEquality ()
+{
+ // create and open 2 ACE_Configuration objects.
+ ACE_Configuration_Heap heap1;
+ ACE_Configuration_Heap heap2;
+ if ((heap1.open ()) != 0)
+ {
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("Cannot open heap1\n")),
+ -1);
+
+ }
+ else if ((heap2.open ()) != 0)
+ {
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("Cannot open heap2\n")),
+ -1);
+ }
+
+ // populate them equally
+ if (build_config_object (heap1) != 0 ||
+ build_config_object (heap2) != 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("could not build config object\n")),
+ -1);
+
+ // test equality
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("The objects should equal...\n")));
+ if (heap1 == heap2)
+ {
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("And they do ;-)\n")));
+ }
+ else
+ {
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("And they do not :-(\n")
+ ACE_TEXT ("operator== Failed when objects equal\n")),
+ -1);
+ }
+
+ // add a section and value to heap1
+ ACE_Configuration_Section_Key root1 = heap1.root_section ();
+ ACE_Configuration_Section_Key NewSection;
+ if (heap1.open_section (root1,
+ ACE_TEXT ("NewSection"),
+ 1,
+ NewSection))
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("Error adding section to heap1\n")),
+ -1);
+ else if (heap1.set_integer_value (NewSection,
+ ACE_TEXT ("TestIntValue"),
+ 100))
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("Error adding value to heap1\n")),
+ -2);
+
+ // test equality
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("The objects should NOT equal...\n")));
+ if (heap1 == heap2)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("They Do :-(\noperator== Failed ")
+ ACE_TEXT ("when lhs contains data not in rhs\n")),
+ -1);
+ else
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("And they do not ;-)\n")));
+
+ //
+ // add same section to heap2
+ //
+ ACE_Configuration_Section_Key root2 = heap2.root_section ();
+ ACE_Configuration_Section_Key NewSection2;
+ if (heap2.open_section (root2,
+ ACE_TEXT ("NewSection"),
+ 1,
+ NewSection2))
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("Error adding section to heap2\n")),
+ -1);
+ else if (heap2.set_integer_value (NewSection2,
+ ACE_TEXT ("TestIntValue"),
+ 100))
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("Error adding value to heap2\n")),
+ -2);
+ else if (heap2.set_integer_value (NewSection2,
+ ACE_TEXT ("TestIntValue2"),
+ 100))
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("Error adding second value to heap2\n")),
+ -2);
+
+ // test equality
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("The objects should NOT equal...\n")));
+ if (heap1 == heap2)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("And They Do :-(\noperator== Failed ")
+ ACE_TEXT ("when rhs contains value not in lhs\n")),
+ -1);
+ else
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("And they do not ;-)\n")));
+
+ // add new value in heap 1
+ if (heap1.set_integer_value (NewSection,
+ ACE_TEXT ("TestIntValue2"),
+ 100))
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("Error adding second value to heap1\n")),
+ -2);
+
+ // test equality
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("The objects should be equal...\n")));
+ if (heap1 == heap2)
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("And they are ;-)\n")));
+ else
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("And they are not :-(\n")
+ ACE_TEXT ("operator== Failed\n")),
+ -1);
+
+ // Add a new section to heap2
+ ACE_Configuration_Section_Key AnotherNewSection2;
+ if (heap2.open_section (root2,
+ ACE_TEXT ("AnotherNewSection"),
+ 1,
+ AnotherNewSection2))
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("Error adding second section to heap2\n")),
+ -1);
+ else if (heap2.set_integer_value (AnotherNewSection2,
+ ACE_TEXT ("TestIntValue"),
+ 100))
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("Error adding value in second section")
+ ACE_TEXT (" to heap2\n")),
+ -2);
+
+ // test equality
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("The objects should NOT equal...\n")));
+ if (heap1 == heap2)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("And they do :-(\noperator== Failed ")
+ ACE_TEXT ("when rhs contains data not in lhs\n")),
+ -1);
+ else
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("And they do not :-)\n")));
+
+ // add section back to heap1
+ ACE_Configuration_Section_Key AnotherNewSection1;
+ if (heap1.open_section (root1,
+ ACE_TEXT ("AnotherNewSection"),
+ 1,
+ AnotherNewSection1))
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("Error adding second section to heap1\n")),
+ -1);
+ else if (heap1.set_integer_value (AnotherNewSection1,
+ ACE_TEXT ("TestIntValue"),
+ 100))
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("Error adding second value to second ")
+ ACE_TEXT ("section in heap1\n")),
+ -2);
+
+ // test equality
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("The objects should be equal...\n")));
+ if (heap1 == heap2)
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("And they are ;-)\n")));
+ else
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("And they are not :-(\n")
+ ACE_TEXT ("operator== Failed\n")),
+ -1);
+
+ this->equality_tested_ = 1;
+ return 0;
+}
+
+/*
+ * Compare INI import data in fromFile to origional data exported (in origional)
+ *
+ * This compare is destructive to the origional object.
+ * I realize that normally you would not do such an obscene thing but
+ * this funciton has a special purpose and I know my origional is not needed
+ * after calling this routine.
+ * This is done because configuration objects that are imported using the INI
+ * import store all data as strings. My origional has type information and I need to
+ * know if the import worked.
+*/
+static int
+iniCompare (ACE_Configuration_Heap& fromFile, ACE_Configuration_Heap& original)
+{
+ bool rc = true; // start by guessing they are equal
+
+ int sectionIndex = 0;
+ ACE_TString sectionName;
+
+ const ACE_Configuration_Section_Key& fromFileRoot = fromFile.root_section ();
+ const ACE_Configuration_Section_Key& originalRoot = original.root_section ();
+ ACE_Configuration_Section_Key originalSection;
+ ACE_Configuration_Section_Key fromFileSection;
+
+ // loop through each section in the fromFile object
+ while ((rc) &&
+ (!fromFile.enumerate_sections (fromFileRoot,
+ sectionIndex,
+ sectionName)) )
+ {
+ // find that section in the original object
+ if (original.open_section (originalRoot,
+ sectionName.c_str (),
+ 0,
+ originalSection) != 0)
+ // If the original object does not contain the section then we
+ // are not equal.
+ rc = false;
+ else if (fromFile.open_section (fromFileRoot,
+ sectionName.c_str (),
+ 0,
+ fromFileSection) != 0)
+ // if there is some error opening the section in the fromFile
+ rc = false;
+ else
+ {
+ // Well the sections match
+ int valueIndex = 0;
+ ACE_TString valueName;
+ ACE_Configuration::VALUETYPE valueType;
+ ACE_Configuration::VALUETYPE originalType;
+
+ // Enumerate each value in the fromFile section
+ while ((rc) &&
+ (!fromFile.enumerate_values (fromFileSection,
+ valueIndex,
+ valueName,
+ valueType)))
+ {
+ // look for the same value in the original section
+ if (original.find_value (originalSection,
+ valueName.c_str (),
+ originalType) != 0)
+ // We're not equal if the same value cannot be found
+ // in the original object.
+ rc = false;
+ else
+ {
+ ACE_TString fromFileString, originalString;
+
+
+ if (fromFile.get_string_value (fromFileSection,
+ valueName.c_str (),
+ fromFileString) != 0)
+ // we're not equal if we cannot get this string
+ rc = false;
+ else if (originalType != ACE_Configuration::STRING) // If the original type is not a string
+ {
+ // convert original data to a string.
+
+ if (originalType == ACE_Configuration::INTEGER)
+ {
+ u_int intValue;
+ ACE_TCHAR int_value[32];
+
+ if (original.get_integer_value (originalSection,
+ valueName.c_str (),
+ intValue) != 0)
+ // we're not equal if we cannot get rhs int
+ rc = false;
+
+ ACE_OS::sprintf (int_value, ACE_LIB_TEXT ("%08x"), intValue);
+ originalString = int_value;
+ }
+ else if (originalType == ACE_Configuration::BINARY)
+ {
+ void* binary_data;
+ size_t binary_length;
+
+ if (original.get_binary_value (originalSection,
+ valueName.c_str (),
+ binary_data,
+ binary_length))
+ // we're not equal if we cannot get this string
+ rc = false;
+ else
+ {
+ ACE_TCHAR bin_value[3];
+
+ unsigned char* ptr = (unsigned char*)binary_data;
+ while (binary_length)
+ {
+ if (ptr != binary_data)
+ originalString += ACE_LIB_TEXT (",");
+
+ ACE_OS::sprintf (bin_value,
+ ACE_LIB_TEXT ("%02x"),
+ *ptr);
+ originalString += bin_value;
+ --binary_length;
+ ++ptr;
+ }
+ delete [] (char *)binary_data;
+ }// end successful binary read
+ }// end if originalType was binary
+ else
+ // if the type is invalid, then go ahead and fail it.
+ rc = false;
+
+ }// end if the original type was not a string.
+ else
+ {
+ if (original.get_string_value (originalSection,
+ valueName.c_str (),
+ originalString) != 0)
+ {
+ // we're not equal if we cannot get rhs string
+ rc = false;
+ }
+
+ }
+
+ rc &= fromFileString == originalString;
+
+ if (rc)
+ // before we move on remove this value from the original.
+ original.remove_value (originalSection,
+ valueName.c_str ());
+
+ }// end else if values match.
+
+ valueIndex++;
+
+ }// end value while loop
+
+ // at this point the original should have no values. look
+ // for values in the original section
+ valueIndex = 0;
+ while ((rc) &&
+ (!original.enumerate_values (originalSection,
+ valueIndex,
+ valueName,
+ originalType)))
+ valueIndex++;
+
+ // having a value indicates a mismatch
+ rc = valueIndex == 0;
+
+ }// end else if sections match.
+
+ if (rc)
+ // before we move on remove the section from the original.
+ original.remove_section (originalRoot,
+ sectionName.c_str (),
+ 0); // do not remove subsections.
+
+ sectionIndex++;
+
+ }// end section while loop
+
+ // Finally, if the original has any sections, then we're not equal
+ sectionIndex = 0;
+ while ((rc) &&
+ (!original.enumerate_sections (originalRoot,
+ sectionIndex,
+ sectionName)))
+ sectionIndex++;
+
+ rc = sectionIndex == 0;
+
+ return rc;
+}
+
+// change a network section value
+int Config_Test::change_one (ACE_Configuration &cfg, u_int a)
+{
+ ACE_Configuration_Section_Key root = cfg.root_section ();
+ ACE_Configuration_Section_Key NetworkSection;
+ ACE_Configuration_Section_Key LoggerSection;
+ ACE_Configuration_Section_Key BinarySection;
+
+ if (cfg.open_section (root,
+ ACE_TEXT ("network"),
+ 1,
+ NetworkSection))
+ return -1;
+
+ if (cfg.set_integer_value (NetworkSection,
+ ACE_TEXT ("TimeToLive"),
+ a))
+ return -2;
+
+ return 0;
+}
+
+// Used to test INI Import Export class
+
+int
+Config_Test::testIniFormat ()
+{
+ int rc = 0;
+ if (!this->equality_tested_)
+ {
+ rc = this->testEquality ();
+ if (rc != 0)
+ {
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Equality Test Failed\n")));
+ return rc;
+ }
+ }
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Testing INI Format Import/Export\n")));
+ ACE_Configuration_Heap fromFile;
+
+ // 1. Creates an ACE_Configuration_Heap object
+ ACE_Configuration_Heap original;
+
+ rc = original.open ();
+ if (rc == 0)
+ {
+ rc = build_config_object (original);
+ // 2. Calls build_config_object to populate
+ if (rc != 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("Error populating original config ")
+ ACE_TEXT ("object (%d)\n"),
+ rc),
+ -1);
+ // 3. Export
+ ACE_Ini_ImpExp importExport (original);
+
+ rc = importExport.export_config (ACE_TEXT ("testConfig.ini"));
+ if (rc != 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("Error Exporting (%d)\n"),
+ rc),
+ -1);
+ }
+ else
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("Could not open original object (%d)\n"),
+ rc),
+ -1);
+
+ // At this point we've successfully created, populated and written
+ // the configuration object
+ // 5. Creates a new ACE_Configuration_Heap object
+ rc = fromFile.open ();
+ if (rc == 0)
+ {
+ // 6. Imports
+ ACE_Ini_ImpExp importExport (fromFile);
+
+ rc = importExport.import_config (ACE_TEXT ("testConfig.ini"));
+ if (rc != 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("Error Exporting (%d)\n"),
+ rc),
+ -1);
+
+ // 7. Compares to original.
+ // This is a special compare since files imported using the
+ // INI file import do not contain type information
+ //
+ // NOTE: After this call the original object will be invalid!!!
+ //
+ if (!iniCompare (fromFile, original))
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("Object read from file does not ")
+ ACE_TEXT ("equal original (%d)\n"),
+ rc),
+ -1);
+ }// end if heap could not be opened.
+ else
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("Could not open fromFile object (%d)\n"),
+ rc),
+ -1);
+
+ // 8. Calls old "read_config" methods on the new object
+
+ int nTimeToLive;
+ int bDelay;
+ int nDestPort;
+ int nReconnectInterval;
+ int nTraceLevel;
+
+ ACE_TCHAR pszDestIPAddress[TEST_MAX_STRING];
+ ACE_TCHAR pszLogFilePath[TEST_MAX_STRING];
+ ACE_TCHAR pszTransactionFilePath[TEST_MAX_STRING];
+ ACE_TCHAR pszHeading[TEST_MAX_STRING];
+ ACE_TCHAR pszJustification[TEST_MAX_STRING];
+
+ ACE_Configuration_Section_Key root = fromFile.root_section ();
+
+ // Process [network] section
+ ACE_Configuration_Section_Key NetworkSection;
+ if (fromFile.open_section (root,
+ ACE_TEXT ("network"),
+ 1,
+ NetworkSection) == 0)
+ {
+ this->get_section_integer (fromFile,
+ NetworkSection,
+ ACE_TEXT ("TimeToLive"),
+ &nTimeToLive,
+ 1,
+ 20);
+
+ this->get_section_boolean (fromFile,
+ NetworkSection,
+ ACE_TEXT ("Delay"),
+ &bDelay);
+
+ this->get_section_string (fromFile,
+ NetworkSection,
+ ACE_TEXT ("DestIPAddress"),
+ pszDestIPAddress,
+ TEST_MAX_STRING);
+
+ this->get_section_integer (fromFile,
+ NetworkSection,
+ ACE_TEXT ("DestPort"),
+ &nDestPort,
+ 0,
+ 65535);
+
+ this->get_section_integer (fromFile,
+ NetworkSection,
+ ACE_TEXT ("ReconnectInterval"),
+ &nReconnectInterval,
+ 0,
+ 65535);
+ }// end of "network" section
+
+ // Process [logger] section
+ ACE_Configuration_Section_Key LoggerSection;
+ if (fromFile.open_section (root,
+ ACE_TEXT ("logger"),
+ 1,
+ LoggerSection) == 0)
+ {
+ this->get_section_string (fromFile,
+ LoggerSection,
+ ACE_TEXT ("Heading"),
+ pszHeading,
+ TEST_MAX_STRING);
+ this->get_section_integer (fromFile,
+ LoggerSection,
+ ACE_TEXT ("TraceLevel"),
+ &nTraceLevel,
+ 1,
+ 20);
+ this->get_section_string (fromFile,
+ LoggerSection,
+ ACE_TEXT ("Justification"),
+ pszJustification,
+ TEST_MAX_STRING);
+ this->get_section_string (fromFile,
+ LoggerSection,
+ ACE_TEXT ("LogFilePath"),
+ pszLogFilePath,
+ TEST_MAX_STRING);
+ this->get_section_string (fromFile,
+ LoggerSection,
+ ACE_TEXT ("TransactionFilePath"),
+ pszTransactionFilePath,
+ TEST_MAX_STRING);
+ }// end of "logger" section
+
+ if (!rc)
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("INI Format Import/Export Works ;-)\n")));
+ return rc;
+}
+
+// Used to test registry Import Export class
+
+int
+Config_Test::testRegFormat ()
+{
+ int rc = 0;
+ if (!this->equality_tested_)
+ {
+ rc = this->testEquality ();
+ if (rc != 0)
+ {
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Equality Test Failed\n")));
+ return rc;
+ }
+
+ }
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Testing Registry Format Import/Export\n")));
+ ACE_Configuration_Heap fromFile;
+
+ // 1. Creates an ACE_Configuration_Heap object
+ ACE_Configuration_Heap original;
+
+ rc = original.open ();
+ if (rc == 0)
+ {
+ // 2. Calls build_config_object to populate
+ rc = build_config_object (original);
+ if (rc != 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("Error populating original config ")
+ ACE_TEXT ("object (%d)\n"),
+ rc),
+ -1);
+ // 3. Export
+ ACE_Registry_ImpExp importExport (original);
+
+ rc = importExport.export_config (ACE_TEXT ("testConfig.ini"));
+ if (rc != 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("Error Exporting (%d)\n"),
+ rc),
+ -1);
+ }
+ else
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("Could not open original object (%d)\n"),
+ rc),
+ -1);
+
+ // At this point we've successfully created, populated and written
+ // the configuration object
+ // 5. Creates a new ACE_Configuration_Heap object
+ rc = fromFile.open ();
+ if (rc == 0)
+ {
+ // 6. Imports
+ ACE_Registry_ImpExp importExport (fromFile);
+
+ rc = importExport.import_config (ACE_TEXT ("testConfig.ini"));
+ if (rc != 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT("Error Exporting (%d)\n"),
+ rc),
+ -1);
+
+ // 7. Compares to original.
+ if (fromFile != original)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("Object read from file does not ")
+ ACE_TEXT ("equal original (%d)\n"),
+ rc),
+ -1);
+
+ // 7.1 Change a value and test NOT equal case
+ change_one (original, 101);
+ if (fromFile == original)
+ {
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("not pass value change test (%d)\n"),
+ rc),
+ -1);
+ }
+
+ // 7.2 change value back, they should be equal now
+ change_one (original, 100);
+ if (fromFile != original)
+ {
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("not pass value change test (%d)\n"),
+ rc),
+ -1);
+ }
+
+ }// end if heap could not be opened.
+ else
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("Could not open fromFile object (%d)\n"),
+ rc),
+ -1);
+
+ if (!rc)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Registry Format Import/Export Works ;-)\n")));
+ return rc;
+}
+
+
+// Reads a string value from a configuration object.
+
+void
+Config_Test::get_section_string (ACE_Configuration& config,
+ ACE_Configuration_Section_Key& SectionKey,
+ const ACE_TCHAR* pszName,
+ ACE_TCHAR* pszVariable,
+ int nMaxLength)
+{
+ ACE_TString StringValue;
+
+ if (config.get_string_value (SectionKey,
+ pszName,
+ StringValue) == 0)
+ {
+ ACE_OS::strncpy (pszVariable,
+ StringValue.c_str (),
+ nMaxLength);
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%s = %s\n"),
+ pszName,
+ pszVariable));
+ }
+}
+
+// Reads an integer value from a configuration object (when it's
+// stored as a string)
+void
+Config_Test::get_section_integer (ACE_Configuration& config,
+ ACE_Configuration_Section_Key& SectionKey,
+ const ACE_TCHAR* pszName,
+ int* nVariable,
+ int nMinValue,
+ int nMaxValue)
+{
+ ACE_TString StringValue;
+ ACE_TCHAR pszString[30];
+ ACE_OS::strcpy (pszString, ACE_TEXT ("0"));
+ int IntegerValue = 0;
+
+ if (config.get_string_value (SectionKey,
+ pszName,
+ StringValue) == 0)
+ {
+ ACE_OS::strncpy (pszString,
+ StringValue.c_str (),
+ 30);
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%s = %s\n"),
+ pszName,
+ pszString));
+ }
+
+ // convert to integer
+ IntegerValue = ACE_OS::atoi (pszString);
+ IntegerValue = (IntegerValue < nMinValue) ? nMinValue : IntegerValue;
+ IntegerValue = (IntegerValue > nMaxValue) ? nMaxValue : IntegerValue;
+ *nVariable = IntegerValue;
+}
+
+// Reads a boolean value from a configuration object (when it's stored as a string).
+
+void
+Config_Test::get_section_boolean (ACE_Configuration& config,
+ ACE_Configuration_Section_Key& SectionKey,
+ const ACE_TCHAR* pszName,
+ int* pVariable)
+{
+ ACE_TString StringValue;
+ ACE_TCHAR pszString[10];
+ ACE_OS::strcpy (pszString, ACE_TEXT ("0"));
+
+ if (config.get_string_value (SectionKey,
+ pszName,
+ StringValue) == 0)
+ {
+ ACE_OS::strncpy (pszString,
+ StringValue.c_str (),
+ 10);
+ for (ACE_TCHAR* pSrc = pszString;
+ *pSrc != ACE_TEXT ('\0');
+ pSrc++)
+ // Convert to uppercase
+ if (ACE_OS::ace_islower (*pSrc))
+ *pSrc = ACE_OS::ace_tolower (*pSrc);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%s = %s\n"),
+ pszName,
+ pszString));
+
+ if (ACE_OS::strcmp (pszString,
+ ACE_TEXT ("TRUE")) == 0)
+ *pVariable = 1;
+ else if (ACE_OS::strcmp (pszString,
+ ACE_TEXT ("FALSE")) == 0)
+ *pVariable = 0;
+ }
+}
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("Config_Test"));
+ int errors = 0;
+ Config_Test manager;
+
+ if ((errors += manager.testEquality ()) != 0)
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Failed the equality Test\n")));
+
+ if ((errors += manager.testRegFormat ()) != 0)
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Failed the REG Format Test\n")));
+
+ if ((errors += manager.testIniFormat ()) != 0)
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Failed the INI Format Test\n")));
+
+ if ((errors += run_tests ()) != 0)
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Failed in run_tests\n")));
+
+ ACE_END_TEST;
+ return errors == 0 ? 0 : 1;
+}
diff --git a/ACE/tests/Config_Test.h b/ACE/tests/Config_Test.h
new file mode 100644
index 00000000000..30c75432d61
--- /dev/null
+++ b/ACE/tests/Config_Test.h
@@ -0,0 +1,77 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// ConfigTest.h
+//
+// = DESCRIPTION
+// This is a test that makes sure the <import_config_as_strings> of
+// <ACE_Configuration_Heap> class works correctly.
+//
+// = AUTHOR
+// Michael Searles <msearles@base16.com> and
+// Jerry D. Odenwelder Jr. <jerry.o@mindspring.com>
+//
+// ============================================================================
+
+#ifndef __CONFIG_TEST_H
+#define __CONFIG_TEST_H
+
+#include "ace/Configuration.h"
+
+const int TEST_MAX_STRING = 256;
+
+class Config_Test
+{
+public:
+ Config_Test (void): equality_tested_ (0) { }
+ ~Config_Test (void) { }
+
+ // Used to test the equality and inequality operations.
+ int testEquality ();
+
+ // Used to test INI Import Export class
+ int testIniFormat ();
+
+ // Used to test Regiastry Import Export class
+ // 1. Creates an ACE_Configuration_Heap object
+ // 2. Calls buildConfigObject to populate
+ // 3. Exports
+ // 5. Creates a new ACE_Configuration_Heap object
+ // 6. Imports
+ // 7. Compares to origional.
+ // 8. Clean-up
+ int testRegFormat ();
+
+
+private:
+ // change a value for value change test
+ int change_one (ACE_Configuration &l, u_int a = 101);
+
+ void get_section_string (ACE_Configuration& config,
+ ACE_Configuration_Section_Key& SectionKey,
+ const ACE_TCHAR* pszName,
+ ACE_TCHAR* pszVariable,
+ int nMaxLength);
+
+ void get_section_integer (ACE_Configuration& config,
+ ACE_Configuration_Section_Key& SectionKey,
+ const ACE_TCHAR* pszName,
+ int* nVariable,
+ int nMinValue,
+ int nMaxValue);
+
+ void get_section_boolean (ACE_Configuration& config,
+ ACE_Configuration_Section_Key& SectionKey,
+ const ACE_TCHAR* pszName,
+ int* pVariable);
+
+private:
+ int equality_tested_; // make sure the equality operator works before proceeding.
+};
+
+#endif /* __CONFIG_TEST_H */
diff --git a/ACE/tests/Config_Test.ini b/ACE/tests/Config_Test.ini
new file mode 100644
index 00000000000..db3df20979f
--- /dev/null
+++ b/ACE/tests/Config_Test.ini
@@ -0,0 +1,22 @@
+# --------------------------------------------------------------------
+# Example test.ini file for import_config_as_strings of the
+# <ACE_Configuration_Heap> class
+# --------------------------------------------------------------------
+# Use whitespace (tabs and spaces) freely.
+# String to the left of the equal sign can be delimited with double
+# quotes.
+# --------------------------------------------------------------------
+[network]
+ TimeToLive = 100
+ Delay = FALSE
+ DestIPAddress = localhost
+ DestPort = 12670
+ ReconnectInterval = 3
+
+[logger]
+ Heading = "ACE - Adaptive Communication Environment"
+ SeekIndex = 14
+ TraceLevel = 6 # Can comment lines like this
+ Justification = left_justified
+ LogFilePath = log/
+ TransactionFilePath = data/
diff --git a/ACE/tests/Config_Test_Import_1.ini b/ACE/tests/Config_Test_Import_1.ini
new file mode 100644
index 00000000000..d3194658cdb
--- /dev/null
+++ b/ACE/tests/Config_Test_Import_1.ini
@@ -0,0 +1,5 @@
+[SectionOne]
+SomeKey=SomeValue
+
+[SectionTwo]
+SomeOtherKey=SomeOtherValue
diff --git a/ACE/tests/Conn_Test.cpp b/ACE/tests/Conn_Test.cpp
new file mode 100644
index 00000000000..2e808d4497b
--- /dev/null
+++ b/ACE/tests/Conn_Test.cpp
@@ -0,0 +1,782 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Conn_Test.cpp
+//
+// = DESCRIPTION
+// This is a test of the <ACE_Acceptor> and <ACE_Connector>
+// classes. The test forks processes or spawns threads (depending
+// upon the platform) and then executes client and server allowing
+// them to connect and exchange data. The test also illustrates
+// how the <ACE_Strategy_Connector> works by showing how you can
+// cache connections on the client.
+//
+// = AUTHOR
+// Douglas C. Schmidt <schmidt@cs.wustl.edu>,
+// Chris Cleeland <cleeland@cs.wustl.edu>,
+// and Irfan Pyarali <irfan@cs.wustl.edu>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/SOCK_Connector.h"
+#include "ace/LOCK_SOCK_Acceptor.h"
+#include "ace/Acceptor.h"
+#include "ace/Handle_Set.h"
+#include "ace/Connector.h"
+#include "ace/Auto_Ptr.h"
+#include "ace/Get_Opt.h"
+#include "ace/Process_Mutex.h"
+#include "ace/Signal.h"
+#include "Conn_Test.h"
+#include "ace/Barrier.h"
+#include "ace/OS_NS_signal.h"
+#include "ace/OS_NS_sys_select.h"
+#include "ace/OS_NS_sys_wait.h"
+#include "ace/OS_NS_unistd.h"
+#include "ace/os_include/os_netdb.h"
+
+ACE_RCSID(tests, Conn_Test, "$Id$")
+
+static const char ACE_ALPHABET[] = "abcdefghijklmnopqrstuvwxyz";
+
+// This test doesn't work well using fork() on MacOS X. So we
+// will force it to use threads instead.
+#if defined (__APPLE__)
+# define ACE_LACKS_FORK
+#endif /* __APPLE__ */
+
+// The following works around bugs with some operating systems, which
+// don't allow multiple threads/process to call accept() on the same
+// listen-mode port/socket. Also, note that since timed accept is
+// implemented using select(), and we use timed accepts with threads,
+// we need a real lock when using timed accepts even if the OS has
+// thread-safe accept.
+//
+#if defined (ACE_LACKS_FORK)
+# if defined (ACE_HAS_THREADS)
+# include "ace/Thread_Mutex.h"
+ typedef ACE_Thread_Mutex ACCEPTOR_LOCKING;
+# else
+# include "ace/Null_Mutex.h"
+ typedef ACE_Null_Mutex ACCEPTOR_LOCKING;
+# endif /* ACE_HAS_THREADS */
+#else
+# if defined (ACE_HAS_THREAD_SAFE_ACCEPT)
+# include "ace/Null_Mutex.h"
+ typedef ACE_Null_Mutex ACCEPTOR_LOCKING;
+# else
+# include "ace/Process_Mutex.h"
+ typedef ACE_Process_Mutex ACCEPTOR_LOCKING;
+# endif /* ACE_HAS_THREAD_SAFE_ACCEPT */
+#endif /* ACE_LACKS_FORK */
+
+#if defined (ACE_HAS_TEMPLATE_TYPEDEFS)
+#define LOCK_SOCK_ACCEPTOR ACE_LOCK_SOCK_Acceptor<ACCEPTOR_LOCKING>
+#else
+#define LOCK_SOCK_ACCEPTOR ACE_LOCK_SOCK_Acceptor<ACCEPTOR_LOCKING>, ACE_INET_Addr
+#endif /* ACE_HAS_TEMPLATE_TYPEDEFS */
+
+typedef ACE_Oneshot_Acceptor<Svc_Handler,
+ LOCK_SOCK_ACCEPTOR>
+ ACCEPTOR;
+typedef ACE_Connector<Svc_Handler,
+ ACE_SOCK_CONNECTOR>
+ CONNECTOR;
+typedef ACE_Strategy_Connector<Svc_Handler,
+ ACE_SOCK_CONNECTOR>
+ STRAT_CONNECTOR;
+typedef ACE_NOOP_Creation_Strategy<Svc_Handler>
+ NULL_CREATION_STRATEGY;
+typedef ACE_NOOP_Concurrency_Strategy<Svc_Handler>
+ NULL_ACTIVATION_STRATEGY;
+typedef ACE_Cached_Connect_Strategy<Svc_Handler,
+ ACE_SOCK_CONNECTOR,
+ ACE_SYNCH_MUTEX>
+ CACHED_CONNECT_STRATEGY;
+
+#define CACHED_CONNECT_STRATEGY ACE_Cached_Connect_Strategy<Svc_Handler, ACE_SOCK_CONNECTOR, ACE_SYNCH_MUTEX>
+#define REFCOUNTED_HASH_RECYCLABLE_ADDR ACE_Refcounted_Hash_Recyclable<ACE_INET_Addr>
+
+// Default number of clients/servers.
+#if defined (ACE_HAS_PHARLAP)
+// PharLap is, by default, resource contrained. Test for something that works
+// on the default configuration.
+static int n_servers = 2;
+static int n_clients = 4;
+#else
+static int n_servers = 5;
+static int n_clients = 5;
+#endif /* ACE_HAS_PHARLAP */
+
+static int n_client_iterations = 3;
+
+Svc_Handler::Svc_Handler (ACE_Thread_Manager *)
+{
+}
+
+int
+Svc_Handler::open (void *)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) opening Svc_Handler %@ with handle %d\n"),
+ this,
+ this->peer ().get_handle ()));
+ // Enable non-blocking I/O.
+ if (this->peer ().enable (ACE_NONBLOCK) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n"),
+ ACE_TEXT ("enable")),
+ -1);
+ return 0;
+}
+
+int
+Svc_Handler::recycle (void *)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) recycling Svc_Handler %@ with handle %d\n"),
+ this,
+ this->peer ().get_handle ()));
+ return 0;
+}
+
+void
+Svc_Handler::send_data (void)
+{
+ // Send data to server.
+
+ for (const char *c = ACE_ALPHABET; *c != '\0'; c++)
+ if (this->peer ().send_n (c, 1) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n"),
+ ACE_TEXT ("send_n")));
+}
+
+void
+Svc_Handler::recv_data (void)
+{
+ ACE_SOCK_Stream &new_stream = this->peer ();
+
+ ACE_Handle_Set handle_set;
+ handle_set.set_bit (new_stream.get_handle ());
+
+ const char *t = ACE_ALPHABET;
+
+ // Read data from client (terminate on error).
+
+ for (ssize_t r_bytes; ;)
+ {
+ // Since we're in non-blocking mode we need to use <select> to
+ // avoid busy waiting.
+#if defined (ACE_WIN64)
+ int select_width = 0;
+#else
+ int select_width = int (new_stream.get_handle ()) + 1;
+#endif /* ACE_WIN64 */
+ if (ACE_OS::select (select_width, handle_set) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n"),
+ ACE_TEXT ("select")));
+ else
+ {
+ char c;
+
+ while ((r_bytes = new_stream.recv (&c, 1)) > 0)
+ {
+ ACE_ASSERT (*t == c);
+
+ // We need to guard against cached connections, which
+ // will send multiple sequences of letters from 'a' ->
+ // 'z' through the same connection.
+ if (*t == 'z')
+ t = ACE_ALPHABET;
+ else
+ t++;
+ }
+
+ if (r_bytes == 0)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) reached end of input, connection closed by client\n")));
+
+ // Close endpoint handle (but don't close <this> yet
+ // since we're going to recycle it for the next
+ // iteration).
+ if (new_stream.close () == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n"),
+ ACE_TEXT ("close")));
+ break;
+ }
+ else if (r_bytes == -1)
+ {
+ if (errno == EWOULDBLOCK)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) no input available, going back to reading\n")));
+ else
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n"),
+ ACE_TEXT ("recv_n")));
+ }
+ }
+ }
+}
+
+int
+Svc_Handler::close (u_long side)
+{
+ // Only run this protocol if we're the write-side (i.e., "1").
+ if (side == 1 && this->peer ().close () == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n"),
+ ACE_TEXT ("close_writer")));
+ // Trigger the shutdown.
+ return this->handle_close ();
+}
+
+int
+Svc_Handler::idle (u_long flags)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) idling Svc_Handler %@ with handle %d\n"),
+ this,
+ this->peer ().get_handle ()));
+ return ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH>::idle (flags);
+}
+
+struct Client_Info
+ // = TITLE
+ // Information passed to the client so it can communicate with the
+ // server.
+{
+ ACE_INET_Addr *server_addr_;
+ // Address of the server to connect with.
+
+ CONNECTOR *connector_;
+ // Connection factory.
+
+ STRAT_CONNECTOR *strat_connector_;
+ // Strategy for connecting.
+
+#if defined (ACE_HAS_THREADS)
+ ACE_Barrier *barrier_;
+ // Performs barrier synchronization.
+#endif /* ACE_HAS_THREADS */
+};
+
+#if !defined (ACE_LACKS_FORK) || defined (ACE_HAS_THREADS)
+
+static void
+timed_blocking_connect (CONNECTOR &con,
+ const ACE_INET_Addr &server_addr)
+{
+ ACE_Time_Value tv (ACE_DEFAULT_TIMEOUT);
+ ACE_Synch_Options options (ACE_Synch_Options::USE_TIMEOUT, tv);
+
+ Svc_Handler *svc_handler;
+ ACE_NEW (svc_handler,
+ Svc_Handler);
+
+ // Perform a timed-blocking connect to the server (this should
+ // connect quickly since we're in the same address space or same
+ // host).
+ if (con.connect (svc_handler,
+ server_addr,
+ options) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n"),
+ ACE_TEXT ("connection failed")));
+ else
+ {
+ // Send the data to the server.
+ svc_handler->send_data ();
+
+ // Close the connection completely.
+ if (svc_handler->close (1) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n"),
+ ACE_TEXT ("close")));
+ }
+}
+
+static void
+blocking_connect (CONNECTOR &con,
+ const ACE_INET_Addr &server_addr)
+{
+ Svc_Handler *svc_handler;
+ ACE_NEW (svc_handler,
+ Svc_Handler);
+
+ // Perform a blocking connect to the server.
+ if (con.connect (svc_handler,
+ server_addr) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n"),
+ ACE_TEXT ("connection failed")));
+ else
+ {
+ // Send the data to the server.
+ svc_handler->send_data ();
+
+ // Close the connection completely.
+ if (svc_handler->close (1) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n"),
+ ACE_TEXT ("close")));
+ }
+}
+
+// This function runs the more sophisticated tests involving the
+// Caching_Connect_Strategy.
+
+static void
+cached_connect (STRAT_CONNECTOR &con,
+ const ACE_INET_Addr &server_addr)
+{
+ Svc_Handler *svc_handler = 0;
+
+ for (int i = 0; i < n_client_iterations; i++)
+ {
+ // Perform a blocking connect to the server using the Strategy
+ // Connector with a connection caching strategy. Since we are
+ // connecting to the same <server_addr> these calls will return
+ // the same dynamically allocated <Svc_Handler> for each
+ // <connect>.
+ if (con.connect (svc_handler,
+ server_addr) == -1)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n"),
+ ACE_TEXT ("connection failed")));
+ return;
+ }
+
+ // Send the data to the server.
+ svc_handler->send_data ();
+
+ // Svc_Handler is now idle, so mark it as such and let the cache
+ // recycle it in another thread.
+ svc_handler->idle (1);
+
+ // Rest for a second to give another thread a chance to reuse the
+ // connection.
+ ACE_OS::sleep (1);
+ }
+}
+
+static void *
+client_connections (void *arg)
+{
+ Client_Info *info = (Client_Info *) arg;
+
+ // Run the timed-blocking test.
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) **** starting timed-blocking connect\n")));
+ timed_blocking_connect (*info->connector_,
+ *info->server_addr_);
+
+#if defined (ACE_HAS_THREADS)
+ // Wait for other threads to join us.
+ info->barrier_->wait ();
+#endif /* ACE_HAS_THREADS */
+
+ // Run the blocking test.
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) **** starting blocking connect\n")));
+ blocking_connect (*info->connector_,
+ *info->server_addr_);
+
+#if defined (ACE_HAS_THREADS)
+ // Wait for other threads to join us.
+ info->barrier_->wait ();
+#endif /* ACE_HAS_THREADS */
+
+ // Run the cached blocking test.
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) **** starting cached blocking connect\n")));
+ cached_connect (*info->strat_connector_,
+ *info->server_addr_);
+ return 0;
+}
+
+// Execute the client tests.
+
+static void *
+client (void *arg)
+{
+ ACE_INET_Addr *remote_addr = reinterpret_cast<ACE_INET_Addr *> (arg);
+ ACE_INET_Addr server_addr (remote_addr->get_port_number (),
+ ACE_DEFAULT_SERVER_HOST);
+ CONNECTOR connector;
+
+ NULL_CREATION_STRATEGY creation_strategy;
+ NULL_ACTIVATION_STRATEGY activation_strategy;
+ // Configure the Strategy Connector with a strategy that caches
+ // connection.
+ CACHED_CONNECT_STRATEGY caching_connect_strategy;
+
+ STRAT_CONNECTOR strat_connector (0,
+ &creation_strategy,
+ &caching_connect_strategy,
+ &activation_strategy);
+ Client_Info info;
+ info.server_addr_ = &server_addr;
+ info.connector_ = &connector;
+ info.strat_connector_ = &strat_connector;
+
+#if defined (ACE_HAS_THREADS)
+ int n_threads = n_clients;
+ ACE_Barrier thread_barrier (n_threads);
+ info.barrier_ = &thread_barrier;
+
+ ACE_Thread_Manager client_manager;
+
+ if (client_manager.spawn_n
+ (n_threads,
+ (ACE_THR_FUNC) client_connections,
+ (void *) &info,
+ THR_NEW_LWP) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n%a"),
+ ACE_TEXT ("client thread spawn failed"),
+ 1));
+
+ // Wait for the threads to exit.
+ client_manager.wait ();
+
+#else /* ACE_HAS_THREADS */
+ client_connections (&info);
+#endif /* ACE_HAS_THREADS */
+ return 0;
+}
+
+// Performs the iterative server activities.
+
+static void *
+server (void *arg)
+{
+#if defined (VXWORKS)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) server stack size is %u\n"),
+ ACE_OS::thr_min_stack ()));
+#endif /* VXWORKS */
+
+ ACCEPTOR *acceptor = (ACCEPTOR *) arg;
+ ACE_INET_Addr cli_addr;
+ ACE_TCHAR peer_host[MAXHOSTNAMELEN];
+ const ACE_Time_Value tv (ACE_DEFAULT_TIMEOUT);
+ ACE_Synch_Options options (ACE_Synch_Options::USE_TIMEOUT, tv);
+
+ Svc_Handler *svc_handler;
+ ACE_NEW_RETURN (svc_handler,
+ Svc_Handler,
+ 0);
+
+ // Keep looping until we timeout on <accept> or fail.
+
+ for (;;)
+ {
+ // Create a new <Svc_Handler> to consume the data.
+
+#if defined (ACE_LACKS_FORK)
+ int result = acceptor->accept (svc_handler,
+ &cli_addr,
+ options);
+#else /* ! ACE_LACKS_FORK */
+ int result = acceptor->accept (svc_handler,
+ &cli_addr);
+ ACE_UNUSED_ARG (options);
+#endif /* ! ACE_LACKS_FORK */
+
+ // Timing out is the only way for threads to stop accepting
+ // since we don't have signals.
+
+ if (result == -1)
+ {
+ // svc_handler->close (); The ACE_Onsehot_Acceptor closed it.
+
+ if (errno == ETIMEDOUT)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("accept timed out\n")));
+ return 0;
+ }
+ else
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n"),
+ ACE_TEXT ("accept failed, shutting down")),
+ 0);
+ }
+ // Use this rather than get_host_name() to properly adjust to the
+ // charset width in use.
+ cli_addr.get_host_name (peer_host, MAXHOSTNAMELEN);
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) client %s connected from %d\n"),
+ peer_host,
+ cli_addr.get_port_number ()));
+
+ svc_handler->recv_data ();
+ }
+
+ ACE_NOTREACHED (return 0);
+}
+
+#endif /* !ACE_LACKS_FORK || ACE_HAS_THREADS */
+
+#if !defined (ACE_LACKS_FORK)
+static void
+handler (int /* signum */)
+{
+ // No printout here, to be safe. Signal handlers must not acquire
+ // locks, etc. It's not even safe to call ACE_OS::exit ()!
+ ACE_OS::exit (0);
+}
+
+// Spawn threads.
+
+static int
+spawn_processes (ACCEPTOR *acceptor,
+ ACE_INET_Addr *server_addr)
+{
+ pid_t *children_ptr = 0;
+ ACE_NEW_RETURN (children_ptr,
+ pid_t[n_servers],
+ -1);
+ ACE_Auto_Basic_Array_Ptr<pid_t> children (children_ptr);
+ int i;
+
+ // Spawn off a number of server processes all of which will listen
+ // on the same port number for clients to connect.
+ for (i = 0; i < n_servers; i++)
+ {
+ pid_t pid = ACE_OS::fork (ACE_TEXT ("child"));
+ switch (pid)
+ {
+ case -1:
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n%a"),
+ ACE_TEXT ("fork failed"),
+ 1));
+ ACE_OS::exit (-1);
+ /* NOTREACHED */
+ case 0: // In the child.
+ {
+ // Register a signal handler to close down the child.
+ ACE_Sig_Action sa ((ACE_SignalHandler) handler, SIGTERM);
+ ACE_UNUSED_ARG (sa);
+
+ server ((void *) acceptor);
+ return 0;
+ /* NOTREACHED */
+ }
+ default: // In the parent.
+ children[i] = pid;
+ break;
+ }
+ }
+
+ client ((void *) server_addr);
+
+ for (i = 0; i < n_servers; i++)
+ // Shutdown the servers.
+ if (ACE_OS::kill (children[i], SIGTERM) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p for %d\n"),
+ ACE_TEXT ("kill"), children[i]));
+
+ pid_t child;
+
+ do
+ {
+ child = ACE_OS::wait ();
+ if (child != -1)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) reaping %d\n"),
+ child));
+ }
+ while (child != -1);
+
+ // Remove the lock so we don't have process semaphores lying around.
+ return acceptor->acceptor ().lock ().remove ();
+}
+#endif /* ! ACE_LACKS_FORK */
+
+#if defined (ACE_LACKS_FORK) && defined (ACE_HAS_THREADS)
+// Spawn threads and run the client and server.
+
+static
+int
+spawn_threads (ACCEPTOR *acceptor,
+ ACE_INET_Addr *server_addr)
+{
+ int status = 0;
+
+#if defined (VXWORKS) && !defined (ACE_HAS_PTHREADS)
+ // Assign thread (VxWorks task) names to test that feature.
+ ACE_thread_t *server_name;
+ ACE_NEW_RETURN (server_name,
+ ACE_thread_t[n_servers],
+ -1);
+
+ // And test ability to provide stacks.
+ size_t *stack_size;
+ ACE_NEW_RETURN (stack_size,
+ size_t[n_servers],
+ -1);
+ char **stack;
+ ACE_NEW_RETURN (stack,
+ char *[n_servers],
+ -1);
+ int i;
+
+ for (i = 0; i < n_servers; ++i)
+ {
+ ACE_NEW_RETURN (server_name[i], ACE_TCHAR[32], -1);
+ ACE_OS::sprintf (server_name[i],
+ ACE_TEXT ("server%u"),
+ i);
+ stack_size[i] = 40000;
+ ACE_NEW_RETURN (stack[i], char[stack_size[i]], -1);
+
+ // Initialize the stack for checkStack.
+ ACE_OS::memset (stack[i], 0xEE, stack_size[i]);
+ }
+
+ ACE_TCHAR *client_name = ACE_TEXT ("Conn client");
+#endif /* VXWORKS && !ACE_HAS_PTHREADS*/
+
+ if (ACE_Thread_Manager::instance ()->spawn_n
+ (
+#if defined (VXWORKS) && !defined (ACE_HAS_PTHREADS)
+ server_name,
+#endif /* VXWORKS */
+ n_servers,
+ (ACE_THR_FUNC) server,
+ (void *) acceptor,
+ THR_NEW_LWP
+#if defined (VXWORKS) && !defined (ACE_HAS_PTHREADS)
+ , ACE_DEFAULT_THREAD_PRIORITY
+ , -1
+#if 0 /* Don't support setting of stack, because it doesn't seem to work. */
+ , (void **) stack
+#else
+ , 0
+#endif /* 0 */
+ , stack_size
+#endif /* VXWORKS */
+ ) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n%a"),
+ ACE_TEXT ("server thread create failed"),
+ 1));
+
+ if (ACE_Thread_Manager::instance ()->spawn
+ ((ACE_THR_FUNC) client,
+ (void *) server_addr,
+ THR_NEW_LWP
+#if defined (VXWORKS) && !defined (ACE_HAS_PTHREADS)
+ , &client_name
+#endif /* VXWORKS */
+ ) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n%a"),
+ ACE_TEXT ("client thread create failed"),
+ 1));
+
+ // Wait for the threads to exit.
+ // But, wait for a limited time because sometimes the test hangs on Irix.
+ const ACE_Time_Value max_wait (200 /* seconds */);
+ const ACE_Time_Value wait_time (ACE_OS::gettimeofday () + max_wait);
+ if (ACE_Thread_Manager::instance ()->wait (&wait_time) == -1)
+ {
+ if (errno == ETIME)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("maximum wait time of %d msec exceeded\n"),
+ max_wait.msec ()));
+ else
+ ACE_OS::perror (ACE_TEXT ("wait"));
+
+ status = -1;
+ }
+
+#if defined (VXWORKS) && !defined (ACE_HAS_PTHREADS)
+ for (i = 0; i < n_servers; ++i)
+ {
+ delete [] server_name[i];
+ delete [] stack[i];
+ }
+ delete [] server_name;
+ delete [] stack;
+ delete [] stack_size;
+#endif /* VXWORKS */
+
+ return status;
+}
+#endif /* ! ACE_LACKS_FORK && ACE_HAS_THREADS */
+
+int
+run_main (int argc, ACE_TCHAR *argv[])
+{
+ ACE_START_TEST (ACE_TEXT ("Conn_Test"));
+ int status = 0;
+
+ ACE_Get_Opt getopt (argc, argv, ACE_TEXT ("c:i:s:"));
+ for (int c; (c = getopt ()) != -1; )
+ switch (c)
+ {
+ case 'c':
+ n_clients = ACE_OS::atoi (getopt.opt_arg ());
+ break;
+ case 'i':
+ n_client_iterations = ACE_OS::atoi (getopt.opt_arg ());
+ break;
+ case 's':
+ n_servers = ACE_OS::atoi (getopt.opt_arg ());
+ break;
+ }
+
+ // Acceptor
+ ACCEPTOR acceptor;
+ ACE_INET_Addr server_addr;
+
+ // Bind acceptor to any port and then find out what the port was.
+ if (acceptor.open (ACE_sap_any_cast (const ACE_INET_Addr &)) == -1
+ || acceptor.acceptor ().get_local_addr (server_addr) == -1)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n"),
+ ACE_TEXT ("open")));
+ ACE_ASSERT (0);
+ }
+ else
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) starting server at port %d\n"),
+ server_addr.get_port_number ()));
+
+#if !defined (ACE_LACKS_FORK)
+ if (spawn_processes (&acceptor,
+ &server_addr) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n"),
+ ACE_TEXT ("spawn_processes")),
+ 1);
+#elif defined (ACE_HAS_THREADS)
+ status = spawn_threads (&acceptor, &server_addr);
+#else /* ACE_LACKS_FORK && ! ACE_HAS_THREADS */
+ ACE_ERROR ((LM_INFO,
+ ACE_TEXT ("(%P|%t) ")
+ ACE_TEXT ("only one thread may be run")
+ ACE_TEXT (" in a process on this platform")));
+#endif /* ACE_LACKS_FORK && ! ACE_HAS_THREADS */
+ }
+
+ ACE_END_TEST;
+ return status;
+}
diff --git a/ACE/tests/Conn_Test.h b/ACE/tests/Conn_Test.h
new file mode 100644
index 00000000000..38e3cda4cd5
--- /dev/null
+++ b/ACE/tests/Conn_Test.h
@@ -0,0 +1,62 @@
+/* -*- C++ -*- */
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Conn_Test.h
+//
+// = DESCRIPTION
+// Define class needed for generating templates. IBM C++ requires this to
+// be in its own file for auto template instantiation.
+//
+// = AUTHOR
+// Irfan Pyarali <irfan@cs.wustl.edu>
+//
+// ============================================================================
+
+#include "ace/Service_Config.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "ace/Null_Condition.h"
+#include "ace/Svc_Handler.h"
+#include "ace/SOCK_Stream.h"
+
+class Svc_Handler : public ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH>
+{
+ // = TITLE
+ // This class is the product created by both <ACE_Connector>
+ // and <ACE_Acceptor> objects.
+ //
+ // = DESCRIPTION
+ // This class gets its own header file to work around AIX C++
+ // compiler "features" related to template instantiation... It is
+ // only used by Conn_Test.cpp.
+public:
+ Svc_Handler (ACE_Thread_Manager * = 0);
+ // Do-nothing constructor.
+
+ virtual int open (void *);
+ // Initialization hook.
+
+ virtual int recycle (void * = 0);
+ // Prepare for recycling.
+
+ void send_data (void);
+ // Send data to server.
+
+ void recv_data (void);
+ // Recv data from client.
+
+ int close (u_long = 0);
+ // Shutdown the <Svc_Handler>.
+
+ int idle (u_long flags);
+ // Set <this> to idle.
+};
diff --git a/ACE/tests/DLL_Test.cpp b/ACE/tests/DLL_Test.cpp
new file mode 100644
index 00000000000..f699d6740d4
--- /dev/null
+++ b/ACE/tests/DLL_Test.cpp
@@ -0,0 +1,188 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// DLL_Test.cpp
+//
+// = DESCRIPTION
+// This test illustrates the use of <ACE_DLL> wrapper class.
+//
+// = AUTHOR
+// Kirthika Parameswaran <kirthika@cs.wustl.edu>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/DLL.h"
+#include "ace/Auto_Ptr.h"
+#include "ace/ACE.h"
+#include "ace/DLL_Manager.h"
+#include "DLL_Test.h"
+
+ACE_RCSID(tests, DLL_Test, "$Id$")
+
+#if defined (ACE_WIN32) && defined (_MSC_VER) && defined (_DEBUG)
+# define OBJ_SUFFIX ACE_TEXT ("d") ACE_DLL_SUFFIX
+#elif defined (ACE_WIN32) && defined (__BORLANDC__)
+# define OBJ_SUFFIX ACE_LD_DECORATOR_STR ACE_DLL_SUFFIX
+#else
+# define OBJ_SUFFIX ACE_DLL_SUFFIX
+#endif /* ACE_WIN32 && && _MSC_VER && _DEBUG */
+
+#if defined (ACE_WIN32) || defined (ACE_OPENVMS)
+# define OBJ_PREFIX ACE_DLL_PREFIX
+#else
+# define OBJ_PREFIX ACE_TEXT("./") ACE_DLL_PREFIX
+#endif /* ACE_WIN32 */
+
+// Declare the type of the symbol:
+typedef Hello *(*Hello_Factory)(void);
+
+typedef int ( *PFN )( Parent* );
+
+int handle_test (ACE_DLL &dll)
+{
+ // Test the get/set_handle methods.
+ ACE_DLL local_dll;
+
+ ACE_SHLIB_HANDLE handle = dll.get_handle (1);
+ if (handle != ACE_SHLIB_INVALID_HANDLE)
+ {
+ if (local_dll.set_handle (handle) != 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("Error setting handle.\n")),
+ -1);
+ return 0;
+ }
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("Error getting handle.\n")),
+ -1);
+}
+
+int basic_test (ACE_DLL &dll)
+{
+#if defined (__KCC)
+ /* With KCC, turning on close-on-destruction will cause problems
+ when libKCC tries to call dtors. */
+ int retval = dll.open (ACE_TEXT (OBJ_PREFIX)
+ ACE_TEXT ("DLL_Test_Lib")
+ ACE_TEXT (OBJ_SUFFIX),
+ ACE_DEFAULT_SHLIB_MODE,
+ 0);
+#else
+ int retval = dll.open (OBJ_PREFIX
+ ACE_TEXT ("DLL_Test_Lib")
+ OBJ_SUFFIX);
+#endif /* __KCC */
+
+ if (retval != 0)
+ {
+ ACE_TCHAR *dll_error = dll.error ();
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("Error in DLL Open: %s\n"),
+ dll_error ? dll_error : ACE_TEXT ("unknown error")),
+ -1);
+ }
+
+ // Just because the ANSI C++ spec says you can no longer cast a
+ // void* to a function pointer. Doesn't allow:
+ // TC f = (Hello_Factory) dll.symbol ("get_hello");
+ void *foo;
+
+ foo = dll.symbol (ACE_TEXT ("get_hello"));
+
+ // Cast the void* to long first.
+ ptrdiff_t tmp = reinterpret_cast<ptrdiff_t> (foo);
+ Hello_Factory factory = reinterpret_cast<Hello_Factory> (tmp);
+ if (factory == 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ dll.error ()),
+ -1);
+
+ auto_ptr<Hello> my_hello (factory ());
+
+ // Make the method calls, as the object pointer is available.
+ my_hello->say_hello ();
+ my_hello->say_next ();
+
+ // Allocate and delete a string allocated via new in a different dll.
+ ACE_TCHAR *new_str = my_hello->new_info ();
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Result for new_info(): %s\n"), new_str));
+ ACE::strdelete (new_str);
+
+ // Allocate and free a string allocated via malloc in a different dll.
+ ACE_TCHAR *malloc_str = my_hello->malloc_info ();
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Result for malloc_info(): %s\n"), malloc_str));
+ ACE_OS::free (malloc_str);
+
+ return 0;
+}
+
+int dynamic_cast_test (ACE_DLL &dll)
+{
+
+#if !defined (ACE_LACKS_RTTI)
+ Child child;
+ child.test();
+
+ Parent *parent = &child;
+
+ void * foo = dll.symbol (ACE_TEXT ("dynamic_cast_test"));
+
+ // Cast the void* to long first.
+ ptrdiff_t tmp = reinterpret_cast<ptrdiff_t> (foo);
+ PFN pfnAcquire = reinterpret_cast<PFN> (tmp);
+ if (pfnAcquire == 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ dll.error ()),
+ -1);
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("before %@ %@\n"),
+ &child, dynamic_cast<Child*> (parent)));
+
+ if (pfnAcquire (&child) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("dynamic_cast failed.\n")), -1);
+#else
+ ACE_UNUSED_ARG (dll);
+#endif /* !ACE_LACKS_RTTI */
+
+ return 0;
+}
+
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("DLL_Test"));
+
+ int retval = 0;
+
+// Protection against this test being run on platforms not supporting Dlls.
+#if defined(ACE_HAS_DYNAMIC_LINKING)
+
+ ACE_DLL dll;
+
+ retval += basic_test (dll);
+
+ retval += dynamic_cast_test (dll);
+
+ retval += handle_test (dll);
+
+ // Call close here so that any errors make it into the log.
+ dll.close ();
+
+#else
+ ACE_ERROR ((LM_INFO,
+ ACE_TEXT ("Dynamically Linkable Libraries not supported on this platform\n")));
+#endif /* ACE_HAS_DYNAMIC_LINKING */
+
+ ACE_END_TEST;
+ return retval == 0 ? 0 : 1;
+}
+
diff --git a/ACE/tests/DLL_Test.h b/ACE/tests/DLL_Test.h
new file mode 100644
index 00000000000..fb55875eff9
--- /dev/null
+++ b/ACE/tests/DLL_Test.h
@@ -0,0 +1,74 @@
+// -*- C++ -*-
+
+// ================================================================
+/**
+ * @file DLL_Test.h
+ *
+ * $Id$
+ *
+ * @author Kirthika Parameswaran <kirthika@cs.wustl.edu>
+ */
+// ================================================================
+
+
+#ifndef ACE_TESTS_DLL_TEST_H
+#define ACE_TESTS_DLL_TEST_H
+
+#include "DLL_Test_Parent.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "ace/Log_Msg.h"
+#include "ace/Trace.h"
+#include "ace/svc_export.h"
+
+/**
+ * @class Hello
+ *
+ * @brief Define the interface used by the DLL_Test
+ */
+class Hello
+{
+public:
+ /// Destructor
+ virtual ~Hello (void)
+ {
+ ACE_TRACE ("Hello::~Hello");
+ }
+
+ /**
+ * @name Methods invoked by the test
+ *
+ * The test invokes four methods, a non-virtual method and a three virtual
+ * methods implemented in the shared library.
+ */
+ //@{
+ void say_hello (void)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Hello\n")));
+ }
+
+ virtual void say_next (void) = 0;
+
+ virtual ACE_TCHAR *new_info (void) = 0;
+
+ virtual ACE_TCHAR *malloc_info (void) = 0;
+ //@}
+};
+
+
+// Used to test dynamic_cast<> in shared libraries.
+class ACE_Svc_Export Child : public Parent
+{
+public:
+
+ virtual ~Child (void);
+
+ virtual void test (void);
+
+};
+
+#endif /* ACE_TESTS_DLL_TEST_H */
diff --git a/ACE/tests/DLL_Test_Impl.cpp b/ACE/tests/DLL_Test_Impl.cpp
new file mode 100644
index 00000000000..4e1af9eb76c
--- /dev/null
+++ b/ACE/tests/DLL_Test_Impl.cpp
@@ -0,0 +1,147 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// DLL_Test.cpp
+//
+// = DESCRIPTION
+// This test illustrates the use of <ACE_DLL> wrapper class.
+//
+// = AUTHOR
+// Kirthika Parameswaran <kirthika@cs.wustl.edu>
+//
+// ============================================================================
+
+#include "DLL_Test_Impl.h"
+#include "ace/ACE.h"
+#include "ace/OS_Errno.h"
+#include "ace/svc_export.h"
+#include "ace/OS_NS_string.h"
+
+ACE_RCSID (tests,
+ DLL_Test_Impl,
+ "$Id$")
+
+Hello_Impl::Hello_Impl (void)
+{
+ ACE_DEBUG ((LM_DEBUG, "Hello_Impl::Hello_Impl\n"));
+}
+
+Hello_Impl::~Hello_Impl (void)
+{
+ ACE_DEBUG ((LM_DEBUG, "Hello_Impl::~Hello_Impl\n"));
+}
+
+void
+Hello_Impl::say_next (void)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("How are you?\n")));
+}
+
+ACE_TCHAR *
+Hello_Impl::new_info (void)
+{
+ return ACE::strnew (ACE_TEXT ("Hello_Impl::new_info() allocated by ACE::strnew()"));
+}
+
+ACE_TCHAR *
+Hello_Impl::malloc_info (void)
+{
+ return ACE_OS::strdup (ACE_TEXT ("Hello_Impl::new_info() allocated by ACE_OS::malloc()"));
+}
+
+void *
+Hello_Impl::operator new (size_t bytes)
+{
+ ACE_DEBUG ((LM_INFO, "Hello_Impl::new\n"));
+ return ::new char[bytes];
+}
+
+#if defined (ACE_HAS_NEW_NOTHROW)
+ /// Overloaded new operator, nothrow_t variant.
+void *
+Hello_Impl::operator new (size_t bytes, const ACE_nothrow_t &nt)
+{
+ ACE_DEBUG ((LM_INFO, "Hello_Impl::new\n"));
+ return ::new (nt) char[bytes];
+}
+
+#if !defined (ACE_LACKS_PLACEMENT_OPERATOR_DELETE)
+void
+Hello_Impl::operator delete (void *ptr, const ACE_nothrow_t&) throw ()
+{
+ ACE_DEBUG ((LM_INFO, "Hello_Impl::delete\n"));
+ ::delete [] static_cast<char *> (ptr);
+}
+#endif /* ACE_LACKS_PLACEMENT_OPERATOR_DELETE */
+
+#endif /* ACE_HAS_NEW_NOTHROW */
+
+void
+Hello_Impl::operator delete (void *ptr)
+{
+ ACE_DEBUG ((LM_INFO, "Hello_Impl::delete\n"));
+ ::delete [] static_cast<char *> (ptr);
+}
+
+extern "C" ACE_Svc_Export Hello *
+get_hello (void)
+{
+ Hello *hello = 0;
+
+ ACE_NEW_RETURN (hello,
+ Hello_Impl,
+ 0);
+
+ return hello;
+}
+
+class Static_Constructor_Test
+{
+public:
+ Static_Constructor_Test (void)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ "Static_Constructor_Test::Static_Constructor_Test\n"));
+ }
+ ~Static_Constructor_Test (void)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ "Static_Constructor_Test::~Static_Constructor_Test\n"));
+ }
+};
+
+static Static_Constructor_Test the_instance;
+
+// --------------------------------------------------------
+
+Child::~Child (void)
+{
+}
+
+void
+Child::test (void)
+{
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("child called\n")));
+}
+
+// --------------------------------------------------------
+
+
+#if !defined (ACE_LACKS_RTTI)
+// Test dynamic cast
+extern "C" ACE_Svc_Export int
+dynamic_cast_test (Parent *target)
+{
+ Child *c = 0;
+ c = dynamic_cast<Child*> (target);
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("dynamic_cast_test: parent %@; child %@\n"),
+ target, c));
+ return target == c ? 0 : -1;
+}
+#endif /* !ACE_LACKS_RTTI */
diff --git a/ACE/tests/DLL_Test_Impl.h b/ACE/tests/DLL_Test_Impl.h
new file mode 100644
index 00000000000..9ef3fb887a8
--- /dev/null
+++ b/ACE/tests/DLL_Test_Impl.h
@@ -0,0 +1,68 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// DLL_Test_Impl.h
+//
+// = AUTHOR
+// Kirthika Parameswaran <kirthika@cs.wustl.edu>
+//
+// ============================================================================
+
+#ifndef ACE_TESTS_DLL_TEST_IMPL_H
+#define ACE_TESTS_DLL_TEST_IMPL_H
+
+#include "DLL_Test.h"
+#include "ace/OS_Memory.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+class Hello_Impl : public Hello
+{
+ // = TITLE
+ // The Hello class in the dynamically linkable library.
+ //
+ // = DESCRIPTION
+ // This class is used in this example to show how a library can
+ // be loaded on demand and its methods called on getting the
+ // symbols from the library.
+public:
+ Hello_Impl (void);
+ // Constructor
+
+ ~Hello_Impl (void);
+ // Destructor
+
+ void say_next (void);
+ // See the documentation in the base class
+
+ ACE_TCHAR *new_info (void);
+ // Uses ACE::strnew() to allocate the returned string.
+
+ ACE_TCHAR *malloc_info (void);
+ // Uses ACE_OS::malloc() to allocate the returned string.
+
+ // Overload the new/delete opertors so the object will be
+ // created/deleted using the memory allocator associated with the
+ // DLL/SO.
+ void *operator new (size_t bytes);
+
+#if defined (ACE_HAS_NEW_NOTHROW)
+ /// Overloaded new operator, nothrow_t variant.
+ void *operator new (size_t bytes, const ACE_nothrow_t &nt);
+#if !defined (ACE_LACKS_PLACEMENT_OPERATOR_DELETE)
+ void operator delete (void *p, const ACE_nothrow_t&) throw ();
+#endif /* ACE_LACKS_PLACEMENT_OPERATOR_DELETE */
+#endif /* ACE_HAS_NEW_NOTHROW */
+
+ void operator delete (void *ptr);
+
+};
+
+#endif /* ACE_TESTS_DLL_TEST_IMPL_H */
diff --git a/ACE/tests/DLL_Test_Parent.cpp b/ACE/tests/DLL_Test_Parent.cpp
new file mode 100644
index 00000000000..0664f5a7c92
--- /dev/null
+++ b/ACE/tests/DLL_Test_Parent.cpp
@@ -0,0 +1,19 @@
+// $Id$
+
+#include "DLL_Test_Parent.h"
+#include "ace/Log_Msg.h"
+
+ACE_RCSID (tests,
+ DLL_Test_Parent,
+ "$Id$")
+
+
+Parent::~Parent (void)
+{
+}
+
+void
+Parent::test (void)
+{
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("parent called\n")));
+}
diff --git a/ACE/tests/DLL_Test_Parent.h b/ACE/tests/DLL_Test_Parent.h
new file mode 100644
index 00000000000..3046dad48d4
--- /dev/null
+++ b/ACE/tests/DLL_Test_Parent.h
@@ -0,0 +1,34 @@
+// -*- C++ -*-
+
+// ================================================================
+/**
+ * @file DLL_Test_Parent.h
+ *
+ * $Id$
+ *
+ * @author Kirthika Parameswaran <kirthika@cs.wustl.edu>
+ * @author Ossama Othman <ossama@dre.vanderbilt.edu>
+ */
+// ================================================================
+
+#ifndef ACE_TESTS_DLL_TEST_PARENT_H
+#define ACE_TESTS_DLL_TEST_PARENT_H
+
+#include "DLL_Test_Parent_Export.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+
+class DLL_Test_Parent_Export Parent
+{
+public:
+
+ virtual ~Parent (void);
+
+ virtual void test (void);
+
+};
+
+#endif /* ACE_TESTS_DLL_TEST_PARENT_H */
diff --git a/ACE/tests/DLL_Test_Parent_Export.h b/ACE/tests/DLL_Test_Parent_Export.h
new file mode 100644
index 00000000000..226d40f5097
--- /dev/null
+++ b/ACE/tests/DLL_Test_Parent_Export.h
@@ -0,0 +1,58 @@
+
+// -*- C++ -*-
+// $Id$
+// Definition for Win32 Export directives.
+// This file is generated automatically by generate_export_file.pl -s DLL_Test_Parent
+// ------------------------------
+#ifndef DLL_TEST_PARENT_EXPORT_H
+#define DLL_TEST_PARENT_EXPORT_H
+
+#include "ace/config-all.h"
+
+#if defined (ACE_AS_STATIC_LIBS) && !defined (DLL_TEST_PARENT_HAS_DLL)
+# define DLL_TEST_PARENT_HAS_DLL 0
+#endif /* ACE_AS_STATIC_LIBS && DLL_TEST_PARENT_HAS_DLL */
+
+#if !defined (DLL_TEST_PARENT_HAS_DLL)
+# define DLL_TEST_PARENT_HAS_DLL 1
+#endif /* ! DLL_TEST_PARENT_HAS_DLL */
+
+#if defined (DLL_TEST_PARENT_HAS_DLL) && (DLL_TEST_PARENT_HAS_DLL == 1)
+# if defined (DLL_TEST_PARENT_BUILD_DLL)
+# define DLL_Test_Parent_Export ACE_Proper_Export_Flag
+# define DLL_TEST_PARENT_SINGLETON_DECLARATION(T) ACE_EXPORT_SINGLETON_DECLARATION (T)
+# define DLL_TEST_PARENT_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) ACE_EXPORT_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK)
+# else /* DLL_TEST_PARENT_BUILD_DLL */
+# define DLL_Test_Parent_Export ACE_Proper_Import_Flag
+# define DLL_TEST_PARENT_SINGLETON_DECLARATION(T) ACE_IMPORT_SINGLETON_DECLARATION (T)
+# define DLL_TEST_PARENT_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) ACE_IMPORT_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK)
+# endif /* DLL_TEST_PARENT_BUILD_DLL */
+#else /* DLL_TEST_PARENT_HAS_DLL == 1 */
+# define DLL_Test_Parent_Export
+# define DLL_TEST_PARENT_SINGLETON_DECLARATION(T)
+# define DLL_TEST_PARENT_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK)
+#endif /* DLL_TEST_PARENT_HAS_DLL == 1 */
+
+// Set DLL_TEST_PARENT_NTRACE = 0 to turn on library specific tracing even if
+// tracing is turned off for ACE.
+#if !defined (DLL_TEST_PARENT_NTRACE)
+# if (ACE_NTRACE == 1)
+# define DLL_TEST_PARENT_NTRACE 1
+# else /* (ACE_NTRACE == 1) */
+# define DLL_TEST_PARENT_NTRACE 0
+# endif /* (ACE_NTRACE == 1) */
+#endif /* !DLL_TEST_PARENT_NTRACE */
+
+#if (DLL_TEST_PARENT_NTRACE == 1)
+# define DLL_TEST_PARENT_TRACE(X)
+#else /* (DLL_TEST_PARENT_NTRACE == 1) */
+# if !defined (ACE_HAS_TRACE)
+# define ACE_HAS_TRACE
+# endif /* ACE_HAS_TRACE */
+# define DLL_TEST_PARENT_TRACE(X) ACE_TRACE_IMPL(X)
+# include "ace/Trace.h"
+#endif /* (DLL_TEST_PARENT_NTRACE == 1) */
+
+#endif /* DLL_TEST_PARENT_EXPORT_H */
+
+// End of auto generated file.
diff --git a/ACE/tests/DLList_Test.cpp b/ACE/tests/DLList_Test.cpp
new file mode 100644
index 00000000000..57155d177ab
--- /dev/null
+++ b/ACE/tests/DLList_Test.cpp
@@ -0,0 +1,129 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// DLList_Test.cpp
+//
+// = DESCRIPTION
+// This test illustrates the use of <ACE_DLList>.
+//
+// = AUTHOR
+// James Hu <jxh@cs.wustl.edu> and Douglas C. Schmidt <schmidt@cs.wustl.edu>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/Containers.h"
+#include "ace/SString.h"
+#include "ace/Malloc_T.h"
+
+typedef ACE_TCHAR *ACE_STRING;
+typedef ACE_DLList<ACE_STRING> STRLIST;
+typedef ACE_DLList_Iterator<ACE_STRING> STRLIST_ITERATOR;
+typedef ACE_DLList_Reverse_Iterator<ACE_STRING> STRLIST_REVERSE_ITERATOR;
+
+static ACE_STRING string_table[] =
+{
+ // Note: all these casts are to appease SC 5.0 which is not pleased
+ // with using string literals (i.e. const char *'s) as char
+ // *'s. It's ugly, but necessary.
+ const_cast<ACE_TCHAR *> (ACE_TEXT ("hello")),
+ const_cast<ACE_TCHAR *> (ACE_TEXT ("guten Tag")),
+ const_cast<ACE_TCHAR *> (ACE_TEXT ("goodbye")),
+ const_cast<ACE_TCHAR *> (ACE_TEXT ("auf wiedersehen")),
+ const_cast<ACE_TCHAR *> (ACE_TEXT ("funny")),
+ const_cast<ACE_TCHAR *> (ACE_TEXT ("lustig")),
+ 0
+};
+
+static void
+run_iterate (STRLIST &list)
+{
+ ACE_STRING *entry;
+ size_t i = 0;
+
+ for (STRLIST_ITERATOR iter (list);
+ (entry = iter.next ()) != 0;
+ iter.advance (), i++)
+ {
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("iterating (%d): [%s]\n"),
+ i,
+ (ACE_TCHAR *) *entry));
+ }
+}
+
+static void
+run_reverse_iterate (STRLIST &list)
+{
+ ACE_STRING *entry;
+ size_t i = 0;
+
+ for (STRLIST_REVERSE_ITERATOR iter (list);
+ iter.next (entry) != 0;
+ iter.advance (), i++)
+ {
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("iterating (%d): [%s]\n"),
+ i,
+ (ACE_TCHAR *) *entry));
+ }
+}
+
+static int
+run_test (void)
+{
+ STRLIST list;
+
+ size_t i;
+
+ for (i = 0; string_table[i] != 0; i++)
+ {
+ if (ACE_EVEN (i)
+ && list.insert_tail ((ACE_STRING *) &string_table[i]) == 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p failed for %s \n"),
+ ACE_TEXT ("insert"),
+ string_table[i]),
+ -1);
+ else if (list.insert_head ((ACE_STRING *) &string_table[i]) == 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p failed for %s \n"),
+ ACE_TEXT ("insert"),
+ string_table[i]),
+ -1);
+ run_iterate (list);
+ run_reverse_iterate (list);
+ }
+
+ run_iterate (list);
+ run_reverse_iterate (list);
+
+ list.delete_tail ();
+ list.delete_tail ();
+
+ run_iterate (list);
+ run_reverse_iterate (list);
+
+ list.delete_head ();
+ list.delete_head ();
+
+ run_iterate (list);
+ run_reverse_iterate (list);
+
+ return 0;
+}
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("DLList_Test"));
+
+ run_test ();
+
+ ACE_END_TEST;
+
+ return 0;
+}
diff --git a/ACE/tests/Date_Time_Test.cpp b/ACE/tests/Date_Time_Test.cpp
new file mode 100644
index 00000000000..ac50bea608f
--- /dev/null
+++ b/ACE/tests/Date_Time_Test.cpp
@@ -0,0 +1,128 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = DESCRIPTION
+// This program verifies the ACE_Date_Time class.
+//
+// = AUTHOR
+// Steve Huston <shuston@riverace.com>
+//
+// ============================================================================
+
+#include "ace/Date_Time.h"
+#include "test_config.h"
+
+ACE_RCSID(tests, Date_Time_Test, "$Id$")
+
+static ACE_Date_Time static_dt; // Making sure it doesn't crash.
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("Date_Time_Test"));
+
+ int error = 0;
+
+ ACE_Date_Time dt;
+
+ long month = dt.month ();
+ long day = dt.day ();
+ long year = dt.year ();
+ long hour = dt.hour ();
+ long minute = dt.minute ();
+ long seconds = dt.second ();
+ long usec = dt.microsec ();
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("ACE_Date_Time (m/d/y, h:m:s.u): %d/%d/%d, %d:%d:%d.%d\n"),
+ month, day, year, hour, minute, seconds, usec));
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("ACE_Log thinks it is: %D\n")));
+
+ if (month < 1 || month > 12)
+ {
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("Month (%d) out of range (1-12)\n"),
+ month));
+ error = 1;
+ }
+ if (day < 1 || day > 31)
+ {
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("Day (%d) out of range (1-31)\n"),
+ day));
+ error = 1;
+ }
+ if (year < 1900 || year > 2100)
+ {
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("Year (%d) out of range (1900-2100)\n"),
+ year));
+ error = 1;
+ }
+ if (hour < 0 || hour > 23)
+ {
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("Hour (%d) out of range (0-23)\n"),
+ hour));
+ error = 1;
+ }
+ if (minute < 0 || minute > 59)
+ {
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("Minute (%d) out of range (0-59)\n"),
+ minute));
+ error = 1;
+ }
+ if (seconds < 0 || seconds > 59)
+ {
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("Seconds (%d) out of range (0-59)\n"),
+ seconds));
+ error = 1;
+ }
+ if (usec < 0 || usec > 999999)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Microseconds (%d) out of range (0-999999)\n"),
+ usec));
+ error = 1;
+ }
+
+ // The static ACE_Date_Time object is primarily to be sure it doesn't
+ // crash; However, let's do some sanity checks on it to be sure it's
+ // legit as well.
+ if (static_dt.month () != month)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Static month (%d) doesn't match %d\n"),
+ static_dt.month (), month));
+ error = 1;
+ }
+ if (static_dt.day () != day)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Static day (%d) doesn't match %d\n"),
+ static_dt.day (), day));
+ error = 1;
+ }
+ if (static_dt.year () != year)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Static year (%d) doesn't match %d\n"),
+ static_dt.year (), year));
+ error = 1;
+ }
+ if (static_dt.hour () != hour)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Static hour (%d) doesn't match %d\n"),
+ static_dt.hour (), hour));
+ error = 1;
+ }
+ if (static_dt.minute () != minute)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Static minute (%d) doesn't match %d\n"),
+ static_dt.minute (), minute));
+ error = 1;
+ }
+ ACE_END_TEST;
+ return error;
+}
diff --git a/ACE/tests/Dev_Poll_Reactor_Test.cpp b/ACE/tests/Dev_Poll_Reactor_Test.cpp
new file mode 100644
index 00000000000..66ed41cad00
--- /dev/null
+++ b/ACE/tests/Dev_Poll_Reactor_Test.cpp
@@ -0,0 +1,596 @@
+//=============================================================================
+/**
+ * @file Dev_Poll_Reactor_Test.cpp
+ *
+ * $Id$
+ *
+ * This test verifies that the Dev_Poll_Reactor is functioning
+ * properly, and demonstrates how "speculative reads" can be
+ * performed. "Speculative reads" are necessary when using event
+ * demultiplexing mechanisms that use a "state change" interface.
+ * Similarly, "speculative writes" may be necessary, i.e. keep
+ * writing until the connection is flow controlled. An example of a
+ * demuxing mechanism with such an interface is Linux's `/dev/epoll'
+ * character device. Mechansims with state change interfaces are
+ * also said to be "edge triggered," versus "level triggered"
+ * mechanisms such as select().
+ *
+ * @author Ossama Othman <ossama@dre.vanderbilt.edu>
+ */
+//=============================================================================
+
+#include "test_config.h"
+
+ACE_RCSID (tests,
+ Dev_Poll_Reactor_Test,
+ "$Id$")
+
+
+#if defined (ACE_HAS_DEV_POLL) || defined (ACE_HAS_EVENT_POLL)
+
+#include "ace/OS_NS_signal.h"
+#include "ace/Reactor.h"
+#include "ace/Dev_Poll_Reactor.h"
+
+#include "ace/Acceptor.h"
+#include "ace/Connector.h"
+
+#include "ace/SOCK_Acceptor.h"
+#include "ace/SOCK_Connector.h"
+#include "ace/SOCK_Stream.h"
+
+#include "ace/OS_NS_unistd.h"
+#include "ace/OS_NS_netdb.h"
+
+
+typedef ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH> SVC_HANDLER;
+
+// ----------------------------------------------------
+
+class Client : public SVC_HANDLER
+{
+public:
+
+ Client (void);
+
+ virtual int open (void * = 0);
+
+ virtual int handle_output (ACE_HANDLE handle);
+
+ virtual int handle_timeout (const ACE_Time_Value &current_time,
+ const void *act);
+
+ virtual int handle_close (ACE_HANDLE handle,
+ ACE_Reactor_Mask mask);
+
+private:
+
+ unsigned int call_count_;
+
+};
+
+
+class Server : public SVC_HANDLER
+{
+public:
+
+ Server (void);
+
+ virtual int handle_input (ACE_HANDLE handle);
+
+ virtual int handle_timeout (const ACE_Time_Value &current_time,
+ const void *act);
+
+ virtual int handle_close (ACE_HANDLE handle,
+ ACE_Reactor_Mask mask);
+
+private:
+
+ unsigned int call_count_;
+
+};
+
+// ----------------------------------------------------
+
+Client::Client (void)
+ : call_count_ (0)
+{
+}
+
+int
+Client::open (void *)
+{
+ // ACE_ASSERT (this->reactor () != 0);
+
+ if (this->reactor ()
+ && this->reactor ()->register_handler (
+ this,
+ ACE_Event_Handler::WRITE_MASK) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%t) %p\n"),
+ ACE_TEXT ("unable to register client handler")),
+ -1);
+
+ return 0;
+}
+
+int
+Client::handle_output (ACE_HANDLE)
+{
+ for (int i = 1; i <= 5; ++i)
+ {
+ char buffer[BUFSIZ] = { 0 };
+
+ ACE_OS::sprintf (buffer, "test message %d.\n", i);
+
+ ssize_t bytes_sent =
+ this->peer ().send (buffer, ACE_OS::strlen (buffer));
+
+ if (bytes_sent == -1)
+ {
+ if (errno == EWOULDBLOCK)
+ return 0; // Flow control kicked in.
+ else if (errno == EPIPE)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Client::handle_output; server ")
+ ACE_TEXT ("closed handle %d\n"),
+ this->peer ().get_handle ()));
+ return -1;
+ }
+ else
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%t) %p\n"),
+ ACE_TEXT ("Client::handle_output")),
+ -1);
+ }
+ else if (bytes_sent == 0)
+ return -1;
+ else
+ ACE_DEBUG ((LM_INFO, ACE_TEXT ("(%t) Sent %s"), buffer));
+ }
+
+ return 0;
+}
+
+int
+Client::handle_timeout (const ACE_Time_Value &, const void *)
+{
+ ACE_DEBUG ((LM_INFO,
+ ACE_TEXT ("(%t) Expected client timeout occured at: %T\n")));
+
+ this->call_count_++;
+
+ int status = this->handle_output (this->get_handle ());
+ if (status == -1 || this->call_count_ > 10)
+ {
+ if (this->reactor ()->end_reactor_event_loop () == 0)
+ ACE_DEBUG ((LM_INFO,
+ ACE_TEXT ("(%t) Successful client reactor shutdown.\n")));
+ else
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%t) %p\n"),
+ ACE_TEXT ("Failed client reactor shutdown")));
+
+ // Force this service handler to be closed in either case.
+ return -1;
+ }
+
+ return 0;
+}
+
+int
+Client::handle_close (ACE_HANDLE handle,
+ ACE_Reactor_Mask mask)
+{
+ ACE_DEBUG ((LM_INFO,
+ ACE_TEXT ("(%t) Client Svc_Handler closed ")
+ ACE_TEXT ("handle <%d> with reactor mask <0x%x>.\n"),
+ handle,
+ mask));
+
+ return 0;
+}
+
+// ----------------------------------------------------
+
+Server::Server (void)
+ : call_count_ (0)
+{
+}
+
+int
+Server::handle_input (ACE_HANDLE /* handle */)
+{
+ char buffer[BUFSIZ+1] = { 0 }; // Insure a trailing nul
+ ssize_t bytes_read = 0;
+
+ char * const begin = buffer;
+ char * const end = buffer + BUFSIZ;
+
+ for (char * buf = begin; buf < end; buf += bytes_read)
+ {
+ // Keep reading until it is no longer possible to do so.
+ //
+ // This is done since the underlying event demultiplexing
+ // mechanism may have a "state change" interface (as opposed to
+ // "state monitoring"), in which case a "speculative" read is
+ // done.
+ bytes_read = this->peer ().recv (buf, end - buf);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("****** bytes_read = %d\n"),
+ bytes_read));
+
+ if (bytes_read == -1)
+ {
+ if (errno == EWOULDBLOCK)
+ {
+
+// ACE_HEX_DUMP ((LM_DEBUG,
+// buf,
+// 80,
+// "BUFFER CONTENTS"));
+ if (buf == buffer)
+ return 0;
+ else
+ break;
+ }
+ else
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%t) %p\n"),
+ ACE_TEXT ("Server::handle_input")),
+ -1);
+ }
+ else if (bytes_read == 0)
+ return -1;
+ }
+
+ ACE_DEBUG ((LM_INFO, ACE_TEXT ("(%t) Message received: %s\n"), buffer));
+
+ return 0;
+}
+
+int
+Server::handle_timeout (const ACE_Time_Value &,
+ const void *)
+{
+ ACE_DEBUG ((LM_INFO,
+ ACE_TEXT ("(%t) Expected server timeout occured at: %T\n")));
+
+// if (this->call_count_ == 0
+// && this->handle_input (this->get_handle ()) != 0
+// && errno != EWOULDBLOCK)
+// return -1;
+
+// ACE_DEBUG ((LM_INFO,
+// "SERVER HANDLE = %d\n",
+// this->get_handle ()));
+
+
+ this->call_count_++;
+
+ if (this->call_count_ > 10)
+ {
+ if (this->reactor ()->end_reactor_event_loop () == 0)
+ ACE_DEBUG ((LM_INFO,
+ ACE_TEXT ("(%t) Successful server reactor shutdown.\n")));
+ else
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%t) %p\n"),
+ ACE_TEXT ("Failed server reactor shutdown")));
+
+ // Force this service handler to be closed in either case.
+ return -1;
+ }
+
+ return 0;
+}
+
+int
+Server::handle_close (ACE_HANDLE handle,
+ ACE_Reactor_Mask mask)
+{
+ if (this->call_count_ > 4)
+ {
+ ACE_DEBUG ((LM_INFO,
+ ACE_TEXT ("(%t) Server Svc_Handler closing ")
+ ACE_TEXT ("handle <%d,%d> with reactor mask <0x%x>.\n"),
+ handle,
+ this->get_handle (),
+ mask));
+
+ return this->peer ().close ();
+ }
+
+ return 0;
+}
+
+// ----------------------------------------------------
+
+typedef ACE_Acceptor<Server, ACE_SOCK_ACCEPTOR> ACCEPTOR;
+typedef ACE_Connector<Client, ACE_SOCK_CONNECTOR> CONNECTOR;
+
+// ----------------------------------------------------
+
+class TestAcceptor : public ACCEPTOR
+{
+public:
+
+ virtual int accept_svc_handler (Server * handler)
+ {
+ int result = this->ACCEPTOR::accept_svc_handler (handler);
+
+ if (result != 0)
+ {
+ if (errno != EWOULDBLOCK)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%t) %p\n"),
+ ACE_TEXT ("Unable to accept connection")));
+
+ return result;
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Accepted connection. ")
+ ACE_TEXT ("Stream handle: <%d>\n"),
+ handler->get_handle ()));
+
+// if (handler->handle_input (handler->get_handle ()) == -1
+// && errno != EWOULDBLOCK)
+// return -1;
+
+// #if 0
+ ACE_Time_Value delay (2, 0);
+ ACE_Time_Value restart (2, 0);
+ if (handler->reactor ()->schedule_timer (handler,
+ 0,
+ delay,
+ restart) == -1)
+ {
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%t) %p\n"),
+ ACE_TEXT ("Unable to schedule server side ")
+ ACE_TEXT ("timer in ACE_Dev_Poll_Reactor")),
+ -1);
+ }
+// #endif /* 0 */
+
+ return result;
+ }
+
+};
+
+// ----------------------------------------------------
+
+class TestConnector : public CONNECTOR
+{
+public:
+
+ virtual int connect_svc_handler (
+ CONNECTOR::handler_type *& handler,
+ const CONNECTOR::addr_type &remote_addr,
+ ACE_Time_Value *timeout,
+ const CONNECTOR::addr_type &local_addr,
+ int reuse_addr,
+ int flags,
+ int perms)
+ {
+ const int result = this->CONNECTOR::connect_svc_handler (handler,
+ remote_addr,
+ timeout,
+ local_addr,
+ reuse_addr,
+ flags,
+ perms);
+
+ if (result != 0)
+ return result;
+
+ ACE_TCHAR hostname[MAXHOSTNAMELEN];
+ if (remote_addr.get_host_name (hostname,
+ sizeof (hostname)) != 0)
+ {
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%t) %p\n"),
+ ACE_TEXT ("Unable to retrieve hostname")),
+ -1);
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Connected to <%s:%d>.\n"),
+ hostname,
+ (int) remote_addr.get_port_number ()));
+
+// #if 0
+ ACE_Time_Value delay (4, 0);
+ ACE_Time_Value restart (3, 0);
+ if (handler->reactor ()->schedule_timer (handler,
+ 0,
+ delay,
+ restart) == -1)
+ {
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%t) %p\n"),
+ ACE_TEXT ("Unable to schedule client side ")
+ ACE_TEXT ("timer in ACE_Dev_Poll_Reactor")),
+ -1);
+ }
+// #endif /* 0 */
+
+ return result;
+ }
+
+ virtual int connect_svc_handler (
+ CONNECTOR::handler_type *& handler,
+ CONNECTOR::handler_type *& sh_copy,
+ const CONNECTOR::addr_type &remote_addr,
+ ACE_Time_Value *timeout,
+ const CONNECTOR::addr_type &local_addr,
+ int reuse_addr,
+ int flags,
+ int perms) {
+ sh_copy = handler;
+ return this->connect_svc_handler (handler, remote_addr, timeout,
+ local_addr, reuse_addr, flags,
+ perms);
+ }
+};
+
+// ----------------------------------------------------
+
+ACE_THR_FUNC_RETURN
+server_worker (void *p)
+{
+ const unsigned short port = *(static_cast<unsigned short *> (p));
+
+ ACE_INET_Addr addr;
+
+ if (addr.set (port, INADDR_LOOPBACK) != 0)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%t) %p\n"),
+ ACE_TEXT ("server_worker - ACE_INET_Addr::set")));
+
+ return (void *) -1;
+ }
+
+ ACE_Dev_Poll_Reactor dp_reactor;
+ dp_reactor.restart (1); // Restart on EINTR
+ ACE_Reactor reactor (&dp_reactor);
+
+ TestAcceptor server;
+
+ int flags = 0;
+ ACE_SET_BITS (flags, ACE_NONBLOCK); // Enable non-blocking in the
+ // Svc_Handlers.
+
+ if (server.open (addr, &reactor, flags) != 0)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%t) %p\n"),
+ ACE_TEXT ("Unable to open server service handler")));
+
+ return (void *) -1;
+ }
+
+ if (reactor.run_reactor_event_loop () != 0)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%t) %p\n"),
+ ACE_TEXT ("Error when running server ")
+ ACE_TEXT ("reactor event loop")));
+
+ return (void *) -1;
+ }
+
+ ACE_DEBUG ((LM_INFO,
+ ACE_TEXT ("(%t) Reactor event loop finished ")
+ ACE_TEXT ("successfully.\n")));
+
+ return 0;
+}
+
+// ----------------------------------------------------
+
+// struct server_arg
+// {
+// unsigned short port;
+
+// ACE_Condition<ACE_SYNCH_MUTEX> * cv;
+// };
+
+// ----------------------------------------------------
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("Dev_Poll_Reactor_Test"));
+
+ // Make sure we ignore SIGPIPE
+ sigset_t sigsetNew[1];
+ sigset_t sigsetOld[1];
+ ACE_OS::sigemptyset (sigsetNew);
+ ACE_OS::sigaddset (sigsetNew, SIGPIPE);
+ ACE_OS::sigprocmask (SIG_BLOCK, sigsetNew, sigsetOld);
+
+ ACE_Dev_Poll_Reactor dp_reactor;
+ dp_reactor.restart (1); // Restart on EINTR
+ ACE_Reactor reactor (&dp_reactor);
+
+ TestConnector client;
+
+ int flags = 0;
+ ACE_SET_BITS (flags, ACE_NONBLOCK); // Enable non-blocking in the
+ // Svc_Handlers.
+
+ if (client.open (&reactor, flags) != 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%t) %p\n"),
+ ACE_TEXT ("Unable to open client service handler")),
+ -1);
+
+// ACE_SYNCH_MUTEX mutex;
+// ACE_Condition<ACE_SYNCH_MUTEX> cv (mutex);
+
+// server_arg arg;
+// arg.port = 54678; // Port the server will listen on.
+// arg.cv = &cv;
+
+ unsigned short port = 54678;
+
+ if (ACE_Thread_Manager::instance ()->spawn (server_worker, &port) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%t) %p\n"),
+ ACE_TEXT ("Unable to spawn server thread")),
+ -1);
+
+ ACE_OS::sleep (5); // Wait for the listening endpoint to be set up.
+
+ ACE_INET_Addr addr;
+ if (addr.set (port, INADDR_LOOPBACK) != 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%t) %p\n"),
+ ACE_TEXT ("ACE_INET_Addr::set")),
+ -1);
+
+ Client *client_handler = 0;
+
+ if (client.connect (client_handler, addr) != 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%t) %p\n"),
+ ACE_TEXT ("Unable to connect to server")),
+ -1);
+
+ if (reactor.run_reactor_event_loop () != 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%t) %p\n"),
+ ACE_TEXT ("Error when running client ")
+ ACE_TEXT ("reactor event loop")),
+ -1);
+
+ if (ACE_Thread_Manager::instance ()->wait () != 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%t) %p\n"),
+ ACE_TEXT ("Error waiting for threads to complete")),
+ -1);
+
+ ACE_END_TEST;
+
+ return 0;
+}
+
+#else
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("Dev_Poll_Reactor_Test"));
+ ACE_ERROR ((LM_INFO,
+ ACE_TEXT ("Dev Poll and Event Poll are not supported ")
+ ACE_TEXT ("on this platform\n")));
+ ACE_END_TEST;
+ return 0;
+}
+
+#endif /* ACE_HAS_DEV_POLL || ACE_HAS_EVENT_POLL */
diff --git a/ACE/tests/Dirent_Test.cpp b/ACE/tests/Dirent_Test.cpp
new file mode 100644
index 00000000000..eaf2dbfd9c2
--- /dev/null
+++ b/ACE/tests/Dirent_Test.cpp
@@ -0,0 +1,336 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Dirent_Test.cpp
+//
+// = DESCRIPTION
+// This is a test of the opendir and readdir emulation provided by the
+// class ACE_Dirent. It is used to ensure that the emulation code
+// works properly on platforms that don't support this capability
+// natively. As the emulation code is not compiled in other
+// platforms, this test also ensures that there is no impact to
+// platforms that natively support directory scanning operations.
+//
+// = AUTHOR
+// Phil Mesnier <mesnier_p@ociweb.com>,
+// Zvika Ashani <zvika@aspectusvi.com>,
+// Rich Newman <RNewman@directv.com>, and
+// Douglas C. Schmidt <d.schmidt@vanderbilt.edu>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/Dirent.h"
+#include "ace/Dirent_Selector.h"
+#include "ace/OS_NS_sys_stat.h"
+#include "ace/OS_NS_unistd.h"
+#include "ace/OS_String.h"
+
+
+ACE_RCSID (tests,
+ Dirent_Test,
+ "$Id Dirent_Test.cpp,v 4.10 2003/05/18 19:17:34 dhinton Exp$")
+
+
+#if (defined (ACE_VXWORKS) && (ACE_VXWORKS < 0x600))
+#define TEST_DIR "log"
+#define DIR_DOT "."
+#define DIR_DOT_DOT ".."
+#define TEST_ENTRY ".."
+#else
+# define TEST_DIR "../tests"
+# if defined (ACE_LACKS_STRUCT_DIR) || !defined (ACE_HAS_SCANDIR)
+# define DIR_DOT ACE_TEXT (".")
+# define DIR_DOT_DOT ACE_TEXT ("..")
+# define TEST_ENTRY ACE_TEXT ("run_test.lst")
+# else
+# define DIR_DOT "."
+# define DIR_DOT_DOT ".."
+# define TEST_ENTRY "run_test.lst"
+# endif /* ACE_LACKS_STRUCT_DIR */
+#endif /* ACE_VXWORKS < 0x600 */
+
+static const int RECURSION_INDENT = 3;
+
+// Number of entries in the directory.
+static int entrycount = 0;
+
+extern "C" {
+
+static int
+selector (const ACE_DIRENT *d)
+{
+ return ACE_OS::strcmp (d->d_name, TEST_ENTRY) == 0;
+}
+
+static int
+comparator (const ACE_DIRENT **d1, const ACE_DIRENT **d2)
+{
+ return ACE_OS::strcmp ((*d1)->d_name, (*d2)->d_name);
+}
+
+} /* extern "C" */
+
+static int
+dirent_selector_test (void)
+{
+ int status;
+ int n;
+
+ ACE_Dirent_Selector sds;
+
+ // Pass in functions that'll specify the selection criteria.
+ status = sds.open (ACE_TEXT (TEST_DIR), selector, comparator);
+ ACE_ASSERT (status != -1);
+
+ // We should only have located ourselves!
+ ACE_ASSERT (sds.length () == 1);
+
+ for (n = 0; n < sds.length (); ++n)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Sorted: %d: %C\n"),
+ n,
+ sds[n]->d_name));
+
+ status = sds.close ();
+ ACE_ASSERT (status != -1);
+
+ ACE_Dirent_Selector ds;
+
+ // Don't specify any selection criteria.
+ status = ds.open (ACE_TEXT (TEST_DIR));
+ ACE_ASSERT (status != -1);
+
+ ACE_ASSERT (entrycount == ds.length ());
+
+ for (n = 0; n < ds.length (); ++n)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Entry %d: %C\n"),
+ n,
+ ds[n]->d_name));
+
+ status = ds.close ();
+ ACE_ASSERT (status != -1);
+
+ return status;
+}
+
+static int
+dirent_test (void)
+{
+ ACE_Dirent dir (ACE_TEXT (TEST_DIR));
+
+ for (ACE_DIRENT *directory;
+ (directory = dir.read ()) != 0;
+ entrycount++)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Entry %d: %C\n"),
+ entrycount,
+ directory->d_name));
+ switch (entrycount)
+ {
+ case 0:
+ ACE_ERROR_RETURN
+ ((LM_ERROR, ACE_TEXT ("readdir failed to read anything\n")), -1);
+ /* NOTREACHED */
+ case 1:
+ ACE_ERROR_RETURN
+ ((LM_ERROR,
+ ACE_TEXT ("readdir failed, only matched directory name\n")),
+ -1);
+ /* NOTREACHED */
+ default:
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("readdir succeeded, read %d entries\n"),
+ entrycount));
+ }
+ return 0;
+}
+
+static int
+dirent_count (const ACE_TCHAR *dir_path,
+ int &dir_count,
+ int &file_count,
+ int recursion_level)
+{
+#if !defined (ACE_LACKS_CHDIR)
+
+# if (defined (ACE_VXWORKS) && (ACE_VXWORKS < 0x600))
+ // VxWorks only allows full paths (incl. device spec if applicable) to be specified
+ ACE_TCHAR full_path[MAXPATHLEN];
+ if (ACE_OS::getcwd (full_path, sizeof(full_path)) == NULL)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("getcwd: failed\n")),
+ -1);
+ if ((ACE_OS::strlen (full_path) + 1 + ACE_OS::strlen (dir_path)) >= sizeof(full_path))
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("getcwd: too long\n")),
+ -1);
+ ACE_OS::strcat (ACE_OS::strcat (full_path, "/"), dir_path);
+ if (ACE_OS::chdir (full_path) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("chdir: %p\n"),
+ full_path),
+ -1);
+# else
+ if (ACE_OS::chdir (dir_path) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("chdir: %p\n"),
+ dir_path),
+ -1);
+# endif
+#endif /* !ACE_LACKS_CHDIR */
+
+ ACE_Dirent dir (ACE_TEXT ("."));
+
+ // Since the dir struct d_name type changes depending on the setting
+ // of ACE_LACKS_STRUCT_DIR, copy each name into a neutral format
+ // array to work on it.
+ const size_t maxnamlen = MAXNAMLEN;
+ ACE_TCHAR tname[maxnamlen + 1];
+
+ int entry_count = 0;
+
+ for (ACE_DIRENT *directory; (directory = dir.read ()) != 0;)
+ {
+ // Skip the ".." and "." files.
+ if (ACE_OS::strcmp (directory->d_name, DIR_DOT) == 0
+ || ACE_OS::strcmp (directory->d_name, DIR_DOT_DOT) == 0)
+ continue;
+ ++entry_count;
+
+#if !defined (ACE_LACKS_STRUCT_DIR) && !defined (__BORLANDC__)
+ ACE_OS::strncpy (tname,
+ ACE_TEXT_CHAR_TO_TCHAR (directory->d_name),
+ maxnamlen);
+#else
+ ACE_OS::strncpy (tname, directory->d_name, maxnamlen);
+#endif /* ACE_LACKS_STRUCT_DIR */
+
+ int local_file_count = 0;
+ int local_dir_count = 0;
+ ACE_stat stat_buf;
+ if (ACE_OS::lstat (directory->d_name, &stat_buf) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ tname),
+ -1);
+
+ switch (stat_buf.st_mode & S_IFMT)
+ {
+ case S_IFREG: // Either a regular file or an executable.
+ ++file_count;
+ break;
+
+ case S_IFLNK: // Either a file or directory link, so let's find out.
+ if (ACE_OS::stat (directory->d_name, &stat_buf) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ tname),
+ -1);
+
+ if ((stat_buf.st_mode & S_IFMT) == S_IFDIR)
+ // Don't recurse through symbolic directory links!
+ ++dir_count;
+ else
+ ++file_count;
+ break;
+
+ case S_IFDIR:
+ ACE_DEBUG ((LM_DEBUG, "%*sentering subdirectory %s\n",
+ recursion_level * RECURSION_INDENT,
+ ACE_TEXT (""),
+ tname));
+ if (dirent_count (tname,
+ local_dir_count,
+ local_file_count,
+ recursion_level + 1) != -1)
+ {
+ ACE_DEBUG
+ ((LM_DEBUG,
+ ACE_TEXT ("%*ssubdirectory %s has %d files and %d subdirectories.\n"),
+ recursion_level * RECURSION_INDENT,
+ ACE_TEXT (""),
+ tname,
+ local_file_count,
+ local_dir_count));
+ ++dir_count;
+
+#if !defined (ACE_LACKS_CHDIR)
+# if (defined (ACE_VXWORKS) && (ACE_VXWORKS < 0x600))
+ // Move back to parent directory.
+ if (ACE_OS::chdir (full_path) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("chdir: %p\n"),
+ full_path),
+ -1);
+# else
+ // Move back up a level.
+ if (ACE_OS::chdir (ACE_TEXT ("..")) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("chdir: %p\n"),
+ dir_path),
+ -1);
+# endif
+#endif /* !ACE_LACKS_CHDIR */
+ }
+ break;
+
+ default: // Must be some other type of file (PIPE/FIFO/device)
+ file_count++;
+ break;
+ }
+ }
+
+ return entry_count;
+}
+
+static int
+dirent_recurse_test (void)
+{
+ int total_dirs = 0;
+ int total_files = 0;
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Starting directory recursion test for %s\n"),
+ ACE_TEXT (TEST_DIR)));
+
+ if (dirent_count (ACE_TEXT (TEST_DIR),
+ total_dirs,
+ total_files,
+ 1) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("Directory recursion test failed for %s\n"),
+ ACE_TEXT (TEST_DIR)),
+ -1);
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Directory recursion test succeeded for %s, read %d files %d dirs\n"),
+ ACE_TEXT (TEST_DIR),
+ total_files,
+ total_dirs));
+ return 0;
+}
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("Dirent_Test"));
+
+ int status = 0;
+
+ status = dirent_test ();
+
+ if (status != -1)
+ status = dirent_selector_test ();
+
+ if (status != -1)
+ status = dirent_recurse_test ();
+
+ ACE_END_TEST;
+ return status;
+}
diff --git a/ACE/tests/Dynamic_Priority_Test.cpp b/ACE/tests/Dynamic_Priority_Test.cpp
new file mode 100644
index 00000000000..e1ec028c631
--- /dev/null
+++ b/ACE/tests/Dynamic_Priority_Test.cpp
@@ -0,0 +1,796 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Dynamic_Priority_Test.cpp (based on Priority_Buffer_Test.cpp)
+//
+// = DESCRIPTION
+// This is a test to verify and illustrate the static and dynamic
+// priority mechanisms of the <ACE_Message_Queue> class and the
+// <ACE_Dynamic_Message_Queue> class. As in the
+// <Priority_Buffer_Test>, a producer generates messages and
+// enqueues them, and a consumer dequeues them and checks their
+// ordering.
+//
+// In these tests, every effort is made to ensure that there is
+// plenty of time for the messages to be enqueued and dequeued,
+// with messages that *should* meet their deadlines actually
+// meeting them, while messages that should miss their deadlines
+// are delayed so that they actually miss them. It is, however,
+// remotely possible that this test could yield a false negative:
+// the dynamic queues could work correctly but due to timing
+// variations the test could indicate failure.
+//
+// Three message queues are obtained from the message queue
+// factory, one static, two dynamic (one deadline based, and one
+// laxity based) and the same supplier behavior is used each time:
+// the messages are preallocated and their static information
+// valued, the current time is obtained and deadlines are set, with
+// half of the messages given late deadlines, and the other half of
+// the messages given reachable deadlines. The producer then
+// immediately enqueues all messages.
+//
+// Two separate tests are run, one which verifies messages are
+// correctly ordered my the given queues, and one which generates
+// performance numbers for the various queues under increasing
+// numbers of messages. In the first test, the consumer is passed
+// the filled queue and a string with the expected order in which
+// the messages should dequeue. In the second test, measurements
+// are made as non-intrusive as possible, with no ordering checks.
+//
+// = AUTHOR
+// Chris Gill <cdgill@cs.wustl.edu>
+//
+// ============================================================================
+
+#include "test_config.h" /* Include first to enable ACE_ASSERT. */
+#include "ace/Message_Queue.h"
+#include "ace/Thread_Manager.h"
+#include "ace/High_Res_Timer.h"
+#include "ace/Sched_Params.h"
+
+#if defined (VXWORKS)
+# include "ace/OS_NS_string.h"
+#endif /* VXWORKS */
+
+ACE_RCSID(tests, Dynamic_Priority_Test, "$Id$")
+
+#if defined (ACE_HAS_TIMED_MESSAGE_BLOCKS)
+enum Test_Type {BEST, WORST, RANDOM};
+
+class ArgStruct
+{
+ // = TITLE
+ // Structure used to pass arguments to test functions.
+public:
+
+ ACE_Message_Queue<ACE_SYNCH> *queue_;
+ // message queue to test
+
+ const char *order_string_;
+ // string of characters to indicate message order
+
+ ACE_Message_Block **array_;
+ // array of message blocks to use
+
+ u_int expected_count_;
+ // expected message count
+};
+
+// Order in which messages are sent.
+static const char send_order [] = "abcdefghijklmnop";
+
+// Order in which messages are received with "FIFO prioritization"
+// (i.e., none)
+// Unused: static const char FIFO_receipt_order [] = "abcdefghijklmnop";
+
+// Order in which messages are received with static prioritization.
+static const char static_receipt_order [] = "ponmlkjihgfedcba";
+
+// Order in which messages are received with deadline prioritization.
+static const char deadline_receipt_order [] = "hgfedcbaponmlkji";
+
+// Order in which messages are received with laxity prioritization.
+static const char laxity_receipt_order [] = "hfgedbcapnomljki";
+
+// Fast and slow execution time values (sec, usec), kept very small to
+// allow comparison of deadline, laxity, and static strategies across
+// a very wide range of message counts.
+static const ACE_Time_Value fast_execution (0, 1);
+static const ACE_Time_Value slow_execution (0, 2);
+
+// Make the queue be capable of being *very* large.
+static const long max_queue = LONG_MAX;
+
+#if defined (VXWORKS)
+// VxWorks Message Queue parameters.
+const int vx_max_queue = INT_MAX;
+const int vx_msg_size = 32;
+#endif /* defined (VXWORKS) */
+
+// Loading parameters (number of messages to push through queues) for
+// performance tests.
+static int MIN_LOAD = 20;
+static int MAX_LOAD = 1000;
+static int LOAD_STEP = 20;
+
+// Time offsets for a minute in the past (for the best case test) and
+// two seconds in the future (for the worst case and randomized
+// tests).
+static const ACE_Time_Value far_past_offset (-60, 0);
+static const ACE_Time_Value near_future_offset (2, 0);
+static const ACE_Time_Value offset_step (0, 5);
+
+// The order consumer dequeues a message from the passed
+// Message_Queue, and checks its data character against the passed
+// string of characters which has the expected ordering. Suppliers
+// and consumers do not allocate or deallocate messages, to avoid
+// timing delays and timing jitter in the test: the main function is
+// responsible for all initialization allocation and cleanup before,
+// between, and after (but not during) the transfer of messages from a
+// supplier to the corresponding consumer.
+
+static void *
+order_consumer (void *args)
+{
+ ACE_ASSERT (args != 0);
+
+ ACE_Message_Queue<ACE_SYNCH> *msg_queue =
+ static_cast<ArgStruct *> (args)->queue_;
+ const char *receipt_order =
+ static_cast<ArgStruct *> (args)->order_string_;
+ u_int expected_count =
+ static_cast<ArgStruct *> (args)->expected_count_;
+
+ ACE_ASSERT (receipt_order != 0);
+ ACE_ASSERT (msg_queue != 0);
+
+ u_int local_count = 0;
+
+ // Keep looping, reading a message out of the queue, until we reach
+ // the end of the receipt order string, which signals us to quit.
+
+ for (const char *expected = receipt_order;
+ *expected != '\0';
+ ++expected)
+ {
+ ACE_Message_Block *mb = 0;
+
+ int result = msg_queue->dequeue_head (mb);
+
+ if (result == -1)
+ break;
+
+ local_count++;
+
+ ACE_ASSERT (*expected == *mb->rd_ptr ());
+ }
+
+ ACE_ASSERT (local_count == ACE_OS::strlen (receipt_order));
+ ACE_ASSERT (local_count == expected_count);
+ return 0;
+}
+
+// The order producer runs through the passed send string, setting the
+// read pointer of the current message to the current character
+// position in the string, and then queueing the message in the
+// message list, where it is removed by the order consumer.
+
+static void *
+order_producer (void *args)
+{
+ ACE_ASSERT (args != 0);
+
+ ACE_Message_Queue<ACE_SYNCH> *msg_queue =
+ static_cast<ArgStruct *> (args)->queue_;
+ const char *send_order =
+ static_cast<ArgStruct *> (args)->order_string_;
+ ACE_Message_Block **block_array =
+ static_cast<ArgStruct *> (args)->array_;
+ int expected_count =
+ static_cast<ArgStruct *> (args)->expected_count_;
+
+ ACE_ASSERT (send_order != 0);
+ ACE_ASSERT (block_array != 0);
+
+ // Iterate through the send order string and the message block
+ // array, setting the current message block's read pointer to the
+ // current position in the send order string.
+ int local_count = 0;
+ const char *c;
+
+ for (local_count = 0, c = send_order; *c != '\0'; ++local_count, ++c)
+ {
+ // point to the current message block
+ ACE_Message_Block *mb = block_array [local_count];
+ ACE_ASSERT (mb != 0);
+
+ // Set the current send character in the current message block
+ // at its read pointer position, and adjust the write pointer.
+ *mb->wr_ptr () = *c;
+ mb->wr_ptr (1);
+
+
+ // Enqueue the message block in priority order.
+ if (msg_queue->enqueue_prio (mb) == -1)
+ break;
+ }
+
+ ACE_ASSERT (local_count == expected_count);
+
+ return 0;
+}
+
+static int
+run_order_test (ACE_Message_Queue<ACE_SYNCH>* msg_queue,
+ const char *send_order,
+ const char *receipt_order)
+{
+ u_int i;
+ u_int array_size = ACE_OS::strlen (send_order);
+
+ ACE_ASSERT (msg_queue != 0);
+ ACE_ASSERT (send_order != 0);
+ ACE_ASSERT (receipt_order != 0);
+ ACE_ASSERT (ACE_OS::strlen (send_order) == ACE_OS::strlen (receipt_order));
+
+ ArgStruct supplier_args, consumer_args;
+
+ supplier_args.queue_ = msg_queue;
+ supplier_args.order_string_ = send_order;
+ supplier_args.expected_count_ = ACE_OS::strlen (send_order);
+
+ // Allocate message blocks, fill in pointer array, set static
+ // information.
+ ACE_NEW_RETURN (supplier_args.array_,
+ ACE_Message_Block *[array_size],
+ -1);
+
+ for (i = 0; i < array_size; ++i)
+ {
+ // Construct a message new block off the heap, to hold a single
+ // character.
+ ACE_NEW_RETURN (supplier_args.array_[i],
+ ACE_Message_Block (1),
+ -1);
+
+ // Assign static (minimal) message priority in ascending order.
+ supplier_args.array_[i]->msg_priority (i);
+
+ // Assign every other message short or long execution time.
+ supplier_args.array_[i]->msg_execution_time (((i % 2)
+ ? slow_execution
+ : fast_execution));
+ }
+
+ consumer_args.queue_ = msg_queue;
+ consumer_args.order_string_ = receipt_order;
+ consumer_args.expected_count_ = ACE_OS::strlen (receipt_order);
+ consumer_args.array_ = 0;
+
+ // Construct pending and late absolute deadline times.
+
+ ACE_Time_Value current_time (0, 0);
+ ACE_Time_Value future_deadline (1, 0);
+ ACE_Time_Value near_deadline (0, 500000);
+ ACE_Time_Value recent_deadline (0, -1);
+ ACE_Time_Value past_deadline (0, -500000);
+
+ current_time = ACE_OS::gettimeofday ();
+
+ future_deadline += current_time;
+ near_deadline += current_time;
+ recent_deadline += current_time;
+ past_deadline += current_time;
+
+ // Set absolute time of deadline associated with the message.
+
+ for (i = 0; i < array_size; ++i)
+ {
+ switch ((4 * i) / array_size)
+ {
+ case 0:
+ supplier_args.array_[i]->msg_deadline_time (future_deadline);
+ break;
+ case 1:
+ supplier_args.array_[i]->msg_deadline_time (near_deadline);
+ break;
+ case 2:
+ supplier_args.array_[i]->msg_deadline_time (recent_deadline);
+ break;
+ case 3:
+ supplier_args.array_[i]->msg_deadline_time (past_deadline);
+ break;
+ // should never reach here, but its better to make sure
+ default:
+ ACE_ASSERT ((4 * i) / array_size < 4);
+ break;
+ }
+ }
+
+ // run the order test producer
+ order_producer (&supplier_args);
+
+ // run the order test consumer
+ order_consumer (&consumer_args);
+
+ // free all the allocated message blocks
+ for (i = 0; i < array_size; ++i)
+ {
+ delete supplier_args.array_[i];
+ }
+
+ // free the allocated pointer array
+ delete [] supplier_args.array_;
+
+ return 0;
+}
+
+// The performance consumer starts a timer, dequeues all messages from
+// the passed Message_Queue, stops the timer, and reports the number
+// of dequeued messages, the elapsed time, and the average time per
+// message.
+
+static void *
+performance_consumer (void * args)
+{
+ ACE_High_Res_Timer timer;
+
+ ACE_ASSERT (args != 0);
+
+ ACE_Message_Queue<ACE_SYNCH> *msg_queue =
+ static_cast<ArgStruct *> (args)->queue_;
+ u_int expected_count =
+ static_cast<ArgStruct *> (args)->expected_count_;
+
+ ACE_ASSERT (msg_queue != 0);
+
+ u_int local_count = 0;
+ ACE_Message_Block *mb = 0;
+
+ // reset, then start timer
+ timer.reset ();
+ timer.start ();
+
+ // Keep looping, reading a message out of the queue, until the
+ // expected number of messages have been dequeued.
+ for (local_count = 0; local_count < expected_count; ++local_count)
+ if (msg_queue->dequeue_head (mb) == -1)
+ break;
+
+ // Stop timer, obtain and report its elapsed time.x
+ timer.stop ();
+ ACE_Time_Value tv;
+ timer.elapsed_time (tv);
+ ACE_DEBUG ((LM_INFO, ACE_TEXT ("%6u, %6u, %f"),
+ local_count,
+ tv.msec (),
+ (ACE_timer_t) tv.msec () / local_count));
+
+ ACE_ASSERT (local_count == expected_count);
+ return 0;
+}
+
+// The performance producer starts a timer, enqueues the passed
+// messages setting the read pointer of each message to the first
+// character position in the passed string, stops the timer, and
+// reports the number of enqueued messages, the elapsed time, and the
+// average time per message.
+
+static void *
+performance_producer (void *args)
+{
+ ACE_High_Res_Timer timer;
+
+ ACE_ASSERT (args != 0);
+
+ ACE_Message_Queue<ACE_SYNCH> *msg_queue =
+ static_cast<ArgStruct *> (args)->queue_;
+ ACE_Message_Block **block_array =
+ static_cast<ArgStruct *> (args)->array_;
+ int expected_count =
+ static_cast<ArgStruct *> (args)->expected_count_;
+
+ ACE_ASSERT (send_order != 0);
+ ACE_ASSERT (block_array != 0);
+
+ // reset, then start timer
+ timer.reset ();
+ timer.start ();
+
+ // Iterate through the message block array, setting the character
+ // under the current message block's read pointer to null before
+ // enqueueing the message block.
+
+ int local_count = 0;
+ for (local_count = 0; local_count < expected_count; ++local_count)
+ {
+ // Point to the current message block.
+ ACE_Message_Block *mb = block_array [local_count];
+ ACE_ASSERT (mb != 0);
+
+ // Set a character in the current message block at its
+ // read pointer position, and adjust the write pointer.
+ mb->reset();
+ *mb->wr_ptr () = 'a';
+ mb->wr_ptr (1);
+
+ // Enqueue the message block in priority order.
+ if (msg_queue->enqueue_prio (mb) == -1)
+ break;
+ }
+
+ // Stop timer, obtain and report its elapsed time.
+ timer.stop ();
+ ACE_Time_Value tv;
+ timer.elapsed_time (tv);
+ ACE_DEBUG ((LM_INFO, ACE_TEXT ("%6u, %6u, %f, "),
+ local_count,
+ tv.msec (),
+ (ACE_timer_t) tv.msec () / local_count));
+
+ ACE_ASSERT (local_count == expected_count);
+ return 0;
+}
+
+static int
+run_performance_test (u_int min_load,
+ u_int max_load,
+ u_int load_step,
+ Test_Type test_type)
+{
+ ArgStruct supplier_args, consumer_args; // supplier and consumer argument strings
+ u_int load = 0; // message load
+ ACE_Time_Value *time_offsets; // pointer to array of time offsets
+ ACE_Time_Value current_time; // current time value
+ u_int shuffle_index; // used to shuffle arrays
+ int random_int = 0; // also used to shuffle arrays
+ ACE_Message_Block *temp_block; // temporary message block pointer
+ ACE_Time_Value temp_time; // temporary time value
+
+ // Build a static queue, a deadline based dynamic queue, and a
+ // laxity based dynamic queue.
+
+ ACE_Message_Queue<ACE_SYNCH> *static_queue =
+ ACE_Message_Queue_Factory<ACE_SYNCH>::create_static_message_queue (max_queue);
+ ACE_ASSERT (static_queue != 0);
+
+ ACE_Message_Queue<ACE_SYNCH> *deadline_queue =
+ ACE_Message_Queue_Factory<ACE_SYNCH>::create_deadline_message_queue (max_queue);
+ ACE_ASSERT (deadline_queue != 0);
+
+ ACE_Message_Queue<ACE_SYNCH> *laxity_queue =
+ ACE_Message_Queue_Factory<ACE_SYNCH>::create_laxity_message_queue (max_queue);
+
+ ACE_ASSERT (laxity_queue != 0);
+
+ // Zero out unused struct members.
+ supplier_args.order_string_ = 0;
+ consumer_args.order_string_ = 0;
+ consumer_args.array_ = 0;
+
+ // Print column headings for the specific test type.
+ switch (test_type)
+ {
+ case BEST:
+ ACE_DEBUG ((LM_INFO,
+ ACE_TEXT ("\n\nenqueued, best static time, best static avg, ")
+ ACE_TEXT ("dequeued, best static time, best static avg, ")
+ ACE_TEXT ("enqueued, best deadline time, best deadline avg, ")
+ ACE_TEXT ("dequeued, best deadline time, best deadline avg, ")
+ ACE_TEXT ("enqueued, best laxity time, best laxity avg, ")
+ ACE_TEXT ("dequeued, best laxity time, best laxity avg\n")));
+ break;
+ case WORST:
+ ACE_DEBUG ((LM_INFO,
+ ACE_TEXT ("\n\nenqueued, worst static time, worst static avg, ")
+ ACE_TEXT ("dequeued, worst static time, worst static avg, ")
+ ACE_TEXT ("enqueued, worst deadline time, worst deadline avg, ")
+ ACE_TEXT ("dequeued, worst deadline time, worst deadline avg, ")
+ ACE_TEXT ("enqueued, worst laxity time, worst laxity avg, ")
+ ACE_TEXT ("dequeued, worst laxity time, worst laxity avg\n")));
+
+ break;
+ case RANDOM:
+ ACE_DEBUG ((LM_INFO,
+ ACE_TEXT ("\n\nenqueued, random static time, random static avg, ")
+ ACE_TEXT ("dequeued, random static time, random static avg, ")
+ ACE_TEXT ("enqueued, random deadline time, random deadline avg, ")
+ ACE_TEXT ("dequeued, random deadline time, random deadline avg, ")
+ ACE_TEXT ("enqueued, random laxity time, random laxity avg, ")
+ ACE_TEXT ("dequeued, random laxity time, random laxity avg\n")));
+ break;
+ default:
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("unknown test type %d"),
+ test_type),
+ -1);
+ }
+
+ // Iterate through the message loads, and at each load do an
+ // identical test on all queues.
+ for (load = min_load; load <= max_load; load += load_step)
+ {
+ u_int i;
+
+ supplier_args.expected_count_ = load;
+ consumer_args.expected_count_ = load;
+
+ // Allocate message blocks, fill in pointer array, set static
+ // information.
+ ACE_NEW_RETURN (supplier_args.array_,
+ ACE_Message_Block *[load],
+ -1);
+
+ // Allocate array of timing offsets.
+ ACE_NEW_RETURN (time_offsets,
+ ACE_Time_Value [load],
+ -1);
+
+ // Fill in information for all types of tests.
+ for (i = 0; i < load; ++i)
+ {
+ // Construct a message new block off the heap, to hold a
+ // single character.
+ ACE_NEW_RETURN (supplier_args.array_[i],
+ ACE_Message_Block (1),
+ -1);
+
+ // Assign every other message short or long execution time.
+ supplier_args.array_[i]->msg_execution_time (((i % 2)
+ ? slow_execution
+ : fast_execution));
+ }
+
+ // Fill in information for the specific type of test.
+ switch (test_type)
+ {
+ case BEST:
+ // Fill in best case information.
+ time_offsets [0] = far_past_offset;
+ supplier_args.array_[0]->msg_priority (load);
+
+ for (i = 1; i < load; ++i)
+ {
+ // Assign static (minimal) message priority in
+ // descending order.
+ supplier_args.array_[i]->msg_priority (load - i);
+
+ // Assign time to deadline in descending order.
+ time_offsets [i] = time_offsets [i - 1] + offset_step;
+ }
+
+ break;
+ case WORST:
+ // Fill in worst case information.
+ time_offsets [0] = near_future_offset;
+ supplier_args.array_[0]->msg_priority (0);
+
+ for (i = 1; i < load; ++i)
+ {
+ // Assign static (minimal) message priority in ascending
+ // order.
+ supplier_args.array_[i]->msg_priority (i);
+
+ // Assign time to deadline in descending order (puts
+ // dynamic priority in ascending order).
+ time_offsets [i] = time_offsets [i - 1] - offset_step;
+ }
+ break;
+ case RANDOM:
+ // Fill in worst case information.
+ time_offsets [0] = near_future_offset;
+ supplier_args.array_[0]->msg_priority (0);
+
+ for (i = 1; i < load; ++i)
+ {
+ // Assign static (minimal) message priority in ascending
+ // order.
+ supplier_args.array_[i]->msg_priority (i);
+
+ // Assign time to deadline in descending order (puts
+ // dynamic priority in ascending order).
+ time_offsets [i] = time_offsets [i - 1] - offset_step;
+ }
+
+ // Then shuffle the arrays in tandem.
+ for (i = 0; i < load; ++i)
+ {
+ // Choose a (pseudo) random integer (evenly distributed
+ // over [0, load-1]).
+ if (RAND_MAX >= load)
+ {
+ // Discard integers in the tail of the random range
+ // that do not distribute evenly modulo the number
+ // of messages.
+ do
+ random_int = ACE_OS::rand ();
+ while (random_int >= (int)(RAND_MAX - (RAND_MAX % load)));
+ }
+ else if (RAND_MAX < load - 1)
+ // This should only happen for a *very* large messages
+ // relative to the system's representation size.
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("Insufficient range of random numbers")),
+ -1);
+ shuffle_index = random_int % load;
+
+ // Swap the message at the current index with the one at
+ // the shuffle index.
+ temp_block = supplier_args.array_[i];
+ supplier_args.array_[i] = supplier_args.array_[shuffle_index];
+ supplier_args.array_[shuffle_index] = temp_block;
+
+ // Swap the time at the current index with the one at
+ // the shuffle index.
+ temp_time = time_offsets [i];
+ time_offsets [i] = time_offsets [shuffle_index];
+ time_offsets [shuffle_index] = temp_time;
+ }
+ break;
+ default:
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("unknown test type %d"),
+ test_type),
+ -1);
+ }
+
+ // Set absolute time of deadline associated with each message.
+ current_time = ACE_OS::gettimeofday ();
+
+ for (i = 0; i < load; ++i)
+ supplier_args.array_[i]->msg_deadline_time (time_offsets [i] + current_time);
+
+ // Run the performance test producer and consumer on the static
+ // queue.
+ supplier_args.queue_ = static_queue;
+ performance_producer (&supplier_args);
+ consumer_args.queue_ = static_queue;
+ performance_consumer (&consumer_args);
+
+ // Add a comma delimiter for most recent outputs.
+ ACE_DEBUG ((LM_INFO,
+ ACE_TEXT (", ")));
+
+ // Run the performance test producer and consumer on the
+ // deadline queue.
+ supplier_args.queue_ = deadline_queue;
+ performance_producer (&supplier_args);
+ consumer_args.queue_ = deadline_queue;
+ performance_consumer (&consumer_args);
+
+ // Add a comma delimiter for most recent outputs.
+ ACE_DEBUG ((LM_INFO,
+ ACE_TEXT (", ")));
+
+ // Run the performance test producer and consumer on the laxity
+ // queue.
+ supplier_args.queue_ = laxity_queue;
+ performance_producer (&supplier_args);
+ consumer_args.queue_ = laxity_queue;
+ performance_consumer (&consumer_args);
+
+ // Move to the next line of output.
+ ACE_DEBUG ((LM_INFO,
+ ACE_TEXT ("\n")));
+
+ delete [] time_offsets;
+
+ // Free all the allocated message blocks.
+ for (i = 0; i < load; ++i)
+ delete supplier_args.array_[i];
+
+ // Free the allocated pointer array.
+ delete [] supplier_args.array_;
+
+ }
+
+ // Free resources and leave.
+ delete static_queue;
+ delete deadline_queue;
+ delete laxity_queue;
+ return 0;
+}
+#endif /* ACE_HAS_TIMED_MESSAGE_BLOCKS */
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("Dynamic_Priority_Test"));
+
+#if defined (ACE_HAS_TIMED_MESSAGE_BLOCKS)
+ // Enable FIFO scheduling, e.g., RT scheduling class on Solaris.
+ if (ACE_OS::sched_params (
+ ACE_Sched_Params (
+ ACE_SCHED_FIFO,
+ ACE_Sched_Params::priority_min (ACE_SCHED_FIFO),
+ ACE_SCOPE_PROCESS)) != 0)
+ {
+ if (ACE_OS::last_error () == EPERM)
+ ACE_DEBUG ((LM_MAX,
+ ACE_TEXT ("user is not superuser, ")
+ ACE_TEXT ("so remain in time-sharing class\n")));
+ else if (ACE_OS::last_error () == ENOTSUP)
+ ACE_DEBUG ((LM_MAX,
+ ACE_TEXT ("process scope scheduling is not available, ")
+ ACE_TEXT ("so remain in time-sharing class\n")));
+ else
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%n: ACE_OS::sched_params failed\n%a")),
+ -1);
+ }
+
+ // Test factory, static message queue.
+ ACE_Message_Queue<ACE_SYNCH> *test_queue =
+ ACE_Message_Queue_Factory<ACE_SYNCH>::create_static_message_queue (max_queue);
+ ACE_ASSERT (test_queue != 0);
+ run_order_test (test_queue,
+ send_order,
+ static_receipt_order);
+ delete test_queue;
+
+ // Test factory, dynamic message queue (deadline strategy).
+ test_queue =
+ ACE_Message_Queue_Factory<ACE_SYNCH>::create_deadline_message_queue (max_queue);
+ ACE_ASSERT (test_queue != 0);
+ run_order_test (test_queue,
+ send_order,
+ deadline_receipt_order);
+ delete test_queue;
+
+ // Test factory, dynamic message queue (laxity strategy).
+ test_queue =
+ ACE_Message_Queue_Factory<ACE_SYNCH>::create_laxity_message_queue (max_queue);
+ ACE_ASSERT (test_queue != 0);
+ run_order_test (test_queue,
+ send_order,
+ laxity_receipt_order);
+ delete test_queue;
+
+#if defined (VXWORKS)
+ // test factory for VxWorks message queue.
+ ACE_Message_Queue_Vx *test_queue_vx =
+ ACE_Message_Queue_Factory<ACE_NULL_SYNCH>::create_Vx_message_queue (vx_max_queue,
+ vx_msg_size);
+ ACE_ASSERT (test_queue_vx != 0);
+ // (TBD - does message receipt order test make any sense for Vx Queue ?
+ // If so, uncomment order test, or if not remove order test, below)
+ // @@ % levine 22 Jul 1998 % It'd be nice to run the test, but:
+ // ACE_Message_Queue_Vx isa
+ // ACE_Message_Queue<ACE_NULL_SYNCH>, not an
+ // ACE_Message_Queue<ACE_MT_SYNCH>, so we're
+ // not type-compatible.
+
+ // run_order_test (test_queue, send_order, static_receipt_order);
+ delete test_queue_vx;
+#endif /* VXWORKS */
+
+ // For each of an increasing number of message loads, run the same
+ // performance test (best case, worst case, and randomized, over
+ // each kind of queue).
+ run_performance_test (MIN_LOAD,
+ MAX_LOAD,
+ LOAD_STEP,
+ BEST);
+
+ run_performance_test (MIN_LOAD,
+ MAX_LOAD,
+ LOAD_STEP,
+ WORST);
+
+ run_performance_test (MIN_LOAD,
+ MAX_LOAD,
+ LOAD_STEP,
+ RANDOM);
+#else
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("ACE is not compiled with ACE_HAS_TIMED_MESSAGE_BLOCKS enabled\n")));
+#endif /* ACE_HAS_TIMED_MESSAGE_BLOCKS */
+
+ ACE_END_TEST;
+ return 0;
+}
diff --git a/ACE/tests/Enum_Interfaces_Test.cpp b/ACE/tests/Enum_Interfaces_Test.cpp
new file mode 100644
index 00000000000..b9bd438c6c0
--- /dev/null
+++ b/ACE/tests/Enum_Interfaces_Test.cpp
@@ -0,0 +1,73 @@
+/* -*- C++ -*- */
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Enum_interfaces.cpp
+//
+// = DESCRIPTION
+// This is a simple test of <ACE::get_ip_interfaces>. This call
+// retrieves the IP addresses assigned to the host by
+// interrogating the kernel. Network applications typically
+// assume gethostbyname(uname()) will work, but this is just a
+// convention. It is also problematic if the resolver code
+// (DNS/NIS+...) is misconfigured. This happens more than
+// programmers realize. It is better to find out by asking the
+// kernel for local address assignments. This API is similar to
+// what netstat -ni or ifconfig -a produces on UNIX or ipconfig on
+// Windows NT. In fact, it was by reverse engineering these tools
+// that this api was created.
+//
+// = AUTHOR
+// Michael R. MacFaden <mrm@cisco.com>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/OS_NS_sys_utsname.h"
+#include "ace/INET_Addr.h"
+
+ACE_RCSID(tests, Enum_Interfaces_Test, "$Id$")
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("Enum_Interfaces_Test"));
+
+ ACE_utsname uname;
+ ACE_OS::uname (&uname);
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Machine: %s running on %s\n"),
+ uname.nodename, uname.machine ));
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Platform: %s, %s, %s\n"),
+ uname.sysname, uname.release, uname.version ));
+
+ ACE_INET_Addr *the_addr_array;
+ size_t how_many = 0;
+
+ int rc = ACE::get_ip_interfaces (how_many, the_addr_array);
+
+ if (rc != 0)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("ACE::get_ip_interfaces failed")));
+ else if (how_many == 0)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("No interfaces presently configured in the kernel\n")));
+ else
+ {
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("there are %d interfaces\n"), how_many));
+
+ for (size_t i = 0; i < how_many; i++)
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\t%s\n"),
+ ACE_TEXT_CHAR_TO_TCHAR (the_addr_array[i].get_host_addr ())));
+
+ delete [] the_addr_array;
+ }
+
+ ACE_END_TEST;
+ return rc != 0; // return 1 if get_ip_interfaces() failed
+}
diff --git a/ACE/tests/Env_Value_Test.cpp b/ACE/tests/Env_Value_Test.cpp
new file mode 100644
index 00000000000..c7a81909aa9
--- /dev/null
+++ b/ACE/tests/Env_Value_Test.cpp
@@ -0,0 +1,118 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = DESCRIPTION
+// This is a simple test to make sure the Env_Value template is
+// working correctly.
+//
+// = AUTHOR
+// Chris Cleeland <cleeland@cs.wustl.edu>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/OS_NS_stdlib.h"
+#include "ace/OS_NS_string.h"
+#include "ace/Process.h"
+#include "ace/Env_Value_T.h"
+
+ACE_RCSID(tests, Env_Value_Test, "$Id$")
+
+#define TEST_THIS(type, varname, defval, expval) \
+do { \
+ ACE_Env_Value<type> val (varname, (defval)); \
+ if (val != (expval)) { \
+ ACE_ERROR ((LM_ERROR, \
+ ACE_TEXT ("val %d does not match expected value of %d\n"), \
+ (int) (type) val, (int) (expval))); \
+ } \
+ ACE_ASSERT (val == (expval)); \
+} while (0)
+
+int
+// This has been unconditionally turned on for the time being since I can't
+// figure out an easy way to enable it and still keep ACE_TMAIN in a seperate
+// cpp.
+#if 1 || defined (ACE_HAS_NONSTATIC_OBJECT_MANAGER) || defined (ACE_LACKS_FORK)
+// ACE_HAS_NONSTATIC_OBJECT_MANAGER only allows main to have two
+// arguments. And on platforms that lack fork (), we can't use spawn.
+run_main (int argc, ACE_TCHAR* [])
+{
+ ACE_UNUSED_ARG (argc);
+
+ // Only Win32 can set wide-char environment strings. So, for all
+ // others, use char string literals regardless of ACE_USES_WCHAR.
+# if defined (ACE_WIN32)
+ ACE_OS::putenv (ACE_TEXT ("TEST_VALUE_POSITIVE=10.2"));
+ ACE_OS::putenv (ACE_TEXT ("TEST_VALUE_NEGATIVE=-10.2"));
+# else
+ ACE_OS::putenv ("TEST_VALUE_POSITIVE=10.2");
+ ACE_OS::putenv ("TEST_VALUE_NEGATIVE=-10.2");
+# endif /* ACE_WIN32 */
+#else /* ! ACE_HAS_NONSTATIC_OBJECT_MANAGER && ! ACE_LACKS_FORK */
+run_main (int argc, ACE_TCHAR * [], ACE_TCHAR *envp[])
+{
+ if (argc == 1)
+ {
+ int status;
+
+ // No arguments means we're the initial test.
+ ACE_Process_Options options (1);
+ status = options.setenv (envp);
+ ACE_ASSERT (status == 0);
+
+ options.command_line (ACE_TEXT (".") ACE_DIRECTORY_SEPARATOR_STR
+ ACE_TEXT ("Env_Value_Test run_as_test"));
+
+ status = options.setenv (ACE_TEXT ("TEST_VALUE_POSITIVE"),
+ ACE_TEXT ("%s"),
+ ACE_TEXT ("10.2"));
+ ACE_ASSERT (status == 0);
+ status = options.setenv (ACE_TEXT ("TEST_VALUE_NEGATIVE"),
+ ACE_TEXT ("%s"),
+ ACE_TEXT ("-10.2"));
+ ACE_ASSERT (status == 0);
+
+ ACE_Process p;
+ pid_t result = p.spawn (options);
+ ACE_ASSERT (result != -1);
+ p.wait ();
+ }
+ else
+#endif /* ! ACE_HAS_NONSTATIC_OBJECT_MANAGER && ! ACE_LACKS_FORK */
+ {
+ // In this case we're the child
+
+ ACE_START_TEST (ACE_TEXT ("Env_Value_Test"));
+
+ TEST_THIS (int, ACE_TEXT ("TEST_VALUE_POSITIVE"), 4, 10);
+#if !defined (ACE_LACKS_FLOATING_POINT)
+ TEST_THIS (double, ACE_TEXT ("TEST_VALUE_POSITIVE"), -1.0, 10.2);
+#endif /* ! ACE_LACKS_FLOATING_POINT */
+ TEST_THIS (long, ACE_TEXT ("TEST_VALUE_POSITIVE"), 0, 10);
+ TEST_THIS (unsigned long, ACE_TEXT ("TEST_VALUE_POSITIVE"), 0, 10);
+ TEST_THIS (short, ACE_TEXT ("TEST_VALUE_POSITIVE"), 0, 10);
+ TEST_THIS (unsigned short, ACE_TEXT ("TEST_VALUE_POSITIVE"), 0, 10);
+
+ TEST_THIS (int, ACE_TEXT ("TEST_VALUE_NEGATIVE"), 4, -10);
+#if !defined (ACE_LACKS_FLOATING_POINT)
+ TEST_THIS (double, ACE_TEXT ("TEST_VALUE_NEGATIVE"), -1.0, -10.2);
+#endif /* ! ACE_LACKS_FLOATING_POINT */
+ TEST_THIS (long, ACE_TEXT ("TEST_VALUE_NEGATIVE"), 0, -10L);
+ TEST_THIS (unsigned long, ACE_TEXT ("TEST_VALUE_NEGATIVE"), 0, (unsigned long) -10);
+ TEST_THIS (short, ACE_TEXT ("TEST_VALUE_NEGATIVE"), 0, -10);
+ TEST_THIS (unsigned short, ACE_TEXT ("TEST_VALUE_NEGATIVE"), 0, (unsigned short) -10);
+
+ const ACE_TCHAR *defstr = ACE_TEXT ("Sarah Cleeland is Two!");
+ ACE_Env_Value<const ACE_TCHAR *> sval (ACE_TEXT ("This_Shouldnt_Be_Set_Hopefully"),
+ defstr);
+ ACE_ASSERT (ACE_OS::strcmp (sval, defstr) == 0);
+ ACE_END_TEST;
+ }
+ return 0;
+}
+
diff --git a/ACE/tests/FIFO_Test.cpp b/ACE/tests/FIFO_Test.cpp
new file mode 100644
index 00000000000..8a7f7a64a44
--- /dev/null
+++ b/ACE/tests/FIFO_Test.cpp
@@ -0,0 +1,311 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// FIFO_Test.cpp
+//
+// = DESCRIPTION
+// This is a test of basic ACE_FIFO_* class functionality.
+// The test forks two processes or spawns two threads (depending
+// upon the platform) and then tests various data exchange
+// scenarios.
+//
+// = AUTHOR
+// Steve Huston <shuston@riverace.com>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/OS_NS_string.h"
+#include "ace/OS_NS_sys_stat.h"
+#include "ace/OS_NS_sys_wait.h"
+#include "ace/OS_NS_unistd.h"
+#include "ace/ACE.h"
+#include "ace/FIFO_Send_Msg.h"
+#include "ace/FIFO_Recv_Msg.h"
+#include "ace/Handle_Set.h"
+#include "ace/Lib_Find.h"
+#include "ace/Thread.h"
+#include "ace/Thread_Manager.h"
+
+ACE_RCSID(tests, SOCK_Test, "$Id$")
+
+#if !defined (ACE_LACKS_MKFIFO)
+
+static const char ACE_ALPHABET[] = "abcdefghijklmnopqrstuvwxyz";
+
+// This length is used for the "big buffer" send/receive.
+static const size_t big_size = (BUFSIZ * 4);
+
+static void *
+client (void *arg)
+{
+ ACE_TCHAR *fifo_path = reinterpret_cast <ACE_TCHAR *> (arg);
+ ACE_FIFO_Send_Msg fifo;
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) client opening %s\n"), fifo_path));
+ if (fifo.open (fifo_path) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("(%P|%t) %p\n"), fifo_path), 0);
+
+ // Try some transfers - the server part is expecting this data.
+ // First, try a nice, easy send.
+ ssize_t send_count;
+ ssize_t expect = static_cast <ssize_t> (ACE_OS::strlen (ACE_ALPHABET));
+ send_count = fifo.send (ACE_ALPHABET, ACE_OS::strlen (ACE_ALPHABET));
+ if (send_count == expect)
+ {
+ // Ok, so far so good. Now try one that will overflow the reader
+ // side to be sure it properly tosses the overflow. Then send another
+ // to be sure it finds the start of the next message ok.
+ char big[big_size];
+ for (size_t i = 0; i < big_size; ++i)
+ big[i] = (i % 2) ? 0x05 : 0x0A; // Make nice pattern in blown stack
+ expect = static_cast <ssize_t> (big_size);
+ send_count = fifo.send (big, big_size);
+ if (send_count == expect)
+ {
+ expect = static_cast <ssize_t> (ACE_OS::strlen (ACE_ALPHABET));
+ send_count = fifo.send (ACE_ALPHABET, ACE_OS::strlen (ACE_ALPHABET));
+ if (send_count != expect)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Final send; sent %d, expected %d")
+ ACE_TEXT ("%p\n"),
+ send_count, expect, ACE_TEXT ("send")));
+ else
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) All sends ok\n")));
+ }
+ else
+ {
+ ACE_ERROR
+ ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Second send expected %d; sent %d. %p\n"),
+ expect, send_count, ACE_TEXT ("send")));
+ }
+ }
+ else
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) First send expected %d; sent %d. %p\n"),
+ expect, send_count, ACE_TEXT ("send")));
+ }
+
+ if (fifo.close () != 0)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%P|%t) %p\n"), ACE_TEXT ("fifo close")));
+
+ return 0;
+}
+
+static void *
+server (void *arg)
+{
+ ACE_FIFO_Recv_Msg *fifo = reinterpret_cast <ACE_FIFO_Recv_Msg *> (arg);
+
+ // Wait for the client to get going and open the FIFO.
+ errno = 0;
+ ACE_Handle_Set h;
+ ACE_Time_Value delay (10);
+ h.set_bit (fifo->get_handle ());
+ if (ACE::select (h.max_set () + 1, h, &delay) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("(%P|%t) server %p\n"),
+ ACE_TEXT ("select")),
+ 0);
+
+ // On AIX, select() always seems to select a fifo handle as a normal file,
+ // always readable. Just wait a second...
+# if defined (AIX) || defined (HPUX) || defined (__osf__)
+ ACE_OS::sleep (1);
+# endif /* AIX || HPUX */
+
+ // Read the things the client is sending; alphabet, huge overflow, then
+ // alphabet.
+
+ char buf[BUFSIZ];
+ ssize_t recv_count;
+ ssize_t expect = static_cast <ssize_t> (ACE_OS::strlen (ACE_ALPHABET));
+ recv_count = fifo->recv (buf, sizeof (buf));
+ if (recv_count != expect)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Recv 1 expected %d, got %d. %p\n"),
+ expect, recv_count, ACE_TEXT ("recv")),
+ 0);
+ buf[recv_count] = '\0';
+ if (ACE_OS::strcmp (buf, ACE_ALPHABET) != 0)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Recv 1 expected alphabet; got %s\n"),
+ buf));
+
+ // See documented return values for ACE_FIFO_Recv_Msg...
+ // We are being sent a message much longer than BUFSIZ.
+ // If this platform has STREAM pipes, the entire message will come
+ // through and we can grab it all. If not, then ACE_FIFO_Recv_Msg ditches
+ // the part of the message we don't read. This is rather a pain in the
+ // neck, but the API doesn't return info that more data is in the message
+ // (for STREAM pipes). When non-ACE_HAS_STREAM_PIPES discards data, the
+ // returned length will be larger than requested, though only the requested
+ // number of bytes are written to the buffer.
+#if defined (ACE_HAS_STREAM_PIPES)
+ for (size_t remaining = big_size;
+ remaining > 0;
+ remaining -= recv_count)
+ {
+#endif /* ACE_HAS_STREAM_PIPES */
+
+ // recv_count is sizeof(buf) on ACE_HAS_STREAM_PIPES; big_size on others.
+#if defined (ACE_HAS_STREAM_PIPES)
+ expect = static_cast <ssize_t> (sizeof (buf));
+#else
+ expect = static_cast <ssize_t> (big_size);
+#endif /* ACE_HAS_STREAM_PIPES */
+ recv_count = fifo->recv (buf, sizeof (buf));
+ if (recv_count != expect)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Recv 2 expected %d, ")
+ ACE_TEXT ("got %d. %p\n"),
+ expect, recv_count, ACE_TEXT ("recv")),
+ 0);
+#if defined (ACE_HAS_STREAM_PIPES)
+ }
+#endif /* ACE_HAS_STREAM_PIPES */
+
+ expect = static_cast <ssize_t> (ACE_OS::strlen (ACE_ALPHABET));
+ recv_count = fifo->recv (buf, sizeof (buf));
+ if (recv_count != expect)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Recv 3 expected %d, got %d. %p\n"),
+ expect, recv_count, ACE_TEXT ("recv")),
+ 0);
+ buf[recv_count] = '\0';
+ if (ACE_OS::strcmp (buf, ACE_ALPHABET) != 0)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Recv 3 expected alphabet; got %s\n"),
+ buf));
+ else
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) All receives ok\n")));
+ return 0;
+}
+
+static int
+test_fifo_msg (void)
+{
+ // Reader side opens first - it may fail if fifo not supported on this
+ // platform.
+ ACE_TCHAR fifo_path[MAXPATHLEN];
+ if (ACE::get_temp_dir (fifo_path, MAXPATHLEN) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"),
+ ACE_TEXT ("get_temp_dir")), 1);
+ ACE_OS::strcat (fifo_path, ACE_TEXT ("FIFO_Test"));
+ ACE_FIFO_Recv_Msg read_side;
+ // Open read only, not persistent (4th arg is 0)
+ if (-1 == read_side.open (fifo_path,
+ O_CREAT | O_RDONLY,
+ ACE_DEFAULT_FILE_PERMS,
+ 0))
+ {
+#if defined (ACE_WIN32)
+ if (errno == ENOTSUP)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("FIFO not supported on Win32; ")
+ ACE_TEXT ("this is correct.\n")));
+ return 0;
+ }
+#endif /* ACE_WIN32 */
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"),
+ ACE_TEXT ("ACE_FIFO_Recv_Msg::open")),
+ 1);
+ }
+
+ // Ok, the FIFO opened clean for read. Now it's safe to spawn a
+ // process/thread and test some transfers.
+
+ int status = 0; // Test status; innocent until proven guilty.
+
+#if !defined (ACE_LACKS_FORK)
+ switch (ACE_OS::fork (ACE_TEXT ("child")))
+ {
+ case -1:
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("fork failed")));
+ status = 1;
+ break;
+ case 0:
+ client (fifo_path);
+ ACE_OS::exit (0);
+ /* NOTREACHED */
+ default:
+ server (&read_side);
+ ACE_OS::wait ();
+ }
+#elif defined (ACE_HAS_THREADS)
+ if (ACE_Thread_Manager::instance ()->spawn
+ (ACE_THR_FUNC (server),
+ &read_side,
+ THR_NEW_LWP | THR_DETACHED) == -1)
+ {
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("server spawn")));
+ ++status;
+ }
+
+ if (ACE_Thread_Manager::instance ()->spawn
+ (ACE_THR_FUNC (client),
+ fifo_path,
+ THR_NEW_LWP | THR_DETACHED) == -1)
+ {
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("client spawn")));
+ ++status;
+ }
+
+ // Wait for the threads to exit.
+ ACE_Thread_Manager::instance ()->wait ();
+#else
+ ACE_ERROR ((LM_INFO,
+ ACE_TEXT ("This test requires multiple threads ")
+ ACE_TEXT ("or processes.\n")));
+#endif /* ACE_HAS_THREADS */
+
+ if (read_side.remove () != 0)
+ {
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("fifo remove")));
+ ++status;
+ }
+
+ ACE_stat fifo_stat;
+ if (ACE_OS::stat (fifo_path, &fifo_stat) == 0)
+ {
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("FIFO %s should be gone but isn't\n"),
+ fifo_path));
+ ++status;
+ ACE_OS::unlink (fifo_path); // Try to get rid of it.
+ }
+
+ return status;
+}
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("FIFO_Test"));
+
+ int errors = 0;
+ errors += test_fifo_msg ();
+
+ ACE_END_TEST;
+ return errors;
+}
+
+#else
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("FIFO_Test"));
+
+ ACE_ERROR ((LM_INFO, ACE_TEXT ("FIFOs are not supported on this platform\n")));
+
+ ACE_END_TEST;
+ return 0;
+}
+
+#endif /* !ACE_LACKS_MKFIFO */
diff --git a/ACE/tests/FlReactor_Test.cpp b/ACE/tests/FlReactor_Test.cpp
new file mode 100644
index 00000000000..0b34751da3c
--- /dev/null
+++ b/ACE/tests/FlReactor_Test.cpp
@@ -0,0 +1,275 @@
+/* -*- C++ -*- */
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// FlReactor_Test.cpp
+//
+// = DESCRIPTION
+// A simple test that ilustrates the integration of the fast-light
+// toolkit (http://fltk.easysw.org/) with ACE, it uses FL to create
+// an OpenGL window and display a polygon, it uses ACE to open an
+// acceptor. Every time there is a connection the number of polygons
+// is increased, a little widget can be used to change the number of
+// polygons too.
+//
+// = AUTHOR
+// Carlos O'Ryan <coryan@cs.wustl.edu>
+//
+// ============================================================================
+
+#include "test_config.h"
+
+ACE_RCSID(tests, FlReactor_Test, "$Id$")
+
+
+#include "ace/FlReactor.h"
+#include "ace/Event_Handler.h"
+#include "ace/Acceptor.h"
+#include "ace/SOCK_Acceptor.h"
+#include "ace/SOCK_Connector.h"
+#include "ace/Service_Config.h"
+#include "ace/Thread_Manager.h"
+
+#include /**/ <FL/Fl.h>
+#include /**/ <FL/Fl_Window.h>
+#include /**/ <FL/Fl_Hor_Slider.h>
+#include /**/ <FL/Fl_Box.h>
+#include /**/ <FL/math.h>
+#include /**/ <FL/gl.h>
+#include /**/ <FL/Fl_Gl_Window.h>
+
+class Test_Window : public Fl_Gl_Window
+{
+public:
+ Test_Window (int x, int y, int w, int h,
+ const char * l = 0);
+ // Constructor
+
+ int sides (void) const;
+ void sides (int s);
+ void incr_sides (void);
+
+private:
+ virtual void draw (void);
+ // from the Fl_Gl_Window...
+
+ int sides_;
+};
+
+Test_Window::Test_Window (int x, int y,
+ int w, int h,
+ const char* l)
+ : Fl_Gl_Window (x, y, w, h, l),
+ sides_ (3)
+{
+}
+
+int
+Test_Window::sides (void) const
+{
+ return this->sides_;
+}
+
+void
+Test_Window::sides (int s)
+{
+ this->sides_ = s;
+ this->redraw ();
+}
+
+void
+Test_Window::incr_sides (void)
+{
+ this->sides_++;
+ if (this->sides_ > 10)
+ this->sides_ = 3;
+ this->redraw ();
+}
+
+void
+Test_Window::draw (void)
+{
+ // the valid() property may be used to avoid reinitializing your
+ // GL transformation for each redraw:
+ if (!this->valid ())
+ {
+ this->valid (1);
+ glLoadIdentity ();
+ glViewport (0, 0, this->w (), this->h ());
+ }
+ // draw an amazing but slow graphic:
+ glClear (GL_COLOR_BUFFER_BIT);
+
+ glBegin (GL_POLYGON);
+ int s = this->sides_;
+
+ for (int i = 0; i != s; ++i)
+ {
+ double ang = i * 2 * M_PI / s;
+ glColor3f (float (i) / s,
+ float (i) / s,
+ float (i) / s);
+ glVertex3f (cos (ang), sin (ang), 0);
+ }
+ glEnd ();
+}
+
+// when you change the data, as in this callback, you must call redraw ():
+void sides_cb (Fl_Widget *o, void *p)
+{
+ Test_Window *tw =
+ reinterpret_cast<Test_Window *> (p);
+ Fl_Slider *slider =
+ dynamic_cast<Fl_Slider*> (o);
+ tw->sides (static_cast<int> (slider->value ()));
+}
+
+class Connection_Handler : public ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH>
+{
+public:
+ Connection_Handler (Test_Window *w = 0,
+ Fl_Box* box = 0);
+
+ virtual int open (void *);
+ virtual int handle_input (ACE_HANDLE);
+
+private:
+ Test_Window *w_;
+ Fl_Box *box_;
+};
+
+class Acceptor : public ACE_Acceptor<Connection_Handler,ACE_SOCK_ACCEPTOR>
+{
+public:
+ Acceptor (Test_Window *w = 0,
+ Fl_Box *box = 0);
+
+ virtual int make_svc_handler (Connection_Handler *&sh);
+
+private:
+ Test_Window* w_;
+ Fl_Box *box_;
+};
+
+Connection_Handler::Connection_Handler (Test_Window *w,
+ Fl_Box *box)
+ : w_ (w),
+ box_ (box)
+{
+}
+
+int
+Connection_Handler::open (void*)
+{
+ if (this->box_ != 0)
+ {
+ ACE_INET_Addr from;
+
+ this->peer ().get_remote_addr (from);
+ const int bufsiz = 128;
+ char buf[bufsiz];
+
+ from.addr_to_string (buf, bufsiz, 0);
+
+ static char msg[256];
+ ACE_OS::sprintf (msg, "connection from <%s>\n", buf);
+
+ this->box_->label (msg);
+ this->box_->redraw ();
+ }
+
+ if (this->w_ != 0)
+ {
+ this->w_->incr_sides ();
+ }
+
+ return this->peer ().enable (ACE_NONBLOCK);
+}
+
+int
+Connection_Handler::handle_input (ACE_HANDLE)
+{
+ char buf[BUFSIZ];
+ if (this->peer ().recv (buf, BUFSIZ) <= 0)
+ return -1;
+ return 0;
+}
+
+Acceptor::Acceptor (Test_Window *w, Fl_Box *box)
+ : w_ (w),
+ box_ (box)
+{
+}
+
+int
+Acceptor::make_svc_handler (Connection_Handler *&sh)
+{
+ if (sh == 0)
+ {
+ ACE_NEW_RETURN (sh, Connection_Handler (this->w_, this->box_), -1);
+ sh->reactor (this->reactor());
+ }
+ return 0;
+}
+
+int run_main (int argc, ACE_TCHAR *argv[])
+{
+ ACE_START_TEST (ACE_TEXT ("FlReactor_Test"));
+
+ Fl_Window window (300, 370);
+
+ Test_Window tw (10, 75, window.w () - 20, window.h ()-90);
+ window.resizable (&tw);
+
+ Fl_Hor_Slider slider (60, 5, window.w () - 70, 30, "Sides:");
+ slider.align (FL_ALIGN_LEFT);
+ slider.callback (sides_cb, &tw);
+ slider.value (tw.sides ());
+ slider.step (1);
+ slider.bounds (3, 10);
+
+ ACE_FlReactor reactor;
+ ACE_Reactor r (&reactor);
+
+ Fl_Box *box = new Fl_Box (FL_UP_BOX, 10, 40,
+ window.w () - 20, 30,
+ "Setting up");
+ box->labelfont (FL_BOLD);
+
+ Acceptor acceptor (&tw, box);
+
+ ACE_INET_Addr address;
+
+ if (acceptor.open (address, &r) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "%p\n",
+ "open acceptor"),
+ -1);
+
+ acceptor.acceptor ().get_local_addr (address);
+
+ const int bufsiz = 128;
+ char buf[bufsiz];
+
+ address.addr_to_string (buf, bufsiz, 0);
+
+ char msg[2 * bufsiz];
+ ACE_OS::sprintf (msg, "Listening on <%s>\n", buf);
+
+ box->label (msg);
+ box->redraw ();
+
+ window.end ();
+ window.show (argc, argv);
+ tw.show ();
+
+ return Fl::run ();
+
+ ACE_END_TEST;
+}
+
diff --git a/ACE/tests/Framework_Component_DLL.cpp b/ACE/tests/Framework_Component_DLL.cpp
new file mode 100644
index 00000000000..f8e4e34dbf0
--- /dev/null
+++ b/ACE/tests/Framework_Component_DLL.cpp
@@ -0,0 +1,82 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Framework_Component_DLL.cpp
+//
+// = DESCRIPTION
+// This is a simple server that can be loaded via the ACE
+// Service Configuration framework and uses the singleton that
+// also lives in this library.
+//
+// = AUTHOR
+// Don Hinton <dhinton@ieee.org>
+//
+// ============================================================================
+
+#include "Framework_Component_DLL.h"
+#include "ace/Service_Config.h"
+#include "ace/Service_Object.h"
+#include "ace/Framework_Component_T.h"
+
+ACE_RCSID (tests,
+ Framework_Component_DLL,
+ "$Id$")
+
+ACE_DLL_UNLOAD_POLICY (Framework_Component_DLL, ACE_DLL_UNLOAD_POLICY_LAZY)
+
+Simple_Service::Simple_Service (void)
+{
+ FRAMEWORK_COMPONENT_DLL_TRACE ("Simple_Service::Simple_Service");
+}
+
+Simple_Service::~Simple_Service (void)
+{
+ FRAMEWORK_COMPONENT_DLL_TRACE ("Simple_Service::~Simple_Service");
+}
+
+const ACE_TCHAR *
+Simple_Service::name (void)
+{
+ FRAMEWORK_COMPONENT_DLL_TRACE ("Simple_Service::dll_name");
+ return ACE_TEXT ("Simple_Service");
+}
+
+/***************************************************************************/
+
+template <int which>
+class Server_T : public ACE_Service_Object
+{
+public:
+ int init (int, ACE_TCHAR *[])
+ {
+ FRAMEWORK_COMPONENT_DLL_TRACE ("Server_T::init");
+
+ // Initialize the singleton
+ FWCT_DLL_Singleton_Adapter_T <Simple_Service> *ss = SS_SINGLETON::instance ();
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Server_T::init() dll_name: %s\n"),
+ ss->dll_name ()));
+ return 0;
+ }
+
+ int fini (void)
+ {
+ FRAMEWORK_COMPONENT_DLL_TRACE ("Server_T::fini");
+ return 0;
+ }
+};
+
+typedef Server_T <1> Server_1;
+FRAMEWORK_COMPONENT_DLL_SINGLETON_DECLARATION(Server_T<1>;)
+ACE_FACTORY_DEFINE (Framework_Component_DLL, Server_1)
+
+typedef Server_T <2> Server_2;
+FRAMEWORK_COMPONENT_DLL_SINGLETON_DECLARATION(Server_T<2>;)
+ACE_FACTORY_DEFINE (Framework_Component_DLL, Server_2)
+
diff --git a/ACE/tests/Framework_Component_DLL.h b/ACE/tests/Framework_Component_DLL.h
new file mode 100644
index 00000000000..c9760b33dcb
--- /dev/null
+++ b/ACE/tests/Framework_Component_DLL.h
@@ -0,0 +1,58 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Framework_Component_DLL.h
+//
+// = DESCRIPTION
+// Define class needed for generating templates. IBM C++ requires this to
+// be in its own file for auto template instantiation.
+//
+// = AUTHOR
+// Don Hinton <dhinton@ieee.org>
+//
+// ============================================================================
+
+#ifndef ACE_TESTS_FRAMEWORK_COMPONENT_DLL_H
+#define ACE_TESTS_FRAMEWORK_COMPONENT_DLL_H
+
+#include "Framework_Component_DLL_Export.h"
+#include "ace/Log_Msg.h"
+#include "ace/Singleton.h"
+#include "ace/Synch_Traits.h"
+
+/// This we will use to test the ACE_Framework_Repository
+class Simple_Service
+{
+public:
+ Simple_Service (void);
+
+ virtual ~Simple_Service (void);
+
+ //virtual const ACE_TCHAR *dll_name (void);
+
+ virtual const ACE_TCHAR *name (void);
+
+};
+
+// Adapter that contains the required dll_name() method and
+// has the "right" name for our DLL.
+template <class TYPE>
+class FWCT_DLL_Singleton_Adapter_T : public TYPE
+{
+public:
+ const ACE_TCHAR *dll_name (void)
+ {
+ FRAMEWORK_COMPONENT_DLL_TRACE ("FWCT_DLL_Singleton_Adapter_T::dll_name");
+ return ACE_TEXT("Framework_Component_DLL");
+ }
+};
+
+typedef ACE_DLL_Singleton_T < FWCT_DLL_Singleton_Adapter_T <Simple_Service>,
+ ACE_SYNCH_MUTEX > SS_SINGLETON;
+
+#endif /* ACE_TESTS_FRAMEWORK_COMPONENT_TEST_H */
diff --git a/ACE/tests/Framework_Component_DLL_Export.h b/ACE/tests/Framework_Component_DLL_Export.h
new file mode 100644
index 00000000000..dbbd38fbf43
--- /dev/null
+++ b/ACE/tests/Framework_Component_DLL_Export.h
@@ -0,0 +1,54 @@
+
+// -*- C++ -*-
+// $Id$
+// Definition for Win32 Export directives.
+// This file is generated automatically by generate_export_file.pl Framework_Component_DLL
+// ------------------------------
+#ifndef FRAMEWORK_COMPONENT_DLL_EXPORT_H
+#define FRAMEWORK_COMPONENT_DLL_EXPORT_H
+
+#include "ace/config-all.h"
+
+#if defined (ACE_AS_STATIC_LIBS) && !defined (FRAMEWORK_COMPONENT_DLL_HAS_DLL)
+# define FRAMEWORK_COMPONENT_DLL_HAS_DLL 0
+#endif /* ACE_AS_STATIC_LIBS && ! TEST_HAS_DLL */
+
+#if !defined (FRAMEWORK_COMPONENT_DLL_HAS_DLL)
+# define FRAMEWORK_COMPONENT_DLL_HAS_DLL 1
+#endif /* ! FRAMEWORK_COMPONENT_DLL_HAS_DLL */
+
+#if defined (FRAMEWORK_COMPONENT_DLL_HAS_DLL) && (FRAMEWORK_COMPONENT_DLL_HAS_DLL == 1)
+# if defined (FRAMEWORK_COMPONENT_DLL_BUILD_DLL)
+# define Framework_Component_DLL_Export ACE_Proper_Export_Flag
+# define FRAMEWORK_COMPONENT_DLL_SINGLETON_DECLARATION(T) ACE_EXPORT_SINGLETON_DECLARATION (T)
+# define FRAMEWORK_COMPONENT_DLL_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) ACE_EXPORT_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK)
+# else /* FRAMEWORK_COMPONENT_DLL_BUILD_DLL */
+# define Framework_Component_DLL_Export ACE_Proper_Import_Flag
+# define FRAMEWORK_COMPONENT_DLL_SINGLETON_DECLARATION(T) ACE_IMPORT_SINGLETON_DECLARATION (T)
+# define FRAMEWORK_COMPONENT_DLL_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) ACE_IMPORT_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK)
+# endif /* FRAMEWORK_COMPONENT_DLL_BUILD_DLL */
+#else /* FRAMEWORK_COMPONENT_DLL_HAS_DLL == 1 */
+# define Framework_Component_DLL_Export
+# define FRAMEWORK_COMPONENT_DLL_SINGLETON_DECLARATION(T)
+# define FRAMEWORK_COMPONENT_DLL_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK)
+#endif /* FRAMEWORK_COMPONENT_DLL_HAS_DLL == 1 */
+
+// Set FRAMEWORK_COMPONENT_DLL_NTRACE = 0 to turn on library specific tracing even if
+// tracing is turned off for ACE.
+#if !defined (FRAMEWORK_COMPONENT_DLL_NTRACE)
+# if (ACE_NTRACE == 1)
+# define FRAMEWORK_COMPONENT_DLL_NTRACE 1
+# else /* (ACE_NTRACE == 1) */
+# define FRAMEWORK_COMPONENT_DLL_NTRACE 0
+# endif /* (ACE_NTRACE == 1) */
+#endif /* !FRAMEWORK_COMPONENT_DLL_NTRACE */
+
+#if (FRAMEWORK_COMPONENT_DLL_NTRACE == 1)
+# define FRAMEWORK_COMPONENT_DLL_TRACE(X)
+#else /* (FRAMEWORK_COMPONENT_DLL_NTRACE == 1) */
+# define FRAMEWORK_COMPONENT_DLL_TRACE(X) ACE_TRACE_IMPL(X)
+#endif /* (FRAMEWORK_COMPONENT_DLL_NTRACE == 1) */
+
+#endif /* FRAMEWORK_COMPONENT_DLL_EXPORT_H */
+
+// End of auto generated file.
diff --git a/ACE/tests/Framework_Component_Test.cpp b/ACE/tests/Framework_Component_Test.cpp
new file mode 100644
index 00000000000..58c753c6200
--- /dev/null
+++ b/ACE/tests/Framework_Component_Test.cpp
@@ -0,0 +1,121 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = DESCRIPTION
+// This program tests both the ACE_Framework_Compondent and ACE_Repository.
+// Since Framework Components are singletons that can live in dlls loaded
+// via the Service Configurator framework, this test uses that framework
+// to load services from a dll that has a singleton based on ACE_DLL_Singleton.
+// When the dll is finally ready to be unloaded, the singleton will be
+// automatically cleaned up just-in-time.
+//
+// = AUTHOR
+// Don Hinton <dhinton@ieee.org>
+//
+// ============================================================================
+
+#include "tests/test_config.h"
+#include "ace/Service_Config.h"
+#include "ace/ARGV.h"
+#include "ace/DLL_Manager.h"
+
+ACE_RCSID(tests, Framework_Component_Test, "$Id$")
+
+// Define a few macros--because they're so much fun, and keep the
+// code below a little cleaner...
+#if (ACE_USES_CLASSIC_SVC_CONF == 1)
+
+# define ADD_SERVICE(X) \
+ ACE_TEXT ("dynamic Server_") ACE_TEXT(#X) \
+ ACE_TEXT (" Service_Object * ") \
+ ACE_TEXT ("Framework_Component_DLL:_make_Server_") ACE_TEXT(#X) \
+ ACE_TEXT ("() ''")
+
+# define REMOVE_SERVICE(X) \
+ ACE_TEXT ("remove Server_") ACE_TEXT(#X)
+
+#else /* ACE_USES_CLASSIC_SVC_CONF */
+
+# define ADD_SERVICE(X) \
+ ACE_TEXT ("<?xml version='1.0'?> <dynamic id='Server_") ACE_TEXT(#X) ACE_TEXT("' ") \
+ ACE_TEXT ("type='service_object'> <initializer init='_make_Server_") ACE_TEXT(#X) ACE_TEXT("' ") \
+ ACE_TEXT ("path='Framework_Component_DLL' params=''/> </dynamic>")
+
+# define REMOVE_SERVICE(X) \
+ ACE_TEXT ( "<?xml version='1.0'?> <remove id='Server_") ACE_TEXT(#X) \
+ ACE_TEXT("'> </remove>")
+
+#endif /* ACE_USES_CLASSIC_SVC_CONF */
+
+int
+run_test (u_long unload_mask = 0)
+{
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Running test with mask = %s|%s\n"),
+ ACE_BIT_ENABLED(unload_mask, ACE_DLL_UNLOAD_POLICY_PER_DLL) == 0
+ ? ACE_TEXT ("PER_PROCESS") : ACE_TEXT ("PER_DLL"),
+ ACE_BIT_ENABLED(unload_mask, ACE_DLL_UNLOAD_POLICY_LAZY) == 0
+ ? ACE_TEXT ("EAGER") : ACE_TEXT ("LAZY")));
+
+ ACE_DLL_Manager::instance ()->unload_policy (unload_mask);
+
+ // Now, let the ACE Service Configurator framework load our service from a
+ // dll, which contains a singleton.
+ ACE_Service_Config::open (ACE_TEXT ("Framework_Component_Test"),
+ ACE_DEFAULT_LOGGER_KEY,
+ 1, 1, 1);
+
+ // Now add server 1.
+ ACE_Service_Config::process_directive (ADD_SERVICE(1));
+
+ // And unload the first one, could unload the dll.
+ ACE_Service_Config::process_directive (REMOVE_SERVICE(1));
+
+ // Now readd server 1.
+ ACE_Service_Config::process_directive (ADD_SERVICE(1));
+
+ // And load another service from the same library.
+ ACE_Service_Config::process_directive (ADD_SERVICE(2));
+
+ // Unload the first one again, should *not* unload the dll this time.
+ ACE_Service_Config::process_directive (REMOVE_SERVICE(1));
+
+ // And unload the second service. Since the ACE_DLL_Handle will no longer
+ // have any references, the ACE_DLL_Manager will apply it's current unloading
+ // strategy and either call ACE_OS::dlclose() immediately, schedule a timeout
+ // the the reactor to call dlclose() some time in the future, or keep the
+ // dll loaded until program termination.
+ ACE_Service_Config::process_directive (REMOVE_SERVICE(2));
+
+ // Force unloading so we'll be ready for the next test.
+ ACE_DLL_Manager::instance ()->unload_policy (ACE_DLL_UNLOAD_POLICY_DEFAULT);
+
+ ACE_Service_Config::close ();
+ return 0;
+}
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT("Framework_Component_Test"));
+
+ int retval = 0;
+
+ // Use defaults, i.e., per process, eager unloading.
+ retval += run_test (ACE_DLL_UNLOAD_POLICY_DEFAULT);
+
+ // Per process, lazy unloading
+ retval += run_test (ACE_DLL_UNLOAD_POLICY_LAZY);
+
+ // Per dll, eager unloading
+ retval += run_test (ACE_DLL_UNLOAD_POLICY_PER_DLL);
+
+ // Per dll, lazy unloading.
+ retval += run_test (ACE_DLL_UNLOAD_POLICY_PER_DLL | ACE_DLL_UNLOAD_POLICY_LAZY);
+
+ ACE_END_TEST;
+ return retval == 0 ? 0 : -1;
+}
diff --git a/ACE/tests/Framework_Component_Test.h b/ACE/tests/Framework_Component_Test.h
new file mode 100644
index 00000000000..d5127477812
--- /dev/null
+++ b/ACE/tests/Framework_Component_Test.h
@@ -0,0 +1,39 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Framework_Component_Test.h
+//
+// = DESCRIPTION
+// Define class needed for generating templates. IBM C++ requires this to
+// be in its own file for auto template instantiation.
+//
+// = AUTHOR
+// Don Hinton <dhinton@ieee.org>
+//
+// ============================================================================
+
+#ifndef ACE_TESTS_FRAMEWORK_COMPONENT_TEST_H
+#define ACE_TESTS_FRAMEWORK_COMPONENT_TEST_H
+
+#include "ace/Log_Msg.h"
+
+/// This we will use to test the ACE_Framework_Repository
+class Simple_Service
+{
+public:
+ Simple_Service (void)
+ {
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Simple_Service::Simple_Service\n")));
+ }
+ virtual ~Simple_Service (void)
+ {
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Simple_Service::~Simple_Service\n")));
+ }
+};
+
+#endif /* ACE_TESTS_FRAMEWORK_COMPONENT_TEST_H */
diff --git a/ACE/tests/Future_Set_Test.cpp b/ACE/tests/Future_Set_Test.cpp
new file mode 100644
index 00000000000..1cbadc1e087
--- /dev/null
+++ b/ACE/tests/Future_Set_Test.cpp
@@ -0,0 +1,576 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Future_Set_Test.cpp
+//
+// = DESCRIPTION
+// This example tests the ACE Future Set and illustrates an
+// implementation of the Active Object pattern, which is available
+// at <http://www.cs.wustl.edu/~schmidt/Act-Obj.ps.gz>. The
+// Active Object itself is very simple -- it determines if numbers
+// are prime.
+//
+// = AUTHOR
+// Andres Kruse <Andres.Kruse@cern.ch>,
+// Douglas C. Schmidt <schmidt@cs.wustl.edu>,
+// Per Andersson <pera@ipso.se> and
+// Johnny Tucker <jtucker@infoglide.com>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/OS_NS_string.h"
+#include "ace/ACE.h"
+#include "ace/Task.h"
+#include "ace/Message_Queue.h"
+#include "ace/Future.h"
+#include "ace/Future_Set.h"
+#include "ace/Method_Request.h"
+#include "ace/Activation_Queue.h"
+#include "ace/Auto_Ptr.h"
+#include "ace/Atomic_Op.h"
+#include "ace/Null_Mutex.h"
+
+ACE_RCSID(tests, Future_Set_Test, "$Id$")
+
+#if defined (ACE_HAS_THREADS)
+
+typedef ACE_Atomic_Op<ACE_Thread_Mutex, int> ATOMIC_INT;
+
+// A counter for the tasks..
+static ATOMIC_INT task_count (0);
+
+class Prime_Scheduler : public ACE_Task_Base
+{
+ // = TITLE
+ // Prime number scheduler for the Active Object.
+ //
+ // = DESCRIPTION
+ // This class also plays the role of the Proxy and the Servant
+ // in the Active Object pattern. Naturally, these roles could
+ // be split apart from the Prime_Scheduler.
+
+ friend class Method_Request_work;
+ friend class Method_Request_name;
+ friend class Method_Request_end;
+public:
+ // = Initialization and termination methods.
+ Prime_Scheduler (const ACE_TCHAR *,
+ Prime_Scheduler * = 0);
+ // Constructor.
+
+ virtual int open (void *args = 0);
+ // Initializer.
+
+ virtual int shutdown (void);
+ // Terminator.
+
+ virtual ~Prime_Scheduler (void);
+ // Destructor.
+
+ // = These methods are part of the Active Object Proxy interface.
+ ACE_Future<u_long> work (u_long param, int count = 1);
+ ACE_Future<const ACE_TCHAR*> name (void);
+ void end (void);
+
+protected:
+ virtual int svc (void);
+ // Runs the Prime_Scheduler's event loop, which dequeues
+ // <Method_Requests> and dispatches them.
+
+ // = These are the Servant methods that do the actual work.
+ u_long work_i (u_long, int);
+ const ACE_TCHAR *name_i (void);
+
+private:
+ // = These are the <Prime_Scheduler> implementation details.
+ ACE_TCHAR *name_;
+ ACE_Activation_Queue activation_queue_;
+ Prime_Scheduler *scheduler_;
+};
+
+class Method_Request_work : public ACE_Method_Request
+{
+ // = TITLE
+ // Reification of the <work> method.
+public:
+ Method_Request_work (Prime_Scheduler *,
+ u_long,
+ int,
+ ACE_Future<u_long> &);
+ virtual ~Method_Request_work (void);
+
+ virtual int call (void);
+ // This is the entry point into the Active Object method.
+
+private:
+ Prime_Scheduler *scheduler_;
+
+ u_long param_;
+ // Parameter to the method that's used to determine if a number if
+ // prime.
+
+ int count_;
+ // Unused.
+
+ ACE_Future<u_long> future_result_;
+ // Store the result of the Future.
+};
+
+Method_Request_work::Method_Request_work (Prime_Scheduler *new_Prime_Scheduler,
+ u_long new_param,
+ int new_count,
+ ACE_Future<u_long> &new_result)
+ : scheduler_ (new_Prime_Scheduler),
+ param_ (new_param),
+ count_ (new_count),
+ future_result_ (new_result)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Method_Request_work created\n")));
+}
+
+Method_Request_work::~Method_Request_work (void)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Method_Request_work will be deleted.\n")));
+}
+
+int
+Method_Request_work::call (void)
+{
+ // Dispatch the Servant's operation and store the result into the
+ // Future.
+ return this->future_result_.set (this->scheduler_->work_i
+ (this->param_,
+ this->count_));
+}
+
+class Method_Request_name : public ACE_Method_Request
+{
+ // = TITLE
+ // Reification of the <name> method.
+public:
+ Method_Request_name (Prime_Scheduler *,
+ ACE_Future<const ACE_TCHAR*> &);
+ virtual ~Method_Request_name (void);
+
+ virtual int call (void);
+ // This is the entry point into the Active Object method.
+
+private:
+ Prime_Scheduler *scheduler_;
+ ACE_Future<const ACE_TCHAR*> future_result_;
+};
+
+Method_Request_name::Method_Request_name (Prime_Scheduler *new_scheduler,
+ ACE_Future<const ACE_TCHAR*> &new_result)
+ : scheduler_ (new_scheduler),
+ future_result_ (new_result)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Method_Request_name created\n")));
+}
+
+Method_Request_name::~Method_Request_name (void)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Method_Request_name will be deleted.\n")));
+}
+
+int
+Method_Request_name::call (void)
+{
+ // Dispatch the Servant's operation and store the result into the
+ // Future.
+ return future_result_.set (scheduler_->name_i ());
+}
+
+class Method_Request_end : public ACE_Method_Request
+{
+ // = TITLE
+ // Reification of the <end> method.
+public:
+ Method_Request_end (Prime_Scheduler *new_Prime_Scheduler);
+ virtual ~Method_Request_end (void);
+ virtual int call (void);
+
+private:
+ Prime_Scheduler *scheduler_;
+};
+
+Method_Request_end::Method_Request_end (Prime_Scheduler *scheduler)
+ : scheduler_ (scheduler)
+{
+}
+
+Method_Request_end::~Method_Request_end (void)
+{
+}
+
+int
+Method_Request_end::call (void)
+{
+ // Shut down the scheduler.
+ this->scheduler_->shutdown ();
+ return -1;
+}
+
+// Constructor
+Prime_Scheduler::Prime_Scheduler (const ACE_TCHAR *newname,
+ Prime_Scheduler *new_scheduler)
+ : scheduler_ (new_scheduler)
+{
+ ACE_NEW (this->name_,
+ ACE_TCHAR[ACE_OS::strlen (newname) + 1]);
+ ACE_OS::strcpy ((ACE_TCHAR *) this->name_,
+ newname);
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Prime_Scheduler %s created\n"),
+ this->name_));
+}
+
+// Destructor
+
+Prime_Scheduler::~Prime_Scheduler (void)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Prime_Scheduler %s will be destroyed\n"),
+ this->name_));
+ delete [] this->name_;
+}
+
+// open
+
+int
+Prime_Scheduler::open (void *)
+{
+ task_count++;
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Prime_Scheduler %s open\n"),
+ this->name_));
+ // Become an Active Object.
+ return this->activate (THR_BOUND | THR_DETACHED);
+}
+
+// close
+
+int
+Prime_Scheduler::shutdown (void)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Prime_Scheduler %s shutdown\n"),
+ this->name_));
+ task_count--;
+ return 0;
+}
+
+// Service..
+
+int
+Prime_Scheduler::svc (void)
+{
+ for (;;)
+ {
+ // Dequeue the next method request (we use an auto pointer in
+ // case an exception is thrown in the <call>).
+ auto_ptr<ACE_Method_Request> mo (this->activation_queue_.dequeue ());
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) calling method request\n")));
+ // Call it.
+ if (mo->call () == -1)
+ break;
+ // Destructor automatically deletes it.
+ }
+
+ /* NOTREACHED */
+ return 0;
+}
+
+void
+Prime_Scheduler::end (void)
+{
+ this->activation_queue_.enqueue (new Method_Request_end (this));
+}
+
+// Here's where the Work takes place. We compute if the parameter is
+// a prime number.
+
+u_long
+Prime_Scheduler::work_i (u_long param,
+ int count)
+{
+ ACE_UNUSED_ARG (count);
+
+ return ACE::is_prime (param, 2, param / 2);
+}
+
+const ACE_TCHAR *
+Prime_Scheduler::name_i (void)
+{
+ return this->name_;
+}
+
+ACE_Future<const ACE_TCHAR *>
+Prime_Scheduler::name (void)
+{
+ if (this->scheduler_)
+ // Delegate to the Prime_Scheduler.
+ return this->scheduler_->name ();
+ else
+ {
+ ACE_Future<const ACE_TCHAR*> new_future;
+
+ // @@ What happens if new fails here?
+ this->activation_queue_.enqueue
+ (new Method_Request_name (this,
+ new_future));
+ return new_future;
+ }
+}
+
+ACE_Future<u_long>
+Prime_Scheduler::work (u_long newparam,
+ int newcount)
+{
+ if (this->scheduler_) {
+ return this->scheduler_->work (newparam, newcount);
+ }
+ else {
+ ACE_Future<u_long> new_future;
+
+ this->activation_queue_.enqueue
+ (new Method_Request_work (this,
+ newparam,
+ newcount,
+ new_future));
+ return new_future;
+ }
+}
+
+// @@ These values should be set by the command line options!
+
+// Total number of loops.
+static int n_loops = 100;
+
+typedef ACE_Future_Rep<u_long> *u_long_key;
+typedef ACE_Future_Holder<u_long> *u_long_value;
+
+typedef ACE_Future_Rep<const ACE_TCHAR *> *char_star_key;
+typedef ACE_Future_Holder<const ACE_TCHAR *> *char_star_value;
+
+#endif /* ACE_HAS_THREADS */
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("Future_Set_Test"));
+
+#if defined (ACE_HAS_THREADS)
+ // @@ Should make these be <auto_ptr>s...
+ Prime_Scheduler *andres, *peter, *helmut, *matias;
+
+ // Create active objects..
+ ACE_NEW_RETURN (andres,
+ Prime_Scheduler (ACE_TEXT ("andres")),
+ -1);
+ int result = andres->open ();
+ ACE_ASSERT (result != -1);
+ ACE_NEW_RETURN (peter,
+ Prime_Scheduler (ACE_TEXT ("peter")),
+ -1);
+ result = peter->open ();
+ ACE_ASSERT (result != -1);
+ ACE_NEW_RETURN (helmut,
+ Prime_Scheduler (ACE_TEXT ("helmut")),
+ -1);
+ result = helmut->open ();
+ ACE_ASSERT (result != -1);
+
+ // Matias passes all asynchronous method calls on to Andres...
+ ACE_NEW_RETURN (matias,
+ Prime_Scheduler (ACE_TEXT ("matias"),
+ andres),
+ -1);
+ result = matias->open ();
+ ACE_ASSERT (result != -1);
+
+ ACE_Future<u_long> fresulta;
+ ACE_Future<u_long> fresultb;
+ ACE_Future<u_long> fresultc;
+ ACE_Future<u_long> fresultd;
+ ACE_Future<const ACE_TCHAR *> fname;
+
+ ACE_Future_Set<u_long> fseta;
+ ACE_Future_Set<u_long> fsetb;
+ ACE_Future_Set<u_long> fsetc;
+ ACE_Future_Set<u_long> fsetd;
+ ACE_Future_Set<const ACE_TCHAR *> fsetname;
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) initializing future sets with non-blocking call\n")));
+
+ for (int i = 0; i < n_loops; i++)
+ {
+ // Spawn off the methods, which run in a separate thread as
+ // active object invocations.
+ fresulta = andres->work (9013);
+ fresultb = peter->work (9013);
+ fresultc = helmut->work (9013);
+ fresultd = matias->work (9013);
+ fname = andres->name ();
+
+ fsetname.insert (fname);
+ fname = peter->name ();
+ fsetname.insert (fname);
+ fname = helmut->name ();
+
+ fseta.insert (fresulta);
+ fsetb.insert (fresultb);
+ fsetc.insert (fresultc);
+ fsetd.insert (fresultd);
+ fsetname.insert (fname);
+ }
+
+
+ // See if the result is available...
+
+ if (!fseta.is_empty ())
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) wow.. set a is not empty.....\n")));
+
+ if (!fsetb.is_empty ())
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) wow.. set b is not empty.....\n")));
+
+ if (!fsetc.is_empty ())
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) wow.. set c is not empty.....\n")));
+
+ if (!fsetd.is_empty ())
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) wow.. set d is not empty.....\n")));
+
+ if (!fsetname.is_empty ())
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) wow.. set name is not empty.....\n")));
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) non-blocking calls done... now blocking...\n")));
+
+ // Save the result of fresulta.
+
+ u_long resulta = 0;
+ u_long resultb = 0;
+ u_long resultc = 0;
+ u_long resultd = 0;
+
+ u_int count = 0;
+ while (fseta.next_readable (fresulta))
+ {
+ fresulta.get (resulta);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) result(%u) a %u\n"),
+ count,
+ (u_int) resulta));
+ }
+
+ count = 0;
+ while (fsetb.next_readable (fresultb))
+ {
+ fresultb.get (resultb);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) result(%u) b %u\n"),
+ count,
+ (u_int) resultb));
+ }
+
+ count = 0;
+ while (fsetc.next_readable (fresultc))
+ {
+ fresultc.get (resultc);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) result(%u) c %u\n"),
+ count,
+ (u_int) resultc));
+ }
+
+ count = 0;
+ while (fsetd.next_readable (fresultd))
+ {
+ fresultd.get (resultd);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) result(%u) d %u\n"),
+ count,
+ (u_int) resultd));
+ }
+
+ const ACE_TCHAR *name = 0;
+ count = 0;
+ while (fsetname.next_readable (fname))
+ {
+ fname.get (name);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) result(%u) name %s\n"),
+ count,
+ name));
+ }
+
+ if (fseta.is_empty ())
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) wow.. set a is empty.....\n")));
+
+ if (fsetb.is_empty ())
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) wow.. set b is empty.....\n")));
+
+ if (fsetc.is_empty ())
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) wow.. set c is empty.....\n")));
+
+ if (fsetd.is_empty ())
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) wow.. set d is empty.....\n")));
+
+ if (fsetname.is_empty ())
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) wow.. set name is empty.....\n")));
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) task_count %d\n"),
+ task_count.value () ));
+
+ // Close things down.
+ andres->end ();
+ peter->end ();
+ helmut->end ();
+ matias->end ();
+
+ ACE_Thread_Manager::instance ()->wait ();
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) task_count %d\n"),
+ task_count.value () ));
+
+ delete andres;
+ delete peter;
+ delete helmut;
+ delete matias;
+
+#else
+ ACE_ERROR ((LM_INFO,
+ ACE_TEXT ("threads not supported on this platform\n")));
+#endif /* ACE_HAS_THREADS */
+ ACE_END_TEST;
+ return 0;
+}
diff --git a/ACE/tests/Future_Test.cpp b/ACE/tests/Future_Test.cpp
new file mode 100644
index 00000000000..a8798a476ba
--- /dev/null
+++ b/ACE/tests/Future_Test.cpp
@@ -0,0 +1,606 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Future_Test.cpp
+//
+// = DESCRIPTION
+// This example tests the ACE Future and illustrates an
+// implementation of the Active Object pattern, which is available
+// at <http://www.cs.wustl.edu/~schmidt/Act-Obj.ps.gz>. The
+// Active Object itself is very simple -- it determines if numbers
+// are prime.
+//
+// = AUTHOR
+// Andres Kruse <Andres.Kruse@cern.ch>,
+// Douglas C. Schmidt <schmidt@cs.wustl.edu>,
+// and Per Andersson <pera@ipso.se>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/OS_NS_string.h"
+#include "ace/OS_NS_sys_time.h"
+#include "ace/ACE.h"
+#include "ace/Task.h"
+#include "ace/Message_Queue.h"
+#include "ace/Future.h"
+#include "ace/Method_Request.h"
+#include "ace/Activation_Queue.h"
+#include "ace/Auto_Ptr.h"
+#include "ace/Atomic_Op.h"
+
+
+ACE_RCSID(tests, Future_Test, "$Id$")
+
+#if defined (ACE_HAS_THREADS)
+
+typedef ACE_Atomic_Op<ACE_Thread_Mutex, int> ATOMIC_INT;
+
+// A counter for the tasks..
+static ATOMIC_INT task_count (0);
+
+// A counter for the futures..
+static ATOMIC_INT future_count (0);
+
+// A counter for the capsules..
+static ATOMIC_INT capsule_count (0);
+
+// A counter for the method requests...
+static ATOMIC_INT method_request_count (0);
+
+class Prime_Scheduler : public ACE_Task_Base
+{
+ // = TITLE
+ // Prime number scheduler for the Active Object.
+ //
+ // = DESCRIPTION
+ // This class also plays the role of the Proxy and the Servant
+ // in the Active Object pattern. Naturally, these roles could
+ // be split apart from the Prime_Scheduler.
+
+ friend class Method_Request_work;
+ friend class Method_Request_name;
+ friend class Method_Request_end;
+public:
+ // = Initialization and termination methods.
+ Prime_Scheduler (const ACE_TCHAR *,
+ Prime_Scheduler * = 0);
+ // Constructor.
+
+ virtual int open (void *args = 0);
+ // Initializer.
+
+ virtual int shutdown (void);
+ // Terminator.
+
+ virtual ~Prime_Scheduler (void);
+ // Destructor.
+
+ // = These methods are part of the Active Object Proxy interface.
+ ACE_Future<u_long> work (u_long param, int count = 1);
+ ACE_Future<const ACE_TCHAR*> name (void);
+ void end (void);
+
+protected:
+ virtual int svc (void);
+ // Runs the Prime_Scheduler's event loop, which dequeues
+ // <Method_Requests> and dispatches them.
+
+ // = These are the Servant methods that do the actual work.
+ u_long work_i (u_long, int);
+ const ACE_TCHAR *name_i (void);
+
+private:
+ // = These are the <Prime_Scheduler> implementation details.
+ ACE_TCHAR *name_;
+ ACE_Activation_Queue activation_queue_;
+ Prime_Scheduler *scheduler_;
+};
+
+class Method_Request_work : public ACE_Method_Request
+{
+ // = TITLE
+ // Reification of the <work> method.
+public:
+ Method_Request_work (Prime_Scheduler *,
+ u_long,
+ int,
+ ACE_Future<u_long> &);
+ virtual ~Method_Request_work (void);
+
+ virtual int call (void);
+ // This is the entry point into the Active Object method.
+
+private:
+ Prime_Scheduler *scheduler_;
+
+ u_long param_;
+ // Parameter to the method that's used to determine if a number if
+ // prime.
+
+ int count_;
+ // Unused.
+
+ ACE_Future<u_long> future_result_;
+ // Store the result of the Future.
+};
+
+Method_Request_work::Method_Request_work (Prime_Scheduler *new_Prime_Scheduler,
+ u_long new_param,
+ int new_count,
+ ACE_Future<u_long> &new_result)
+ : scheduler_ (new_Prime_Scheduler),
+ param_ (new_param),
+ count_ (new_count),
+ future_result_ (new_result)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Method_Request_work created\n")));
+}
+
+Method_Request_work::~Method_Request_work (void)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Method_Request_work will be deleted.\n")));
+}
+
+int
+Method_Request_work::call (void)
+{
+ // Dispatch the Servant's operation and store the result into the
+ // Future.
+ return this->future_result_.set (this->scheduler_->work_i
+ (this->param_,
+ this->count_));
+}
+
+class Method_Request_name : public ACE_Method_Request
+{
+ // = TITLE
+ // Reification of the <name> method.
+public:
+ Method_Request_name (Prime_Scheduler *,
+ ACE_Future<const ACE_TCHAR*> &);
+ virtual ~Method_Request_name (void);
+
+ virtual int call (void);
+ // This is the entry point into the Active Object method.
+
+private:
+ Prime_Scheduler *scheduler_;
+ ACE_Future<const ACE_TCHAR*> future_result_;
+};
+
+Method_Request_name::Method_Request_name (Prime_Scheduler *new_scheduler,
+ ACE_Future<const ACE_TCHAR*> &new_result)
+ : scheduler_ (new_scheduler),
+ future_result_ (new_result)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Method_Request_name created\n")));
+}
+
+Method_Request_name::~Method_Request_name (void)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Method_Request_name will be deleted.\n")));
+}
+
+int
+Method_Request_name::call (void)
+{
+ // Dispatch the Servant's operation and store the result into the
+ // Future.
+ return future_result_.set (scheduler_->name_i ());
+}
+
+class Method_Request_end : public ACE_Method_Request
+{
+ // = TITLE
+ // Reification of the <end> method.
+public:
+ Method_Request_end (Prime_Scheduler *new_Prime_Scheduler);
+ virtual ~Method_Request_end (void);
+ virtual int call (void);
+
+private:
+ Prime_Scheduler *scheduler_;
+};
+
+Method_Request_end::Method_Request_end (Prime_Scheduler *scheduler)
+ : scheduler_ (scheduler)
+{
+}
+
+Method_Request_end::~Method_Request_end (void)
+{
+}
+
+int
+Method_Request_end::call (void)
+{
+ // Shut down the scheduler.
+ this->scheduler_->shutdown ();
+ return -1;
+}
+
+// Constructor
+Prime_Scheduler::Prime_Scheduler (const ACE_TCHAR *newname,
+ Prime_Scheduler *new_scheduler)
+ : scheduler_ (new_scheduler)
+{
+ ACE_NEW (this->name_,
+ ACE_TCHAR[ACE_OS::strlen (newname) + 1]);
+ ACE_OS::strcpy ((ACE_TCHAR *) this->name_,
+ newname);
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Prime_Scheduler %s created\n"),
+ this->name_));
+}
+
+// Destructor
+
+Prime_Scheduler::~Prime_Scheduler (void)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Prime_Scheduler %s will be destroyed\n"),
+ this->name_));
+ delete [] this->name_;
+}
+
+// open
+
+int
+Prime_Scheduler::open (void *)
+{
+ task_count++;
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Prime_Scheduler %s open\n"),
+ this->name_));
+ // Become an Active Object.
+ return this->activate (THR_BOUND | THR_DETACHED);
+}
+
+// close
+
+int
+Prime_Scheduler::shutdown (void)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Prime_Scheduler %s shutdown\n"),
+ this->name_));
+ task_count--;
+ return 0;
+}
+
+// Service..
+
+int
+Prime_Scheduler::svc (void)
+{
+ for (;;)
+ {
+ // Dequeue the next method request (we use an auto pointer in
+ // case an exception is thrown in the <call>).
+ auto_ptr<ACE_Method_Request> mo (this->activation_queue_.dequeue ());
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) calling method request\n")));
+ // Call it.
+ if (mo->call () == -1)
+ break;
+ // Destructor automatically deletes it.
+ }
+
+ /* NOTREACHED */
+ return 0;
+}
+
+void
+Prime_Scheduler::end (void)
+{
+ this->activation_queue_.enqueue (new Method_Request_end (this));
+}
+
+// Here's where the Work takes place. We compute if the parameter is
+// a prime number.
+
+u_long
+Prime_Scheduler::work_i (u_long param,
+ int count)
+{
+ ACE_UNUSED_ARG (count);
+
+ return ACE::is_prime (param, 2, param / 2);
+}
+
+const ACE_TCHAR *
+Prime_Scheduler::name_i (void)
+{
+ return this->name_;
+}
+
+ACE_Future<const ACE_TCHAR *>
+Prime_Scheduler::name (void)
+{
+ if (this->scheduler_)
+ // Delegate to the Prime_Scheduler.
+ return this->scheduler_->name ();
+ else
+ {
+ ACE_Future<const ACE_TCHAR*> new_future;
+
+ // @@ What happens if new fails here?
+ this->activation_queue_.enqueue
+ (new Method_Request_name (this,
+ new_future));
+ return new_future;
+ }
+}
+
+ACE_Future<u_long>
+Prime_Scheduler::work (u_long newparam,
+ int newcount)
+{
+ if (this->scheduler_) {
+ return this->scheduler_->work (newparam, newcount);
+ }
+ else {
+ ACE_Future<u_long> new_future;
+
+ this->activation_queue_.enqueue
+ (new Method_Request_work (this,
+ newparam,
+ newcount,
+ new_future));
+ return new_future;
+ }
+}
+
+// @@ These values should be set by the command line options!
+
+// Total number of loops.
+static int n_loops = 100;
+
+#endif /* ACE_HAS_THREADS */
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("Future_Test"));
+
+#if defined (ACE_HAS_THREADS)
+ // @@ Should make these be <auto_ptr>s...
+ Prime_Scheduler *andres, *peter, *helmut, *matias;
+
+ // Create active objects..
+ ACE_NEW_RETURN (andres,
+ Prime_Scheduler (ACE_TEXT ("andres")),
+ -1);
+ int result = andres->open ();
+ ACE_ASSERT (result != -1);
+ ACE_NEW_RETURN (peter,
+ Prime_Scheduler (ACE_TEXT ("peter")),
+ -1);
+ result = peter->open ();
+ ACE_ASSERT (result != -1);
+ ACE_NEW_RETURN (helmut,
+ Prime_Scheduler (ACE_TEXT ("helmut")),
+ -1);
+ result = helmut->open ();
+ ACE_ASSERT (result != -1);
+
+ // Matias passes all asynchronous method calls on to Andres...
+ ACE_NEW_RETURN (matias,
+ Prime_Scheduler (ACE_TEXT ("matias"),
+ andres),
+ -1);
+ result = matias->open ();
+ ACE_ASSERT (result != -1);
+
+ for (int i = 0; i < n_loops; i++)
+ {
+ {
+ ACE_Future<u_long> fresulta;
+ ACE_Future<u_long> fresultb;
+ ACE_Future<u_long> fresultc;
+ ACE_Future<u_long> fresultd;
+ ACE_Future<u_long> fresulte;
+ ACE_Future<const ACE_TCHAR *> fname;
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) going to do a non-blocking call\n")));
+
+ // Spawn off the methods, which run in a separate thread as
+ // active object invocations.
+ fresulta = andres->work (9013);
+ fresultb = peter->work (9013);
+ fresultc = helmut->work (9013);
+ fresultd = matias->work (9013);
+ fname = andres->name ();
+
+ // See if the result is available...
+ if (fresulta.ready ())
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) wow.. work is ready.....\n")));
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) non-blocking call done... now blocking...\n")));
+
+ // Save the result of fresulta.
+
+ fresulte = fresulta;
+
+ if (i % 3 == 0)
+ {
+ // Every 3rd time... disconnect the futures... but
+ // "fresulte" should still contain the result...
+ fresulta.cancel (10ul);
+ fresultb.cancel (20ul);
+ fresultc.cancel (30ul);
+ fresultd.cancel (40ul);
+ }
+
+ u_long resulta = 0, resultb = 0, resultc = 0, resultd = 0, resulte = 0;
+
+ fresulta.get (resulta);
+ fresultb.get (resultb);
+ fresultc.get (resultc);
+ fresultd.get (resultd);
+ fresulte.get (resulte);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) result a %u\n")
+ ACE_TEXT ("(%t) result b %u\n")
+ ACE_TEXT ("(%t) result c %u\n")
+ ACE_TEXT ("(%t) result d %u\n")
+ ACE_TEXT ("(%t) result e %u\n"),
+ (u_int) resulta,
+ (u_int) resultb,
+ (u_int) resultc,
+ (u_int) resultd,
+ (u_int) resulte));
+
+ const ACE_TCHAR *name = 0;
+ fname.get (name);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) name %s\n"),
+ name));
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) task_count %d future_count %d ")
+ ACE_TEXT ("capsule_count %d method_request_count %d\n"),
+ task_count.value (),
+ future_count.value (),
+ capsule_count.value (),
+ method_request_count.value ()));
+ }
+
+ // Close things down.
+ andres->end ();
+ peter->end ();
+ helmut->end ();
+ matias->end ();
+
+ ACE_Thread_Manager::instance ()->wait ();
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) task_count %d future_count %d ")
+ ACE_TEXT ("capsule_count %d method_request_count %d\n"),
+ task_count.value (),
+ future_count.value (),
+ capsule_count.value (),
+ method_request_count.value ()));
+ {
+ // Check if set then get works, older versions of <ACE_Future>
+ // will lock forever (or until the timer expires), will use a
+ // small timer value to avoid blocking the process.
+
+ ACE_Future<int> f1;
+ f1.set (100);
+
+ // Note you need to use absolute time, not relative time.
+ ACE_Time_Value timeout (ACE_OS::gettimeofday () + ACE_Time_Value (10));
+ int value = 0;
+
+ if (f1.get (value, &timeout) == 0
+ && value == 100)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Ace_Future<T>::Set followed by Ace_Future<T>::Get works.\n")));
+ else
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("ACE_Future<T>::Set followed by Ace_Future<T>::Get does ")
+ ACE_TEXT ("not work, broken Ace_Future<> implementation.\n")));
+ }
+
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Checking if Ace_Future<T>::operator= is implemented ")
+ ACE_TEXT ("incorrectly this might crash the program.\n")));
+ ACE_Future<int> f1;
+ {
+ // To ensure that a rep object is created.
+ ACE_Future<int> f2 (f1);
+ }
+ // Now it is one ACE_Future<int> referencing the rep instance
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("0.\n")));
+
+ //Check that self assignment works.
+ f1 = f1;
+
+ // Is there any repesentation left, and if so what is the ref
+ // count older ACE_Future<> implementations have deleted the rep
+ // instance at this moment
+
+ // The stuff below might crash the process if the <operator=>
+ // implementation was bad.
+ int value = 0;
+
+ ACE_Time_Value timeout (ACE_OS::gettimeofday () + ACE_Time_Value (10));
+
+ f1.set (100);
+ f1.get (value, &timeout);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("1.\n")));
+ {
+ // Might delete the same data a couple of times.
+ ACE_Future<int> f2 (f1);
+ f1.set (100);
+ f1.get (value, &timeout);
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("2.\n")));
+ {
+ ACE_Future<int> f2 (f1);
+ f1.set (100);
+ f1.get (value, &timeout);
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("3.\n")));
+ {
+ ACE_Future<int> f2 (f1);
+ f1.set (100);
+ f1.get (value, &timeout);
+ }
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("4.\n")));
+ {
+ ACE_Future<int> f2 (f1);
+ f1.set (100);
+ f1.get (value, &timeout);
+ }
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("5.\n")));
+ {
+ ACE_Future<int> f2 (90);
+ f2.get (value, &timeout);
+ f1.get (value, &timeout);
+ }
+ }
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("No it did not crash the program.\n")));
+
+ delete andres;
+ delete peter;
+ delete helmut;
+ delete matias;
+
+#else
+ ACE_ERROR ((LM_INFO,
+ ACE_TEXT ("threads not supported on this platform\n")));
+#endif /* ACE_HAS_THREADS */
+ ACE_END_TEST;
+ return 0;
+}
diff --git a/ACE/tests/Get_Opt_Test.cpp b/ACE/tests/Get_Opt_Test.cpp
new file mode 100644
index 00000000000..b34c9e64f2f
--- /dev/null
+++ b/ACE/tests/Get_Opt_Test.cpp
@@ -0,0 +1,346 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = DESCRIPTION
+// This program tests both the short and long option support in
+// <ACE_Get_Opt>, and demonstrates how to use it.
+//
+// = AUTHOR
+// Don Hinton <dhinton@dresystems.com>
+//
+// ============================================================================
+
+#include "tests/test_config.h"
+#include "ace/Get_Opt.h"
+#include "ace/ARGV.h"
+#include "ace/SString.h"
+#include "ace/OS_NS_stdlib.h"
+#include "tests/test_config.h"
+
+ACE_RCSID(tests, Get_Opt_Test, "$Id$")
+
+/*
+ * This is the heart of the test. It sets up the optstring, instantiates
+ * ACE_Get_Opt, add long options, processes them in a loop, and prints out
+ * the results to the log.
+ *
+ * It returns 0 for success and 1 for error so we can keep track of the
+ * total error count.
+ */
+
+static const ACE_TString empty (ACE_TEXT (""));
+
+static int
+parse_args (int test_number,
+ int ordering,
+ const ACE_TCHAR *test_args,
+ int skip_argv = 1,
+ int report_errors = 1,
+ const ACE_TString &opt_prefix = empty)
+{
+ ACE_TString test;
+ ACE_TString optstring (opt_prefix);
+
+ // Test the skip_argv for the first test only.
+ if (skip_argv > 0)
+ {
+ test = ACE_TEXT ("Test_");
+ ACE_TCHAR s[20];
+ test += ACE_OS::itoa (test_number, s, 10);
+ test += ACE_TEXT (" ");
+ }
+
+ test += test_args;
+ optstring += ACE_TEXT ("fr:o::sW;");
+
+ ACE_DEBUG ((LM_INFO,
+ ACE_TEXT (" TEST %d *****************************************")
+ ACE_TEXT ("*******************\n"),
+ test_number));
+ ACE_DEBUG ((LM_INFO, " Command line: \"%s\"\n", test.c_str ()));
+
+ ACE_ARGV args (test.c_str ());
+
+ ACE_Get_Opt get_opt (args.argc (),
+ args.argv (),
+ optstring.c_str (),
+ skip_argv,
+ report_errors,
+ ordering);
+
+ // Now add the default long args.
+ if (get_opt.long_option (ACE_TEXT ("flag"),
+ 'f',
+ ACE_Get_Opt::NO_ARG) != 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT (" Unable to add long option 'f' \n")), 1);
+
+ if (get_opt.long_option (ACE_TEXT ("requires_arg"),
+ 'r',
+ ACE_Get_Opt::ARG_REQUIRED) != 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT (" Unable to add long option 'r' \n")), 1);
+
+ if (get_opt.long_option (ACE_TEXT ("optional_arg"),
+ 'o',
+ ACE_Get_Opt::ARG_OPTIONAL) != 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT (" Unable to add long option 'o' \n")), 1);
+
+ if (get_opt.long_option (ACE_TEXT ("long_option"),
+ 'l',
+ ACE_Get_Opt::ARG_OPTIONAL) != 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT (" Unable to add long option 'l' \n")), 1);
+
+ if (get_opt.long_option (ACE_TEXT ("long_only"),
+ -11,
+ ACE_Get_Opt::ARG_REQUIRED) != 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT (" Unable to add long option ")
+ ACE_TEXT ("\"long_only\" \n")), 1);
+
+ if (get_opt.long_option (ACE_TEXT ("long_no_arg")) != 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT (" Unable to add long option ")
+ ACE_TEXT ("\"long_no_arg\" \n")), 1);
+
+ // This is the special case of providing a non-alpha numeric corresponding
+ // short option. This lets you use the corresponding short option in a
+ // switch statement, even thought a meaningful short options isn't available
+ // (afterall, there are only so many alpha numeric characters available).
+ if (get_opt.long_option (ACE_TEXT ("non_alpha-num_short"),
+ -10,
+ ACE_Get_Opt::ARG_OPTIONAL) != 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT (" Unable to add long option ")
+ ACE_TEXT ("\"non_alpha_short\" \n")), 1);
+
+ // We print out the optstring here because adding long_options that
+ // have corresponding short options that aren't yet present, are added.
+ ACE_DEBUG ((LM_INFO,
+ ACE_TEXT (" optstring: \"%s\" skip_argv: %d\n"),
+ get_opt.optstring (), skip_argv));
+
+ // Now, let's parse it...
+ int c = 0;
+ while ((c = get_opt ()) != EOF)
+ {
+ switch (c)
+ {
+ case 0:
+ // Long Option.
+ if (!get_opt.long_option ())
+ ACE_ERROR_RETURN ((LM_ERROR, " Long option doesn't exist.\n"), 1);
+
+ ACE_DEBUG ((LM_INFO, " Found long option \"%s\" %s %s\n",
+ get_opt.long_option (),
+ get_opt.opt_arg () ? ACE_TEXT ("with argument:")
+ : ACE_TEXT (""),
+ get_opt.opt_arg () ? get_opt.opt_arg ()
+ : ACE_TEXT ("")));
+ break;
+ case 'f':
+ // This flag was added in both the optstring in the ctor and with
+ // long_option().
+ case 's':
+ // This one is only short and has no long option.
+ ACE_DEBUG ((LM_INFO, " Found option flag '%s'\n",
+ get_opt.last_option ()));
+ break;
+ case 'r':
+ // This one has a required argument, we wouldn't be here if the
+ // arg were missing. Note that we call get_opt.opt_arg () to return
+ // the argument, but we could have used get_opt.opt_arg () since
+ // opt_arg () is defined as "opt_arg ()".
+ ACE_DEBUG ((LM_INFO,
+ " Found option '%s' with required argument \"%s\"\n",
+ get_opt.last_option (), get_opt.opt_arg ()));
+ break;
+ case 'o':
+ // This one has an optional argument.
+ case 'l':
+ // This short options was set automatically added to optstring.
+ ACE_DEBUG ((LM_INFO,
+ " Found option '%s' with optional argument \"%s\"\n",
+ get_opt.last_option (),
+ get_opt.opt_arg () ? get_opt.opt_arg ()
+ : ACE_TEXT ("default")));
+ break;
+ case 1:
+ // Non-option when in RETURN_IN_ORDER mode.
+ ACE_DEBUG ((LM_INFO,
+ " Found a non-option argument \"%s\" before finding "
+ "\"--\" (must be in RETURN_IN_ORDER mode).\n",
+ get_opt.opt_arg ()));
+ break;
+ case -10:
+ // we found the short option that isn't alpha numeric.
+ ACE_DEBUG ((LM_INFO,
+ " Found option '%s' with optional argument \"%s\"\n",
+ get_opt.last_option (),
+ get_opt.opt_arg () ? get_opt.opt_arg ()
+ : ACE_TEXT ("default")));
+ break;
+ case -11:
+ // we found the short option that isn't alpha numeric.
+ ACE_DEBUG ((LM_INFO,
+ " Found option '%s' with argument \"%s\"\n",
+ get_opt.last_option (), get_opt.opt_arg ()));
+ break;
+ case ':':
+ // This means an option requiring an argument didn't have one.
+ ACE_DEBUG ((LM_INFO,
+ ACE_TEXT (" Option '%c' (%s) requires an argument ")
+ ACE_TEXT ("but none was supplied\n"),
+ get_opt.opt_opt (), get_opt.last_option ()));
+ break;
+ case '?':
+ // An unrecognized option.
+ default:
+ // This is an error, perhaps you could handle them, but let's
+ // just log it and keep going
+ ACE_DEBUG ((LM_INFO,
+ " Found an unknown option (%s) we couldn't handle.\n",
+ get_opt.last_option ()));
+ }
+ }
+
+ // Print out the rest of the arguments left in the command line (if any).
+ int index = 0;
+ for (index = get_opt.opt_ind (); index < args.argc (); index++)
+ ACE_DEBUG ((LM_INFO, " Found non-option argument \"%s\"\n",
+ args.argv ()[index]));
+
+ // Now print them all so we can examine the permuted cmd line.
+ for (index = 0; index < args.argc (); index++)
+ ACE_DEBUG ((LM_INFO, " argv[%u] \"%s\"\n",
+ index, args.argv ()[index]));
+ return 0;
+}
+
+/*
+ * Add new tests cases here. We increment the test number and pass the
+ * type of ordering we want so that each test can be tested with multiple
+ * ordering values in order to demostrate the difference.
+ *
+ * The return value is cumulative, and serves as a failure count that is
+ * returned at the end of all the tests.
+ */
+static int
+run_test (int& test_number, int ordering)
+{
+ int retval = 0;
+
+ ACE_DEBUG ((LM_INFO,
+ " ########## Running Tests with ordering = %s ##########\n",
+ ordering == 1 ? "REQUIRE_ORDER" :
+ ordering == 2 ? "PERMUTE_ARGS" :
+ "RETURN_IN_ORDER"));
+
+ // Basic test, but don't use the program name and don't skip any args.
+ retval += parse_args
+ (test_number++, ordering,
+ ACE_TEXT ("-f -rreq-arg -oopt-arg -lopt-arg --long_only=lo_arg -s arg1 arg2"),
+ 0);
+
+ // Same, but combining short args that don't take args
+ retval += parse_args
+ (test_number++, ordering,
+ ACE_TEXT ("-fsrreq-arg -oopt-arg -lopt-arg --long_only=lo_arg arg1 arg2"));
+
+ // Now we use defaults for options with optional args.
+ retval += parse_args
+ (test_number++, ordering,
+ ACE_TEXT ("-fsrreq-arg -o -l --long_only=lo_arg arg1 arg2"));
+
+ // Let's mix up the options and non-options an see what happens.
+ retval += parse_args
+ (test_number++, ordering,
+ ACE_TEXT ("-fs arg1 -rreq-arg -o arg2 -l --long_only=lo_arg"));
+
+ // Now we turn off options parsing explicitely by passing "--" in the middle.
+ retval += parse_args
+ (test_number++, ordering,
+ ACE_TEXT ("-fs -rreq-arg -- arg1 -o arg2 -l --long_only=lo_arg"));
+
+ // Let's try the same thing but mix up the options and non-options.
+ retval += parse_args
+ (test_number++, ordering,
+ ACE_TEXT ("-fs arg1 arg2 -rreq-arg -- arg3 -o"));
+
+ // One more time but with "-W".
+ retval += parse_args
+ (test_number++, ordering,
+ ACE_TEXT ("-fs arg1 arg2 -rreq-arg -W long_option=opt-arg -- arg3 -o"));
+
+ // Let's pass some long options.
+ retval += parse_args
+ (test_number++, ordering,
+ ACE_TEXT ("--flag -s --requires_arg=req-arg --optional_arg --long_only lo_arg arg1 arg2"));
+
+ // And long options without the '='.
+ retval += parse_args
+ (test_number++, ordering,
+ ACE_TEXT ("--flag -s --requires_arg req-arg --optional_arg --long_only=lo_arg arg1 arg2"));
+
+ // Pass "-W" to cause the next argument to be read as a long option.
+ retval += parse_args
+ (test_number++, ordering,
+ ACE_TEXT ("-fso -W requires_arg=req-arg -Woptional_arg -l arg1 arg2"));
+
+ // This is the special case of a non-alpha numeric short option.
+ retval += parse_args
+ (test_number++, ordering,
+ ACE_TEXT ("-fso --non_alpha-num_short=xxx arg1 arg2"));
+
+ // Now, let's test some error conditions (we turn off report_errors since they are
+ // intentional, we don't want to break the test script)
+ int report_errors = 0;
+
+ // Bad short option.
+ retval += parse_args (test_number++, ordering, ACE_TEXT ("-X"), 1, report_errors);
+
+ // Short option with missing required arg.
+ ACE_TString report_missing (ACE_TEXT (":"));
+ retval += parse_args (test_number++, ordering, ACE_TEXT ("-r"), 1, report_errors, report_missing);
+
+ // Short option with missing required arg with trailing "--".
+ // This reads "--" as the arg, but should it?
+ retval += parse_args (test_number++, ordering, ACE_TEXT ("-r --"), 1, report_errors);
+
+ // Long option with missing required arg.
+ retval += parse_args (test_number++, ordering, ACE_TEXT ("--long_only"), 1, report_errors);
+
+ // Long option that doesn't take an arg has one.
+ retval += parse_args (test_number++, ordering, ACE_TEXT ("--long_no_arg=bad_arg"), 1, report_errors);
+
+ // Unknown long option.
+ retval += parse_args (test_number++, ordering, ACE_TEXT ("--unknown"), 1, report_errors);
+
+ // Ambigous long option.
+ retval += parse_args (test_number++, ordering, ACE_TEXT ("--long"), 1, report_errors);
+
+ return retval;
+}
+
+int
+run_main (int, ACE_TCHAR *argv[])
+{
+ ACE_START_TEST (ACE_TEXT ("Get_Opt_Test"));
+ ACE_UNUSED_ARG (argv);
+ int retval = 0;
+ int test_number = 0;
+
+ // Run the tests for each type of ordering.
+ retval = run_test (test_number, ACE_Get_Opt::PERMUTE_ARGS);
+ retval += run_test (test_number, ACE_Get_Opt::REQUIRE_ORDER);
+ retval += run_test (test_number, ACE_Get_Opt::RETURN_IN_ORDER);
+
+ ACE_END_TEST;
+ return retval;
+}
diff --git a/ACE/tests/HTBP/HTBP_Config.conf b/ACE/tests/HTBP/HTBP_Config.conf
new file mode 100644
index 00000000000..49dfd238ec3
--- /dev/null
+++ b/ACE/tests/HTBP/HTBP_Config.conf
@@ -0,0 +1,4 @@
+[htbp]
+proxy_port=3128
+proxy_host=rtai.ociweb.com
+htid_url=http://rtai.ociweb.com/cgi-bin/HTIOP_ID_Generator.cgi
diff --git a/ACE/tests/HTBP/Makefile.am b/ACE/tests/HTBP/Makefile.am
new file mode 100644
index 00000000000..7fd964b7c84
--- /dev/null
+++ b/ACE/tests/HTBP/Makefile.am
@@ -0,0 +1,16 @@
+## Process this file with automake to create Makefile.in
+##
+## $Id$
+##
+## This file was generated by MPC. Any changes made directly to
+## this file will be lost the next time it is generated.
+##
+## MPC Command:
+## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu
+
+SUBDIRS = \
+ Reactor_Tests \
+ Send_Large_Msg \
+ Send_Recv_Tests \
+ ping
+
diff --git a/ACE/tests/HTBP/README b/ACE/tests/HTBP/README
new file mode 100644
index 00000000000..65a2bde0320
--- /dev/null
+++ b/ACE/tests/HTBP/README
@@ -0,0 +1,16 @@
+$Id$
+
+Test cases for the HTTP Tunneling Bidirectional Protocol. For more
+information on the protocol itself, refer to ace/HTBP/README. These
+tests are adaptations of essential ACE SOCK tests, with the minimal
+changes to support using HTBP rather than SOCK.
+
+Contained in this directory:
+
+HTBP_Config.conf A sample configuration file. This file is site
+ specific, and must be editted before use.
+ping This test is shows the most basic connection
+ establishment with one request and reply.
+Reactor_Tests A test to show use through the reactor.
+Send_Large_Msg A test for sending large messages
+Send_Recv_Tests A test for a variety of message sending methods.
diff --git a/ACE/tests/HTBP/Reactor_Tests/.cvsignore b/ACE/tests/HTBP/Reactor_Tests/.cvsignore
new file mode 100644
index 00000000000..955ffdc75d5
--- /dev/null
+++ b/ACE/tests/HTBP/Reactor_Tests/.cvsignore
@@ -0,0 +1,4 @@
+client
+client
+server
+server
diff --git a/ACE/tests/HTBP/Reactor_Tests/Makefile.am b/ACE/tests/HTBP/Reactor_Tests/Makefile.am
new file mode 100644
index 00000000000..813229103d5
--- /dev/null
+++ b/ACE/tests/HTBP/Reactor_Tests/Makefile.am
@@ -0,0 +1,64 @@
+## Process this file with automake to create Makefile.in
+##
+## $Id$
+##
+## This file was generated by MPC. Any changes made directly to
+## this file will be lost the next time it is generated.
+##
+## MPC Command:
+## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu
+
+ACE_BUILDDIR = $(top_builddir)
+ACE_ROOT = $(top_srcdir)
+
+noinst_PROGRAMS =
+
+## Makefile.Reactor_Tests_Client.am
+
+if !BUILD_ACE_FOR_TAO
+
+noinst_PROGRAMS += client
+
+client_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR) \
+ -I$(ACE_ROOT)/protocols
+
+client_SOURCES = \
+ client.cpp \
+ test_config.h
+
+client_LDADD = \
+ $(ACE_BUILDDIR)/protocols/ace/HTBP/libACE_HTBP.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_ACE_FOR_TAO
+
+## Makefile.Reactor_Tests_Server.am
+
+if !BUILD_ACE_FOR_TAO
+
+noinst_PROGRAMS += server
+
+server_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR) \
+ -I$(ACE_ROOT)/protocols
+
+server_SOURCES = \
+ server.cpp \
+ test_config.h
+
+server_LDADD = \
+ $(ACE_BUILDDIR)/protocols/ace/HTBP/libACE_HTBP.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_ACE_FOR_TAO
+
+## Clean up template repositories, etc.
+clean-local:
+ -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.*
+ -rm -f gcctemp.c gcctemp so_locations *.ics
+ -rm -rf cxx_repository ptrepository ti_files
+ -rm -rf templateregistry ir.out
+ -rm -rf ptrepository SunWS_cache Templates.DB
diff --git a/ACE/tests/HTBP/Reactor_Tests/Reactor_Tests.mpc b/ACE/tests/HTBP/Reactor_Tests/Reactor_Tests.mpc
new file mode 100755
index 00000000000..61e59146a93
--- /dev/null
+++ b/ACE/tests/HTBP/Reactor_Tests/Reactor_Tests.mpc
@@ -0,0 +1,19 @@
+// -*- MPC -*-
+//
+// $Id$
+
+project(*Server): aceexe, htbp {
+ exename = server
+
+ Source_Files {
+ server.cpp
+ }
+}
+
+project(*Client): aceexe, htbp {
+ exename = client
+
+ Source_Files {
+ client.cpp
+ }
+}
diff --git a/ACE/tests/HTBP/Reactor_Tests/client.cpp b/ACE/tests/HTBP/Reactor_Tests/client.cpp
new file mode 100644
index 00000000000..2813d9116f3
--- /dev/null
+++ b/ACE/tests/HTBP/Reactor_Tests/client.cpp
@@ -0,0 +1,136 @@
+/**
+ * client for a reactor based connection establishment test using HTBP
+ *
+ * $Id$
+ */
+
+#include "ace/Log_Msg.h"
+
+#include "ace/HTBP/HTBP_Session.h"
+#include "ace/HTBP/HTBP_Stream.h"
+#include "ace/HTBP/HTBP_Addr.h"
+#include "ace/HTBP/HTBP_ID_Requestor.h"
+#include "ace/HTBP/HTBP_Environment.h"
+
+int
+ACE_TMAIN (int argc, ACE_TCHAR *argv[])
+{
+
+ ACE_OS::socket_init (ACE_WSOCK_VERSION);
+
+ if (argc < 2)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT("Usage: client <remote host>\n")),
+ 0);
+
+ ACE::HTBP::Environment env (0,0,ACE_TEXT("inside.env"));
+#if 0 // this should be a taken from a command line argument.
+ env.import_config ("inside.conf");
+#endif /* 0 */
+
+ ACE::HTBP::ID_Requestor req (&env);
+ ACE::HTBP::Addr local = ACE_TEXT_ALWAYS_CHAR(req.get_HTID());
+
+ unsigned remote_port = 8088;
+ const ACE_TCHAR * remote_host = argv[1];
+
+ unsigned proxy_port = 0;
+ ACE_TString proxy_host;
+
+ if (env.get_proxy_port(proxy_port) != 0 ||
+ env.get_proxy_host(proxy_host) != 0)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT("no proxy address in ")
+ ACE_TEXT("config, using direct connect\n")));
+ proxy_port = remote_port;
+ proxy_host = remote_host;
+ }
+
+ ACE_INET_Addr proxy(proxy_port,proxy_host.c_str());
+ ACE::HTBP::Addr remote (remote_port,ACE_TEXT_ALWAYS_CHAR(remote_host));
+
+ ACE::HTBP::Session session(remote,local,ACE::HTBP::Session::next_session_id(),&proxy);
+ ACE::HTBP::Stream stream (&session);
+
+ char buffer[1000];
+ ssize_t n = 0;
+ int retrycount = 10;
+ for (int i = 0; i < 3; i++)
+ {
+ ACE::HTBP::Channel *ch = session.outbound();
+ ACE_OS::sprintf (buffer,"Do you hear me? %d",i);
+ n = stream.send (buffer,ACE_OS::strlen(buffer)+1);
+ if (n == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT("%p\n"),
+ ACE_TEXT("stream send")),-1);
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT("send returned %d\n"),n));
+
+ retrycount = 10;
+ while ((n = ch->recv_ack()) == -1
+ && (errno == EWOULDBLOCK || errno == ETIME)
+ && retrycount > 0)
+ {
+ retrycount--;
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT("waiting for ack, %d tries left\n"),
+ retrycount));
+ ACE_OS::sleep (1);
+ }
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT("After wait for ack, n = %d, retry = %d\n"),
+ n,retrycount,errno));
+
+ retrycount = 10;
+ while ((n = stream.recv(buffer,1000)) == -1
+ && (errno == EWOULDBLOCK || errno == ETIME)
+ && retrycount > 0)
+ {
+ retrycount--;
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT("waiting for inbound data, %d tries left\n"),
+ retrycount));
+ ACE_OS::sleep(1);
+ }
+ if (retrycount == 0 || n < 0)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT("bailing after wait, %p\n"),
+ ACE_TEXT("recv")));
+ break;
+ }
+
+ buffer[n] = 0;
+
+ ACE_DEBUG ((LM_DEBUG,"Got: \"%s\"\n",buffer));
+ }
+ ACE::HTBP::Channel *ch = session.outbound();
+ if (ch == 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT("session's outbound channel is null!\n")),1);
+ n = stream.send ("goodbye",7);
+ if (n == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT("%p\n"),
+ ACE_TEXT("stream send")),-1);
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT("send returned %d\n"),n));
+
+ retrycount = 10;
+ while (ch &&
+ (n = ch->recv_ack()) == -1
+ && (errno == EWOULDBLOCK || errno == ETIME)
+ && retrycount > 0)
+ {
+ retrycount--;
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT("waiting for ack, %d tries left\n"),
+ retrycount));
+ ACE_OS::sleep (1);
+ }
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT("After wait for ack, n = %d, retry = %d\n"),
+ n,retrycount,errno));
+
+ return 0;
+}
diff --git a/ACE/tests/HTBP/Reactor_Tests/inside.conf b/ACE/tests/HTBP/Reactor_Tests/inside.conf
new file mode 100644
index 00000000000..a5bcbc14420
--- /dev/null
+++ b/ACE/tests/HTBP/Reactor_Tests/inside.conf
@@ -0,0 +1,5 @@
+[root]
+[htbp]
+proxy_port=3128
+proxy_host=rtai.ociweb.com
+htid_url=http://rtai.ociweb.com/cgi-bin/HTIOP_ID_Generator.cgi
diff --git a/ACE/tests/HTBP/Reactor_Tests/run_test.pl b/ACE/tests/HTBP/Reactor_Tests/run_test.pl
new file mode 100755
index 00000000000..ae4c56c7fb2
--- /dev/null
+++ b/ACE/tests/HTBP/Reactor_Tests/run_test.pl
@@ -0,0 +1,39 @@
+eval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}'
+ & eval 'exec perl -S $0 $argv:q'
+ if 0;
+
+# $Id$
+# -*- perl -*-
+
+use lib "$ENV{ACE_ROOT}/bin";
+use PerlACE::Run_Test;
+use Sys::Hostname;
+
+$status = 0;
+
+$SV = new PerlACE::Process ("server");
+
+$host = hostname();
+
+# The client code should later be modified to get the hostname
+# using ACE_OS::hostname so the same script can be run on all
+# hosts without havng to reset the host where it has to be run.
+$CL = new PerlACE::Process ("client", $host);
+
+$SV->Spawn ();
+
+$client = $CL->SpawnWaitKill (300);
+
+if ($client != 0) {
+ print STDERR "ERROR: client returned $client\n";
+ $status = 1;
+}
+
+$server = $SV->WaitKill (10);
+
+if ($server != 0) {
+ print STDERR "ERROR: server returned $server\n";
+ $status = 1;
+}
+
+exit $status;
diff --git a/ACE/tests/HTBP/Reactor_Tests/server.cpp b/ACE/tests/HTBP/Reactor_Tests/server.cpp
new file mode 100644
index 00000000000..87a914163c2
--- /dev/null
+++ b/ACE/tests/HTBP/Reactor_Tests/server.cpp
@@ -0,0 +1,180 @@
+/**
+ * server for a reactor based connection establishment test using HTBP
+ *
+ * $Id$
+ */
+
+#include "ace/Log_Msg.h"
+
+#include "ace/HTBP/HTBP_Session.h"
+#include "ace/HTBP/HTBP_Stream.h"
+#include "ace/HTBP/HTBP_Addr.h"
+
+#include "ace/SOCK_Acceptor.h"
+#include "ace/SOCK_Stream.h"
+#include "ace/Event_Handler.h"
+#include "ace/Reactor.h"
+
+class Accept_Handler : public ACE_Event_Handler
+{
+public:
+ Accept_Handler (ACE_SOCK_Acceptor& a);
+ virtual ~Accept_Handler (void);
+ virtual int handle_input (ACE_HANDLE );
+private:
+ ACE_SOCK_Acceptor& acceptor_;
+ ACE::HTBP::Channel *channels_[2];
+};
+
+class Stream_Handler : public ACE_Event_Handler
+{
+public:
+ Stream_Handler (ACE::HTBP::Stream &s);
+ virtual ~Stream_Handler ();
+ virtual int handle_input (ACE_HANDLE );
+private:
+ ACE::HTBP::Stream &stream_;
+};
+
+
+Accept_Handler::Accept_Handler(ACE_SOCK_Acceptor &a)
+ :ACE_Event_Handler(),
+ acceptor_(a)
+{
+ this->channels_[0] = this->channels_[1] = 0;
+ if (this->reactor() == 0)
+ this->reactor(ACE_Reactor::instance());
+ this->reactor()->register_handler (acceptor_.get_handle(),
+ this,
+ ACE_Event_Handler::ACCEPT_MASK);
+}
+
+Accept_Handler::~Accept_Handler()
+{
+ this->reactor()->remove_handler (acceptor_.get_handle(),
+ ACE_Event_Handler::ACCEPT_MASK|
+ ACE_Event_Handler::DONT_CALL);
+ acceptor_.close();
+}
+
+int
+Accept_Handler::handle_input (ACE_HANDLE h)
+{
+ ACE::HTBP::Channel **ch = 0;
+ if (h == acceptor_.get_handle())
+ {
+ ACE_SOCK_Stream *sock = new ACE_SOCK_Stream;
+ acceptor_.accept(*sock);
+ ch = channels_[0] == 0 ? &channels_[0] :& channels_[1];
+ *ch = new ACE::HTBP::Channel(*sock);
+ this->reactor()->register_handler (sock->get_handle(),
+ this,
+ ACE_Event_Handler::READ_MASK);
+ return 0;
+ }
+ for (int i = 0; i < 2; i++)
+ if (channels_[i] && channels_[i]->get_handle() == h)
+ {
+ ch = &channels_[i];
+ break;
+ }
+ if (ch == 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("Accept_Handler::handle_input, ")
+ ACE_TEXT ("unknown handle %d\n") ,h),
+ -1);
+ int result = (*ch)->pre_recv();
+ if (result == 0)
+ {
+ this->reactor()->remove_handler (h,
+ ACE_Event_Handler::READ_MASK |
+ ACE_Event_Handler::DONT_CALL);
+
+ (*ch)->register_notifier(this->reactor());
+ ACE::HTBP::Session *session = (*ch)->session();
+
+ ACE::HTBP::Stream *stream = new ACE::HTBP::Stream(session);
+ ACE_Event_Handler *handler = session->handler();
+
+ if (handler == 0)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Creating new stream handler for %d\n"),
+ stream->get_handle()));
+ Stream_Handler *sh = new Stream_Handler(*stream);
+ session->handler (sh);
+ }
+ else
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("There is already a handler for %d\n"),
+ stream->get_handle()));
+
+ if ((*ch)->state() == ACE::HTBP::Channel::Data_Queued)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Issuing notification on handler\n")));
+ this->reactor()->notify (session->handler(),
+ ACE_Event_Handler::READ_MASK);
+ }
+
+ *ch = 0;
+ }
+ return 0;
+}
+
+Stream_Handler::Stream_Handler (ACE::HTBP::Stream &s)
+ :stream_(s)
+{}
+Stream_Handler::~Stream_Handler ()
+{
+}
+
+int
+Stream_Handler::handle_input (ACE_HANDLE h)
+{
+ char buffer[1000];
+ ssize_t n = this->stream_.recv (buffer,1000);
+ if (n == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("Stream_Handler::handle_input %p\n"),
+ ACE_TEXT ("recv")),
+ 0);
+ buffer[n] = 0;
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Stream_Handler::handle_input (%d) read %d:\n%C\n"),
+ h, n, buffer));
+
+ const char *tok_loc = ACE_OS::strstr (buffer, "goodbye");
+ if (tok_loc != 0)
+ this->reactor()->end_event_loop();
+ else
+ {
+ ACE::HTBP::Channel *ch = stream_.session()->outbound();
+ if (ch != 0)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Sending reply on %d\n"),
+ ch->ace_stream().get_handle()));
+ else
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Can't send reply on nul channel\n")));
+ this->stream_.send ("Back atcha!",11);
+ }
+ return 0;
+}
+
+int
+ACE_TMAIN (int, ACE_TCHAR *[])
+{
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("At start of main\n")));
+ ACE_OS::socket_init (ACE_WSOCK_VERSION);
+
+ ACE_INET_Addr local(8088);
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("got address\n")));
+ ACE_SOCK_Acceptor acc(local,1);
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("opened listener\n")));
+
+ Accept_Handler handler (acc);
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("server is ready\n")));
+
+ ACE_Reactor::instance()->run_reactor_event_loop();
+ return 0;
+}
diff --git a/ACE/tests/HTBP/Reactor_Tests/test_config.h b/ACE/tests/HTBP/Reactor_Tests/test_config.h
new file mode 100644
index 00000000000..efd4eb7bcc6
--- /dev/null
+++ b/ACE/tests/HTBP/Reactor_Tests/test_config.h
@@ -0,0 +1,319 @@
+// -*- C++ -*-
+
+
+// ============================================================================
+/**
+ * @file test_config.h
+ *
+ * $Id$
+ *
+ * This file factors out common macros and other utilities used by the
+ * ACE automated regression tests.
+ *
+ * @author Prashant Jain <pjain@cs.wustl.edu>
+ * @author Tim Harrison <harrison@cs.wustl.edu>
+ * @author David Levine <levine@cs.wustl.edu>
+ */
+// ============================================================================
+
+#ifndef ACE_TEST_CONFIG_H
+#define ACE_TEST_CONFIG_H
+
+#include "ace/config-all.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#if defined (ACE_NLOGGING)
+// ACE_NLOGGING must not be set if the tests are to produce any output.
+#undef ACE_NLOGGING
+#endif /* ACE_NLOGGING */
+
+// This first #undef protects against command-line definitions.
+#undef ACE_NDEBUG
+#include "ace/OS.h"
+#include "ace/streams.h"
+#include "ace/Singleton.h"
+#include "ace/Synch.h"
+#include "ace/Log_Msg.h"
+#include "ace/ACE.h"
+
+// The second #undef protects against being reset in a config.h file.
+#undef ACE_NDEBUG
+
+#undef ACE_TEXT
+#define ACE_TEXT ACE_LIB_TEXT
+
+#if defined (ACE_HAS_WINCE)
+// Note that Pocket PC 2002 will NOT create a directory if it does not start with a leading '\'.
+// PPC 2002 only accepts '\log' as a valid directory name, while 'log\' works under WinCE 3.0.
+# define ACE_LOG_DIRECTORY_FOR_MKDIR ACE_TEXT ("\\log")
+# define ACE_LOG_DIRECTORY ACE_TEXT ("\\log\\")
+# define MAKE_PIPE_NAME(X) ACE_TEXT ("\\\\.\\pipe\\"#X)
+#elif defined (ACE_WIN32)
+# define ACE_LOG_DIRECTORY ACE_TEXT ("log\\")
+# define MAKE_PIPE_NAME(X) ACE_TEXT ("\\\\.\\pipe\\"#X)
+#else
+# define ACE_LOG_DIRECTORY ACE_TEXT ("log/")
+# define MAKE_PIPE_NAME(X) ACE_TEXT (X)
+#endif /* ACE_WIN32 */
+
+#if defined (ACE_HAS_WINCE)
+#define ACE_LOG_FILE_EXT_NAME ACE_TEXT (".txt")
+#else
+#define ACE_LOG_FILE_EXT_NAME ACE_TEXT (".log")
+#endif /* ACE_HAS_WINCE */
+
+#if defined (ACE_HAS_WINCE) || defined (ACE_HAS_PHARLAP)
+const size_t ACE_MAX_CLIENTS = 4;
+#else
+const size_t ACE_MAX_CLIENTS = 30;
+#endif /* ACE_HAS_WINCE */
+
+const size_t ACE_NS_MAX_ENTRIES = 1000;
+const size_t ACE_DEFAULT_USECS = 1000;
+const size_t ACE_MAX_TIMERS = 4;
+const size_t ACE_MAX_DELAY = 10;
+const size_t ACE_MAX_INTERVAL = 0;
+const size_t ACE_MAX_ITERATIONS = 10;
+const size_t ACE_MAX_PROCESSES = 10;
+const size_t ACE_MAX_THREADS = 4;
+
+#define ACE_START_TEST(NAME) \
+ const ACE_TCHAR *program = NAME; \
+ ACE_LOG_MSG->open (program, ACE_Log_Msg::OSTREAM | ACE_Log_Msg::VERBOSE_LITE); \
+ if (ace_file_stream::instance()->set_output (program) != 0) \
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("set_output failed")), -1); \
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) Starting %s test at %D\n"), program))
+
+#define ACE_END_TEST \
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) Ending %s test at %D\n"), program)); \
+ ace_file_stream::instance()->close ()
+
+#define ACE_CLOSE_TEST_LOG ace_file_stream::instance()->close ()
+
+#if !defined (ACE_WIN32)
+#define ACE_APPEND_LOG(NAME) \
+ const ACE_TCHAR *program = NAME; \
+ ACE_LOG_MSG->open (program, ACE_Log_Msg::OSTREAM | ACE_Log_Msg::VERBOSE_LITE); \
+ ace_file_stream::instance()->close (); \
+ if (ace_file_stream::instance()->set_output (program, 1) != 0) \
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("set_output failed")), -1); \
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) Starting %s test at %D\n"), program));
+#else /* ACE_WIN32 */
+#define ACE_APPEND_LOG(NAME) \
+ const ACE_TCHAR *program = NAME; \
+ ACE_LOG_MSG->open (program, ACE_Log_Msg::OSTREAM | ACE_Log_Msg::VERBOSE_LITE); \
+ if (ace_file_stream::instance()->set_output (program, 1) != 0) \
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("set_output failed")), -1); \
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) Starting %s test at %D\n"), program));
+#endif /* ACE_WIN32 */
+
+#define ACE_END_LOG \
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) Ending %s test at %D\n\n"), program)); \
+ ACE_LOG_MSG->set_flags(ACE_Log_Msg::SILENT); \
+ ace_file_stream::instance()->close ();
+
+#if defined (VXWORKS)
+// This is the only way I could figure out to avoid an error
+// about attempting to unlink a non-existant file.
+#define ACE_INIT_LOG(NAME) \
+ ACE_TCHAR temp[MAXPATHLEN]; \
+ ACE_OS::sprintf (temp, ACE_TEXT ("%s%s%s"), \
+ ACE_LOG_DIRECTORY, \
+ ACE::basename (NAME, ACE_DIRECTORY_SEPARATOR_CHAR), \
+ ACE_LOG_FILE_EXT_NAME); \
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) Deleting old log file %s (if any)\n\n"), temp)); \
+ int fd_init_log; \
+ if ((fd_init_log = ACE_OS::open (temp, \
+ O_WRONLY|O_CREAT, \
+ S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) != ERROR) \
+ { \
+ ACE_OS::close (fd_init_log); \
+ ACE_OS::unlink (temp); \
+ }
+
+#if defined (ghs)
+# // Rename main to ace_main for compatibility with run_tests.vxworks.
+# undef ACE_MAIN
+# define ACE_MAIN ace_main
+#endif /* ghs */
+#else /* ! VXWORKS */
+#define ACE_INIT_LOG(NAME) \
+ ACE_TCHAR temp[MAXPATHLEN]; \
+ ACE_OS::sprintf (temp, ACE_TEXT ("%s%s%s"), \
+ ACE_LOG_DIRECTORY, \
+ ACE::basename (NAME, ACE_DIRECTORY_SEPARATOR_CHAR), \
+ ACE_LOG_FILE_EXT_NAME); \
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) Deleting old log file %s (if any)\n\n"), temp)); \
+ ACE_OS::unlink (temp);
+#endif /* ! VXWORKS */
+
+#if defined (ACE_LACKS_IOSTREAM_TOTALLY)
+#define OFSTREAM FILE
+#else
+#define OFSTREAM ofstream
+#endif /* ACE_LACKS_IOSTREAM_TOTALLY */
+
+class ACE_Test_Output
+{
+public:
+ ACE_Test_Output (void);
+ ~ACE_Test_Output (void);
+ int set_output (const ACE_TCHAR *filename, int append = 0);
+ OFSTREAM *output_file (void);
+ void close (void);
+
+private:
+ OFSTREAM *output_file_;
+};
+
+inline ACE_Test_Output::ACE_Test_Output (void)
+ : output_file_ (0)
+{
+#if !defined (ACE_LACKS_IOSTREAM_TOTALLY)
+ this->output_file_ = new OFSTREAM;
+#endif /* ACE_LACKS_IOSTREAM_TOTALLY */
+}
+
+inline ACE_Test_Output::~ACE_Test_Output (void)
+{
+#if !defined (ACE_LACKS_IOSTREAM_TOTALLY) && !defined (ACE_PSOS)
+ ACE_LOG_MSG->msg_ostream (&cerr);
+#endif /* ! ACE_LACKS_IOSTREAM_TOTALLY && ! ACE_PSOS */
+
+ ACE_LOG_MSG->clr_flags (ACE_Log_Msg::OSTREAM);
+ ACE_LOG_MSG->set_flags (ACE_Log_Msg::STDERR);
+
+#if !defined (ACE_LACKS_IOSTREAM_TOTALLY) && !defined (ACE_HAS_PHARLAP)
+ delete this->output_file_;
+#endif /* ! ACE_LACKS_IOSTREAM_TOTALLY */
+}
+
+inline OFSTREAM *
+ACE_Test_Output::output_file (void)
+{
+ return this->output_file_;
+}
+
+inline int
+ACE_Test_Output::set_output (const ACE_TCHAR *filename, int append)
+{
+#if defined (ACE_HAS_PHARLAP)
+ // For PharLap, just send it all to the host console for now - redirect
+ // to a file there for saving/analysis.
+ EtsSelectConsole(ETS_CO_HOST);
+ ACE_LOG_MSG->msg_ostream (&cout);
+
+#else
+ ACE_TCHAR temp[MAXPATHLEN];
+ // Ignore the error value since the directory may already exist.
+ const ACE_TCHAR *test_dir;
+
+#if !defined (ACE_HAS_WINCE)
+ test_dir = ACE_OS::getenv (ACE_TEXT ("ACE_TEST_DIR"));
+
+ if (test_dir == 0)
+#endif /* ACE_HAS_WINCE */
+ test_dir = ACE_TEXT ("");
+
+ ACE_OS::sprintf (temp,
+ ACE_TEXT ("%s%s%s%s"),
+ test_dir,
+ ACE_LOG_DIRECTORY,
+ ACE::basename (filename, ACE_DIRECTORY_SEPARATOR_CHAR),
+ ACE_LOG_FILE_EXT_NAME);
+
+#if defined (VXWORKS)
+ // This is the only way I could figure out to avoid a console
+ // warning about opening an existing file (w/o O_CREAT), or
+ // attempting to unlink a non-existant one.
+ ACE_HANDLE fd = ACE_OS::open (temp,
+ O_WRONLY|O_CREAT,
+ S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
+ if (fd != ERROR)
+ {
+ ACE_OS::close (fd);
+ ACE_OS::unlink (temp);
+ }
+# else /* ! VXWORKS */
+ // This doesn't seem to work on VxWorks if the directory doesn't
+ // exist: it creates a plain file instead of a directory. If the
+ // directory does exist, it causes a wierd console error message
+ // about "cat: input error on standard input: Is a directory". So,
+ // VxWorks users must create the directory manually.
+# if defined (ACE_HAS_WINCE)
+ ACE_OS::mkdir (ACE_LOG_DIRECTORY_FOR_MKDIR);
+# else
+ ACE_OS::mkdir (ACE_LOG_DIRECTORY);
+# endif // ACE_HAS_WINCE
+# endif /* ! VXWORKS */
+
+# if !defined (ACE_LACKS_IOSTREAM_TOTALLY)
+ this->output_file_->open (ACE_TEXT_ALWAYS_CHAR (temp),
+ ios::out | (append ? ios::app : ios::trunc));
+ if (this->output_file_->bad ())
+ return -1;
+#else /* when ACE_LACKS_IOSTREAM_TOTALLY */
+ ACE_TCHAR *fmode = 0;
+ if (append)
+ fmode = ACE_TEXT ("a");
+ else
+ fmode = ACE_TEXT ("w");
+ this->output_file_ = ACE_OS::fopen (temp, fmode);
+# endif /* ACE_LACKS_IOSTREAM_TOTALLY */
+
+ ACE_LOG_MSG->msg_ostream (this->output_file ());
+#endif /* ACE_HAS_PHARLAP */
+
+ ACE_LOG_MSG->clr_flags (ACE_Log_Msg::STDERR | ACE_Log_Msg::LOGGER );
+ ACE_LOG_MSG->set_flags (ACE_Log_Msg::OSTREAM);
+
+ return 0;
+}
+
+inline void
+ACE_Test_Output::close (void)
+{
+#if !defined (ACE_LACKS_IOSTREAM_TOTALLY)
+ this->output_file_->flush ();
+ this->output_file_->close ();
+#else
+ ACE_OS::fflush (this->output_file_);
+ ACE_OS::fclose (this->output_file_);
+#endif /* !ACE_LACKS_IOSTREAM_TOTALLY */
+ ACE_LOG_MSG->msg_ostream (0);
+}
+
+inline void
+randomize (int array[], size_t size)
+{
+ size_t i;
+
+ for (i = 0; i < size; i++)
+ array [i] = static_cast<int> (i);
+
+ // See with a fixed number so that we can produce "repeatable"
+ // random numbers.
+ ACE_OS::srand (0);
+
+ // Generate an array of random numbers from 0 .. size - 1.
+
+ for (i = 0; i < size; i++)
+ {
+ size_t index = ACE_OS::rand() % size--;
+ int temp = array [index];
+ array [index] = array [size];
+ array [size] = temp;
+ }
+}
+
+typedef ACE_Singleton<ACE_Test_Output, ACE_Null_Mutex> ace_file_stream;
+
+#if defined (ACE_HAS_EXPLICIT_STATIC_TEMPLATE_MEMBER_INSTANTIATION)
+template ACE_Singleton<ACE_Test_Output, ACE_Null_Mutex> *
+ACE_Singleton<ACE_Test_Output, ACE_Null_Mutex>::singleton_;
+#endif /* ACE_HAS_EXPLICIT_STATIC_TEMPLATE_MEMBER_INSTANTIATION */
+
+#endif /* ACE_TEST_CONFIG_H */
diff --git a/ACE/tests/HTBP/Send_Large_Msg/.cvsignore b/ACE/tests/HTBP/Send_Large_Msg/.cvsignore
new file mode 100644
index 00000000000..955ffdc75d5
--- /dev/null
+++ b/ACE/tests/HTBP/Send_Large_Msg/.cvsignore
@@ -0,0 +1,4 @@
+client
+client
+server
+server
diff --git a/ACE/tests/HTBP/Send_Large_Msg/Makefile.am b/ACE/tests/HTBP/Send_Large_Msg/Makefile.am
new file mode 100644
index 00000000000..2773356439b
--- /dev/null
+++ b/ACE/tests/HTBP/Send_Large_Msg/Makefile.am
@@ -0,0 +1,64 @@
+## Process this file with automake to create Makefile.in
+##
+## $Id$
+##
+## This file was generated by MPC. Any changes made directly to
+## this file will be lost the next time it is generated.
+##
+## MPC Command:
+## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu
+
+ACE_BUILDDIR = $(top_builddir)
+ACE_ROOT = $(top_srcdir)
+
+noinst_PROGRAMS =
+
+## Makefile.Send_Large_Msg_Client.am
+
+if !BUILD_ACE_FOR_TAO
+
+noinst_PROGRAMS += client
+
+client_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR) \
+ -I$(ACE_ROOT)/protocols
+
+client_SOURCES = \
+ client.cpp
+
+client_LDADD = \
+ $(top_builddir)/tests/libTest_Output.la \
+ $(ACE_BUILDDIR)/protocols/ace/HTBP/libACE_HTBP.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_ACE_FOR_TAO
+
+## Makefile.Send_Large_Msg_Server.am
+
+if !BUILD_ACE_FOR_TAO
+
+noinst_PROGRAMS += server
+
+server_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR) \
+ -I$(ACE_ROOT)/protocols
+
+server_SOURCES = \
+ server.cpp
+
+server_LDADD = \
+ $(top_builddir)/tests/libTest_Output.la \
+ $(ACE_BUILDDIR)/protocols/ace/HTBP/libACE_HTBP.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_ACE_FOR_TAO
+
+## Clean up template repositories, etc.
+clean-local:
+ -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.*
+ -rm -f gcctemp.c gcctemp so_locations *.ics
+ -rm -rf cxx_repository ptrepository ti_files
+ -rm -rf templateregistry ir.out
+ -rm -rf ptrepository SunWS_cache Templates.DB
diff --git a/ACE/tests/HTBP/Send_Large_Msg/Send_Large_Msg.mpc b/ACE/tests/HTBP/Send_Large_Msg/Send_Large_Msg.mpc
new file mode 100644
index 00000000000..d973b59748f
--- /dev/null
+++ b/ACE/tests/HTBP/Send_Large_Msg/Send_Large_Msg.mpc
@@ -0,0 +1,23 @@
+// -*- MPC -*-
+//
+// $Id$
+
+project(*Server): aceexe, htbp {
+ exename = server
+ after += Test_Output
+ libs += Test_Output
+
+ Source_Files {
+ server.cpp
+ }
+}
+
+project(*Client): aceexe, htbp {
+ exename = client
+ after += Test_Output
+ libs += Test_Output
+
+ Source_Files {
+ client.cpp
+ }
+}
diff --git a/ACE/tests/HTBP/Send_Large_Msg/client.cpp b/ACE/tests/HTBP/Send_Large_Msg/client.cpp
new file mode 100644
index 00000000000..62cd9140da8
--- /dev/null
+++ b/ACE/tests/HTBP/Send_Large_Msg/client.cpp
@@ -0,0 +1,98 @@
+// $Id$
+
+#include "tests/test_config.h"
+
+#include "ace/HTBP/HTBP_Session.h"
+#include "ace/HTBP/HTBP_Stream.h"
+#include "ace/HTBP/HTBP_Addr.h"
+#include "ace/HTBP/HTBP_ID_Requestor.h"
+#include "ace/HTBP/HTBP_Environment.h"
+
+#include "ace/Log_Msg.h"
+
+const ssize_t Send_Size = 4*1024;
+const size_t Loops = 10;
+const size_t Total_Size = Send_Size * Loops;
+
+int
+ACE_TMAIN (int argc, ACE_TCHAR *argv[])
+{
+ ACE_START_TEST (ACE_TEXT ("HTBP_Send_Large_Msg_client"));
+
+ ACE_OS::socket_init (ACE_WSOCK_VERSION);
+
+ if (argc < 2)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "Usage: client <remote host>\n"),
+ 0);
+ ACE::HTBP::Environment env;
+#if 0 // this should be a taken from a command line argument
+ env.import_config (ACE_TEXT("../HTBP_Config.conf"));
+#endif /* 0 */
+
+
+ ACE::HTBP::ID_Requestor req (&env);
+ ACE::HTBP::Addr local(ACE_TEXT_ALWAYS_CHAR(req.get_HTID()));
+
+ unsigned remote_port = 8088;
+ const ACE_TCHAR * remote_host = argv[1];
+
+ unsigned proxy_port = 0;
+ ACE_TString proxy_host;
+
+ if (env.get_proxy_port(proxy_port) != 0 ||
+ env.get_proxy_host(proxy_host) != 0)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT("no proxy address in ")
+ ACE_TEXT("config, using direct connect\n")));
+ proxy_port = remote_port;
+ proxy_host = remote_host;
+ }
+
+ ACE_INET_Addr proxy(proxy_port,proxy_host.c_str());
+ ACE::HTBP::Addr remote (remote_port,ACE_TEXT_ALWAYS_CHAR(remote_host));
+
+ ACE::HTBP::Session session(remote,
+ local,
+ ACE::HTBP::Session::next_session_id(),
+ &proxy);
+
+ ACE::HTBP::Stream *stream = new ACE::HTBP::Stream(&session);
+ ACE_DEBUG ((LM_DEBUG,ACE_TEXT("Sending message\n")));
+ char buffer[Send_Size];
+ ACE_OS::memset (buffer,'a',Send_Size);
+ ssize_t n = 0;
+ for (size_t i = 0; i < Loops ; ++i)
+ {
+ errno = 0;
+ while (n < Send_Size)
+ {
+ n += stream->send (buffer+n,Send_Size);
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT("Sending %d of %d\n"), n, Send_Size));
+ }
+ if (n == -1 && errno != 0)
+ {
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT("%p\n %d"),
+ ACE_TEXT("stream send"), errno), -1);
+ }
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT("In round %d, send returned %d\n"), i, n));
+ }
+
+ buffer[0] = 0;
+ n = stream->recv (buffer,1000);
+ while (n == -1)
+ {
+ if (errno == EWOULDBLOCK)
+ n = stream->recv (buffer,1000);
+ else
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT("%p\n"),
+ ACE_TEXT("stream.recv")),-1);
+ }
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT("received %d, %s\n"),n,buffer));
+
+ ACE_END_TEST;
+ return 0;
+}
diff --git a/ACE/tests/HTBP/Send_Large_Msg/run_test.pl b/ACE/tests/HTBP/Send_Large_Msg/run_test.pl
new file mode 100755
index 00000000000..6b295afbf17
--- /dev/null
+++ b/ACE/tests/HTBP/Send_Large_Msg/run_test.pl
@@ -0,0 +1,43 @@
+eval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}'
+ & eval 'exec perl -S $0 $argv:q'
+ if 0;
+
+# $Id$
+# -*- perl -*-
+
+use lib "$ENV{ACE_ROOT}/bin";
+use PerlACE::Run_Test;
+use Sys::Hostname;
+
+$iorfile = PerlACE::LocalFile ("server.ior");
+
+unlink $iorfile;
+$status = 0;
+
+$SV = new PerlACE::Process ("server");
+$host = hostname();
+
+# The client code should later be modified to get the hostname
+# using ACE_OS::hostname so the same script can be run on all
+# hosts without havng to reset the host where it has to be run.
+$CL = new PerlACE::Process ("client", $host);
+
+$SV->Spawn ();
+
+$client = $CL->SpawnWaitKill (300);
+
+if ($client != 0) {
+ print STDERR "ERROR: client returned $client\n";
+ $status = 1;
+}
+
+$server = $SV->WaitKill (10);
+
+if ($server != 0) {
+ print STDERR "ERROR: server returned $server\n";
+ $status = 1;
+}
+
+unlink $iorfile;
+
+exit $status;
diff --git a/ACE/tests/HTBP/Send_Large_Msg/server.cpp b/ACE/tests/HTBP/Send_Large_Msg/server.cpp
new file mode 100644
index 00000000000..7b7f51cf1b9
--- /dev/null
+++ b/ACE/tests/HTBP/Send_Large_Msg/server.cpp
@@ -0,0 +1,103 @@
+// $Id$
+
+#include "tests/test_config.h"
+
+#include "ace/Log_Msg.h"
+
+#include "ace/HTBP/HTBP_Session.h"
+#include "ace/HTBP/HTBP_Stream.h"
+#include "ace/HTBP/HTBP_Addr.h"
+
+#include "ace/SOCK_Acceptor.h"
+#include "ace/SOCK_Stream.h"
+
+const size_t Send_Size = 4*1024;
+const size_t Loops = 10;
+const size_t Total_Size = Send_Size * Loops;
+
+int
+ACE_TMAIN (int argc, ACE_TCHAR *argv[])
+{
+
+ ACE_UNUSED_ARG (argc);
+ ACE_UNUSED_ARG (argv);
+
+ char buffer[1000];
+
+ ACE_OS::socket_init (ACE_WSOCK_VERSION);
+
+ ACE_INET_Addr local(8088);
+ ACE_SOCK_Stream sock[2];
+ ACE_SOCK_Acceptor acc(local,1);
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT("server is ready\n")));
+
+ acc.accept(sock[0]);
+ ACE::HTBP::Channel channel1(sock[0]);
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT("Got sock[0], handle = %d\n"),
+ sock[0].get_handle()));
+ acc.accept(sock[1]);
+ ACE::HTBP::Channel channel2(sock[1]);
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT("Got sock[1], handle = %d\n"),
+ sock[1].get_handle()));
+ int res = 0;
+ while ((res =channel1.pre_recv()) != 0)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT("res = %d. waiting 1 sec. %p\n"),
+ res,
+ ACE_TEXT("stream.pre_recv()")));
+ ACE_OS::sleep (1);
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT("Read from channel2\n")));
+ while ((res = channel2.pre_recv()) != 0)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT("res = %d, waiting 1 sec. %p\n"),
+ res,
+ ACE_TEXT("stream2.pre_recv()")));
+ ACE_OS::sleep (1);
+ }
+
+ ACE::HTBP::Session *session = channel1.session();
+ ACE::HTBP::Stream stream (session);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT("using streams %d, %d. Got sesssion = %x\n"),
+ sock[0].get_handle(),sock[1].get_handle(),session));
+
+ ssize_t got = 1;
+ ssize_t total_recv = 0;
+
+ while (got != 0)
+ {
+ errno = 0;
+ got = stream.recv (buffer, sizeof (buffer));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT("got : %s %d "), buffer, got));
+
+ if (got < 0)
+ break;
+ total_recv += got;
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT("received %d, %s\n"),total_recv,buffer));
+
+
+ ACE_OS::strcpy (buffer,"I hear you !");
+ ssize_t n = stream.send (buffer,ACE_OS::strlen(buffer)+1);
+ if (n == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT("%p\n"),
+ ACE_TEXT("stream.send")),-1);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT("send returned %d\n"),n));
+ return 0;
+
+}
diff --git a/ACE/tests/HTBP/Send_Recv_Tests/.cvsignore b/ACE/tests/HTBP/Send_Recv_Tests/.cvsignore
new file mode 100644
index 00000000000..b82dc859445
--- /dev/null
+++ b/ACE/tests/HTBP/Send_Recv_Tests/.cvsignore
@@ -0,0 +1,2 @@
+SendRecv_Test
+SendRecv_Test
diff --git a/ACE/tests/HTBP/Send_Recv_Tests/Makefile.am b/ACE/tests/HTBP/Send_Recv_Tests/Makefile.am
new file mode 100644
index 00000000000..03775f077a4
--- /dev/null
+++ b/ACE/tests/HTBP/Send_Recv_Tests/Makefile.am
@@ -0,0 +1,42 @@
+## Process this file with automake to create Makefile.in
+##
+## $Id$
+##
+## This file was generated by MPC. Any changes made directly to
+## this file will be lost the next time it is generated.
+##
+## MPC Command:
+## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu
+
+ACE_BUILDDIR = $(top_builddir)
+ACE_ROOT = $(top_srcdir)
+
+
+## Makefile.SendRecv_Test.am
+
+if !BUILD_ACE_FOR_TAO
+
+noinst_PROGRAMS = SendRecv_Test
+
+SendRecv_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR) \
+ -I$(ACE_ROOT)/protocols
+
+SendRecv_Test_SOURCES = \
+ SendRecv_Test.cpp
+
+SendRecv_Test_LDADD = \
+ $(top_builddir)/tests/libTest_Output.la \
+ $(ACE_BUILDDIR)/protocols/ace/HTBP/libACE_HTBP.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_ACE_FOR_TAO
+
+## Clean up template repositories, etc.
+clean-local:
+ -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.*
+ -rm -f gcctemp.c gcctemp so_locations *.ics
+ -rm -rf cxx_repository ptrepository ti_files
+ -rm -rf templateregistry ir.out
+ -rm -rf ptrepository SunWS_cache Templates.DB
diff --git a/ACE/tests/HTBP/Send_Recv_Tests/SendRecv_Test.cpp b/ACE/tests/HTBP/Send_Recv_Tests/SendRecv_Test.cpp
new file mode 100644
index 00000000000..d462a11c3d3
--- /dev/null
+++ b/ACE/tests/HTBP/Send_Recv_Tests/SendRecv_Test.cpp
@@ -0,0 +1,388 @@
+// $Id$
+
+// ===========================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Send_Recv_Test.cpp
+//
+// = DESCRIPTION This is a test of the <ACE_SOCK>'s various send and
+// receive methods, over HTBP. The test forks two processes or spawns
+// two threads (depending upon the platform) and then executes client
+// and server allowing them to connect and exchange data in ways
+// designed to exercise the send and recv functions.
+//
+// Right now, it primarily tests the iov-like send and recv
+// functions, but others should be added to completely cover the
+// possible scenarios.
+//
+// = AUTHOR
+// Steve Huston <shuston@riverace.com>
+//
+// ============================================================================
+
+#include "tests/test_config.h"
+
+#include "ace/HTBP/HTBP_Stream.h"
+#include "ace/HTBP/HTBP_Session.h"
+#include "ace/HTBP/HTBP_ID_Requestor.h"
+#include "ace/HTBP/HTBP_Environment.h"
+
+#include "ace/OS.h"
+#include "ace/Thread.h"
+#include "ace/Thread_Manager.h"
+#include "ace/SOCK_Connector.h"
+#include "ace/SOCK_Acceptor.h"
+#include "ace/SOCK_Stream.h"
+
+ACE_RCSID(tests,
+ SOCK_Send_Recv_Test,
+ "$Id$")
+
+// Change to non-zero if test fails
+static int Test_Result = 0;
+
+#if !defined (ACE_LACKS_FORK) || defined (ACE_HAS_THREADS)
+
+// In test 3, a large amount of data is sent. The purpose is to overflow the
+// TCP send window, causing the sender to block (it's a send_n). This value
+// is the amount to send. The assumption is that no implementation has a
+// receive window larger than 128K bytes. If one is found, this is the place
+// to change it.
+// For some odd reason, NT will try to send a single large buffer, but not
+// multiple smaller ones that add up to the large size.
+const size_t Test3_Send_Size = 4*1024;
+const size_t Test3_Loops = 10;
+const size_t Test3_Total_Size = Test3_Send_Size * Test3_Loops;
+
+
+static void *
+client (void *arg)
+{
+ ACE_OS::socket_init (ACE_WSOCK_VERSION);
+ ACE::HTBP::Environment ht_env;
+
+#if 0 // this needs to take the config file name as an argument.
+ ht_env.import_config ("../HTBP_Config.conf");
+#endif /* 0 */
+
+ ACE::HTBP::ID_Requestor req (&ht_env);
+ ACE::HTBP::Addr local(ACE_TEXT_ALWAYS_CHAR(req.get_HTID()));
+
+ char hostname [128];
+
+ if (ACE_OS::hostname (hostname,128) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "Could not get the host name\n"),0);
+
+ ACE_INET_Addr *remote_addr = reinterpret_cast<ACE_INET_Addr *> (arg);
+ ACE::HTBP::Addr remote (remote_addr->get_port_number (),hostname);
+
+ unsigned pport;
+ ACE_TString phost;
+ ht_env.get_proxy_port(pport);
+ ht_env.get_proxy_host(phost);
+
+ ACE_INET_Addr proxy(pport,phost.c_str());
+ ACE::HTBP::Session session(remote,local,ACE::HTBP::Session::next_session_id(),&proxy);
+ ACE::HTBP::Stream stream(&session);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Connecting to port %d\n"),
+ remote.get_port_number()));
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) connected to %s\n"),
+ ACE_TEXT_CHAR_TO_TCHAR(remote.get_host_name ())));
+
+ //******************* TEST 1 ******************************
+ //
+ // Do a iovec sendv - send the 255 byte buffer in 5 chunks. The
+ // server will verify that the correct data is sent, and that there
+ // is no more and no less.
+
+ u_char buffer[255];
+ size_t i;
+ ssize_t len;
+
+ // The server will verify that this data pattern gets there intact.
+
+ for (i = 0; i < sizeof buffer; ++i)
+ buffer[i] = static_cast<u_char> (i);
+
+ iovec iov[5];
+
+ iov[0].iov_base = reinterpret_cast<char *> (&buffer[0]);
+ iov[0].iov_len = 50;
+
+ iov[1].iov_base = reinterpret_cast<char *> (&buffer[50]);
+ iov[1].iov_len = 25;
+
+ iov[2].iov_base = reinterpret_cast<char *> (&buffer[75]);
+ iov[2].iov_len = 150;
+
+ iov[3].iov_base = reinterpret_cast<char *> (&buffer[225]);
+ iov[3].iov_len = 29;
+
+ iov[4].iov_base = reinterpret_cast<char *> (&buffer[254]);
+ iov[4].iov_len = 1;
+
+ len = stream.sendv (iov, 5);
+ if (len == -1)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n"),
+ ACE_TEXT ("Test 1, sendv failed")));
+ Test_Result = 1;
+ }
+ else
+ ACE_ASSERT (len == 255);
+
+
+ ACE_DEBUG ((LM_DEBUG, "***** client TEST 2 ***** \n"));
+
+ //******************* TEST 2 ******************************
+ //
+ // The same data is coming back - receive it using recv (size_t n,
+ // ...) and compare it to the original data.
+
+ u_char buffer2[255];
+ // Give it a chance to get here
+ ACE_OS::sleep (2);
+
+ len = stream.recv_n (buffer2,
+ 155);
+
+
+ len = stream.recv_n (buffer2,
+ 105);
+
+ for (i = 0; i < 255; i++)
+ if (buffer2[i] != buffer[i])
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Test 2, rcvd byte %d is %d, not %d\n"),
+ i, buffer2[i], buffer[i]));
+ Test_Result = 1;
+ }
+
+
+ stream.close ();
+
+ return 0;
+}
+
+static void *
+server (void *arg)
+{
+
+ ACE_OS::socket_init (ACE_WSOCK_VERSION);
+ ACE_SOCK_Acceptor *peer_acceptor = (ACE_SOCK_Acceptor *) arg;
+ ACE_INET_Addr cli_addr;
+
+ ACE_Time_Value timeout (ACE_DEFAULT_TIMEOUT);
+
+ ACE_SOCK_Stream sock[2];
+ ACE_DEBUG ((LM_DEBUG,"server is ready\n"));
+
+ if (peer_acceptor->accept(sock[0],&cli_addr,&timeout) == -1)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n"),
+ ACE_TEXT ("accept")));
+ Test_Result = 1;
+ return 0;
+ }
+
+ ACE::HTBP::Channel channel1(sock[0]);
+ ACE_DEBUG ((LM_DEBUG,"Got sock[0], handle = %d\n",sock[0].get_handle()));
+
+ if (peer_acceptor->accept(sock[0],&cli_addr,&timeout) == -1)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n"),
+ ACE_TEXT ("accept")));
+ Test_Result = 1;
+ return 0;
+ }
+
+ ACE::HTBP::Channel channel2(sock[1]);
+ ACE_DEBUG ((LM_DEBUG,"Got sock[1], handle = %d\n",sock[1].get_handle()));
+ int res = 0;
+ while ((res = channel1.pre_recv()) != 0)
+ {
+ ACE_DEBUG ((LM_DEBUG,"res = %d. waiting 1 sec. %p\n",res,
+ "stream.pre_recv()"));
+ ACE_OS::sleep (1);
+ }
+
+ ACE_DEBUG ((LM_DEBUG,"Read from channel2\n"));
+ while ((res = channel2.pre_recv()) != 0)
+ {
+ ACE_DEBUG ((LM_DEBUG,"res = %d, waiting 1 sec. %p\n",res,
+ "stream2.pre_recv()"));
+ ACE_OS::sleep (1);
+ }
+
+ ACE::HTBP::Session *session = channel1.session();
+ ACE::HTBP::Stream stream (session);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) client %s connected from %d\n"),
+ ACE_TEXT_CHAR_TO_TCHAR(cli_addr.get_host_name ()),
+ cli_addr.get_port_number ()));
+
+ //******************* TEST 1 ******************************
+ //
+ // Do a iovec recvv - the client should send 255 bytes, which we
+ // will be detected and read into a ACE-allocated buffer. Use a 5
+ // second timeout to give the client a chance to send it all.
+
+ ACE_OS::sleep (5);
+
+ u_char buffer[255];
+
+ iovec iov[3];
+
+ ssize_t len;
+ int i;
+
+ iov[0].iov_base = reinterpret_cast<char *> (&buffer[0]);
+ iov[0].iov_len = 75;
+
+ iov[1].iov_base = reinterpret_cast<char *> (&buffer[75]);
+ iov[1].iov_len = 100;
+
+ iov[2].iov_base = reinterpret_cast<char *> (&buffer[175]);
+ iov[2].iov_len = 80;
+
+ len = stream.recvv (iov, 3);
+ if (len == -1)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n"),
+ ACE_TEXT ("Test 1, recvv failed")));
+ Test_Result = 1;
+ }
+
+ for (i = 0; i < 255; i++)
+ if (buffer[i] != i)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Test 1, rcvd byte %d is %d, not %d\n"),
+ i,
+ buffer[i],
+ i));
+ Test_Result = 1;
+ }
+
+ ACE_DEBUG ((LM_DEBUG, "***** TEST 2 ***** \n"));
+
+ //******************* TEST 2 ******************************
+ //
+ // Send the buffer back, using send (size_t n, ...) in 3 pieces.
+
+ len = stream.send (buffer, 6);
+ len += stream.send (buffer,42);
+ len += stream.send (buffer,189);
+ len += stream.send_n (buffer,18);
+ ACE_ASSERT (len == 255);
+ sock[0].close();
+ sock[1].close();
+ stream.close ();
+ return 0;
+}
+
+#endif /* !ACE_LACKS_FORK || ACE_HAS_THREADS */
+
+static void
+spawn (void)
+{
+ // Acceptor
+ ACE_SOCK_Acceptor peer_acceptor;
+
+ // Create a server address.
+ ACE_INET_Addr server_addr;
+
+ char hostname[BUFSIZ];
+
+ if (ACE_OS::hostname (hostname, BUFSIZ) != 0)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Could not get the hostname\n")));
+ }
+
+ ACE::HTBP::Addr addr (8088, hostname);
+
+ // Bind listener to any port and then find out what the port was.
+ if (peer_acceptor.open (addr) == -1
+ || peer_acceptor.get_local_addr (server_addr) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n"),
+ ACE_TEXT ("open")));
+ else
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) starting server at port %d\n"),
+ server_addr.get_port_number ()));
+
+#if !defined (ACE_LACKS_FORK)
+ switch (ACE_OS::fork (ACE_TEXT("child")))
+ {
+ case -1:
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n%a"),
+ ACE_TEXT ("fork failed"),
+ 1));
+ /* NOTREACHED */
+ case 0:
+ client (&server_addr);
+ ACE_OS::exit (0);
+ /* NOTREACHED */
+ default:
+ server (reinterpret_cast<void *> (&peer_acceptor));
+ ACE_OS::wait ();
+ }
+#elif defined (ACE_HAS_THREADS)
+ if (ACE_Thread_Manager::instance ()->spawn
+ (ACE_THR_FUNC (server),
+ reinterpret_cast<void *> (&peer_acceptor),
+ THR_NEW_LWP | THR_DETACHED) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n%a"),
+ ACE_TEXT ("thread create failed"),
+ 1));
+
+ if (ACE_Thread_Manager::instance ()->spawn
+ (ACE_THR_FUNC (client),
+ reinterpret_cast<void *> (&server_addr),
+ THR_NEW_LWP | THR_DETACHED) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n%a"),
+ ACE_TEXT ("thread create failed"),
+ 1));
+
+ // Wait for the threads to exit.
+ ACE_Thread_Manager::instance ()->wait ();
+#else
+ ACE_ERROR ((LM_INFO,
+ ACE_TEXT ("(%P|%t) ")
+ ACE_TEXT ("only one thread may be run ")
+ ACE_TEXT ("in a process on this platform\n")));
+#endif /* ACE_HAS_THREADS */
+
+ peer_acceptor.close ();
+ }
+}
+
+int
+ACE_TMAIN (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("SOCK_Send_Recv_Test"));
+
+ spawn ();
+
+ ACE_END_TEST;
+ return Test_Result;
+}
diff --git a/ACE/tests/HTBP/Send_Recv_Tests/SendRecv_Test.mpc b/ACE/tests/HTBP/Send_Recv_Tests/SendRecv_Test.mpc
new file mode 100644
index 00000000000..64a40f688d1
--- /dev/null
+++ b/ACE/tests/HTBP/Send_Recv_Tests/SendRecv_Test.mpc
@@ -0,0 +1,14 @@
+// -*- MPC -*-
+//
+// $Id$
+//
+
+project: aceexe, htbp {
+ exename = SendRecv_Test
+ after += Test_Output
+ libs += Test_Output
+
+ Source_Files {
+ SendRecv_Test.cpp
+ }
+}
diff --git a/ACE/tests/HTBP/htbptest.mpb b/ACE/tests/HTBP/htbptest.mpb
new file mode 100644
index 00000000000..c12f33ef7ba
--- /dev/null
+++ b/ACE/tests/HTBP/htbptest.mpb
@@ -0,0 +1,6 @@
+// -*- MPC -*-
+//
+// $Id$
+project : aceexe, htbp {
+ libs += Test_Output
+}
diff --git a/ACE/tests/HTBP/ping/.cvsignore b/ACE/tests/HTBP/ping/.cvsignore
new file mode 100644
index 00000000000..955ffdc75d5
--- /dev/null
+++ b/ACE/tests/HTBP/ping/.cvsignore
@@ -0,0 +1,4 @@
+client
+client
+server
+server
diff --git a/ACE/tests/HTBP/ping/Makefile.am b/ACE/tests/HTBP/ping/Makefile.am
new file mode 100644
index 00000000000..279d82a03c0
--- /dev/null
+++ b/ACE/tests/HTBP/ping/Makefile.am
@@ -0,0 +1,62 @@
+## Process this file with automake to create Makefile.in
+##
+## $Id$
+##
+## This file was generated by MPC. Any changes made directly to
+## this file will be lost the next time it is generated.
+##
+## MPC Command:
+## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu
+
+ACE_BUILDDIR = $(top_builddir)
+ACE_ROOT = $(top_srcdir)
+
+noinst_PROGRAMS =
+
+## Makefile.Ping_Client.am
+
+if !BUILD_ACE_FOR_TAO
+
+noinst_PROGRAMS += client
+
+client_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR) \
+ -I$(ACE_ROOT)/protocols
+
+client_SOURCES = \
+ client.cpp
+
+client_LDADD = \
+ $(ACE_BUILDDIR)/protocols/ace/HTBP/libACE_HTBP.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_ACE_FOR_TAO
+
+## Makefile.Ping_Server.am
+
+if !BUILD_ACE_FOR_TAO
+
+noinst_PROGRAMS += server
+
+server_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR) \
+ -I$(ACE_ROOT)/protocols
+
+server_SOURCES = \
+ server.cpp
+
+server_LDADD = \
+ $(ACE_BUILDDIR)/protocols/ace/HTBP/libACE_HTBP.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_ACE_FOR_TAO
+
+## Clean up template repositories, etc.
+clean-local:
+ -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.*
+ -rm -f gcctemp.c gcctemp so_locations *.ics
+ -rm -rf cxx_repository ptrepository ti_files
+ -rm -rf templateregistry ir.out
+ -rm -rf ptrepository SunWS_cache Templates.DB
diff --git a/ACE/tests/HTBP/ping/client.cpp b/ACE/tests/HTBP/ping/client.cpp
new file mode 100644
index 00000000000..e7753faab6d
--- /dev/null
+++ b/ACE/tests/HTBP/ping/client.cpp
@@ -0,0 +1,130 @@
+/**
+ * client for a basic connection establishment test using HTBP
+ *
+ * $Id$
+ */
+
+
+#include "ace/Log_Msg.h"
+
+#include "ace/HTBP/HTBP_Session.h"
+#include "ace/HTBP/HTBP_Stream.h"
+#include "ace/HTBP/HTBP_Addr.h"
+#include "ace/HTBP/HTBP_ID_Requestor.h"
+#include "ace/HTBP/HTBP_Environment.h"
+
+int
+ACE_TMAIN(int argc, ACE_TCHAR *argv[])
+{
+
+ ACE_OS::socket_init (ACE_WSOCK_VERSION);
+
+ if (argc < 2)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "Usage: client <remote host>\n"),
+ 0);
+ ACE::HTBP::Environment env;
+#if 0 // this should be a taken from a command line argument
+ env.import_config (ACE_TEXT("../HTBP_Config.conf"));
+#endif /* 0 */
+
+
+ ACE::HTBP::ID_Requestor req (&env);
+ ACE::HTBP::Addr local(ACE_TEXT_ALWAYS_CHAR(req.get_HTID()));
+
+ unsigned remote_port = 8088;
+ const ACE_TCHAR * remote_host = argv[1];
+
+ unsigned proxy_port = 0;
+ ACE_TString proxy_host;
+
+ if (env.get_proxy_port(proxy_port) != 0 ||
+ env.get_proxy_host(proxy_host) != 0)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT("no proxy address in ")
+ ACE_TEXT("config, using direct connect\n")));
+ proxy_port = remote_port;
+ proxy_host = remote_host;
+ }
+
+ ACE_INET_Addr proxy(proxy_port,proxy_host.c_str());
+ ACE::HTBP::Addr remote (remote_port,ACE_TEXT_ALWAYS_CHAR(remote_host));
+
+ ACE::HTBP::Session session(remote,
+ local,
+ ACE::HTBP::Session::next_session_id(),
+ &proxy);
+ ACE::HTBP::Stream stream (&session);
+
+ char buffer[1000];
+ ssize_t n = 0;
+ int retrycount = 10;
+ for (int i = 0; i < 3; i++)
+ {
+ ACE_OS::sprintf (buffer,"Do you hear me? %d",i);
+ ACE::HTBP::Channel *ob = session.outbound();
+ n = stream.send (buffer,ACE_OS::strlen(buffer)+1);
+ if (n == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "%p\n","stream send"),-1);
+
+ ACE_DEBUG ((LM_DEBUG, "send returned %d\n",n));
+
+ retrycount = 10;
+ ACE_DEBUG ((LM_DEBUG,"after send, outbound = %x, ob = %x\n",
+ session.outbound(), ob));
+ while ((n = ob->recv_ack()) == -1
+ && (errno == EWOULDBLOCK || errno == ETIME)
+ && retrycount > 0)
+ {
+ retrycount--;
+ ACE_DEBUG ((LM_DEBUG,"waiting for ack, %d tries left\n",
+ retrycount));
+ ACE_OS::sleep (1);
+ }
+ ACE_DEBUG ((LM_DEBUG,"After wait for ack, n = %d, retry = %d\n",
+ n,retrycount,errno));
+
+ retrycount = 10;
+ while ((n = stream.recv(buffer,1000)) == -1
+ && (errno == EWOULDBLOCK || errno == ETIME)
+ && retrycount > 0)
+ {
+ retrycount--;
+ ACE_DEBUG ((LM_DEBUG,"waiting for inbound data, %d tries left\n",
+ retrycount));
+ ACE_OS::sleep(1);
+ }
+ if (retrycount == 0 || n < 0)
+ {
+ ACE_DEBUG ((LM_DEBUG,"bailing after wait, %p\n","recv"));
+ break;
+ }
+
+ buffer[n] = 0;
+
+ ACE_DEBUG ((LM_DEBUG,"Got: \"%s\"\n",buffer));
+ }
+
+ ACE::HTBP::Channel *ob = session.outbound();
+ n = stream.send ("goodbye",7);
+ if (n == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "%p\n","stream send"),-1);
+
+ ACE_DEBUG ((LM_DEBUG, "send returned %d\n",n));
+
+ retrycount = 10;
+ while ((n = ob->recv_ack()) == -1
+ && (errno == EWOULDBLOCK || errno == ETIME)
+ && retrycount > 0)
+ {
+ retrycount--;
+ ACE_DEBUG ((LM_DEBUG,"waiting for ack, %d tries left\n",
+ retrycount));
+ ACE_OS::sleep (1);
+ }
+ ACE_DEBUG ((LM_DEBUG,"After wait for ack, n = %d, retry = %d\n",
+ n,retrycount,errno));
+
+ return 0;
+}
diff --git a/ACE/tests/HTBP/ping/ping.mpc b/ACE/tests/HTBP/ping/ping.mpc
new file mode 100755
index 00000000000..61e59146a93
--- /dev/null
+++ b/ACE/tests/HTBP/ping/ping.mpc
@@ -0,0 +1,19 @@
+// -*- MPC -*-
+//
+// $Id$
+
+project(*Server): aceexe, htbp {
+ exename = server
+
+ Source_Files {
+ server.cpp
+ }
+}
+
+project(*Client): aceexe, htbp {
+ exename = client
+
+ Source_Files {
+ client.cpp
+ }
+}
diff --git a/ACE/tests/HTBP/ping/run_test.pl b/ACE/tests/HTBP/ping/run_test.pl
new file mode 100755
index 00000000000..ae4c56c7fb2
--- /dev/null
+++ b/ACE/tests/HTBP/ping/run_test.pl
@@ -0,0 +1,39 @@
+eval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}'
+ & eval 'exec perl -S $0 $argv:q'
+ if 0;
+
+# $Id$
+# -*- perl -*-
+
+use lib "$ENV{ACE_ROOT}/bin";
+use PerlACE::Run_Test;
+use Sys::Hostname;
+
+$status = 0;
+
+$SV = new PerlACE::Process ("server");
+
+$host = hostname();
+
+# The client code should later be modified to get the hostname
+# using ACE_OS::hostname so the same script can be run on all
+# hosts without havng to reset the host where it has to be run.
+$CL = new PerlACE::Process ("client", $host);
+
+$SV->Spawn ();
+
+$client = $CL->SpawnWaitKill (300);
+
+if ($client != 0) {
+ print STDERR "ERROR: client returned $client\n";
+ $status = 1;
+}
+
+$server = $SV->WaitKill (10);
+
+if ($server != 0) {
+ print STDERR "ERROR: server returned $server\n";
+ $status = 1;
+}
+
+exit $status;
diff --git a/ACE/tests/HTBP/ping/server.cpp b/ACE/tests/HTBP/ping/server.cpp
new file mode 100644
index 00000000000..d20d46b8b09
--- /dev/null
+++ b/ACE/tests/HTBP/ping/server.cpp
@@ -0,0 +1,124 @@
+/**
+ * server for a basic connection establishment test using HTBP
+ *
+ * $Id$
+ */
+
+#include "ace/Log_Msg.h"
+
+#include "ace/HTBP/HTBP_Session.h"
+#include "ace/HTBP/HTBP_Stream.h"
+#include "ace/HTBP/HTBP_Addr.h"
+
+#include "ace/SOCK_Acceptor.h"
+#include "ace/SOCK_Stream.h"
+
+int
+ACE_TMAIN (int, ACE_TCHAR *[])
+{
+ char buffer[1000];
+ ssize_t n = 0;
+
+ ACE_OS::socket_init (ACE_WSOCK_VERSION);
+
+ ACE_INET_Addr local(8088);
+ ACE_SOCK_Stream sock[2];
+ ACE_SOCK_Acceptor acc(local,1);
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("server is ready\n")));
+
+ acc.accept (sock[0]);
+ ACE::HTBP::Channel channel1(sock[0]);
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Got sock[0], handle = %d\n"),
+ sock[0].get_handle()));
+ acc.accept (sock[1]);
+ ACE::HTBP::Channel channel2 (sock[1]);
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Got sock[1], handle = %d\n"),
+ sock[1].get_handle()));
+ int res = 0;
+ while ((res = channel1.pre_recv ()) != 0)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("res = %d. waiting 1 sec. %p\n"),
+ res,
+ ACE_TEXT ("stream.pre_recv()")));
+ ACE_OS::sleep (1);
+ }
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Read from channel2\n")));
+ while ((res = channel2.pre_recv()) != 0)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("res = %d, waiting 1 sec. %p\n"),
+ res,
+ ACE_TEXT ("stream2.pre_recv()")));
+ ACE_OS::sleep (1);
+ }
+
+ ACE::HTBP::Session *session = channel1.session();
+ ACE::HTBP::Stream stream (session);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("using streams %d, %d. Got sesssion = %@\n"),
+ sock[0].get_handle(),
+ sock[1].get_handle(),
+ session));
+
+ for (int i = 0; i >= 0; i++)
+ {
+ int retrycount = 10;
+ while ((n = stream.recv(buffer,1000)) == -1
+ && (errno == EWOULDBLOCK || errno == ETIME)
+ && retrycount > 0)
+ {
+ retrycount--;
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("waiting for inbound data, %d tries left\n"),
+ retrycount));
+ ACE_OS::sleep(1);
+ }
+ if (retrycount == 0 || n < 0)
+ break;
+
+ buffer[n] = 0;
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Got: \"%C\"\n"), buffer));
+
+ if (ACE_OS::strstr (buffer,"goodbye") != 0)
+ break;
+
+ ACE_OS::sprintf (buffer,"I hear you %d",i);
+ n = stream.send (buffer,ACE_OS::strlen(buffer)+1);
+ if (n == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"),
+ ACE_TEXT ("stream.send")),
+ -1);
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Send returned %d\n"), n));
+
+ int got[2] = {-1,-1};
+ while (got[0] == -1 || got[1] == -1)
+ {
+ if (got[0] == -1)
+ {
+ if ((got[0] = (res =channel1.pre_recv())) == -1)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("res = %d, waiting 1 sec. %p\n"),
+ got[0],
+ ACE_TEXT ("channel1.pre_recv()")));
+ }
+ if (got[1] == -1)
+ {
+ if ((got[1] = (res =channel2.pre_recv())) == -1)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("res = %d, waiting 1 sec. %p\n"),
+ got[1],
+ ACE_TEXT ("channel2.pre_recv()")));
+ }
+ if (got[0] == -1 || got[1] == -1)
+ ACE_OS::sleep (1);
+ }
+ }
+ return 0;
+}
diff --git a/ACE/tests/Handle_Set_Test.cpp b/ACE/tests/Handle_Set_Test.cpp
new file mode 100644
index 00000000000..e28226fd838
--- /dev/null
+++ b/ACE/tests/Handle_Set_Test.cpp
@@ -0,0 +1,246 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Handle_Set_Test.cpp
+//
+// = DESCRIPTION
+// This test illustrates the use of ACE_Handle_Set to maintain a
+// set of handles. No command line arguments are needed to run
+// the test.
+//
+// = AUTHOR
+// Prashant Jain <pjain@cs.wustl.edu>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/OS_NS_stdlib.h"
+#include "ace/Profile_Timer.h"
+#include "ace/Handle_Set.h"
+#include "ace/Containers.h"
+
+ACE_RCSID(tests, Handle_Set_Test, "$Id$")
+
+static void
+test_duplicates (size_t count)
+{
+ size_t duplicates = 0;
+ size_t sets = 0;
+ size_t clears = 0;
+
+ ACE_Handle_Set handle_set;
+
+ ACE_OS::srand (ACE_OS::time (0L));
+
+ for (size_t i = 0; i < count; i++)
+ {
+ size_t handle =
+ static_cast<size_t> (ACE_OS::rand () % ACE_Handle_Set::MAXSIZE);
+
+ if (ACE_ODD (handle))
+ {
+ if (handle_set.is_set ((ACE_HANDLE) handle))
+ duplicates++;
+
+ handle_set.set_bit ((ACE_HANDLE) handle);
+ sets++;
+ }
+ else
+ {
+ if (handle_set.is_set ((ACE_HANDLE) handle))
+ duplicates--;
+
+ handle_set.clr_bit ((ACE_HANDLE) handle);
+ clears++;
+ }
+ }
+
+ ACE_ASSERT (count == sets + clears);
+ ACE_ASSERT (handle_set.num_set () + duplicates == sets);
+}
+
+// This is the vector of handles to test. These numbers are chosen to
+// test for boundaries conditions. Note that if
+// <ACE_DEFAULT_SELECT_REACTOR_SIZE> is less than any of these
+// <HANDLE> values, the logic in <test_boundaries> will simply ignore
+// these values.
+#if defined (ACE_WIN64)
+ // The casts below are legit...
+# pragma warning(push)
+# pragma warning(disable : 4312)
+#endif /* ACE_WIN64 */
+static ACE_HANDLE handle_vector[] =
+{
+ (ACE_HANDLE) 0,
+ (ACE_HANDLE) 1,
+ (ACE_HANDLE) 31,
+ (ACE_HANDLE) 32,
+ (ACE_HANDLE) 63,
+ (ACE_HANDLE) 64,
+ (ACE_HANDLE) 65,
+ (ACE_HANDLE) 127,
+ (ACE_HANDLE) 128,
+ (ACE_HANDLE) 129,
+ (ACE_HANDLE) 254,
+ (ACE_HANDLE) 255,
+ (ACE_HANDLE) (ACE_DEFAULT_SELECT_REACTOR_SIZE - 1),
+ (ACE_HANDLE) ACE_DEFAULT_SELECT_REACTOR_SIZE,
+ ACE_INVALID_HANDLE
+};
+#if defined (ACE_WIN64)
+# pragma warning(pop)
+#endif /* ACE_WIN64 */
+
+static void
+test_boundaries (void)
+{
+ ACE_Handle_Set handle_set;
+ ACE_Unbounded_Set<ACE_HANDLE> set;
+ ACE_HANDLE handle;
+
+ // First test an empty set.
+
+ for (ACE_Handle_Set_Iterator i1 (handle_set);
+ (handle = i1 ()) != ACE_INVALID_HANDLE;
+ )
+ {
+#if defined (ACE_PSOS_DIAB)
+ // Workaround for some compiler confusion with strings in
+ // assertions.
+ const int SET_IS_EMPTY_SO_SHOULD_NOT_SEE_THIS = 1;
+ ACE_ASSERT (0 == SET_IS_EMPTY_SO_SHOULD_NOT_SEE_THIS);
+#else /* ! defined (ACE_PSOS_DIAB) */
+ ACE_ASSERT (0 ==
+ ACE_TEXT ("this shouldn't get called since ")
+ ACE_TEXT ("the set is empty!\n"));
+#endif /* defined (ACE_PSOS_DIAB) */
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("ACE_DEFAULT_SELECT_REACTOR_SIZE %d\n"),
+ ACE_DEFAULT_SELECT_REACTOR_SIZE));
+
+ // Insert the vector of <ACE_HANDLE>s into the set.
+
+#if defined (ACE_WIN64)
+ // The casts below are legit...
+# pragma warning(push)
+# pragma warning(disable : 4312)
+#endif /* ACE_WIN64 */
+ for (int i = 0;
+ handle_vector[i] != ACE_INVALID_HANDLE;
+ i++)
+ {
+ if (handle_vector[i] < (ACE_HANDLE) ACE_DEFAULT_SELECT_REACTOR_SIZE)
+ {
+ handle_set.set_bit (handle_vector[i]);
+ set.insert (handle_vector[i]);
+ }
+ }
+#if defined (ACE_WIN64)
+# pragma warning(pop)
+#endif /* ACE_WIN64 */
+
+ int count = 0;
+
+ for (ACE_Handle_Set_Iterator i2 (handle_set);
+ (handle = i2 ()) != ACE_INVALID_HANDLE;
+ )
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("obtained handle %d\n"),
+ handle));
+ int done = set.remove (handle);
+ ACE_ASSERT (done == 0);
+ count++;
+ }
+
+ ACE_ASSERT (count == handle_set.num_set ());
+}
+
+static void
+test_performance (size_t max_handles,
+ size_t max_iterations)
+{
+ ACE_Handle_Set handle_set;
+ size_t i;
+
+ for (i = 0; i < max_handles; i++)
+ handle_set.set_bit ((ACE_HANDLE) i);
+
+ ACE_Profile_Timer timer;
+ size_t count = 0;
+
+ timer.start ();
+
+ for (i = 0; i < max_iterations; i++)
+ {
+ ACE_Handle_Set_Iterator iter (handle_set);
+
+ // Only iterate up to <handle_set.max_set ()>.
+ while (iter () != ACE_INVALID_HANDLE)
+ count++;
+ }
+
+ timer.stop ();
+
+ ACE_ASSERT (count == max_handles * max_iterations);
+
+ ACE_Profile_Timer::ACE_Elapsed_Time et;
+
+ timer.elapsed_time (et);
+
+#if defined (ACE_LACKS_FLOATING_POINT)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("real time = %u usecs\n"),
+ et.real_time));
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("time per each of the %d calls = %u usecs\n"),
+ count,
+ et.real_time / count));
+#else /* ! ACE_LACKS_FLOATING_POINT */
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("real time = %f secs, user time = %f secs, ")
+ ACE_TEXT ("system time = %f secs\n"),
+ et.real_time,
+ et.user_time,
+ et.system_time));
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("time per each of the %d calls = %f usecs\n"),
+ count,
+ et.real_time / double (count) * 1000000));
+#endif /* ! ACE_LACKS_FLOATING_POINT */
+}
+
+int
+run_main (int argc, ACE_TCHAR *argv[])
+{
+ ACE_START_TEST (ACE_TEXT ("Handle_Set_Test"));
+
+ int count = argc > 1
+ ? ACE_OS::atoi (argv[1])
+ : ACE_Handle_Set::MAXSIZE;
+ size_t max_handles =
+ argc > 2
+ ? ACE_OS::atoi (argv[2])
+ : ACE_Handle_Set::MAXSIZE;
+ size_t max_iterations =
+ argc > 3
+ ? ACE_OS::atoi (argv[3])
+ : ACE_MAX_ITERATIONS;
+
+ test_duplicates (count);
+ test_boundaries ();
+ test_performance (max_handles,
+ max_iterations);
+ ACE_END_TEST;
+ return 0;
+}
+
diff --git a/ACE/tests/Hash_Map_Bucket_Iterator_Test.cpp b/ACE/tests/Hash_Map_Bucket_Iterator_Test.cpp
new file mode 100644
index 00000000000..ab1cae561df
--- /dev/null
+++ b/ACE/tests/Hash_Map_Bucket_Iterator_Test.cpp
@@ -0,0 +1,122 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Hash_Map_Bucket_Iterator_Test.cpp
+//
+// = DESCRIPTION
+// This is a simple test of the <Hash_Map_Bucket_Iterator>.
+//
+// = AUTHOR
+// Irfan Pyarali <irfan@cs.wustl.edu>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/OS_NS_stdlib.h"
+#include "ace/Hash_Map_Manager.h"
+#include "ace/Synch_Traits.h"
+#include "ace/Null_Mutex.h"
+#include "ace/Get_Opt.h"
+#include "ace/Functor.h"
+
+ACE_RCSID(tests, Hash_Map_Bucket_Iterator_Test, "$Id$")
+
+static ACE_UINT32 iterations = ACE_MAX_ITERATIONS * 10;
+static ACE_UINT32 table_size = ACE_MAX_ITERATIONS;
+
+int
+parse_args (int argc, ACE_TCHAR *argv[])
+{
+ ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("t:i:"));
+
+ int cc;
+
+ while ((cc = get_opt ()) != -1)
+ switch (cc)
+ {
+ case 't':
+ table_size = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'i':
+ iterations = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case '?':
+ case 'h':
+ default:
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("usage: %s ")
+ ACE_TEXT ("[-i (iterations)] ")
+ ACE_TEXT ("[-t (table size)] "),
+ ACE_TEXT ("Hash_Map_Bucket_Iterator_Test")));
+ return -1;
+ }
+
+ return 0;
+}
+
+typedef ACE_Hash_Map_Manager_Ex<ACE_UINT32,
+ ACE_UINT32,
+ ACE_Hash<ACE_UINT32>,
+ ACE_Equal_To<ACE_UINT32>,
+ ACE_SYNCH_NULL_MUTEX> HASH_MAP;
+
+typedef ACE_Hash_Map_Bucket_Iterator<ACE_UINT32,
+ ACE_UINT32,
+ ACE_Hash<ACE_UINT32>,
+ ACE_Equal_To<ACE_UINT32>,
+ ACE_SYNCH_NULL_MUTEX> HASH_MAP_BUCKET_ITERATOR;
+
+int
+run_main (int argc, ACE_TCHAR *argv[])
+{
+ // Validate options.
+ int result = parse_args (argc, argv);
+ if (result != 0)
+ return result;
+
+ // Start the test only if options are valid.
+ ACE_START_TEST (ACE_TEXT ("Hash_Map_Bucket_Iterator_Test"));
+ ACE_LOG_MSG->clr_flags (ACE_Log_Msg::VERBOSE_LITE);
+
+ ACE_UINT32 i = 0;
+ HASH_MAP map (table_size);
+
+ for (i = 0; i < iterations; ++i)
+ {
+ int result = map.bind (i, i);
+ ACE_ASSERT (result == 0);
+ ACE_UNUSED_ARG (result);
+ }
+
+ for (i = 0; i < table_size; ++i)
+ {
+ HASH_MAP_BUCKET_ITERATOR iterator (map,
+ i);
+
+ HASH_MAP_BUCKET_ITERATOR end (map,
+ i,
+ 1);
+
+ for (;
+ iterator != end;
+ ++iterator)
+ {
+ ACE_DEBUG ((LM_DEBUG, "%d ", (*iterator).int_id_));
+ ACE_UINT32 key = (*iterator).ext_id_;
+ ACE_ASSERT (((key - i) % table_size) == 0);
+ }
+
+ ACE_DEBUG ((LM_DEBUG, "\n"));
+ }
+
+ ACE_LOG_MSG->set_flags (ACE_Log_Msg::VERBOSE_LITE);
+ ACE_END_TEST;
+
+ return 0;
+}
+
diff --git a/ACE/tests/Hash_Map_Manager_Test.cpp b/ACE/tests/Hash_Map_Manager_Test.cpp
new file mode 100644
index 00000000000..fdb6604e5dd
--- /dev/null
+++ b/ACE/tests/Hash_Map_Manager_Test.cpp
@@ -0,0 +1,336 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Hash_Map_Manager_Test.cpp
+//
+// = DESCRIPTION
+// This test illustrates the use of <ACE_Hash_Map_Manager> to
+// maintain a hash table using strings. In addition, it also
+// illustrates how the <ACE_Static_Allocator> works in
+// conjunction with the <ACE_Hash_Map_Manager>.
+//
+// = AUTHOR
+// James Hu <jxh@cs.wustl.edu> and
+// Douglas C. Schmidt <schmidt@cs.wustl.edu>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/Hash_Map_Manager.h"
+#include "ace/Malloc_T.h"
+#include "ace/Null_Mutex.h"
+
+ACE_RCSID(tests, Hash_Map_Manager_Test, "$Id$")
+
+static const size_t STRING_TABLE_ENTRIES = 3 * 2;
+static const size_t MAX_HASH = 6;
+
+typedef ACE_Hash_Map_Entry<const ACE_TCHAR *,
+ const ACE_TCHAR *> HASH_STRING_ENTRY;
+
+// @@ The following requires too much internal implementation
+// information about the <ACE_Hash_Map_Manager>. We need to figure
+// out how to simplify this.
+static const size_t STRING_TABLE_SIZE =
+ sizeof (HASH_STRING_ENTRY) * (STRING_TABLE_ENTRIES + MAX_HASH);
+
+static ACE_Static_Allocator<STRING_TABLE_SIZE> ace_test_allocator;
+
+typedef ACE_Hash_Map_Manager_Ex<const ACE_TCHAR *,
+ const ACE_TCHAR *,
+ ACE_Hash<const ACE_TCHAR *>,
+ ACE_Equal_To<const ACE_TCHAR *>,
+ ACE_Null_Mutex> HASH_STRING_MAP;
+
+typedef ACE_Hash_Map_Iterator_Ex<const ACE_TCHAR *,
+ const ACE_TCHAR *,
+ ACE_Hash<const ACE_TCHAR *>,
+ ACE_Equal_To<const ACE_TCHAR *>,
+ ACE_Null_Mutex> HASH_STRING_ITER;
+
+typedef ACE_Hash_Map_Const_Iterator_Ex<const ACE_TCHAR *,
+ const ACE_TCHAR *,
+ ACE_Hash<const ACE_TCHAR *>,
+ ACE_Equal_To<const ACE_TCHAR *>,
+ ACE_Null_Mutex> HASH_STRING_CONST_ITER;
+
+typedef ACE_Hash_Map_Reverse_Iterator_Ex<const ACE_TCHAR *,
+ const ACE_TCHAR *,
+ ACE_Hash<const ACE_TCHAR *>,
+ ACE_Equal_To<const ACE_TCHAR *>,
+ ACE_Null_Mutex> HASH_STRING_REVERSE_ITER;
+
+struct String_Table
+{
+ const ACE_TCHAR *key_;
+ const ACE_TCHAR *value_;
+};
+
+static String_Table string_table[] =
+{
+ {
+ ACE_TEXT ("hello"),
+ ACE_TEXT ("guten Tag")
+ },
+ {
+ ACE_TEXT ("goodbye"),
+ ACE_TEXT ("auf wiedersehen")
+ },
+ {
+ ACE_TEXT ("funny"),
+ ACE_TEXT ("lustig")
+ },
+ {
+ 0,
+ 0
+ }
+};
+
+static
+int test_two_allocators ()
+{
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Testing both allocators\n")));
+ int status = 0;
+
+ // Number of entries in string_table above:
+ size_t chunks = 3;
+ size_t chunk_size = sizeof (HASH_STRING_MAP::ENTRY);
+
+ // Allocators:
+ ACE_Dynamic_Cached_Allocator<ACE_Null_Mutex> table_alloc (1 , chunk_size * chunks);
+ ACE_Dynamic_Cached_Allocator<ACE_Null_Mutex> table_alloc_small (1, chunk_size * chunks - 1);
+ ACE_Cached_Allocator<HASH_STRING_MAP::ENTRY, ACE_Null_Mutex> entry_alloc (chunks);
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Testing hash map manager with %d elements...\n"), chunks));
+
+ HASH_STRING_MAP hash;
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Opening hash map manager with ")
+ ACE_TEXT ("insufficient table allocator, should fail...\n")));
+ ACE_OS::last_error (0);
+ status = hash.open (chunks, &table_alloc_small, &entry_alloc);
+ if (status < 0)
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("OK, failed: %d (%s)\n"),
+ status, ACE_OS::strerror (ACE_OS::last_error ())));
+ else
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("*** Something is wrong...\n")), -1);
+
+ status = hash.close ();
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Table allocator depth: %d.\n"),
+ table_alloc.pool_depth ()));
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Entry allocator depth: %d.\n"),
+ entry_alloc.pool_depth ()));
+
+ ACE_DEBUG
+ ((LM_DEBUG,
+ ACE_TEXT ("Opening hash map manager again, should succeed...\n")));
+ ACE_OS::last_error (0);
+ status = hash.open (chunks, &table_alloc, &entry_alloc);
+ if (status < 0)
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("*** Something is wrong: %d (%s)\n"),
+ status, ACE_OS::strerror (ACE_OS::last_error ())), -1);
+ else
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("OK.\n")));
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Table allocator depth: %d\n"),
+ table_alloc.pool_depth ()));
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Entry allocator depth: %d.\n"),
+ entry_alloc.pool_depth ()));
+
+ for (size_t i = 0; i < chunks; i++)
+ {
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("- Binding ('%s', '%s'), should succeed...\n"),
+ string_table[i].key_ , string_table[i].value_));
+ ACE_OS::last_error (0);
+ status = hash.bind (string_table[i].key_, string_table[i].value_);
+ if (status < 0)
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("*** Something is wrong: %d (%s)\n"),
+ status, ACE_OS::strerror (ACE_OS::last_error ())), -1);
+ else
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("OK, entry allocator depth: %d\n"),
+ entry_alloc.pool_depth ()));
+ }
+
+ const ACE_TCHAR *key = ACE_TEXT ("key");
+ const ACE_TCHAR *val = ACE_TEXT ("value");
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("- Binding ('%s', '%s'), should fail...\n"),
+ key, val));
+ ACE_OS::last_error (0);
+ status = hash.bind (key, val);
+ if (status < 0)
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("OK, failed (%s).\n"),
+ ACE_OS::strerror (ACE_OS::last_error ())));
+ else
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("*** Something is wrong: %d (%s)\n"),
+ status, ACE_OS::strerror (ACE_OS::last_error ())), -1);
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Closing hash map.\n")));
+ status = hash.close ();
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Table allocator depth: %d.\n"),
+ table_alloc.pool_depth ()));
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Entry allocator depth: %d.\n"),
+ entry_alloc.pool_depth ()));
+
+ return 0;
+}
+
+static int
+run_test (void)
+{
+ ace_test_allocator.dump ();
+
+ HASH_STRING_MAP hash (MAX_HASH, &ace_test_allocator);
+
+ size_t i;
+
+ // Check the <bind> operation.
+ for (i = 0; string_table[i].key_ != 0; i++)
+ if (hash.bind (string_table[i].key_,
+ string_table[i].value_) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p failed for %s \n"),
+ ACE_TEXT ("bind"),
+ string_table[i].key_), -1);
+
+ const ACE_TCHAR *entry;
+
+ // Check the <find> operation.
+ for (i = 0; string_table[i].key_ != 0; i++)
+ if (hash.find (string_table[i].key_,
+ entry) == 0)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("`%s' found `%s'\n"),
+ string_table[i].key_,
+ entry));
+ else
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("`%s' not found\n"),
+ string_table[i].key_),
+ -1);
+
+ // Check the <trybind> operation.
+ {
+ const ACE_TCHAR *pc = string_table[1].value_;
+ if (hash.trybind (string_table[0].key_,
+ pc) != 1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("::trybind missed existing entry.")),
+ -1);
+ else if (pc != string_table[0].value_)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("::trybind doesn't return existing value.")),
+ -1);
+ }
+
+ // Let's test the iterator while we are at it.
+ {
+ HASH_STRING_ENTRY *entry = 0;
+ size_t i = 0;
+
+ for (HASH_STRING_ITER hash_iter (hash);
+ hash_iter.next (entry) != 0;
+ hash_iter.advance ())
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("iterating (%d): [%s, %s]\n"),
+ i,
+ entry->ext_id_,
+ entry->int_id_));
+ i++;
+ }
+ }
+
+ // And now test the const iterator
+ {
+ HASH_STRING_ENTRY *entry = 0;
+ size_t i = 0;
+
+ for (HASH_STRING_CONST_ITER hash_iter (hash);
+ hash_iter.next (entry) != 0;
+ hash_iter.advance ())
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("const iterating (%d): [%s, %s]\n"),
+ i,
+ entry->ext_id_,
+ entry->int_id_));
+ i++;
+ }
+ }
+
+ hash.unbind (string_table[2].key_, entry);
+
+ // Check the <find> operation again.
+ for (i = 0; string_table[i].key_ != 0; i++)
+ if (hash.find (string_table[i].key_,
+ entry) == 0)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("`%s' found `%s'\n"),
+ string_table[i].key_,
+ entry));
+ else if (i != 2)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("`%s' not found\n"),
+ string_table[i].key_),
+ -1);
+
+ // Let's test the iterator backwards.
+ {
+ HASH_STRING_ENTRY *entry = 0;
+ size_t i = 0;
+
+ for (HASH_STRING_REVERSE_ITER hash_iter (hash);
+ hash_iter.next (entry) != 0;
+ hash_iter.advance ())
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("iterating (%d): [%s, %s]\n"),
+ i,
+ entry->ext_id_,
+ entry->int_id_));
+ i++;
+ }
+ }
+
+ // Remove all the entries.
+ if (hash.unbind_all () != 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("unbind_all failed\n")),
+ -1);
+
+ // Redo the <bind> operations.
+ for (i = 0; string_table[i].key_ != 0; i++)
+ if (hash.bind (string_table[i].key_,
+ string_table[i].value_) != 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p failed for %s \n"),
+ ACE_TEXT ("bind"),
+ string_table[i].key_), -1);
+
+ ace_test_allocator.dump ();
+
+ test_two_allocators();
+
+ return 0;
+}
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("Hash_Map_Manager_Test"));
+
+ run_test ();
+
+ ACE_END_TEST;
+
+ return 0;
+}
diff --git a/ACE/tests/High_Res_Timer_Test.cpp b/ACE/tests/High_Res_Timer_Test.cpp
new file mode 100644
index 00000000000..5398157d8d3
--- /dev/null
+++ b/ACE/tests/High_Res_Timer_Test.cpp
@@ -0,0 +1,176 @@
+// $Id$
+//============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// High_Res_Timer_Test.cpp
+//
+// = DESCRIPTION
+// Simple test of ACE_High_Res_Timer.
+//
+// = AUTHOR
+// David L. Levine <levine@cs.wustl.edu>
+//
+//============================================================================
+
+#include "test_config.h"
+#include "ace/Log_Msg.h"
+#include "ace/High_Res_Timer.h"
+#include "ace/Sched_Params.h"
+#include "ace/Get_Opt.h"
+#include "ace/OS_NS_unistd.h"
+
+ACE_RCSID(tests, High_Res_Timer_Test, "High_Res_Timer_Test.cpp,v 4.6 2000/04/23 04:43:58 brunsch Exp")
+
+static
+u_int
+check (const u_int interval, const u_int measured)
+{
+ const u_int threshold = 25 /* percent */;
+
+ const u_int difference =
+ interval > measured ? interval - measured : measured - interval;
+
+ const u_int percentage_difference = difference * 100 / interval;
+
+ if (percentage_difference < threshold)
+ return 0;
+ else
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("The measured time of %u differs from ")
+ ACE_TEXT ("the interval of %u by %u percent.\n"),
+ measured,
+ interval,
+ percentage_difference),
+ 1);
+}
+
+// Does a sanity check of the microseconds vs nanoseconds. They're supposed
+// to represent the same interval.
+static u_int
+check_micro_nano (ACE_hrtime_t microinterval, ACE_hrtime_t nanointerval)
+{
+ const u_int threshold = 8 /* promille */;
+
+ microinterval *= 1000u;
+ ACE_hrtime_t hr_difference = (microinterval > nanointerval ?
+ microinterval - nanointerval :
+ nanointerval - microinterval );
+ const u_int difference = ACE_HRTIME_CONVERSION (hr_difference);
+ if (nanointerval == 0)
+ nanointerval = 1; // Prevent divide-by-zero
+ const u_int promille_difference = difference * 1000 /
+ ACE_HRTIME_CONVERSION(nanointerval);
+
+ if ((promille_difference < threshold) || (difference < 1500))
+ return 0;
+ else
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("The microseconds * 1000 of %u differs from ")
+ ACE_TEXT ("the nanoseconds of %u by %u promille\n"),
+ ACE_HRTIME_CONVERSION (microinterval),
+ ACE_HRTIME_CONVERSION (nanointerval),
+ promille_difference),
+ 1);
+}
+
+static
+ACE_Time_Value
+time_interval (const ACE_Time_Value &interval,
+ ACE_hrtime_t& nanoseconds,
+ ACE_hrtime_t& microseconds)
+{
+ ACE_High_Res_Timer timer;
+
+ timer.start ();
+ ACE_OS::sleep (interval);
+ timer.stop ();
+
+ ACE_Time_Value measured;
+ timer.elapsed_time (measured);
+ timer.elapsed_time (nanoseconds);
+ timer.elapsed_microseconds (microseconds);
+ return measured;
+}
+
+
+static
+u_int
+intervals [] = {0, 1, 10, 100, 1000, 10000, 100000, 1000000, 4000000}; /*usec*/
+
+int
+run_main (int argc, ACE_TCHAR *argv[])
+{
+ ACE_START_TEST (ACE_TEXT ("High_Res_Timer_Test"));
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("The ACE_High_Res_Timer scale factor is %u ")
+ ACE_TEXT ("1/microsecond\n"),
+ ACE_High_Res_Timer::global_scale_factor ()));
+
+ u_int errors = 0;
+
+ u_int iterations = 1;
+
+ ACE_Get_Opt getopt (argc, argv, ACE_TEXT ("i:"));
+ for (int c; (c = getopt ()) != -1; )
+ switch (c)
+ {
+ case 'i':
+ iterations = ACE_OS::atoi (getopt.opt_arg ());
+ break;
+ }
+
+ // We don't check for errors if the interval is shorter than this
+ // value because the OS has a finite resolution anyway.
+ const u_int TIMER_RESOLUTION = 10000;
+
+ for (u_int i = 0; i < sizeof intervals / sizeof (u_int); ++i)
+ {
+ for (u_int j = 0; j < iterations; ++j)
+ {
+ const ACE_Time_Value interval (0, intervals[i]);
+ ACE_hrtime_t nanoseconds;
+ ACE_hrtime_t microseconds;
+ const ACE_Time_Value measured = time_interval (interval,
+ nanoseconds,
+ microseconds);
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("interval: %u usec, measured: %u usec%s\n"),
+ interval.sec () * 1000000 + interval.usec (),
+ measured.sec () * 1000000 + measured.usec (),
+ intervals[i] <= TIMER_RESOLUTION ?
+ ACE_TEXT (" (interval and measured may differ)") :
+ ACE_TEXT ("")));
+
+ if (intervals[i] > TIMER_RESOLUTION)
+ {
+ errors += check (interval.sec () * 1000000 + interval.usec (),
+ measured.sec () * 1000000 + measured.usec ());
+ // Don't check for error for intervals below 10 msec.
+ }
+ // Check the ACE_Timer_Value-calculated microseconds against
+ // the ACE_High_Res_Timer-calculated nanoseconds.
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("ACE_Time_Value usec: %u, ACE_HR nsec: %u\n"),
+ measured.sec () * 1000000 + measured.usec (),
+ ACE_HRTIME_CONVERSION (nanoseconds)));
+ // This gives problems -> should be fixed
+ errors += check_micro_nano (measured.sec () * 1000000 +
+ measured.usec (),
+ nanoseconds);
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("ACE_High_Res_Timer usec: %u, nsec: %u\n"),
+ ACE_HRTIME_CONVERSION (microseconds),
+ ACE_HRTIME_CONVERSION (nanoseconds)));
+ // Now check the ACE_High_Res_Timer-calculated values against
+ // each other.
+ errors += check_micro_nano (microseconds, nanoseconds);
+ }
+ }
+
+ ACE_END_TEST;
+ return errors == 0 ? 0 : 1;
+}
diff --git a/ACE/tests/INET_Addr_Test.cpp b/ACE/tests/INET_Addr_Test.cpp
new file mode 100644
index 00000000000..5a25bd54fba
--- /dev/null
+++ b/ACE/tests/INET_Addr_Test.cpp
@@ -0,0 +1,223 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// INET_Addr_Test.cpp
+//
+// = DESCRIPTION
+// Performs several tests on the ACE_INET_Addr class. It creates several
+// IPv4 and IPv6 addresses and checks that the address formed by the
+// class is valid.
+//
+// = AUTHOR
+// John Aughey (jha@aughey.com)
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/OS_NS_string.h"
+#include "ace/INET_Addr.h"
+#include "ace/Log_Msg.h"
+#include "ace/OS_NS_arpa_inet.h"
+
+// Make sure that ACE_Addr::addr_type_ is the same
+// as the family of the inet_addr_.
+int check_type_consistency (const ACE_INET_Addr &addr)
+{
+ int family = -1;
+
+ if (addr.get_type () == AF_INET)
+ {
+ struct sockaddr_in *sa4 = (struct sockaddr_in *)addr.get_addr();
+ family = sa4->sin_family;
+ }
+#if defined (ACE_HAS_IPV6)
+ else if (addr.get_type () == AF_INET6)
+ {
+ struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)addr.get_addr();
+ family = sa6->sin6_family;
+ }
+#endif
+
+ if (addr.get_type () != family)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Inconsistency between ACE_SOCK::addr_type_ (%d) ")
+ ACE_TEXT ("and the sockaddr family (%d)\n"),
+ addr.get_type (),
+ family));
+ return 1;
+ }
+ return 0;
+}
+
+
+int run_main (int argc, ACE_TCHAR *argv[])
+{
+ ACE_UNUSED_ARG (argc);
+ ACE_UNUSED_ARG (argv);
+
+ ACE_START_TEST (ACE_TEXT ("INET_Addr_Test"));
+
+ int status = 0; // Innocent until proven guilty
+
+ const char *ipv4_addresses[] =
+ {
+ "127.0.0.1", "138.38.180.251", "64.219.54.121", "192.0.0.1", "10.0.0.1", 0
+ };
+
+ ACE_INET_Addr addr;
+ status |= check_type_consistency (addr);
+ char hostaddr[1024];
+
+ for (int i=0; ipv4_addresses[i] != 0; i++)
+ {
+ struct in_addr addrv4;
+ ACE_UINT32 addr32;
+
+ ACE_OS::inet_pton (AF_INET, ipv4_addresses[i], &addrv4);
+
+ ACE_OS::memcpy (&addr32, &addrv4, sizeof (addr32));
+
+ addr.set (80, ipv4_addresses[i]);
+ status |= check_type_consistency (addr);
+
+ /*
+ ** Now check to make sure get_ip_address matches and get_host_addr
+ ** matches.
+ */
+ if (addr.get_ip_address () != ACE_HTONL (addr32))
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Error: %s failed get_ip_address() check\n")
+ ACE_TEXT ("0x%x != 0x%x\n"),
+ ipv4_addresses[i],
+ addr.get_ip_address (),
+ addr32));
+ status = 1;
+ }
+
+ if (0 != ACE_OS::strcmp (addr.get_host_addr(), ipv4_addresses[i]))
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("%s failed get_host_addr() check\n")
+ ACE_TEXT ("%s != %s\n"),
+ ipv4_addresses[i],
+ addr.get_host_addr (),
+ ipv4_addresses[i]));
+ status = 1;
+ }
+
+ // Now we check the operation of get_host_addr(char*,int)
+ const char* haddr = addr.get_host_addr (&hostaddr[0], sizeof(hostaddr));
+ if (0 != ACE_OS::strcmp (&hostaddr[0], haddr))
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("%s failed get_host_addr(char* buf,int) check\n")
+ ACE_TEXT ("buf ['%s'] != return value ['%s']\n"),
+ ipv4_addresses[i],
+ &hostaddr[0],
+ haddr));
+ status = 1;
+ }
+ if (0 != ACE_OS::strcmp (&hostaddr[0], ipv4_addresses[i]))
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("%s failed get_host_addr(char*,int) check\n")
+ ACE_TEXT ("buf ['%s'] != expected value ['%s']\n"),
+ ipv4_addresses[i],
+ &hostaddr[0],
+ ipv4_addresses[i]));
+ status = 1;
+ }
+
+ // Clear out the address by setting it to 1 and check
+ addr.set (0, ACE_UINT32 (1), 1);
+ status |= check_type_consistency (addr);
+ if (addr.get_ip_address () != 1)
+ {
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("Failed to set address to 1\n")));
+ status = 1;
+ }
+
+ // Now set the address using a 32 bit number and check that we get
+ // the right string out of get_host_addr().
+ addr.set (80, addr32, 0); // addr32 is already in network byte order
+ status |= check_type_consistency(addr);
+
+ if (0 != ACE_OS::strcmp (addr.get_host_addr (), ipv4_addresses[i]))
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("%s failed second get_host_addr() check\n")
+ ACE_TEXT ("return value ['%s'] != expected value ['%s']\n"),
+ ipv4_addresses[i],
+ addr.get_host_addr (),
+ ipv4_addresses[i]));
+ status = 1;
+ }
+
+ // Test for ACE_INET_Addr::set_addr().
+ struct sockaddr_in sa4;
+ sa4.sin_family = AF_INET;
+ sa4.sin_addr = addrv4;
+ sa4.sin_port = ACE_HTONS (8080);
+
+ addr.set (0, ACE_UINT32 (1), 1);
+ addr.set_addr (&sa4, sizeof(sa4));
+ status |= check_type_consistency (addr);
+
+ if (addr.get_port_number () != 8080)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("ACE_INET_Addr::set_addr() ")
+ ACE_TEXT ("failed to update port number.\n")));
+ status = 1;
+ }
+
+ if (addr.get_ip_address () != ACE_HTONL (addr32))
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("ACE_INET_Addr::set_addr() ")
+ ACE_TEXT ("failed to update address.\n")));
+ status = 1;
+ }
+
+ }
+
+#if defined (ACE_HAS_IPV6)
+ if (ACE::ipv6_enabled ())
+ {
+ const char *ipv6_addresses[] = {
+ "1080::8:800:200c:417a", // unicast address
+ "ff01::101", // multicast address
+ "::1", // loopback address
+ "::", // unspecified addresses
+ 0
+ };
+
+ for (int i=0; ipv6_addresses[i] != 0; i++)
+ {
+ ACE_INET_Addr addr (80, ipv6_addresses[i]);
+ status |= check_type_consistency (addr);
+
+ if (0 != ACE_OS::strcmp (addr.get_host_addr (), ipv6_addresses[i]))
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("IPv6 get_host_addr failed: %s != %s\n"),
+ addr.get_host_addr (),
+ ipv6_addresses[i]));
+ status = 1;
+ }
+ }
+ }
+
+#endif
+
+ ACE_END_TEST;
+
+ return status;
+}
diff --git a/ACE/tests/INET_Addr_Test_IPV6.cpp b/ACE/tests/INET_Addr_Test_IPV6.cpp
new file mode 100644
index 00000000000..134119ae7b9
--- /dev/null
+++ b/ACE/tests/INET_Addr_Test_IPV6.cpp
@@ -0,0 +1,167 @@
+// $Id$
+
+// ============================================================================
+/**
+ * @file INET_Addr_Test_IPV6.cpp
+ *
+ * @brief Additional tests on the ACE_INET_Addr class above and beyond
+ * those found in INET_Addr_Test. These primarily focus on additional
+ * functionality and bug fixes to ACE_INET_Addr.
+ *
+ * @author John Aughey <jha@aughey.com>
+ * Brian Buesker <bbuesker@qualcomm.com>
+ */
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/OS_NS_string.h"
+#include "ace/INET_Addr.h"
+#include "ace/Log_Msg.h"
+#include "ace/OS_NS_arpa_inet.h"
+
+#define LINK_LOCAL_ADDR ACE_TEXT ("fe80::")
+#define INTERFACE ("eth0")
+
+// Make sure that ACE_Addr::addr_type_ is the same
+// as the family of the inet_addr_.
+int check_type_consistency (const ACE_INET_Addr &addr)
+{
+ int family = -1;
+
+ if (addr.get_type () == AF_INET)
+ {
+ struct sockaddr_in *sa4 = (struct sockaddr_in *)addr.get_addr();
+ family = sa4->sin_family;
+ }
+#if defined (ACE_HAS_IPV6)
+ else if (addr.get_type () == AF_INET6)
+ {
+ struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)addr.get_addr();
+ family = sa6->sin6_family;
+ }
+#endif
+
+ if (addr.get_type () != family)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Inconsistency between ACE_SOCK::addr_type_ (%d) ")
+ ACE_TEXT ("and the sockaddr family (%d)\n"),
+ addr.get_type (),
+ family));
+ return 1;
+ }
+ return 0;
+}
+
+
+int run_main (int argc, ACE_TCHAR *argv[])
+{
+ ACE_UNUSED_ARG (argc);
+ ACE_UNUSED_ARG (argv);
+
+ ACE_START_TEST (ACE_TEXT ("INET_Addr_Test_IPV6"));
+
+ int status = 0; // Innocent until proven guilty
+
+#if defined (ACE_HAS_IPV6)
+ if (ACE::ipv6_enabled ())
+ {
+ ACE_INET_Addr addr ("::");
+
+ // this should switch it back to an IPv4 address
+ addr.set (80);
+
+ if (AF_INET != addr.get_type())
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("set failed: Address type %d != AF_INET\n"),
+ addr.get_type()));
+ status = 1;
+ }
+
+ // this should get mapped to an IPv6 address
+ addr.set (80, ACE_UINT32 (INADDR_ANY), 1, 1);
+
+ if (AF_INET6 != addr.get_type())
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("set failed: Address type %d != AF_INET6\n"),
+ addr.get_type()));
+ status = 1;
+ }
+
+ // Test for ACE_INET_Addr::set_addr().
+ struct in_addr addrv4;
+
+ ACE_OS::inet_pton (AF_INET, "127.0.0.1", &addrv4);
+
+ struct sockaddr_in sa4;
+ sa4.sin_family = AF_INET;
+ sa4.sin_addr = addrv4;
+ sa4.sin_port = ACE_HTONS (8080);
+
+ addr.set (0, ACE_UINT32 (1), 1);
+
+ // test to make sure this doesn't get mapped to an IPv6 address
+ addr.set_addr (&sa4, sizeof(sa4), 0);
+
+ if (addr.get_type() != AF_INET)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT
+ ("set_addr failed: Address type %d != AF_INET\n"),
+ addr.get_type()));
+ status = 1;
+ }
+
+ // now test to make sure it does get mapped to an IPv6 address
+ addr.set_addr (&sa4, sizeof(sa4), 1);
+
+ if (addr.get_type() != AF_INET6)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT
+ ("set_addr failed: Address type %d != AF_INET6\n"),
+ addr.get_type()));
+ status = 1;
+ }
+
+ // test to make sure that the type gets set correctly when set is
+ // called with another ACE_INET_Addr
+ addr.set (0, ACE_UINT32 (1), 1);
+
+ ACE_INET_Addr addrIPv6 ((u_short) 0, ACE_IPV6_LOCALHOST);
+
+ addr.set (addrIPv6);
+
+ status |= check_type_consistency (addr);
+
+#if defined (__linux__)
+ // test a link local address to make sure the set_interface method works
+ ACE_INET_Addr link_local_addr (80, LINK_LOCAL_ADDR);
+ if (0 != ACE_OS::strcmp (ACE_TEXT_CHAR_TO_TCHAR(link_local_addr.get_host_addr ()),
+ LINK_LOCAL_ADDR))
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("IPv6 get_host_addr failed: %s != %s\n"),
+ link_local_addr.get_host_addr (),
+ LINK_LOCAL_ADDR));
+ status = 1;
+ }
+
+ if (-1 == link_local_addr.set_interface (INTERFACE))
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("IPv6 set_interface failed\n")));
+ status = 1;
+ }
+#endif /* __linux__ */
+ }
+
+#endif /* ACE_HAS_IPV6 */
+
+ ACE_END_TEST;
+
+ return status;
+}
diff --git a/ACE/tests/INTEGRITY.ld b/ACE/tests/INTEGRITY.ld
new file mode 100644
index 00000000000..7b77515f096
--- /dev/null
+++ b/ACE/tests/INTEGRITY.ld
@@ -0,0 +1,31 @@
+# default link map for INTEGRITY
+# text (readonly) and data (read/write) areas must be page-aligned
+
+-sec
+{
+# text/readonly segment
+ .picbase 0x10000 :
+ .text :
+ .syscall :
+ .intercall :
+ .interfunc :
+ .secinfo :
+ .rodata :
+ .sdata2 :
+ .fixaddr :
+ .fixtype :
+# .textchecksum MUST be the last section of the text/readonly segment
+ .textchecksum :
+
+# data/readwrite segment
+ .pidbase align(0x4000) :
+ .data :
+ .sdabase :
+ .sdata :
+# .datachecksum MUST be the last section of the data portion of the
+# data/read/write segment (i.e., it must come before the BSS sections).
+ .datachecksum :
+ .sbss :
+ .bss :
+ .heap align(16) pad(0x800000) :
+}
diff --git a/ACE/tests/IOStream_Test.cpp b/ACE/tests/IOStream_Test.cpp
new file mode 100644
index 00000000000..cd3c42a46a0
--- /dev/null
+++ b/ACE/tests/IOStream_Test.cpp
@@ -0,0 +1,502 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// IOStream_Test.cpp
+//
+// = DESCRIPTION
+// This is a simple test of the IOStream class that illustrates
+// how to use iostream operations on almost arbitrary I/O classes.
+//
+// = AUTHOR
+// James CE Johnson <jcej@lads.com>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/Thread.h"
+#include "ace/Acceptor.h"
+#include "ace/SOCK_Connector.h"
+#include "ace/SOCK_Acceptor.h"
+#include "ace/IOStream.h"
+#include "ace/OS_NS_sys_wait.h"
+
+ACE_RCSID (tests, IOStream_Test, "$Id$")
+
+#if !defined (ACE_LACKS_ACE_IOSTREAM)
+# include "ace/OS_NS_unistd.h"
+# include "ace/os_include/os_ctype.h" // Needed for isspace() function
+
+typedef ACE_IOStream<ACE_SOCK_Stream> ACE_SOCK_IOStream;
+
+/* The biggest drawback to an iostream is that it generally
+ eats up whitespace when performing a get (>>) operation.
+
+ That may be good if you're reading non-textual data but
+ if you're trying to read a stream of words with embedded
+ whitespace, it isn't going to be pleasant.
+
+ If you've been blessed with the GNU String class, I've
+ already provided a derived class, QuotedString, that
+ makes dealing with strings very easy.
+
+ If you're stuck with an array of characters then you
+ will probably need somthing like I have below.
+
+ On the other hand, one of the biggest advantages to an
+ iostream is that it eats up whitespace :-)
+
+ If you put (<<) your non-textual data to the iostream
+ with any number of whitespace between the data then
+ you can easily get (>>) the data from the iostream
+ without having to worry about delimeters and such.
+
+ The main thing to keep in mind when using an iostream
+ between peers is that you MUST keep the data "fields"
+ in sync. That is, if the "putter" puts an int followed
+ by a float followed by a double, you must make sure
+ that the "getter" will be attempting to get an int
+ then a float then a double.
+ */
+
+// Since I can't rely on GNU's String class being everywhere (yet),
+// here's a simple class that will work with quoted strings. Use at
+// your own risk! It is very incomplete!
+
+class qchar
+{
+public:
+ qchar (void) { c_ = '\0'; }
+
+ qchar (char c) : c_ (c) { };
+
+ operator char () const { return c_; }
+
+ qchar operator= (char c) { return c_ = c; }
+
+ bool operator== (char c) { return c_ == c; }
+
+ friend ACE_SOCK_IOStream &operator>> (ACE_SOCK_IOStream & stream, qchar * buf);
+ friend ACE_SOCK_IOStream &operator<< (ACE_SOCK_IOStream & stream, qchar * buf);
+ friend ostream &operator<< (ostream & stream, qchar * buf);
+
+private:
+ char c_;
+};
+
+// This is taken almost directly from the QuotedString object that has
+// been derived from GNU's String class. The advantage to using
+// QuotedString is that it is MUCH more robust than qchar will every
+// be.
+
+ACE_SOCK_IOStream &
+operator>> (ACE_SOCK_IOStream & stream, qchar *buf)
+{
+ char c;
+
+ *buf = '\0'; // Initialize the string
+
+ stream.get (c);
+
+ if (!stream) // eat space up to the first char
+ return stream;
+
+ // if we don't have a quote, append until we see space
+ if (c != '"')
+ for (*buf++ = c;
+#ifdef CHORUS
+ stream.get (c) && !isspace (c);
+#else
+ (void *) stream.get (c) && !isspace (c);
+#endif /* CHORUS */
+ *buf++ = c)
+ continue;
+ else
+#ifdef CHORUS
+ for (; stream.get (c) && c != '"'; *buf++ = c)
+#else
+ for (; (void *) stream.get (c) && c != '"'; *buf++ = c)
+#endif /* CHORUS */
+ if (c == '\\')
+ {
+ stream.get (c);
+ if (c != '"')
+ *buf++ = '\\';
+ }
+
+ *buf = '\0';
+
+ return stream;
+}
+
+ACE_SOCK_IOStream &
+operator<< (ACE_SOCK_IOStream &stream, qchar *buf)
+{
+ stream.put ('"');
+
+ while (*buf)
+ {
+ if (*buf == '"')
+ stream.put ('\\');
+
+ stream.put ((char) *buf++);
+ }
+
+ stream.put ('"');
+
+ return stream;
+}
+
+ostream &
+operator<< (ostream &stream, qchar *buf)
+{
+ while (*buf)
+ stream.put ((char) *buf++);
+
+ return stream;
+}
+
+// Our client thread will initiate the test by sending some data to
+// the server.
+
+static void *
+client (void *arg = 0)
+{
+ ACE_UNUSED_ARG (arg);
+
+ // We don't _need_ to dynamically allocate the ACE_SOCK_IOStream.
+ // But if we don't, it doesn't get destroyed on some platforms,
+ // e.g., g++ 2.7.2.1 and Sun C++ 4.2 on Solaris 2.5.1. (It does work
+ // on Linux, so the code seems fine.) If we manage the storage
+ // ourselves, we _will_ destroy it at the end of this function.
+ ACE_SOCK_IOStream server;
+
+ ACE_INET_Addr *remote_addr = (ACE_INET_Addr *) arg;
+ ACE_INET_Addr addr (remote_addr->get_port_number (),
+ ACE_DEFAULT_SERVER_HOST);
+ ACE_SOCK_Connector connector;
+
+ if (connector.connect (server, addr) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT (" (%t) %p\n"),
+ ACE_TEXT ("Failed to connect to server thread")),
+ 0);
+
+ // Send a string to the server which it can interpret as a qchar[]
+ const char *str = "\"This is a test string.\"";
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT (" (%P|%t) Client Sending: (%s)\n"),
+ ACE_TEXT_CHAR_TO_TCHAR (str)));
+ server << str << endl;
+
+ // Allow the server to get the string and echo it to the user. (The
+ // iostream doesn't need this, but humans do :)
+ ACE_OS::sleep (2);
+
+ // Send another string but this time the server will read it as a
+ // char[]. Notice how the server's output doesn't include all of
+ // the spaces sent by the client.
+
+ str = "\"THIS IS A TEST STRING.\"";
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT (" (%P|%t) Client Sending: (%s)\n"),
+ str));
+ server << str << endl;
+
+ // Again, give the server time to display the happenings to the
+ // user.
+ ACE_OS::sleep (2);
+
+ // Read from the server an int, float, long, float double. The
+ // iostream will pull them out by using the whitespace provided by
+ // the server.
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT (" (%P|%t) Client Receiving\n")));
+
+ ACE_Time_Value timeout (2);
+ ACE_Time_Value *timeoutp = &timeout;
+
+ server >> timeoutp;
+
+ int i;
+ float f1, f2;
+ long l;
+ double d;
+
+ while (! (server >> i))
+ {
+ int eof = server.eof ();
+ if (eof)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT (" (%P|%t) Unrecoverable stream error/eof\n")));
+ break;
+ }
+ else
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT (" (%P|%t) Recoverable stream error/timed out)\n")));
+ server.clear (0);
+ }
+ }
+
+ server >> f1;
+ server >> l;
+ server >> f2;
+ server >> d;
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT (" (%P|%t) Client Received: int %d float %f long %d float %f double %f\n"),
+ i,
+ f1,
+ (int) l,
+ f2,
+ d));
+
+ // Check for proper received values.
+ ACE_ASSERT (i == 1 && (f1 >= 0.123420 && f1 <= 0.123422)
+ && l == 666555444 && (f2 >= 23.44 && f2 <= 23.46)
+ && (d >= -47.1e+9 && d <= -45.9e+9));
+ // Reset the precision to limit ourselves to two significant digits.
+ server.precision (2);
+
+ // Now, make a little change & send 'em back.
+ i *= -1; server << i << " ";
+ f1 *= -1.0; server << f1 << " ";
+ l *= -1; server << l << " ";
+ f2 *= -1.0; server << f2 << " ";
+ d *= -1; server << d << " ";
+ server << endl;
+
+ // Shut down the test.
+ server.close ();
+
+ return 0;
+}
+
+// Test the server's ability to receive data from the client and then
+// begin a two-way conversation.
+
+static void *
+server (void *arg = 0)
+{
+ // We don't _need_ to dynamically allocate the ACE_SOCK_IOStream.
+ // But if we don't, it doesn't get destroyed on some platforms,
+ // e.g., g++ 2.7.2.1 and Sun C++ 4.2 on Solaris 2.5.1. (It does work
+ // on Linux, so the code seems fine.) If we manage the storage
+ // ourselves, we _will_ destroy it at the end of this function.
+ ACE_SOCK_IOStream client_handler;
+
+ ACE_INET_Addr server_addr;
+ ACE_SOCK_Acceptor *acceptor =
+ reinterpret_cast<ACE_SOCK_Acceptor *> (arg);
+
+ if (acceptor->get_local_addr (server_addr) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("get_local_addr")),
+ 0);
+
+#if defined (ACE_HAS_THREADS)
+ if (ACE_Thread_Manager::instance ()->spawn (ACE_THR_FUNC (client),
+ (void *) &server_addr,
+ THR_NEW_LWP | THR_DETACHED) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT (" (%t) %p\n"),
+ ACE_TEXT ("spawing client thread")),
+ 0);
+#endif /* ACE_HAS_THREADS */
+
+ if (acceptor->accept (client_handler) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT (" (%P|%t) Failed to accept new client_handler")),
+ 0);
+
+ // Read a qbuf[] from the client. Notice that all of the client's
+ // whitespace is preserved.
+ qchar qbuf[BUFSIZ];
+ ACE_OS::memset (qbuf, 0, sizeof qbuf);
+ client_handler >> qbuf;
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT (" (%P|%t) Server Received: (\"%s\")\n"),
+ ACE_TEXT_CHAR_TO_TCHAR ((char *) qbuf)));
+
+ // Give the client time to announce the next test to the user.
+ ACE_OS::sleep (2);
+
+ // Now we try to use a char[] to get a string from the client.
+ // Compared to the method above, this is quite messy. Notice also
+ // that whitespace is lost.
+
+#if defined (ACE_HAS_STRING_CLASS) && defined (ACE_HAS_STANDARD_CPP_LIBRARY)
+ ACE_IOStream_String buf;
+ ACE_DEBUG ((LM_DEBUG,
+ " (%P|%t) Server Received: ("));
+
+ while (client_handler &&
+ (buf.length () == 0 || buf[buf.length () - 1] != '"'))
+ {
+ if (! (client_handler >> buf))
+ break;
+
+ if (buf.length () > 0)
+ ACE_DEBUG ((LM_DEBUG,
+ "%s ",
+ buf.c_str ()));
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ")\n"));
+#else
+ char buf[BUFSIZ];
+ ACE_OS::memset (buf, 0, sizeof buf);
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT (" (%P|%t) Server Received: (")));
+
+ while (ACE_OS::strlen (buf) == 0
+ || buf[ACE_OS::strlen (buf) - 1] != '"')
+ {
+ if (! (client_handler >> buf))
+ break;
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%s "),
+ ACE_TEXT_CHAR_TO_TCHAR (buf)));
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT (")\n")));
+#endif /* ACE_HAS_STRING_CLASS */
+
+ // Send some non-textual data to the client. We use a single
+ // character to separate the fields but we could have used any valid
+ // whitespace. The data will be sent if the iostream's buffer gets
+ // filled or when we flush it with an explicit client.sync ()
+ // command or the implicit <<endl.
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT (" (%P|%t) Server sleeping\n")));
+ ACE_OS::sleep (5);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT (" (%P|%t) Server Sending: 1 .12342134 666555444 23.45 -46.5e9 \n")));
+ client_handler << 1 << " ";
+ client_handler << .12342134 << " ";
+ client_handler << 666555444 << " ";
+ client_handler << 23.45 << " ";
+ client_handler << -46.5e9 << " ";
+ client_handler << endl;
+
+ // The client will have changed the sign of each data field and sent
+ // 'em all back to us. At the same time, the client used the
+ // precision () function to change the significant digits for
+ // non-integer values.
+ int i;
+ float f1, f2;
+ long l;
+ double d;
+ client_handler >> i >> f1 >> l >> f2 >> d;
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT (" (%P|%t) Server Received: int %d float %f long %d float %f double %f\n"),
+ i,
+ f1,
+ (int) l,
+ f2,
+ d));
+
+ // check for proper received values
+ ACE_ASSERT (i == -1 && (f1 >= -0.13 && f1 <= -0.11)
+ && l == -666555444 && (f2 >= -24.0 && f2 <= -22.0)
+ && (d >= 45e+9 && d <= 47e+9));
+
+ client_handler.close ();
+
+ return 0;
+}
+
+static int
+spawn (void)
+{
+ // Acceptor;
+ ACE_SOCK_Acceptor acceptor;
+
+ if (acceptor.open (ACE_sap_any_cast (const ACE_INET_Addr &)) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT (" (%P|%t) %p\n"),
+ ACE_TEXT ("open")),
+ -1);
+#if defined (ACE_HAS_THREADS)
+ else if (ACE_Thread_Manager::instance ()->spawn (ACE_THR_FUNC (server),
+ &acceptor,
+ THR_NEW_LWP | THR_DETACHED) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("spawning server thread")),
+ -1);
+
+ // Wait for the client and server thread to exit.
+ ACE_Thread_Manager::instance ()->wait ();
+
+#elif !defined (ACE_LACKS_FORK)
+
+ switch (ACE_OS::fork ("child"))
+ {
+ case -1:
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("%p\n%a"),
+ ACE_TEXT ("fork failed")));
+ ACE_OS::_exit (-1);
+ case 0: // In child
+ {
+ ACE_APPEND_LOG ("IOStream_Test-children");
+ ACE_INET_Addr server_addr;
+
+ if (acceptor.get_local_addr (server_addr) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("get_local_addr")));
+ else
+ client ((void *) &server_addr);
+ ACE_END_LOG;
+ break;
+ }
+ default: // In parent
+ server (&acceptor);
+
+ // Allow the client to exit, then remove the Process_Mutex.
+ ACE_OS::wait ();
+ break;
+ }
+#else
+ ACE_ERROR_RETURN ((LM_INFO,
+ ACE_TEXT ("threads *and* processes not supported on this platform\n")),
+ -1);
+#endif /* ACE_HAS_THREADS */
+
+ acceptor.close ();
+
+ return 0;
+}
+#endif /* !ACE_LACKS_ACE_IOSTREAM */
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("IOStream_Test"));
+
+#if !defined (ACE_LACKS_ACE_IOSTREAM)
+ ACE_INIT_LOG (ACE_TEXT ("IOStream_Test-children"));
+ spawn ();
+#else
+ ACE_ERROR ((LM_INFO,
+ ACE_TEXT ("ACE_IOSTREAM not supported on this platform\n")));
+#endif /* !ACE_LACKS_ACE_IOSTREAM */
+ ACE_END_TEST;
+ return 0;
+}
+
diff --git a/ACE/tests/Lazy_Map_Manager_Test.cpp b/ACE/tests/Lazy_Map_Manager_Test.cpp
new file mode 100644
index 00000000000..d7434bbada0
--- /dev/null
+++ b/ACE/tests/Lazy_Map_Manager_Test.cpp
@@ -0,0 +1,335 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Lazy_Map_Manager_Test.cpp
+//
+// = DESCRIPTION
+// This is a simple test of the <ACE_Map_Manager> and
+// <ACE_Active_Map_Manager> that illustrates how lazy map managers
+// allow the deletion of entries while iterating over the map.
+//
+// = AUTHOR
+// Irfan Pyarali <irfan@cs.wustl.edu>,
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/Map_Manager.h"
+#include "ace/Active_Map_Manager.h"
+
+ACE_RCSID(tests, Map_Manager_Test, "$Id$")
+
+// Simple map manager.
+typedef ACE_Map_Manager<int, int, ACE_Null_Mutex> LAZY_MAP;
+
+// Displaying the contents of a map manager.
+
+void
+display_map (LAZY_MAP &map)
+{
+ {
+ // Simple iteration printing the entries.
+ for (LAZY_MAP::iterator iter = map.begin ();
+ iter != map.end ();
+ ++iter)
+ {
+ LAZY_MAP::ENTRY &entry = *iter;
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%d "),
+ entry.int_id_));
+ }
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\n")));
+ }
+
+ {
+ // Simple reverse iteration printing the entries.
+ for (LAZY_MAP::reverse_iterator iter = map.rbegin ();
+ iter != map.rend ();
+ ++iter)
+ {
+ LAZY_MAP::ENTRY &entry = *iter;
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%d "),
+ entry.int_id_));
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\n")));
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\n")));
+}
+
+// Test for map manager.
+
+void
+map_test (void)
+{
+ // Map of size 3.
+ LAZY_MAP map (3);
+ int i = 0;
+
+ // Insert a few entries.
+ for (i = 0; i < 3; ++i)
+ map.bind (i, i);
+
+ display_map (map);
+
+ // Remove middle one.
+ map.unbind (1);
+
+ display_map (map);
+
+ // Remove the entry on one end.
+ map.unbind (0);
+
+ display_map (map);
+
+ // Remove the entry on the other end.
+ map.unbind (2);
+
+ display_map (map);
+
+ // If we have lazy map managers, we can delete entries while
+ // iterating over the map.
+
+#if defined (ACE_HAS_LAZY_MAP_MANAGER)
+
+ // Insert a few entries.
+ for (i = 0; i < 3; ++i)
+ map.bind (i, i);
+
+ display_map (map);
+
+ // Remove middle one.
+ {
+ // Deletion while iterating.
+ for (LAZY_MAP::iterator iter = map.begin ();
+ iter != map.end ();
+ ++iter)
+ {
+ LAZY_MAP::ENTRY &entry = *iter;
+ if (entry.int_id_ == 1)
+ map.unbind (1);
+ }
+
+ display_map (map);
+ }
+
+ // Remove the entry on one end.
+ {
+ // Deletion while iterating.
+ for (LAZY_MAP::iterator iter = map.begin ();
+ iter != map.end ();
+ ++iter)
+ {
+ LAZY_MAP::ENTRY &entry = *iter;
+ if (entry.int_id_ == 0)
+ map.unbind (0);
+ }
+
+ display_map (map);
+ }
+
+ // Remove the entry on the other end.
+ {
+ // Deletion while iterating.
+ for (LAZY_MAP::iterator iter = map.begin ();
+ iter != map.end ();
+ ++iter)
+ {
+ LAZY_MAP::ENTRY &entry = *iter;
+ if (entry.int_id_ == 2)
+ map.unbind (2);
+ }
+
+ display_map (map);
+ }
+
+#endif /* ACE_HAS_LAZY_MAP_MANAGER */
+
+ // Insert a few entries. This will force an increase in map size.
+ for (i = 0; i < 4; ++i)
+ map.bind (i, i);
+
+ display_map (map);
+
+ // Remove a few entries (in reverse order).
+ for (i = 3; i >= 0; --i)
+ map.unbind (i);
+
+ display_map (map);
+}
+
+// Simple active map manager.
+typedef ACE_Active_Map_Manager<int> ACTIVE_MAP;
+
+// Displaying the contents of an active map manager.
+
+void
+display_map (ACTIVE_MAP &map)
+{
+ {
+ // Simple iteration printing the entries.
+ for (ACTIVE_MAP::iterator iter = map.begin ();
+ iter != map.end ();
+ ++iter)
+ {
+ ACTIVE_MAP::ENTRY &entry = *iter;
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%d "),
+ entry.int_id_));
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\n")));
+ }
+
+ {
+ // Simple reverse iteration printing the entries.
+ for (ACTIVE_MAP::reverse_iterator iter = map.rbegin ();
+ iter != map.rend ();
+ ++iter)
+ {
+ ACTIVE_MAP::ENTRY &entry = *iter;
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%d "),
+ entry.int_id_));
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\n")));
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\n")));
+}
+
+// Test for active map manager.
+
+void
+active_map_test (void)
+{
+ // Map of size 3.
+ ACTIVE_MAP map (3);
+ ACE_Active_Map_Manager_Key keys[4];
+ int i = 0;
+
+ // Insert a few entries.
+ for (i = 0; i < 3; ++i)
+ map.bind (i, keys[i]);
+
+ display_map (map);
+
+ // Remove middle one.
+ map.unbind (keys[1]);
+
+ display_map (map);
+
+ // Remove the entry on one end.
+ map.unbind (keys[0]);
+
+ display_map (map);
+
+ // Remove the entry on the other end.
+ map.unbind (keys[2]);
+
+ display_map (map);
+
+ // If we have lazy map managers, we can delete entries while
+ // iterating over the map.
+
+#if defined (ACE_HAS_LAZY_MAP_MANAGER)
+
+ // Insert a few entries.
+ for (i = 0; i < 3; ++i)
+ map.bind (i, keys[i]);
+
+ display_map (map);
+
+ // Remove middle one.
+ {
+ // Deletion while iterating.
+ for (ACTIVE_MAP::iterator iter = map.begin ();
+ iter != map.end ();
+ ++iter)
+ {
+ ACTIVE_MAP::ENTRY &entry = *iter;
+ if (entry.int_id_ == 1)
+ map.unbind (keys[1]);
+ }
+
+ display_map (map);
+ }
+
+ // Remove the entry on one end.
+ {
+ // Deletion while iterating.
+ for (ACTIVE_MAP::iterator iter = map.begin ();
+ iter != map.end ();
+ ++iter)
+ {
+ ACTIVE_MAP::ENTRY &entry = *iter;
+ if (entry.int_id_ == 0)
+ map.unbind (keys[0]);
+ }
+
+ display_map (map);
+ }
+
+ // Remove the entry on the other end.
+ {
+ // Deletion while iterating.
+ for (ACTIVE_MAP::iterator iter = map.begin ();
+ iter != map.end ();
+ ++iter)
+ {
+ ACTIVE_MAP::ENTRY &entry = *iter;
+ if (entry.int_id_ == 2)
+ map.unbind (keys[2]);
+ }
+
+ display_map (map);
+ }
+
+#endif /* ACE_HAS_LAZY_MAP_MANAGER */
+
+ // Insert a few entries. This will force an increase in map size.
+ for (i = 0; i < 4; ++i)
+ map.bind (i, keys[i]);
+
+ display_map (map);
+
+ // Remove a few entries (in reverse order).
+ for (i = 3; i >= 0; --i)
+ map.unbind (keys[i]);
+
+ display_map (map);
+}
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("Lazy_Map_Manager_Test"));
+ ACE_LOG_MSG->clr_flags (ACE_Log_Msg::VERBOSE_LITE);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\nMap Manager...\n\n")));
+ map_test ();
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\nActive Map Manager...\n\n")));
+ active_map_test ();
+
+ ACE_LOG_MSG->set_flags (ACE_Log_Msg::VERBOSE_LITE);
+ ACE_END_TEST;
+ return 0;
+}
+
diff --git a/ACE/tests/Log_Msg_Test.cpp b/ACE/tests/Log_Msg_Test.cpp
new file mode 100644
index 00000000000..4436a90b26c
--- /dev/null
+++ b/ACE/tests/Log_Msg_Test.cpp
@@ -0,0 +1,607 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Log_Msg_Test.cpp
+//
+// = DESCRIPTION
+// This program tests the <ACE_Log_Msg> class in various ways and
+// also illustrates many of the features of the <ACE_Log_Msg> For
+// instance, this program tests the <ACE_Log_Msg> abstraction wrt
+// writing to stderr and to a file. It also tests writing to user
+// defined callback objects.
+//
+// = AUTHOR
+// Douglas C. Schmidt <schmidt@cs.wustl.edu>
+//
+// ============================================================================
+
+#include "test_config.h"
+
+// FUZZ: disable check_for_streams_include
+#include "ace/streams.h"
+
+#include "ace/FILE_Connector.h"
+#include "ace/Auto_Ptr.h"
+#include "ace/Log_Msg_Callback.h"
+#include "ace/Log_Record.h"
+#include "ace/OS_NS_fcntl.h"
+#include "ace/OS_NS_string.h"
+#include "ace/OS_NS_unistd.h"
+#include "ace/OS_Memory.h"
+
+ACE_RCSID(tests, Log_Msg_Test, "$Id$")
+
+static void
+cleanup (void)
+{
+ ACE_DEBUG ((LM_INFO,
+ ACE_TEXT ("cleanup hook (%P)!\n")));
+}
+
+static void
+cause_error (void)
+{
+ errno = EWOULDBLOCK;
+ ACE_ERROR ((LM_DEBUG,
+ ACE_TEXT ("would block\n")));
+}
+
+class Logger : public ACE_Log_Msg_Callback
+{
+public:
+ Logger (int be_recursive = 1);
+ // Constructor sets whether we're testing "recursive" callback
+ // logging!
+
+ void log (ACE_Log_Record &log_record);
+ // Logging callback
+
+ void verbose (int be_verbose);
+
+private:
+ int verbose_logging_;
+ // Flag for testing verbose logging.
+
+ int recursive_;
+ // Flag for testing recursive callback logging.
+};
+
+void
+Logger::verbose (int be_verbose)
+{
+ this->verbose_logging_ = be_verbose;
+}
+
+Logger::Logger (int be_recursive)
+ : recursive_ (be_recursive)
+{
+}
+
+void
+Logger::log (ACE_Log_Record &log_record)
+{
+ int use_log_msg = 0;
+ if (this->recursive_)
+ {
+ this->recursive_ = 0;
+ use_log_msg = 1;
+ }
+
+ if (!this->verbose_logging_)
+ {
+ if (use_log_msg)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Logger::log->%s\n"),
+ log_record.msg_data ()));
+#if !defined (ACE_LACKS_IOSTREAM_TOTALLY)
+ else
+ *ace_file_stream::instance ()->output_file ()
+ << "Recursive Logger callback = "
+ << log_record.msg_data ()
+ << endl;
+#endif /* ACE_LACKS_IOSTREAM_TOTALLY */
+ }
+ else
+ {
+ ACE_TCHAR verbose_msg[ACE_Log_Record::MAXVERBOSELOGMSGLEN];
+ int result = log_record.format_msg (ACE_LOG_MSG->local_host (),
+ ACE_LOG_MSG->flags (),
+ verbose_msg);
+ if (result == 0)
+ {
+ if (use_log_msg)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Logger::log->%s\n"),
+ verbose_msg));
+#if !defined (ACE_LACKS_IOSTREAM_TOTALLY)
+ else
+ *ace_file_stream::instance ()->output_file ()
+ << "Recursive Logger callback = "
+ << log_record.msg_data ()
+ << endl;
+#endif /* ACE_LACKS_IOSTREAM_TOTALLY */
+ }
+ }
+
+ // Cleanup on the way out.
+ if (use_log_msg)
+ this->recursive_ = 1;
+}
+
+static void
+test_callbacks (void)
+{
+ // This message should show up in stderr.
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) first message\n")));
+
+ ACE_LOG_MSG->clr_flags (ACE_Log_Msg::OSTREAM);
+
+ // This message should not show up anywhere.
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) second message\n")));
+
+ ACE_LOG_MSG->set_flags (ACE_Log_Msg::MSG_CALLBACK);
+
+ // This message should not show up anywhere since no callback object
+ // has been specified.
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) third message\n")));
+
+ // Create a callback object and make it "verbose".
+ Logger logger;
+ logger.verbose (1);
+
+ // Set the callback object.
+ ACE_LOG_MSG->msg_callback (&logger);
+
+ // This message should show up via the Logger callback.
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) forth message\n")));
+
+ ACE_LOG_MSG->set_flags (ACE_Log_Msg::VERBOSE_LITE);
+
+ // This message should show up via the Logger callback (somewhat
+ // verbosely).
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) fifth message\n")));
+
+ ACE_LOG_MSG->set_flags (ACE_Log_Msg::VERBOSE);
+
+ // This message should show up via the Logger callback (really
+ // verbosely).
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) sixth message\n")));
+
+ logger.verbose (0);
+
+ // This message should show up via the Logger callback (not
+ // verbosely).
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) seventh message\n")));
+
+ ACE_LOG_MSG->set_flags (ACE_Log_Msg::OSTREAM);
+
+ // This message should show up in stderr and the Logger callback.
+ // The one from the Logger callback will not be verbose, but the one
+ // from stderr should be verbose.
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) eighth message\n")));
+ ACE_LOG_MSG->msg_callback (0);
+}
+
+static void
+test_log_msg_features (const ACE_TCHAR *program)
+{
+ // Note that the default behavior is to log to STDERR...
+
+ int counter = 1 ;
+
+ if (ACE_LOG_MSG->open (program) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("cannot open logger!!!\n")));
+
+ cause_error ();
+
+ // Check to see what happened.
+ if (ACE_LOG_MSG->op_status () == -1
+ && ACE_LOG_MSG->errnum () == EWOULDBLOCK)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("op_status and errnum work!\n")));
+ else
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("op_status and errnum failed!\n")));
+
+ const char *badname = "badname";
+
+ // We use the DEBUG messages instead of error messages. This is to
+ // help the scripts. If we print out error messages the scripts
+ // start catching them as errors.
+ if (ACE_OS::open (badname,
+ O_RDONLY) == ACE_INVALID_HANDLE)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%n: (%x), can't open %C%r\n"),
+ 10000,
+ badname,
+ cleanup));
+
+// Don't try this on VxWorks, it will result in an overflow and end the test.
+// Platforms that don't define ACE_HAS_SNPRINTF are candidates to fail here.
+// This then proves that logging to big messages is problematic but on VxWorks
+// we know this and we want to rest of the test to continue
+#if !defined (VXWORKS)
+ // Try a log operation that would overflow the logging buffer if not
+ // properly guarded.
+ ACE_TCHAR big[ACE_Log_Record::MAXLOGMSGLEN + 1];
+ size_t i = 0;
+ static const ACE_TCHAR alphabet[] = ACE_TEXT ("abcdefghijklmnopqrstuvwxyz");
+ size_t j = ACE_OS::strlen (alphabet);
+ while (i < ACE_Log_Record::MAXLOGMSGLEN)
+ {
+ size_t const index = i++;
+ big[index] = alphabet[i % j];
+ }
+ ACE_DEBUG ((LM_INFO, ACE_TEXT ("This is too big: %s\n"), big));
+#endif /* !VXWORKS */
+
+ // Exercise many different combinations of OSTREAM.
+
+ double f = 3.1416 * counter++;
+ int n = 10000;
+
+ ACE_DEBUG ((LM_INFO,
+ ACE_TEXT ("%10f, %*s%s = %d\n"),
+ f,
+ 8,
+ ACE_TEXT (""),
+ ACE_TEXT ("hello"),
+ n));
+
+ ACE_LOG_MSG->set_flags (ACE_Log_Msg::OSTREAM);
+ ACE_LOG_MSG->msg_ostream (ace_file_stream::instance ()->output_file ());
+
+ f = 3.1416 * counter;
+ n = 10000 * counter++;
+
+ ACE_DEBUG ((LM_INFO,
+ ACE_TEXT ("%10f, %*s%s = %d\n"),
+ f,
+ 8,
+ ACE_TEXT (""),
+ ACE_TEXT ("world"),
+ n));
+
+ ACE_LOG_MSG->clr_flags (ACE_Log_Msg::OSTREAM);
+
+ // The next two messages shouldn't print.
+
+ f = 3.1416 * counter;
+ n = 10000 * counter++;
+
+ ACE_DEBUG ((LM_INFO,
+ ACE_TEXT ("%10f, %*s%s = %d\n"),
+ f,
+ 8,
+ ACE_TEXT (""),
+ ACE_TEXT ("world"),
+ n));
+
+ f = 3.1416 * counter;
+ n = 10000 * counter++;
+
+ ACE_DEBUG ((LM_INFO,
+ ACE_TEXT ("%10f, %*s%s = %d\n"),
+ f,
+ 8,
+ ACE_TEXT (""),
+ ACE_TEXT ("world"),
+ n));
+
+ ACE_LOG_MSG->set_flags (ACE_Log_Msg::OSTREAM);
+
+ f = 3.1416 * counter;
+ n = 10000 * counter++;
+
+ ACE_DEBUG ((LM_INFO,
+ ACE_TEXT ("%10f, %*s%s = %d\n"),
+ f,
+ 8,
+ ACE_TEXT (""),
+ ACE_TEXT ("world"),
+ n));
+
+ static int array[] = {1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048};
+
+ // Print out the binary bytes of the array in hex form.
+ ACE_LOG_MSG->log_hexdump (LM_DEBUG,
+ (char *) array,
+ sizeof array);
+
+ // Disable the LM_DEBUG and LM_INFO messages.
+ u_long priority_mask =
+ ACE_LOG_MSG->priority_mask (ACE_Log_Msg::PROCESS);
+ ACE_CLR_BITS (priority_mask,
+ LM_DEBUG | LM_INFO);
+ ACE_LOG_MSG->priority_mask (priority_mask,
+ ACE_Log_Msg::PROCESS);
+
+ ACE_DEBUG ((LM_INFO,
+ ACE_TEXT ("This LM_INFO message should not print!\n")));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("This LM_DEBUG message should not print!\n")));
+
+ ACE_SET_BITS (priority_mask,
+ LM_INFO);
+ ACE_LOG_MSG->priority_mask (priority_mask,
+ ACE_Log_Msg::PROCESS);
+
+ ACE_DEBUG ((LM_INFO,
+ ACE_TEXT ("This LM_INFO message should print!\n")));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("This LM_DEBUG message should not print!\n")));
+
+ ACE_CLR_BITS (priority_mask, LM_INFO);
+ ACE_LOG_MSG->priority_mask (priority_mask,
+ ACE_Log_Msg::PROCESS);
+
+ ACE_DEBUG ((LM_INFO,
+ ACE_TEXT ("This LM_INFO message should not print!\n")));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("This LM_DEBUG message should not print!\n")));
+}
+
+static int
+test_ostream (void)
+{
+ // This message should show up in the log file.
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("first message\n")));
+
+ ACE_LOG_MSG->clr_flags (ACE_Log_Msg::OSTREAM);
+
+ // This message should not show up anywhere.
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("second message\n")));
+
+ ACE_LOG_MSG->set_flags (ACE_Log_Msg::OSTREAM);
+
+#if !defined (ACE_LACKS_IOSTREAM_TOTALLY)
+ // Create a persistent store.
+ const ACE_TCHAR *filename = ACE_TEXT ("output");
+ ofstream myostream (ACE_TEXT_ALWAYS_CHAR (filename), ios::out | ios::trunc);
+
+ // Check for errors.
+ if (myostream.bad ())
+ return -1;
+
+ OFSTREAM *old_stream = ace_file_stream::instance ()->output_file ();
+ // Set the ostream.
+ ACE_LOG_MSG->msg_ostream (&myostream);
+
+ // This message should show up in the ostream.
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("fourth message\n")));
+ // Set the ostream back to the test's log file.
+ ACE_LOG_MSG->msg_ostream (old_stream);
+ // Now close the ostream file and check its contents.
+ myostream.close ();
+
+ ACE_FILE_Connector connector;
+ ACE_FILE_IO file;
+
+ // Open up the file.
+ if (connector.connect (file,
+ ACE_FILE_Addr (filename)) == -1)
+ {
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("connect failed for %p\n"),
+ filename),
+ 1);
+ }
+
+ // Unlink this file right away so that it is automatically removed
+ // when the process exits.Ignore error returns in case this operation
+ // is not supported.
+ ACE_OS::unlink(filename);
+
+ ACE_FILE_Info info;
+ if (file.get_info (info) == -1)
+ {
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("get_info failed on %p\n"),
+ filename),
+ -1);
+ }
+
+ // Allocate the input buffer
+ char *buffer = 0;
+ ACE_NEW_RETURN (buffer,
+ char[info.size_ + 1],
+ -1);
+ // Make sure <buffer> is released automagically.
+ ACE_Auto_Basic_Array_Ptr<char> b (buffer);
+
+ // Read the file into the buffer.
+ ssize_t size = file.recv (buffer,
+ info.size_);
+ if (size != info.size_)
+ {
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("Read %d bytes, rather than expected %d bytes\n"),
+ size,
+ info.size_),
+ -1);
+ }
+ // Make sure to NUL-terminate this turkey!
+ buffer[size] = '\0';
+
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%C"),
+ buffer));
+
+#endif /* ACE_LACKS_IOSTREAM_TOTALLY */
+
+ // This message should show up in stderr and the ostream (without
+ // ACE_LACKS_IOSTREAM_TOTALLY).
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("fifth message\n")));
+
+ return 0;
+}
+
+
+// For testing the format specifiers, a class is defined as a callback
+// mechanism. It will get the formatted messages and check them for
+// correctness. The test_format_specs() function will set the first
+// few characters to say which test is being run, and the Log_Spec_Verify
+// class will use that to decide how to verify the results.
+
+class Log_Spec_Verify : public ACE_Log_Msg_Callback
+{
+public:
+ Log_Spec_Verify () : fail_ (0) {};
+
+ void log (ACE_Log_Record &log_record);
+ // Logging callback
+
+ int result ();
+
+private:
+ int fail_;
+ // Count how many tests failed.
+};
+
+void
+Log_Spec_Verify::log (ACE_Log_Record &log_record)
+{
+ const ACE_TCHAR *b = log_record.msg_data ();
+ const ACE_TCHAR *expect = 0;
+
+ if (ACE_OS::strncmp (b, ACE_TEXT ("l1:"), 3) == 0)
+ {
+ expect = ACE_TEXT ("42");
+ b += 4; //3
+ }
+ else if (ACE_OS::strncmp (b, ACE_TEXT ("l2:"), 3) == 0)
+ {
+ expect = ACE_TEXT (" 42");
+ b += 3;
+ }
+ else if (ACE_OS::strncmp (b, ACE_TEXT ("l3N1:"), 4) == 0)
+ {
+ expect = ACE_TEXT ("0042,Log_Msg");
+ b += 4;
+ }
+ else
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Log_Spec_Verify, unrecognized test: %s\n"),
+ b));
+ this->fail_++;
+ }
+
+ if (b != log_record.msg_data () && ACE_OS::strcmp (b, expect) != 0)
+ {
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("Test %s failed; expected %s\n"),
+ log_record.msg_data (), expect));
+ this->fail_++;
+ }
+
+ return;
+}
+
+int
+Log_Spec_Verify::result (void)
+{
+ if (this->fail_ == 0)
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("All logging specifier tests passed.\n")));
+ else
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("%d logging specifier tests failed!\n"),
+ this->fail_));
+ return this->fail_;
+}
+
+static int
+test_format_specs (void)
+{
+#if 0
+ Log_Spec_Verify verifier;
+ ACE_Log_Msg logger;
+
+ if (logger.open (ACE_TEXT ("Log_Msg_Test"), ACE_Log_Msg::MSG_CALLBACK) != 0)
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"),
+ ACE_TEXT ("%T: test_format_specs open")),
+ 1);
+ logger.msg_callback (&verifier);
+
+ logger.linenum (42);
+ logger.file (ACE_TEXT ("Log_Msg_Test.cpp"));
+ logger.log (LM_DEBUG, ACE_TEXT ("l1:%l"));
+ logger.log (LM_DEBUG, ACE_TEXT ("l2:%5l"));
+ logger.log (LM_DEBUG, ACE_TEXT ("l3N1:%0*l,%.7N"), 4);
+ return verifier.result ();
+#else
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("l1:%l\n")));
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("l2:%5l\n")));
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("l3N1:%0*l,%.7N\n"), 4));
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("%*ISTART INDENTING %{\n"), 4));
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("%IONE%{\n")));
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("%ITWO%{\n")));
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("%ITHREE\n")));
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("%}%ITWO\n")));
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("%}%IONE\n")));
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("%}%IENDINDENTING\n")));
+ errno = ENOENT;
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("%m %p\n"), ACE_TEXT("perror")));
+ return 0;
+#endif
+}
+
+// Main function.
+
+int
+run_main (int argc, ACE_TCHAR *argv[])
+{
+ ACE_START_TEST (ACE_TEXT ("Log_Msg_Test"));
+
+ int status = 0;
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("**** running ostream test\n")));
+
+ // Test the <ACE_Log_Msg> abstraction wrt writing to stderr and to a
+ // file.
+ test_ostream ();
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%M **** running callback test\n")));
+
+ // Test the <ACE_Log_Msg> callback mechanism.
+ test_callbacks ();
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("**** running features test\n")));
+
+ // Test various features of the <ACE_Log_Msg>.
+ test_log_msg_features ((argc > 0 ? argv[0] : ACE_TEXT ("program")));
+
+ // Test the format specifiers
+
+ // Restore this mask so diags and the shutdown message will print correctly!
+ ACE_LOG_MSG->priority_mask (ACE_LOG_MSG->priority_mask () | LM_DEBUG,
+ ACE_Log_Msg::PROCESS);
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("**** running format specifiers test\n")));
+ if (test_format_specs () != 0)
+ status = 1;
+
+ ACE_END_TEST;
+ return status;
+}
+
diff --git a/ACE/tests/Logging_Strategy_Test.cpp b/ACE/tests/Logging_Strategy_Test.cpp
new file mode 100644
index 00000000000..2a53c83606f
--- /dev/null
+++ b/ACE/tests/Logging_Strategy_Test.cpp
@@ -0,0 +1,514 @@
+// $Id$
+
+//==========================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Logging_Strategy_Test.cpp
+//
+// = DESCRIPTION
+// This program tests the <ACE_Logging_Strategy> class in various
+// ways and also illustrates many of the features of the
+// <ACE_Log_Msg>. The test works as follows:
+// -Load the inserted arguments;
+// -Remove existent log_files with the file_name specified by the
+// user;
+// -Generate 1000 messages to create the DEBUG statements to be
+// stored in the files;
+// -Counts the created log_files and if it was specified a maximum
+// number of log_files, compare and verify if they are the same.
+// -Verify the order of the files with the order argument.
+//
+// When Dlls are used, we utilize the dynamic service
+// configuration mechanism to activate the logging strategy. This
+// is not a must though, and you may activate the logging strategy
+// as described in the non-DLL section below under DLL
+// environments as well.
+//
+// = AUTHOR
+// Orlando Ribeiro <oribeiro@inescporto.pt>
+//
+//==========================================================================
+
+#include "test_config.h"
+#include "ace/OS_NS_stdio.h"
+#include "ace/OS_NS_string.h"
+#include "ace/OS_NS_unistd.h"
+#include "ace/OS_NS_sys_stat.h"
+#include "ace/Auto_Ptr.h"
+#include "ace/Service_Config.h"
+#include "ace/Reactor.h"
+#include "ace/Thread_Manager.h"
+
+#if defined (ACE_AS_STATIC_LIBS) || \
+ (!defined (ACE_WIN32) && !defined (ACE_HAS_SVR4_DYNAMIC_LINKING) && \
+ !defined (__hpux))
+#include "ace/Logging_Strategy.h"
+#endif
+
+#include "ace/Auto_Ptr.cpp"
+#include "ace/Get_Opt.h"
+#include "ace/OS_NS_time.h"
+
+ACE_RCSID(tests, Logging_Strategy_Test, "$Id$")
+
+// Considering UNIX OS to be default. On Win32 platforms, the symbols
+// are got form the .exe as one cant have .exe and .dll for the same
+// .cpp. Also, on Win32 platforms one cant use the .obj to obtain
+// symbols dynamically at runtime.
+
+#if defined (ACE_WIN32)
+# define OBJ_SUFFIX ACE_TEXT (".exe")
+# define OBJ_PREFIX ACE_TEXT ("")
+#else
+# define OBJ_SUFFIX ACE_DLL_SUFFIX
+# define OBJ_PREFIX "./" ACE_DLL_PREFIX
+#endif /*ACE_WIN32*/
+
+ACE_TCHAR const *
+cdecl_decoration (ACE_TCHAR const *func_name)
+{
+#if defined (__BORLANDC__)
+ static ACE_TCHAR decorated_func_name[10*1024];
+ ACE_OS::sprintf (decorated_func_name,
+ ACE_TEXT ("_%s"),
+ func_name);
+ return decorated_func_name;
+#else
+ return func_name;
+#endif /* __BORLANDC__ */
+}
+
+// Global variables.
+static ACE_TCHAR *file_name = 0;
+static int max_size_files = 0;
+static int max_num_files = 0;
+static int interval_time = 0;
+static bool order_state = false;
+static int num_files = 0;
+static bool wipeout_logfile = false;
+
+// This adapter function runs the Reactor's event loop in a separate
+// thread of control.
+
+static void *
+run_reactor (void *)
+{
+ ACE_Reactor::instance ()->owner
+ (ACE_Thread_Manager::instance ()->thr_self ());
+ ACE_Reactor::instance ()->run_reactor_event_loop ();
+ return 0;
+}
+
+// Initiate the cycle of messages.
+
+static
+void print_till_death (void)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ "\n-> start generating messages... \n"));
+
+ for (int i = 0; i < 1000; i++)
+ {
+ if (i % 50 == 0)
+ ACE_OS::sleep (1);
+
+ if (i == 0)
+ ACE_DEBUG ((LM_DEBUG,
+ " (%t) (%D) message\n"));
+ else
+ ACE_DEBUG ((LM_DEBUG,
+ " (%t) %d message\n",
+ i));
+ }
+
+ if (ACE_Reactor::instance ()->end_reactor_event_loop () == -1)
+ ACE_ERROR ((LM_ERROR,
+ "Error ending reactor.\n"));
+
+ ACE_DEBUG ((LM_DEBUG,
+ "-< generating messages finished \n\n"));
+}
+
+// Count the generated files.
+
+static void
+count_files (void)
+{
+ int i = 0;
+ int error = 0;
+ FILE *stream;
+ ACE_TCHAR backup_ct[MAXPATHLEN+1];
+ ACE_DEBUG ((LM_DEBUG,
+ "-> start counting...\n"));
+
+ do
+ {
+ if (i == 0)
+ ACE_OS::sprintf (backup_ct,
+ ACE_TEXT ("%s"),
+ file_name);
+ else
+ ACE_OS::sprintf (backup_ct,
+ ACE_TEXT ("%s.%d"),
+ file_name,
+ i);
+
+ stream = ACE_OS::fopen (backup_ct, ACE_TEXT ("r"));
+ if (stream == 0)
+ error = 1;
+ else
+ {
+ i++;
+ ACE_OS::fclose (stream);
+ }
+
+ }
+ while (error != 1);
+
+ num_files = i;
+
+ if (max_num_files !=0)
+ {
+ if (max_num_files != num_files)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Creating files...Failed!")
+ ACE_TEXT (" Input value=%d, Checked value=%d"),
+ max_num_files,
+ num_files));
+ else
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT (" Creating files...OK!")
+ ACE_TEXT (" Input value=%d, Checked value=%d"),
+ max_num_files,
+ num_files));
+ }
+ else
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT (" The number of files generated is: %d"),
+ num_files));
+
+ ACE_DEBUG ((LM_DEBUG,
+ "\n-< counting finished... \n"));
+}
+
+// get the file statistics
+
+static time_t
+get_statistics (ACE_TCHAR *f_name)
+{
+ ACE_stat buf;
+ int result;
+
+ // Get data associated with "file_name":
+ result = ACE_OS::stat (f_name, &buf);
+
+ // Check if statistics are valid:
+ if (result != 0)
+ ACE_OS::perror (ACE_TEXT ("\nProblem getting information"));
+ else
+ {
+ // Output some of the statistics:
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT (" File name : %s\n"),
+ f_name));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT (" File size (B): %d\n"),
+ buf.st_size));
+
+#if defined (ACE_HAS_WINCE)
+ time_t tm = buf.st_mtime.sec();
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT (" Time modified : %s\n"),
+ ACE_OS::ctime (&tm)));
+#else
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT (" Time modified : %s\n"),
+ ACE_OS::ctime (&buf.st_mtime)));
+#endif // ACE_HAS_WINCE
+ }
+
+#if defined (ACE_HAS_WINCE)
+ return buf.st_mtime.sec();
+#else
+ return buf.st_mtime;
+#endif // ACE_HAS_WINCE
+}
+
+// analyse the file order
+static void
+order (void)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\n-> start testing order... \n")));
+
+ if (num_files <= 2)
+ {
+ if (num_files == 1)
+ get_statistics (file_name);
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT (" Ordering...OK! - ")
+ ACE_TEXT (" Only %d file (s) was (were) generated"),
+ num_files));
+ }
+ else
+ {
+ time_t tm_bk_1, tm_bk_2;
+ ACE_TCHAR backup_1[MAXPATHLEN+1];
+ ACE_TCHAR backup_2[MAXPATHLEN+1];
+ ACE_OS::sprintf (backup_1,
+ ACE_TEXT ("%s.%d"),
+ file_name,
+ 1);
+ ACE_OS::sprintf (backup_2,
+ ACE_TEXT ("%s.%d"),
+ file_name,
+ num_files - 1);
+
+ tm_bk_1 = get_statistics (backup_1);
+ tm_bk_2 = get_statistics (backup_2);
+
+ if (tm_bk_1 > tm_bk_2 && !order_state)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT (" %s (newest) ; %s (oldest)\n"),
+ backup_1,
+ backup_2));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT (" Ordering...OK!")));
+ }
+ else
+ {
+ if (tm_bk_1 < tm_bk_2 && order_state)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT (" %s (newest);")
+ ACE_TEXT ("%s (oldest)\n"),
+ backup_2,
+ backup_1));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT (" Ordering...OK!")));
+ }
+ else
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT (" Ordering...FAILED!")
+ ACE_TEXT ("- The files are disorderly")));
+ }
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\n-< testing order finished...\n\n")));
+}
+
+// remove log_files
+
+static void
+remove_files (void)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("-> removing existent files...\n")));
+
+ int error = 0;
+ int test;
+ int i = 0;
+ ACE_TCHAR backup[MAXPATHLEN+1];
+
+ do
+ {
+ i++;
+ ACE_OS::sprintf (backup,
+ ACE_TEXT ("%s.%d"),
+ file_name,
+ i);
+ test = ACE_OS::unlink (backup);
+ if (test != 0)
+ error = 1;
+ }
+ while (error != 1);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("-< removing existing files...\n\n")));
+}
+
+static int
+parse_args (int argc, ACE_TCHAR *argv[])
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Specifications:\n")));
+ ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("s:i:m:f:N:ow"));
+ int c;
+
+ while ((c = get_opt ()) != EOF)
+ {
+ switch (c)
+ {
+ case 's':
+ file_name = get_opt.opt_arg ();
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("File name: %s\n"),
+ file_name));
+ break;
+ case 'i':
+ interval_time = ACE_OS::atoi (get_opt.opt_arg ());
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Interval time (s): %d\n"),
+ interval_time));
+ break;
+ case 'm':
+ max_size_files = ACE_OS::atoi (get_opt.opt_arg ());
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Maximum size (KB): %d\n"),
+ max_size_files));
+ break;
+ case 'f':
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Modes: %s\n"),
+ get_opt.opt_arg ()));
+ break;
+ case 'N':
+ max_num_files = ACE_OS::atoi (get_opt.opt_arg ());
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Maximum files number: %d\n"),
+ max_num_files));
+ break;
+ case 'o':
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Ordering files activated\n")));
+ order_state = true;
+ break;
+ case 'w':
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Wipeout logfile activated\n")));
+ wipeout_logfile = true;
+ break;
+ default:
+ ACE_ERROR_RETURN
+ ((LM_ERROR,
+ ACE_TEXT ("usage: [-s]<file_name>")
+ ACE_TEXT ("[-i]<sample_interval> ")
+ ACE_TEXT ("[-m]<max_size> [-f]<msg_flags> ")
+ ACE_TEXT ("[-n]<num_files> [-o]\n")
+ ACE_TEXT ("\t-s: Specify the name of the log files.\n")
+ ACE_TEXT ("\t-i: Define the sample interval in secs.\n")
+ ACE_TEXT ("\t-m: Define the max size for the log_files in KB.\n")
+ ACE_TEXT ("\t-f: Indicates the Log_Msg flags.\n")
+ ACE_TEXT ("\t-N: Define the maximum number of log_files.\n")
+ ACE_TEXT ("\t-o: If activated puts the log_files ordered.\n"),
+ ACE_TEXT ("\t-w: If activated cause the logfile to be wiped out,")
+ ACE_TEXT (" both on startup and on reconfigure.\n")),
+ -1);
+ /* NOTREACHED */
+ break;
+ }
+ }
+
+ ACE_UNUSED_ARG (wipeout_logfile);
+ return 0;
+}
+
+int run_main (int argc, ACE_TCHAR *argv [])
+{
+ ACE_START_TEST (ACE_TEXT ("Logging_Strategy_Test"));
+
+ ACE_TCHAR *l_argv[4];
+
+ if (argc > 1)
+ {
+ if (parse_args (argc, argv) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "Invalid command-line parameters.\n"),
+ 1);
+ }
+ else
+ {
+ l_argv[0] = (ACE_TCHAR *)ACE_TEXT ("Logging_Strategy_Test");
+ l_argv[1] =
+ (ACE_TCHAR *) ACE_TEXT ("-slog/Logging_Strategy_Test")
+ ACE_LOG_FILE_EXT_NAME;
+ l_argv[2] = (ACE_TCHAR *) ACE_TEXT ("-o");
+ l_argv[3] = 0;
+
+ if (parse_args (3, l_argv) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "Invalid command-line parameters.\n"),
+ 1);
+ argv = l_argv;
+ argc = 3;
+ }
+
+ // Remove existing files.
+ remove_files ();
+
+ // This is necessary only if the provided logfile name is the same
+ // as the default name. If so, nothing will be written as the
+ // previous ofstream is closed only at the end (ACE_END_TEST)
+ ACE_CLOSE_TEST_LOG;
+
+ // When Dlls are used, we utilize the dynamic service configuration
+ // mechanism to activate the logging strategy. This is not a must
+ // though, and you may activate the logging strategy as described in
+ // the non-DLL section below under DLL environments as well.
+
+#if !defined (ACE_AS_STATIC_LIBS) && \
+ (defined (ACE_WIN32) || defined (ACE_HAS_SVR4_DYNAMIC_LINKING) || \
+ defined (__hpux))
+
+ // Platform support DLLs, and not configured to link statically
+ ACE_TCHAR arg_str[250];
+ ACE_OS::sprintf (arg_str,
+ ACE_TEXT ("dynamic Logger Service_Object ")
+ ACE_TEXT ("*ACE:_make_ACE_Logging_Strategy()")
+ ACE_TEXT ("\""));
+
+ for (int i = 1; i < argc; i++)
+ {
+ ACE_OS::strcat (arg_str, argv[i]);
+ ACE_OS::strcat (arg_str, ACE_TEXT (" "));
+ }
+
+ ACE_OS::strcat (arg_str, ACE_TEXT ("\""));
+
+ if (ACE_Service_Config::process_directive (arg_str) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "Error opening _make_ACE_Log_Strategy.\n"),
+ 1);
+#else // Platform doesn't support DLLs, or configured to link
+ // statically
+ ACE_Logging_Strategy logging_strategy;
+ char ls_argc = argc - 1;
+ ACE_Auto_Basic_Ptr<ACE_TCHAR *> ls_argv (new ACE_TCHAR *[ls_argc]);
+
+ for (char c = 0; c < ls_argc; c++)
+ (ls_argv.get ())[c] = argv[c+1];
+
+ if (logging_strategy.init (ls_argc, ls_argv.get ()) == -1)
+ ACE_ERROR_RETURN
+ ((LM_ERROR,
+ "Error initializing the ACE_Logging_Strategy.\n"),
+ 1);
+#endif /* !ACE_AS_STATIC_LIBS && (ACE_WIN32 ||
+ ACE_HAS_SVR4_DYNAMIC_LINKING || __hpux) */
+
+ // launch a new Thread
+ if (ACE_Thread_Manager::instance ()->spawn
+ (ACE_THR_FUNC (run_reactor)) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "Spawning Reactor.\n"),
+ 1);
+
+ // Function to print the message
+ print_till_death ();
+
+ // Counts the generated files
+ count_files ();
+
+ // Get the file order
+ order ();
+
+ // Wait for the thread to exit before we exit.
+ ACE_Thread_Manager::instance ()->wait ();
+ ACE_END_TEST;
+ return 0;
+}
diff --git a/ACE/tests/MEM_Stream_Test.cpp b/ACE/tests/MEM_Stream_Test.cpp
new file mode 100644
index 00000000000..d581fd46180
--- /dev/null
+++ b/ACE/tests/MEM_Stream_Test.cpp
@@ -0,0 +1,527 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// MEM_Stream_Test.cpp
+//
+// = DESCRIPTION
+// This is a test of the <ACE_MEM_Acceptor> and
+// <ACE_MEM_Connector> classes.
+//
+// = AUTHOR
+// Nanbor Wang <nanbor@cs.wustl.edu>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/OS_NS_stdio.h"
+#include "ace/OS_NS_string.h"
+#include "ace/OS_NS_unistd.h"
+#include "ace/Get_Opt.h"
+#include "ace/Thread_Manager.h"
+#include "ace/MEM_Connector.h"
+#include "ace/MEM_Acceptor.h"
+#include "ace/Select_Reactor.h"
+#include "ace/Connector.h"
+#include "ace/Acceptor.h"
+#include "ace/Svc_Handler.h"
+#include "ace/Singleton.h"
+#include "ace/Atomic_Op.h"
+
+ACE_RCSID(tests, MEM_Stream_Test, "$Id$")
+
+#if (defined (ACE_HAS_THREADS) || defined (ACE_HAS_PROCESS_SPAWN)) && \
+ (ACE_HAS_POSITION_INDEPENDENT_POINTERS == 1)
+
+#if !defined (ACE_HAS_PROCESS_SPAWN) && defined (ACE_HAS_THREADS)
+# define _TEST_USES_THREADS
+#else
+# define _TEST_USES_PROCESSES
+# include "ace/Process.h"
+# include "ace/Process_Manager.h"
+#endif /* ACE_HAS_FORK */
+
+#include "MEM_Stream_Test.h" // Defines Echo_Handler
+
+#define NUMBER_OF_REACTIVE_CONNECTIONS 3
+#if defined (ACE_WIN32) || !defined (_ACE_USE_SV_SEM)
+# define NUMBER_OF_MT_CONNECTIONS 3
+#else
+ // We will use SysV Semaphore in this case which is not very scalable
+ // and can only handle one connection.
+# define NUMBER_OF_MT_CONNECTIONS 1
+#endif /* ACE_WIN32 || !_ACE_USE_SV_SEM */
+
+#define NUMBER_OF_ITERATIONS 100
+
+// If we don't have winsock2 we can't use WFMO_Reactor.
+#if defined (ACE_WIN32) \
+ && !defined (ACE_HAS_WINCE) \
+ && defined (ACE_HAS_WINSOCK2) \
+ && ACE_HAS_WINSOCK2 != 0
+# define TEST_CAN_USE_WFMO_REACTOR
+#endif
+
+#if defined (TEST_CAN_USE_WFMO_REACTOR)
+static const int opt_wfmo_reactor = 1;
+#endif /* TEST_CAN_USE_WFMO_REACTOR */
+
+static int opt_select_reactor = 1;
+static ACE_MEM_IO::Signal_Strategy client_strategy = ACE_MEM_IO::Reactive;
+
+typedef ACE_Atomic_Op <ACE_SYNCH_MUTEX, u_short> WaitingCounter;
+typedef ACE_Singleton <WaitingCounter, ACE_SYNCH_RECURSIVE_MUTEX> Waiting;
+
+// Number of connections that are currently open
+static u_short connection_count = 0;
+
+typedef ACE_Acceptor<Echo_Handler, ACE_MEM_ACCEPTOR> ACCEPTOR;
+typedef ACE_Strategy_Acceptor<Echo_Handler, ACE_MEM_ACCEPTOR> S_ACCEPTOR;
+
+static void reset_handler (int conn)
+{
+ // Reset the number of connection the test should perform.
+ *Waiting::instance () = conn;
+ connection_count = 0;
+}
+
+int
+Echo_Handler::open (void *)
+{
+ return 0;
+}
+
+Echo_Handler::Echo_Handler (ACE_Thread_Manager *thr_mgr)
+ : ACE_Svc_Handler<ACE_MEM_STREAM, ACE_SYNCH> (thr_mgr),
+ connection_ (++connection_count)
+{
+ ACE_OS::sprintf (this->name_, ACE_TEXT ("Connection %d --> "),
+ this->connection_);
+}
+
+int
+Echo_Handler::handle_input (ACE_HANDLE)
+{
+ ACE_TCHAR buf[MAXPATHLEN];
+ ssize_t len;
+
+ len = this->peer ().recv (buf, MAXPATHLEN * sizeof (ACE_TCHAR));
+
+ if (len == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("Error receiving from MEM_Stream\n")),
+ -1);
+ else if (len == 0) // Connection closed.
+ {
+ ACE_DEBUG ((LM_INFO,
+ ACE_TEXT ("Connection %d closed\n"),
+ this->connection_));
+ return -1;
+ }
+
+ ACE_TCHAR return_buf[MAXPATHLEN];
+ ACE_OS::strcpy (return_buf, this->name_);
+ ACE_OS::strcat (return_buf, buf);
+ len = (ACE_OS::strlen (return_buf) + 1) * sizeof (ACE_TCHAR);
+
+ if (this->peer ().send (return_buf, len) != len)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("Error sending from MEM_Stream\n")),
+ -1);
+
+ return 0;
+}
+
+int
+Echo_Handler::handle_close (ACE_HANDLE,
+ ACE_Reactor_Mask mask)
+{
+ // Reduce count.
+ (*Waiting::instance ())--;
+
+ if (client_strategy != ACE_MEM_IO::Reactive)
+ this->reactor ()->remove_handler (this,
+ mask | ACE_Event_Handler::DONT_CALL);
+
+ // If no connections are open.
+ if (*Waiting::instance () == 0)
+ ACE_Reactor::instance ()->end_reactor_event_loop ();
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Echo_Handler %d::handle_close closing down\n"),
+ this->connection_));
+
+ // Shutdown
+ this->destroy ();
+ return 0;
+}
+
+int
+Echo_Handler::svc (void)
+{
+ while (this->handle_input (this->get_handle ()) >= 0)
+ continue;
+ return 0;
+}
+
+static int
+run_client (u_short port,
+ ACE_MEM_IO::Signal_Strategy strategy)
+{
+ int status = 0;
+ ACE_MEM_Addr to_server (port);
+ ACE_MEM_Connector connector;
+ connector.preferred_strategy (strategy);
+ ACE_MEM_Stream stream;
+
+ // connector.preferred_strategy (ACE_MEM_IO::MT);
+
+ if (connector.connect (stream, to_server.get_remote_addr ()) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"), ACE_TEXT ("connector.connect()")),
+ -1);
+
+ ACE_TCHAR buf[MAXPATHLEN];
+
+ for (ssize_t cntr = 0; cntr < NUMBER_OF_ITERATIONS; cntr ++)
+ {
+ ACE_OS::sprintf (buf, ACE_TEXT ("Iteration ")ACE_SSIZE_T_FORMAT_SPECIFIER,
+ cntr);
+
+ ssize_t slen = (ACE_OS::strlen (buf) + 1) * sizeof (ACE_TCHAR);
+
+ if (stream.send (buf, slen) < slen)
+ {
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"),
+ ACE_TEXT ("In stream.send()")));
+ status = -1;
+ break;
+ }
+
+ if (stream.recv (buf, MAXPATHLEN) == -1)
+ {
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"),
+ ACE_TEXT ("stream.recv()")));
+ status = -1;
+ break;
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("run_client(), got echo %s\n"),
+ buf));
+ }
+
+ status = stream.close () == -1 ? -1 : status;
+ return status;
+}
+
+#if defined (_TEST_USES_THREADS)
+static ACE_THR_FUNC_RETURN
+connect_client (void *arg)
+{
+ u_short *sport = reinterpret_cast <u_short *> (arg);
+ run_client (*sport, client_strategy);
+ return 0;
+}
+#endif
+
+static void
+create_reactor (void)
+{
+ ACE_Reactor_Impl *impl = 0;
+
+#if defined (TEST_CAN_USE_WFMO_REACTOR)
+ if (opt_wfmo_reactor)
+ ACE_NEW (impl,
+ ACE_WFMO_Reactor);
+#endif /* TEST_CAN_USE_WFMO_REACTOR */
+
+ if (impl == 0 && opt_select_reactor)
+ ACE_NEW (impl,
+ ACE_Select_Reactor);
+
+ ACE_Reactor *reactor = 0;
+ ACE_NEW (reactor,
+ ACE_Reactor (impl));
+ ACE_Reactor::instance (reactor);
+}
+
+static int
+test_reactive (const ACE_TCHAR *prog,
+ ACE_MEM_Addr &server_addr)
+{
+ ACE_DEBUG ((LM_DEBUG, "Testing Reactive MEM_Stream\n\n"));
+
+ int status = 0;
+
+ client_strategy = ACE_MEM_IO::Reactive; // Echo_Handler uses this.
+
+ ACE_Accept_Strategy<Echo_Handler, ACE_MEM_ACCEPTOR> accept_strategy;
+ ACE_Creation_Strategy<Echo_Handler> create_strategy;
+ ACE_Reactive_Strategy<Echo_Handler> reactive_strategy (ACE_Reactor::instance ());
+ S_ACCEPTOR acceptor;
+ if (acceptor.open (server_addr,
+ ACE_Reactor::instance (),
+ &create_strategy,
+ &accept_strategy,
+ &reactive_strategy) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("MEM_Acceptor::accept\n")), 1);
+ acceptor.acceptor ().mmap_prefix (ACE_TEXT ("MEM_Acceptor_"));
+
+ ACE_MEM_Addr local_addr;
+ if (acceptor.acceptor ().get_local_addr (local_addr) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("MEM_Acceptor::get_local_addr\n")),
+ 1);
+
+ u_short sport = local_addr.get_port_number ();
+
+#if defined (_TEST_USES_THREADS)
+ if (ACE_Thread_Manager::instance ()->spawn_n (NUMBER_OF_REACTIVE_CONNECTIONS,
+ connect_client,
+ &sport) == -1)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("spawn_n ()")));
+#else
+ ACE_Process_Options opts;
+# if defined (ACE_WIN32) || !defined (ACE_USES_WCHAR)
+ const ACE_TCHAR *cmdline_fmt = ACE_TEXT ("%s -p%d -r");
+# else
+ const ACE_TCHAR *cmdline_fmt = ACE_TEXT ("%ls -p%d -r");
+# endif /* ACE_WIN32 || !ACE_USES_WCHAR */
+ opts.command_line (cmdline_fmt, prog, sport);
+ if (ACE_Process_Manager::instance ()->spawn_n (NUMBER_OF_REACTIVE_CONNECTIONS,
+ opts) == -1)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("spawn_n ()")));
+#endif /* _TEST_USES_THREADS */
+
+ ACE_Time_Value tv (60, 0);
+ ACE_Reactor::instance ()->run_reactor_event_loop (tv);
+
+ if (tv == ACE_Time_Value::zero)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Reactor::run_event_loop timeout\n")));
+ status = 1;
+ }
+ else
+ ACE_DEBUG ((LM_DEBUG, "Reactor::run_event_loop finished\n"));
+
+#if defined (_TEST_USES_THREADS)
+ if (ACE_Thread_Manager::instance ()->wait () == -1)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("wait ()")));
+#else
+ if (ACE_Process_Manager::instance ()->wait () == -1)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("wait ()")));
+#endif /* _TEST_USES_THREADS */
+
+ if (acceptor.close () == -1)
+ {
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"),
+ ACE_TEXT ("MEM_Acceptor::close\n")));
+ status = 1;
+ }
+
+ ACE_UNUSED_ARG (prog);
+ return status;
+}
+
+static int
+test_concurrent (const ACE_TCHAR *prog,
+ ACE_MEM_Addr &server_addr)
+{
+ ACE_DEBUG ((LM_DEBUG, "Testing Multithreaded MEM_Stream\n\n"));
+
+ int status = 0;
+ client_strategy = ACE_MEM_IO::MT; // Echo_Handler uses this.
+
+ ACE_Accept_Strategy<Echo_Handler, ACE_MEM_ACCEPTOR> accept_strategy;
+ ACE_Creation_Strategy<Echo_Handler> create_strategy;
+#if defined (ACE_HAS_THREADS)
+ ACE_Thread_Strategy<Echo_Handler> act_strategy;
+#else
+ ACE_Reactive_Strategy<Echo_Handler> act_strategy (ACE_Reactor::instance ());
+#endif /* ACE_HAS_THREADS */
+ S_ACCEPTOR acceptor;
+
+ if (acceptor.open (server_addr,
+ ACE_Reactor::instance (),
+ &create_strategy,
+ &accept_strategy,
+ &act_strategy) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("MEM_Acceptor::accept\n")), 1);
+
+ // Make sure the MEM_Stream created by the underlying MEM_Acceptor
+ // is capable of passing messages of 1MB.
+ acceptor.acceptor ().init_buffer_size (1024 * 1024);
+ acceptor.acceptor ().mmap_prefix (ACE_TEXT ("MEM_Acceptor_"));
+ acceptor.acceptor ().preferred_strategy (ACE_MEM_IO::MT);
+
+ ACE_MEM_Addr local_addr;
+ if (acceptor.acceptor ().get_local_addr (local_addr) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("MEM_Acceptor::get_local_addr\n")),
+ 1);
+
+ u_short sport = local_addr.get_port_number ();
+
+#if defined (_TEST_USES_THREADS)
+ ACE_UNUSED_ARG (prog);
+
+ if (ACE_Thread_Manager::instance ()->spawn_n (NUMBER_OF_MT_CONNECTIONS,
+ connect_client,
+ &sport) == -1)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("spawn_n()")));
+#else
+ ACE_Process_Options opts;
+# if defined (ACE_WIN32) || !defined (ACE_USES_WCHAR)
+ const ACE_TCHAR *cmdline_fmt = ACE_TEXT ("%s -p%d -m");
+# else
+ const ACE_TCHAR *cmdline_fmt = ACE_TEXT ("%ls -p%d -m");
+# endif /* ACE_WIN32 || !ACE_USES_WCHAR */
+ opts.command_line (cmdline_fmt, prog, sport);
+ if (ACE_Process_Manager::instance ()->spawn_n (NUMBER_OF_MT_CONNECTIONS,
+ opts) == -1)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("spawn_n()")));
+#endif /* _TEST_USES_THREADS */
+
+ ACE_Time_Value tv (60, 0);
+ ACE_Reactor::instance ()->run_reactor_event_loop (tv);
+
+ if (tv == ACE_Time_Value::zero)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Reactor::run_event_loop timeout\n")));
+ status = 1;
+ }
+ else
+ ACE_DEBUG ((LM_DEBUG, "Reactor::run_event_loop finished\n"));
+
+#if defined (_TEST_USES_THREADS)
+ if (ACE_Thread_Manager::instance ()->wait () == -1)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("wait ()")));
+#else
+ if (ACE_Process_Manager::instance ()->wait () == -1)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("wait ()")));
+#endif /* _TEST_USES_THREADS */
+
+ if (acceptor.close () == -1)
+ {
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"),
+ ACE_TEXT ("MEM_Acceptor::close")));
+ status = 1;
+ }
+
+ return status;
+}
+
+int
+run_main (int argc, ACE_TCHAR *argv[])
+{
+ u_short port = 0;
+
+ if (argc == 1)
+ {
+ // This is the "master" process.
+
+ ACE_START_TEST (ACE_TEXT ("MEM_Stream_Test"));
+ create_reactor ();
+ ACE_MEM_Addr server_addr (port);
+
+ reset_handler (NUMBER_OF_REACTIVE_CONNECTIONS);
+
+#if defined (ACE_HAS_WINCE)
+ test_reactive (ACE_TEXT("\\Windows\\Start Menu\\MEM_Stream_Test_WinCE.exe"), server_addr);
+#else
+ test_reactive (ACE_TEXT ("MEM_Stream_Test"), server_addr);
+#endif // ACE_HAS_WINCE
+
+ ACE_Reactor::instance ()->reset_reactor_event_loop ();
+
+#if !defined (ACE_WIN32) && defined (_ACE_USE_SV_SEM)
+ ACE_ERROR ((LM_DEBUG,
+ ACE_TEXT ("\n *** Platform only supports non-scalable SysV semaphores ***\n\n")));
+#endif /* !ACE_WIN32 && _ACE_USE_SV_SEM */
+ reset_handler (NUMBER_OF_MT_CONNECTIONS);
+
+#if defined (ACE_HAS_WINCE)
+ test_concurrent (ACE_TEXT("\\Windows\\Start Menu\\MEM_Stream_Test_WinCE.exe"), server_addr);
+#else
+ test_concurrent (ACE_TEXT ("MEM_Stream_Test"), server_addr);
+#endif // ACE_HAS_WINCE
+
+ ACE_END_TEST;
+ return 0;
+ }
+ else
+ {
+ // We end up here if this is a child process spawned for one of
+ // the test passes. command line is: -p <port> -r (reactive) |
+ // -m (multithreaded)
+
+ ACE_TCHAR lognm[MAXPATHLEN];
+ int mypid (ACE_OS::getpid ());
+ ACE_OS::sprintf(lognm, ACE_TEXT ("MEM_Stream_Test-%d"), mypid);
+ ACE_START_TEST (lognm);
+
+ ACE_Get_Opt opts (argc, argv, ACE_TEXT ("p:rm"));
+ int opt, iport, status;
+ ACE_MEM_IO::Signal_Strategy model = ACE_MEM_IO::Reactive;
+
+ while ((opt = opts()) != -1)
+ {
+ switch (opt)
+ {
+ case 'p':
+ iport = ACE_OS::atoi (opts.opt_arg ());
+ port = static_cast <u_short> (iport);
+ break;
+
+ case 'r':
+ model = ACE_MEM_IO::Reactive;
+ break;
+
+ case 'm':
+ model = ACE_MEM_IO::MT;
+ break;
+
+ default:
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("Invalid option (-p <port> -r | -m)\n")),
+ 1);
+ }
+ }
+ status = run_client (port, model);
+ ACE_END_TEST;
+ return status;
+ }
+}
+
+#if defined (ACE_HAS_EXPLICIT_STATIC_TEMPLATE_MEMBER_INSTANTIATION)
+
+template ACE_Singleton<ACE_Atomic_Op<ACE_SYNCH_MUTEX, u_short>,
+ ACE_SYNCH_RECURSIVE_MUTEX> *
+ ACE_Singleton<ACE_Atomic_Op<ACE_SYNCH_MUTEX, u_short>,
+ ACE_SYNCH_RECURSIVE_MUTEX>::singleton_;
+
+#endif /* ACE_HAS_EXPLICIT_STATIC_TEMPLATE_MEMBER_INSTANTIATION */
+
+#else
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("MEM_Stream_Test"));
+
+ ACE_ERROR ((LM_INFO,
+ ACE_TEXT ("position independent pointers ")
+ ACE_TEXT ("not supported on this platform\n")));
+
+ ACE_END_TEST;
+ return 0;
+}
+#endif /* (ACE_HAS_THREADS || ACE_HAS_PROCESS_SPAWN) && ACE_HAS_POSITION_INDEPENDENT_POINTERS == 1 */
diff --git a/ACE/tests/MEM_Stream_Test.h b/ACE/tests/MEM_Stream_Test.h
new file mode 100644
index 00000000000..b9ed6924463
--- /dev/null
+++ b/ACE/tests/MEM_Stream_Test.h
@@ -0,0 +1,57 @@
+/* -*- C++ -*- */
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// MEM_Stream_Test.h
+//
+// = DESCRIPTION
+// This file has the class definitions needed for template generation in
+// MEM_Stream_Test.cpp. They have to be in a separate file so AIX xlC can
+// find them at auto-instantiate time.
+//
+// = AUTHOR
+// Steve Huston <shuston@riverace.com>
+//
+// ============================================================================
+
+#ifndef ACE_TESTS_MEM_STREAM_TEST_H
+#define ACE_TESTS_MEM_STREAM_TEST_H
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "ace/MEM_Stream.h"
+#include "ace/Reactor.h"
+#include "ace/Svc_Handler.h"
+#include "ace/Synch_Traits.h"
+
+#if (ACE_HAS_POSITION_INDEPENDENT_POINTERS == 1)
+
+class Echo_Handler : public ACE_Svc_Handler<ACE_MEM_STREAM, ACE_SYNCH>
+{
+ // = TITLE
+ // Simple class for reading in the data and then sending it back
+public:
+ Echo_Handler (ACE_Thread_Manager *thr_mgr = 0);
+ virtual int open (void *);
+ static void reset_handler (void);
+ virtual int handle_input (ACE_HANDLE h);
+ virtual int handle_close (ACE_HANDLE handle,
+ ACE_Reactor_Mask close_mask);
+ // The Svc_Handler callbacks.
+ virtual int svc (void);
+
+private:
+ ACE_TCHAR name_[MAXPATHLEN];
+ u_short connection_;
+};
+
+#endif /* ACE_HAS_POSITION_INDEPENDENT_POINTERS */
+
+#endif /* ACE_TESTS_MEM_STREAM_TEST_H */
diff --git a/ACE/tests/MM_Shared_Memory_Test.cpp b/ACE/tests/MM_Shared_Memory_Test.cpp
new file mode 100644
index 00000000000..557c9c38fe5
--- /dev/null
+++ b/ACE/tests/MM_Shared_Memory_Test.cpp
@@ -0,0 +1,232 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Shared_Memory_MM_Test.cpp
+//
+// = DESCRIPTION
+// This is a simple test of <ACE_Shared_Memory_MM>. The test
+// forks two processes or spawns two threads (depending upon the
+// platform) and then executes child and parent allowing them to
+// exchange data using shared memory. No user input is required as
+// far as command line arguments are concerned.
+//
+// = AUTHOR
+// Prashant Jain <pjain@cs.wustl.edu>
+// and Douglas C. Schmidt <schmidt@cs.wustl.edu>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/Shared_Memory_MM.h"
+#include "ace/SV_Semaphore_Simple.h"
+#include "ace/Process_Semaphore.h"
+#include "ace/Thread_Manager.h"
+#include "ace/ACE.h"
+#include "ace/OS_NS_string.h"
+#include "ace/OS_NS_unistd.h"
+
+ACE_RCSID(tests, MM_Shared_Memory_Test, "$Id$")
+
+#if !defined (ACE_LACKS_MMAP)
+
+static const char ACE_ALPHABET[] = "abcdefghijklmnopqrstuvwxyz";
+const int SHMSZ = 27;
+static ACE_TCHAR *shm_key;
+
+#if defined (ACE_LACKS_FORK)
+#include "ace/Thread_Semaphore.h"
+typedef ACE_Thread_Semaphore SYNCHRONIZER;
+#elif defined (ACE_HAS_POSIX_SEM) && defined(ACE_HAS_SYSV_IPC)
+class SYNCHRONIZER : public ACE_SV_Semaphore_Simple
+{
+ // = TITLE
+ // If the platform has native cross-process POSIX semaphores, we
+ // must *force* this test to use the System V Semaphores in order
+ // to get the right semantics.
+public:
+ SYNCHRONIZER (int initial_value)
+ : ACE_SV_Semaphore_Simple ((const char *) 0,
+ ACE_SV_Semaphore_Simple::ACE_CREATE,
+ initial_value)
+ {}
+};
+#else
+typedef ACE_Process_Semaphore SYNCHRONIZER;
+#endif /* !defined (ACE_LACKS_FORK) */
+
+// Synchronize the start of the parent and the child.
+static SYNCHRONIZER *synchronizer = 0;
+
+static void *
+child (void * = 0)
+{
+ int result;
+
+ // Wait for the parent to be initialized.
+ result = synchronizer->acquire ();
+ ACE_ASSERT (result != -1);
+
+ const char *t = ACE_ALPHABET;
+ ACE_Shared_Memory_MM shm_child;
+
+ result = shm_child.open (shm_key);
+ ACE_ASSERT (result != -1);
+
+ char *shm = (char *) shm_child.malloc ();
+
+ ACE_ASSERT (shm != 0);
+
+ for (char *s = shm; *s != '\0'; s++)
+ {
+ ACE_ASSERT (*t == s[0]);
+ t++;
+ }
+
+ // Indicate to the parent that we're done.
+ *shm = '*';
+
+ return 0;
+}
+
+static void *
+parent (void * = 0)
+{
+ int result;
+ ACE_Shared_Memory_MM shm_parent;
+
+ result = shm_parent.open (shm_key, SHMSZ);
+ ACE_ASSERT (result != -1);
+
+ char *shm = (char *) shm_parent.malloc ();
+
+ ACE_ASSERT (shm != 0);
+
+ char *s = shm;
+
+ for (const char *c = ACE_ALPHABET; *c != '\0'; c++)
+ *s++ = *c;
+
+ *s = '\0';
+
+ // Allow the child to proceed.
+ result = synchronizer->release ();
+ ACE_ASSERT (result != -1);
+
+ // Perform a "busy wait" until the child sets the character to '*'.
+ while (*shm != '*')
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P) spinning in parent!\n")));
+
+ result = shm_parent.remove ();
+ ACE_ASSERT (result != -1);
+
+ ACE_OS::unlink (shm_key);
+ return 0;
+}
+
+static int
+spawn (void)
+{
+ // Create the synchronizer before spawning the child process/thread,
+ // to avoid race condition between the creation in the parent and
+ // use in the child.
+ ACE_NEW_RETURN (synchronizer,
+ SYNCHRONIZER ((unsigned int)0), // Locked by default...
+ -1);
+
+#if !defined (ACE_LACKS_FORK)
+ switch (ACE_OS::fork (ACE_TEXT ("child")))
+ {
+ case -1:
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n"),
+ ACE_TEXT ("fork failed")),
+ 1);
+ /* NOTREACHED */
+ case 0:
+ parent ();
+ // Remove the semaphore.
+ synchronizer->remove ();
+ delete synchronizer;
+ break;
+ /* NOTREACHED */
+ default:
+ child ();
+ delete synchronizer;
+ break;
+ /* NOTREACHED */
+ }
+#elif defined (ACE_HAS_THREADS)
+ if (ACE_Thread_Manager::instance ()->spawn
+ (ACE_THR_FUNC (child),
+ (void *) 0,
+ THR_NEW_LWP | THR_DETACHED) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n"),
+ ACE_TEXT ("thread create failed")),
+ 1);
+ else if (ACE_Thread_Manager::instance ()->spawn
+ (ACE_THR_FUNC (parent),
+ (void *) 0,
+ THR_NEW_LWP | THR_DETACHED) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n"),
+ ACE_TEXT ("thread create failed")),
+ 1);
+ ACE_Thread_Manager::instance ()->wait ();
+ delete synchronizer;
+#else
+ ACE_UNUSED_ARG (synchronizer);
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("only one thread may be run in a process on this platform\n")),
+ 1);
+#endif /* ACE_HAS_THREADS */
+ return 0;
+}
+#endif /* !ACE_LACKS_MMAP */
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("MM_Shared_Memory_Test"));
+
+#if !defined (ACE_LACKS_MMAP)
+ ACE_TCHAR temp_file[MAXPATHLEN + 1];
+
+ // Get the temporary directory,
+ // The - 24 is for the filename, mm_shared_mem_testXXXXXX
+ if (ACE::get_temp_dir (temp_file, MAXPATHLEN - 24) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("Temporary path too long\n")), -1);
+
+ // Add the filename to the end
+ ACE_OS::strcat (temp_file, ACE_TEXT ("mm_shared_mem_testXXXXXX"));
+
+ // Store in the global variable.
+ shm_key = temp_file;
+
+ if (ACE_OS::mktemp (shm_key) == 0
+ || (ACE_OS::unlink (shm_key) == -1
+#ifndef ACE_HAS_WINCE
+ && errno == EPERM
+#endif
+ ))
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n"),
+ shm_key),
+ 1);
+ spawn ();
+
+#else /* !ACE_LACKS_MMAP */
+ ACE_ERROR ((LM_INFO,
+ ACE_TEXT ("mmap ")
+ ACE_TEXT ("is not supported on this platform\n")));
+#endif /* !ACE_LACKS_MMAP */
+
+ ACE_END_TEST;
+ return 0;
+}
diff --git a/ACE/tests/MT_Reactor_Timer_Test.cpp b/ACE/tests/MT_Reactor_Timer_Test.cpp
new file mode 100644
index 00000000000..5a714be719b
--- /dev/null
+++ b/ACE/tests/MT_Reactor_Timer_Test.cpp
@@ -0,0 +1,374 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// MT_Reactor_Timer_Test.cpp
+//
+// = DESCRIPTION
+// This is a simple test that illustrates the timer mechanism of
+// the reactor scheduling timers, handling expired timers and
+// cancelling scheduled timers from multiple threads. No command
+// line arguments are needed to run the test.
+//
+// = AUTHOR
+// Steve Huston <shuston@riverace.com>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "MT_Reactor_Timer_Test.h"
+#include "ace/ACE.h"
+#include "ace/OS_NS_unistd.h"
+
+ACE_RCSID(tests, MT_Reactor_Timer_Test, "$Id$")
+
+#if defined (ACE_HAS_THREADS)
+
+// This test exercises the setting and cancelling of timers from a
+// thread other than the one the reactor is running in. It sets up an
+// initial set of timers (3, 4, 5 seconds) from the main thread. When
+// the second thread starts, it cancels the 3 second timer and sets a
+// 2-second timer and an already-expired timer, which should be the
+// first to fire. It then sleeps for 3 seconds (letting the 2 second
+// timer fire, and if things are slow, the 4 second timer will also
+// fire. Then it sets 2 more timers at 10 and 12 seconds and cancels
+// the original 5 second timer. Then returns, ending the thread. The
+// destructor for Time_Handler insures that everything happened
+// correctly.
+
+Time_Handler::Time_Handler (void)
+{
+ for (int i = 0;
+ i < Time_Handler::TIMER_SLOTS;
+ this->timer_id_[i++] = Time_Handler::TIMER_NOTSET)
+ continue;
+
+ this->prev_timer_ = -1;
+}
+
+// Set up initial timer conditions. Timers set up at 3, 4, and 5
+// seconds. The one at 3 seconds will get cancelled when the thread
+// starts.
+
+void
+Time_Handler::setup (void)
+{
+ ACE_Reactor *r = ACE_Reactor::instance ();
+
+ this->timer_id_[2] = r->schedule_timer (this,
+ (const void *) 2,
+ ACE_Time_Value (3));
+ this->timer_id_[3] = r->schedule_timer (this,
+ (const void *) 3,
+ ACE_Time_Value (4));
+ this->timer_id_[4] = r->schedule_timer (this,
+ (const void *) 4,
+ ACE_Time_Value (5));
+ return;
+}
+
+int
+Time_Handler::verify_results (void)
+{
+ ACE_ASSERT (this->timer_id_[0] == Time_Handler::TIMER_FIRED);
+ ACE_ASSERT (this->timer_id_[1] == Time_Handler::TIMER_FIRED);
+ ACE_ASSERT (this->timer_id_[2] == Time_Handler::TIMER_CANCELLED);
+ ACE_ASSERT (this->timer_id_[3] == Time_Handler::TIMER_FIRED);
+ ACE_ASSERT (this->timer_id_[4] == Time_Handler::TIMER_CANCELLED);
+ ACE_ASSERT (this->timer_id_[5] == Time_Handler::TIMER_FIRED);
+ ACE_ASSERT (this->timer_id_[6] == Time_Handler::TIMER_FIRED);
+
+ for (int i = 7; i < Time_Handler::TIMER_SLOTS; i++)
+ ACE_ASSERT (this->timer_id_[i] == Time_Handler::TIMER_NOTSET);
+
+ return 0;
+}
+
+int
+Time_Handler::svc (void)
+{
+ ACE_Reactor *r = ACE_Reactor::instance ();
+
+ ACE_ASSERT (r->cancel_timer (this->timer_id_[2]) == 1);
+ this->timer_id_[2] = Time_Handler::TIMER_CANCELLED;
+
+ this->timer_id_[1] = r->schedule_timer(this,
+ (const void *) 1,
+ ACE_Time_Value (2));
+ // This one may get the callback before we return, so serialize.
+ this->lock_.acquire ();
+ this->timer_id_[0] = r->schedule_timer(this,
+ (const void *) 0,
+ ACE_Time_Value (0, -5));
+ this->lock_.release ();
+ ACE_OS::sleep(3);
+
+ this->timer_id_[5] = r->schedule_timer(this,
+ (const void *)5,
+ ACE_Time_Value (10));
+ this->timer_id_[6] = r->schedule_timer(this,
+ (const void *)6,
+ ACE_Time_Value (12));
+
+ ACE_ASSERT (r->cancel_timer (this->timer_id_[4]) == 1);
+ this->timer_id_[4] = Time_Handler::TIMER_CANCELLED;
+
+ return 0;
+}
+
+int
+Time_Handler::handle_timeout (const ACE_Time_Value &tv,
+ const void *arg)
+{
+ long time_tag = static_cast <long> (reinterpret_cast <size_t> (arg));
+ ACE_UNUSED_ARG(tv);
+
+ ACE_GUARD_RETURN (ACE_Thread_Mutex, id_lock, this->lock_, 0);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%T (%t): Timer #%d (id #%d) expired\n"),
+ time_tag,
+ this->timer_id_[time_tag]));
+
+ ACE_ASSERT (time_tag > this->prev_timer_);
+ ACE_ASSERT (this->timer_id_[time_tag] != Time_Handler::TIMER_NOTSET);
+ ACE_ASSERT (this->timer_id_[time_tag] != Time_Handler::TIMER_CANCELLED);
+ ACE_ASSERT (this->timer_id_[time_tag] != Time_Handler::TIMER_FIRED);
+ this->timer_id_[time_tag] = Time_Handler::TIMER_FIRED;
+ this->prev_timer_ = time_tag;
+
+ return 0;
+}
+
+#endif /* ACE_HAS_THREADS */
+
+Dispatch_Count_Handler::Dispatch_Count_Handler (void)
+{
+
+ ACE_Reactor *r = ACE_Reactor::instance ();
+
+ this->input_seen_ = this->notify_seen_ = 0;
+ this->timers_fired_ = 0;
+
+ // Initialize the pipe.
+ if (this->pipe_.open () == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("ACE_Pipe::open")));
+ // Register the "read" end of the pipe.
+ else if (r->register_handler (this->pipe_.read_handle (),
+ this,
+ ACE_Event_Handler::READ_MASK) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("register_handler")));
+ // Put something in our pipe and smoke it... ;-)
+ else if (ACE::send (this->pipe_.write_handle (),
+ "z",
+ 1) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("send")));
+ // Call notify to prime the pump for this, as well.
+ else if (r->notify (this) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("notify")));
+}
+
+int
+Dispatch_Count_Handler::handle_close (ACE_HANDLE h,
+ ACE_Reactor_Mask m)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%T (%t): handle_close\n")));
+
+ ACE_ASSERT (h == this->pipe_.read_handle ()
+ && m == ACE_Event_Handler::READ_MASK);
+
+ return 0;
+}
+
+int
+Dispatch_Count_Handler::handle_input (ACE_HANDLE h)
+{
+ char c;
+
+ ACE_ASSERT (this->input_seen_ == 0);
+ this->input_seen_ = 1;
+
+ if (ACE::recv (h, &c, 1) != 1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("recv")),
+ -1);
+
+ ACE_ASSERT (c == 'z');
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%T (%t): handle_input\n")));
+ // Trigger the <handle_close> hook.
+ return -1;
+}
+
+int
+Dispatch_Count_Handler::handle_exception (ACE_HANDLE h)
+{
+ ACE_UNUSED_ARG (h);
+
+ ACE_ASSERT (this->notify_seen_ == 0);
+ this->notify_seen_ = 1;
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%T (%t): handle_exception\n")));
+ return 0;
+}
+
+int
+Dispatch_Count_Handler::handle_timeout (const ACE_Time_Value &tv,
+ const void *arg)
+{
+ ACE_UNUSED_ARG (tv);
+
+ ++this->timers_fired_;
+
+ long value = static_cast <long> (reinterpret_cast <size_t> (arg));
+
+ // This case just tests to make sure the Reactor is counting timer
+ // expiration correctly.
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%T (%t): expiration %d\n"),
+ value));
+ return 0;
+}
+
+int
+Dispatch_Count_Handler::verify_results (void)
+{
+ int result = 0;
+
+ if (this->input_seen_ != 1)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("input_seen_ is not 1 but %d\n"),
+ input_seen_));
+ result = -1;
+ }
+
+ if (this->notify_seen_ != 1)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("notify_seen_ is not 1 but %d\n"),
+ notify_seen_));
+ result = -1;
+ }
+
+ if (this->timers_fired_ != ACE_MAX_TIMERS)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("timers fired not equal max timers: %d != %d\n"),
+ this->timers_fired_,
+ ACE_MAX_TIMERS));
+ result = -1;
+ }
+
+ return result;
+}
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("MT_Reactor_Timer_Test"));
+
+ int status = 0;
+ int test_result = 0;
+
+ ACE_Reactor *r = ACE_Reactor::instance ();
+
+ Dispatch_Count_Handler callback;
+
+ for (int i = ACE_MAX_TIMERS; i > 0; i--)
+ // Schedule a timeout to expire immediately.
+ if (r->schedule_timer (&callback,
+ reinterpret_cast <const void *> (static_cast <size_t> (i)),
+ ACE_Time_Value (0)) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("schedule_timer")),
+ 1);
+
+ ACE_Time_Value no_waiting (0);
+ size_t events = 0;
+
+ while (1)
+ {
+ int result = r->handle_events (no_waiting);
+
+ // Timeout.
+ if (result == 0)
+ break;
+
+ // Make sure there were no errors.
+ ACE_ASSERT (result != -1);
+
+ events += result;
+ }
+
+ // All <ACE_MAX_TIMERS> + 2 I/O dispatches (one for <handle_input>
+ // and the other for <handle_exception>) should be counted in
+ // events.
+ if (events < ACE_MAX_TIMERS + 2)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("expected %d events, got %d instead\n"),
+ ACE_MAX_TIMERS + 2,
+ events));
+ }
+
+ status = callback.verify_results ();
+ if (status != 0)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Dispatch counting test failed.\n")));
+ test_result = 1;
+ }
+
+#if defined (ACE_HAS_THREADS)
+
+ Time_Handler other_thread;
+ ACE_Time_Value time_limit (30);
+
+ // Set up initial set of timers.
+ other_thread.setup ();
+
+ other_thread.activate (THR_NEW_LWP | THR_JOINABLE);
+ status = ACE_Reactor::instance()->run_reactor_event_loop (time_limit);
+ // Should have returned only because the time limit is up...
+ ACE_ASSERT (status != -1);
+ ACE_ASSERT (time_limit.sec () == 0);
+
+ status = other_thread.wait ();
+ if (status == -1)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("%p, errno is %d\n"),
+ "wait ()",
+ errno));
+ ACE_ASSERT (status != -1);
+ }
+
+ status = other_thread.verify_results ();
+ if (status != 0)
+ test_result = 1;
+
+#else
+ ACE_ERROR ((LM_INFO,
+ ACE_TEXT ("threads not supported on this platform\n")));
+#endif /* ACE_HAS_THREADS */
+
+ ACE_END_TEST;
+ return test_result;
+}
diff --git a/ACE/tests/MT_Reactor_Timer_Test.h b/ACE/tests/MT_Reactor_Timer_Test.h
new file mode 100644
index 00000000000..d3dce675ed4
--- /dev/null
+++ b/ACE/tests/MT_Reactor_Timer_Test.h
@@ -0,0 +1,108 @@
+/* -*- C++ -*- */
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// MT_Reactor_Timer_Test.h
+//
+// = DESCRIPTION
+// This file contains class definitions needed for template
+// instantiation in the MT_Reactor_Timer_Test.cpp file.
+//
+// = AUTHOR
+// Steve Huston <shuston@riverace.com>
+//
+// ============================================================================
+
+#ifndef ACE_TESTS_MT_REACTOR_TIMER_TEST_H
+#define ACE_TESTS_MT_REACTOR_TIMER_TEST_H
+
+#include "ace/Reactor.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "ace/Task.h"
+#include "ace/Pipe.h"
+
+class Time_Handler : public ACE_Task<ACE_SYNCH>
+{
+ // = TITLE
+ // Test out the multi-threading features of the Reactor's timer
+ // mechanism.
+public:
+ Time_Handler (void);
+
+ void setup (void);
+
+ int verify_results(void);
+
+ virtual int svc (void);
+ // Run by a daemon thread to handle deferred processing.
+
+ virtual int handle_timeout (const ACE_Time_Value &tv,
+ const void *arg);
+
+private:
+ enum
+ {
+ TIMER_SLOTS = 10
+ };
+
+ long timer_id_[TIMER_SLOTS];
+ // The timer_id_ array holds timer IDs. They also have some other values
+ // that are specific to this test:
+ // -1 the timer has not been set
+ // -2 the timer was set, but has been cancelled
+ // -3 the timer was set, and it already fired
+ enum { TIMER_NOTSET = -1, TIMER_CANCELLED = -2, TIMER_FIRED = -3 };
+
+ long prev_timer_;
+
+#if defined ACE_HAS_THREADS
+ ACE_Thread_Mutex lock_;
+#endif /* ACE_HAS_THREADS */
+
+};
+
+class Dispatch_Count_Handler : public ACE_Event_Handler
+{
+ // = TITLE
+ // A simple test to ensure that the Reactor counts the number of
+ // dispatches correctly.
+public:
+ Dispatch_Count_Handler (void);
+
+ int handle_close (ACE_HANDLE h,
+ ACE_Reactor_Mask m);
+ // Clean up resources from the Reactor.
+
+ virtual int handle_timeout (const ACE_Time_Value &tv,
+ const void *arg);
+ // Keep track of the number of timeouts.
+
+ virtual int handle_input (ACE_HANDLE);
+ // Keep track of the number of I/O events.
+
+ virtual int handle_exception (ACE_HANDLE);
+ // Keep track of the number of notifies.
+
+ int verify_results (void);
+ // Verify that the expected events did happen.
+
+private:
+ ACE_Pipe pipe_;
+ // Provide something to trigger I/O.
+
+ int input_seen_;
+ int notify_seen_;
+ size_t timers_fired_;
+
+};
+
+#endif /* ACE_TESTS_MT_REACTOR_TIMER_TEST_H */
diff --git a/ACE/tests/MT_Reactor_Upcall_Test.cpp b/ACE/tests/MT_Reactor_Upcall_Test.cpp
new file mode 100644
index 00000000000..49c203b5f2c
--- /dev/null
+++ b/ACE/tests/MT_Reactor_Upcall_Test.cpp
@@ -0,0 +1,367 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// MT_Reactor_Upcall_Test.cpp
+//
+// = DESCRIPTION
+// This is a test that shows how to handle upcalls from the
+// TP_Reactor and the WFMO_Reactor when the event loop is being run
+// by multiple threads.
+//
+// = AUTHOR
+// Irfan Pyarali <irfan@cs.wustl.edu>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/OS_NS_string.h"
+#include "ace/OS_NS_unistd.h"
+#include "ace/Reactor.h"
+#include "ace/TP_Reactor.h"
+#include "ace/WFMO_Reactor.h"
+#include "ace/Dev_Poll_Reactor.h"
+#include "ace/Pipe.h"
+#include "ace/Task.h"
+#include "ace/Get_Opt.h"
+#include "ace/ACE.h"
+
+ACE_RCSID(tests, MT_Reactor_Upcall_Test, "$Id$")
+
+int number_of_event_loop_threads = 3;
+int number_of_messages = 10;
+int sleep_time_in_msec = 100;
+int lock_upcall = 1;
+static const char *message = "Hello there!";
+
+class Guard
+{
+public:
+ Guard (ACE_SYNCH_MUTEX &lock)
+ : lock_ (lock)
+ {
+ if (lock_upcall)
+ lock.acquire ();
+ }
+
+ ~Guard (void)
+ {
+ if (lock_upcall)
+ this->lock_.release ();
+ }
+
+ ACE_SYNCH_MUTEX &lock_;
+};
+
+struct Message
+{
+ enum Type
+ {
+ DATA,
+ SHUTDOWN
+ };
+
+ Type type_;
+ size_t size_;
+ char data_[BUFSIZ];
+};
+
+class Handler : public ACE_Event_Handler
+{
+public:
+ Handler (ACE_Reactor &reactor);
+ int handle_input (ACE_HANDLE fd);
+
+ ACE_Pipe pipe_;
+ int number_of_messages_read_;
+ ACE_SYNCH_MUTEX lock_;
+ int shutdown_;
+};
+
+Handler::Handler (ACE_Reactor &reactor)
+ : ACE_Event_Handler (&reactor),
+ number_of_messages_read_ (0),
+ shutdown_ (0)
+{
+ // Create the pipe.
+ int result
+ = this->pipe_.open ();
+ ACE_ASSERT (result == 0);
+
+ // Register for input events.
+ result =
+ this->reactor ()->register_handler (this->pipe_.read_handle (),
+ this,
+ ACE_Event_Handler::READ_MASK);
+ ACE_ASSERT (result == 0);
+}
+
+int
+Handler::handle_input (ACE_HANDLE fd)
+{
+ Guard monitor (this->lock_);
+
+ // If we have been shutdown, return.
+ if (this->shutdown_)
+ return 0;
+
+ // Read fixed parts of message.
+ Message message;
+ ssize_t result =
+ ACE::recv_n (fd,
+ &message.type_,
+ sizeof (message.type_));
+ if (result != static_cast<ssize_t> (sizeof (message.type_)))
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%t): read %d, %p\n"),
+ result,
+ ACE_TEXT ("recv 1")));
+ result =
+ ACE::recv_n (fd,
+ &message.size_,
+ sizeof (message.size_));
+ if (result != static_cast<ssize_t> (sizeof (message.size_)))
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%t): read %d, %p\n"),
+ result,
+ ACE_TEXT ("recv 2")));
+
+ // On shutdown message, stop the event loop.
+ if (message.type_ == Message::SHUTDOWN)
+ {
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) Shutdown message\n")));
+
+ this->shutdown_ = 1;
+
+ this->reactor ()->end_reactor_event_loop ();
+
+ // Remove self from Reactor.
+ return -1;
+ }
+
+ // Else it is a data message: read the data.
+ result =
+ ACE::recv_n (fd,
+ &message.data_,
+ message.size_);
+ if (result != static_cast<ssize_t> (message.size_))
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%t): read %d, %p\n"),
+ result,
+ ACE_TEXT ("recv 3")));
+ else
+ {
+ message.data_[result] = '\0';
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Starting to handle message %d: %s\n"),
+ this->number_of_messages_read_ + 1,
+ message.data_));
+ }
+
+ // Process message (sleep).
+ ACE_OS::sleep (ACE_Time_Value (0,
+ sleep_time_in_msec * 1000));
+
+ // Keep count.
+ this->number_of_messages_read_++;
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Completed handling message %d\n"),
+ this->number_of_messages_read_));
+
+ return 0;
+}
+
+class Event_Loop_Task : public ACE_Task_Base
+{
+public:
+ Event_Loop_Task (ACE_Reactor &reactor);
+ int svc (void);
+
+private:
+ ACE_Reactor &reactor_;
+};
+
+Event_Loop_Task::Event_Loop_Task (ACE_Reactor &reactor)
+ : reactor_ (reactor)
+{
+}
+
+int
+Event_Loop_Task::svc (void)
+{
+ return this->reactor_.run_reactor_event_loop ();
+}
+
+void
+test_reactor_upcall (ACE_Reactor &reactor)
+{
+ Handler handler (reactor);
+ Event_Loop_Task event_loop_task (reactor);
+
+ // Start up the event loop threads.
+ int result =
+ event_loop_task.activate (THR_NEW_LWP | THR_JOINABLE,
+ number_of_event_loop_threads);
+ ACE_ASSERT (result == 0);
+
+ // Data message.
+ Message data_message;
+ data_message.type_ =
+ Message::DATA;
+ data_message.size_ =
+ ACE_OS::strlen (message);
+ ACE_OS::strcpy (data_message.data_, message);
+
+ // Send in three pieces because the struct members may not be adjacent
+ // in memory.
+ for (int i = 0;
+ i < number_of_messages;
+ ++i)
+ {
+ // This should trigger a call to <handle_input>.
+ ssize_t sent =
+ ACE::send_n (handler.pipe_.write_handle (),
+ &data_message.type_,
+ sizeof (data_message.type_));
+ if (sent == -1)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%t): %p\n"), ACE_TEXT ("send 1")));
+ sent =
+ ACE::send_n (handler.pipe_.write_handle (),
+ &data_message.size_,
+ sizeof (data_message.size_));
+ if (sent == -1)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%t): %p\n"), ACE_TEXT ("send 2")));
+ sent =
+ ACE::send_n (handler.pipe_.write_handle (),
+ &data_message.data_,
+ data_message.size_);
+ if (sent == -1)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%t): %p\n"), ACE_TEXT ("send 3")));
+ }
+
+ // We are done: send shutdown message.
+ Message shutdown_message;
+ shutdown_message.type_ =
+ Message::SHUTDOWN;
+ shutdown_message.size_ = 0;
+
+ // This should trigger a call to <handle_input>.
+ ssize_t sent = ACE::send_n (handler.pipe_.write_handle (),
+ &shutdown_message.type_,
+ sizeof (shutdown_message.type_));
+ if (sent == -1)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%t): %p\n"), ACE_TEXT ("send 4")));
+ sent = ACE::send_n (handler.pipe_.write_handle (),
+ &shutdown_message.size_,
+ sizeof (shutdown_message.size_));
+ if (sent == -1)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%t): %p\n"), ACE_TEXT ("send 5")));
+
+ // Wait for the event loop tasks to exit.
+ event_loop_task.wait ();
+}
+
+int
+parse_args (int argc, ACE_TCHAR *argv[])
+{
+ ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("t:m:s:l:"));
+
+ int c;
+
+ while ((c = get_opt ()) != -1)
+ switch (c)
+ {
+ case 't':
+ number_of_event_loop_threads =
+ ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'm':
+ number_of_messages =
+ ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 's':
+ sleep_time_in_msec =
+ ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'l':
+ lock_upcall =
+ ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ default:
+ ACE_ERROR_RETURN
+ ((LM_ERROR,
+ ACE_TEXT ("usage: %s\n")
+ ACE_TEXT ("\t-m <number of messages> (defaults to %d)\n")
+ ACE_TEXT ("\t-t <number of event loop threads> (defaults to %d)\n")
+ ACE_TEXT ("\t-s <sleep time in msec> (defaults to %d)\n")
+ ACE_TEXT ("\t-l <lock upcall> (defaults to %d)\n")
+ ACE_TEXT ("\n"),
+ argv [0],
+ number_of_messages,
+ number_of_event_loop_threads,
+ sleep_time_in_msec,
+ lock_upcall),
+ -1);
+ }
+
+ return 0;
+}
+
+int
+run_main (int argc, ACE_TCHAR *argv[])
+{
+ ACE_START_TEST (ACE_TEXT ("MT_Reactor_Upcall_Test"));
+
+#if defined (ACE_HAS_THREADS)
+
+ // ACE_LOG_MSG->clr_flags (ACE_Log_Msg::VERBOSE_LITE);
+
+ int result =
+ parse_args (argc, argv);
+
+ if (result != 0)
+ return result;
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Testing TP Reactor\n")));
+
+ ACE_TP_Reactor tp_reactor_impl;
+ ACE_Reactor tp_reactor (&tp_reactor_impl);
+
+ test_reactor_upcall (tp_reactor);
+
+#if defined (ACE_HAS_EVENT_POLL)
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Testing Dev Poll Reactor\n")));
+
+ ACE_Dev_Poll_Reactor dev_poll_reactor_impl;
+ ACE_Reactor dev_poll_reactor (&dev_poll_reactor_impl);
+
+ test_reactor_upcall (dev_poll_reactor);
+
+#endif /* ACE_HAS_EVENT_POLL */
+
+#if defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Testing WFMO Reactor\n")));
+
+ ACE_WFMO_Reactor wfmo_reactor_impl;
+ ACE_Reactor wfmo_reactor (&wfmo_reactor_impl);
+
+ test_reactor_upcall (wfmo_reactor);
+
+#endif /* ACE_WIN32 && !ACE_HAS_WINCE */
+
+#else /* ACE_HAS_THREADS */
+ ACE_UNUSED_ARG(argc);
+ ACE_UNUSED_ARG(argv);
+
+ ACE_ERROR ((LM_INFO,
+ ACE_TEXT ("threads not supported on this platform\n")));
+
+#endif /* ACE_HAS_THREADS */
+
+ ACE_END_TEST;
+ return 0;
+}
diff --git a/ACE/tests/MT_Reference_Counted_Event_Handler_Test.cpp b/ACE/tests/MT_Reference_Counted_Event_Handler_Test.cpp
new file mode 100644
index 00000000000..f2e52a5c24f
--- /dev/null
+++ b/ACE/tests/MT_Reference_Counted_Event_Handler_Test.cpp
@@ -0,0 +1,1424 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// MT_Reference_Counted_Event_Handler_Test.cpp
+//
+// = DESCRIPTION
+//
+// This test tries to represents what happens in the ORB wrt to
+// event handlers, reactors, timer queues, threads, and connection
+// caches, minus the other complexities. The following reactors
+// are tested: Select, TP, WFMO, and Dev Poll (if enabled).
+//
+// The test checks proper use and shutting down of client-side
+// event handlers when it is used by invocation threads and/or
+// event loop threads. Server-side event handlers are either
+// threaded or reactive. A purger thread is introduced to check the
+// connection recycling and cache purging. Nested upcalls are also
+// tested.
+//
+// = AUTHOR
+// Irfan Pyarali <irfan@oomworks.com>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/Reactor.h"
+#include "ace/Select_Reactor.h"
+#include "ace/TP_Reactor.h"
+#include "ace/WFMO_Reactor.h"
+#include "ace/Dev_Poll_Reactor.h"
+#include "ace/Get_Opt.h"
+#include "ace/Task.h"
+#include "ace/SOCK_Acceptor.h"
+#include "ace/SOCK_Connector.h"
+#include "ace/Auto_Event.h"
+#include "ace/OS_NS_signal.h"
+#include "ace/OS_NS_time.h"
+#include "ace/OS_NS_sys_socket.h"
+#include "ace/OS_NS_unistd.h"
+
+ACE_RCSID(tests, MT_Reference_Counted_Event_Handler_Test, "$Id$")
+
+#if defined (ACE_HAS_THREADS)
+
+static const char message[] = "abcdefghijklmnopqrstuvwxyz";
+static const int message_size = 26;
+static int test_select_reactor = 1;
+static int test_tp_reactor = 1;
+static int test_wfmo_reactor = 1;
+static int test_dev_poll_reactor = 1;
+static int debug = 0;
+static int number_of_connections = 5;
+static int max_nested_upcall_level = 10;
+static int close_timeout = 500;
+static int pipe_open_attempts = 10;
+static int pipe_retry_timeout = 1;
+static int make_invocations = -1;
+static int run_event_loop_thread = -1;
+static int run_purger_thread = -1;
+static int run_receiver_thread = -1;
+static int nested_upcalls = -1;
+
+static ACE_HANDLE server_handle = ACE_INVALID_HANDLE;
+static ACE_HANDLE client_handle = ACE_INVALID_HANDLE;
+
+static int number_of_options = 5;
+static int test_configs[][5] =
+ {
+ //
+ // make_invocations, run_event_loop_thread, run_purger_thread, run_receiver_thread, nested_upcalls
+ //
+
+ // { 0, 0, 0, 0, 0, }, // At least one thread should be running.
+ // { 0, 0, 0, 1, 0, }, // If event_loop_thread is not running and invocation_thread is not making invocations,
+ // no thread will know that the socket is closed.
+ // { 0, 0, 1, 0, 0, }, // If invocation_thread is not making invocations and if receiver is not threaded,
+ // we cannot decide which socket to close.
+ // { 0, 0, 1, 1, 0, }, // If event_loop_thread is not running and invocation_thread is not making invocations,
+ // no thread will know that the socket is closed.
+ // { 0, 1, 0, 0, 0, }, // If invocation_thread is not making invocations and if receiver is not threaded,
+ // we cannot decide which socket to close.
+ { 0, 1, 0, 1, 0, },
+ // { 0, 1, 0, 1, 1, }, // No need for nested upcalls without invocations.
+ // { 0, 1, 1, 0, 0, }, // If invocation_thread is not making invocations and if receiver is not threaded,
+ // we cannot decide which socket to close.
+ { 0, 1, 1, 1, 0, },
+ // { 0, 1, 1, 1, 1, }, // No need for nested upcalls without invocations.
+ // { 1, 0, 0, 0, 0, }, // If both event_loop_thread and receiver are not threaded,
+ // no thread can receive the messages.
+ { 1, 0, 0, 1, 0, },
+ // { 1, 0, 0, 1, 1, }, // No need for nested upcalls without event loop being used by the receiver.
+ // { 1, 0, 1, 0, 0, }, // If both event_loop_thread and receiver are not threaded,
+ // no thread can receive the messages.
+ { 1, 0, 1, 1, 0, },
+ // { 1, 0, 1, 1, 1, }, // No need for nested upcalls without event loop being used by the receiver.
+ { 1, 1, 0, 0, 0, },
+ { 1, 1, 0, 0, 1, },
+ { 1, 1, 0, 1, 0, },
+ // { 1, 1, 0, 1, 1, }, // No need for nested upcalls without event loop being used by the receiver.
+ { 1, 1, 1, 0, 0, },
+ { 1, 1, 1, 0, 1, },
+ { 1, 1, 1, 1, 0, },
+ // { 1, 1, 1, 1, 1, }, // No need for nested upcalls without event loop being used by the receiver.
+ };
+
+/* Replication of the ACE_Pipe class. Only difference is that this
+ class always uses two sockets to create the pipe, even on platforms
+ that support pipes. */
+
+class Pipe
+{
+public:
+
+ Pipe (void);
+
+ int open (void);
+
+ ACE_HANDLE read_handle (void) const;
+
+ ACE_HANDLE write_handle (void) const;
+
+private:
+ ACE_HANDLE handles_[2];
+};
+
+int
+Pipe::open (void)
+{
+ ACE_INET_Addr my_addr;
+ ACE_SOCK_Acceptor acceptor;
+ ACE_SOCK_Connector connector;
+ ACE_SOCK_Stream reader;
+ ACE_SOCK_Stream writer;
+ int result = 0;
+
+ // Bind listener to any port and then find out what the port was.
+ if (acceptor.open (ACE_Addr::sap_any) == -1
+ || acceptor.get_local_addr (my_addr) == -1)
+ result = -1;
+ else
+ {
+ ACE_INET_Addr sv_addr (my_addr.get_port_number (),
+ ACE_LOCALHOST);
+
+ // Establish a connection within the same process.
+ if (connector.connect (writer, sv_addr) == -1)
+ result = -1;
+ else if (acceptor.accept (reader) == -1)
+ {
+ writer.close ();
+ result = -1;
+ }
+ }
+
+ // Close down the acceptor endpoint since we don't need it anymore.
+ acceptor.close ();
+ if (result == -1)
+ return -1;
+
+ this->handles_[0] = reader.get_handle ();
+ this->handles_[1] = writer.get_handle ();
+
+ return 0;
+}
+
+Pipe::Pipe (void)
+{
+ this->handles_[0] = ACE_INVALID_HANDLE;
+ this->handles_[1] = ACE_INVALID_HANDLE;
+}
+
+ACE_HANDLE
+Pipe::read_handle (void) const
+{
+ return this->handles_[0];
+}
+
+ACE_HANDLE
+Pipe::write_handle (void) const
+{
+ return this->handles_[1];
+}
+
+class Connection_Cache;
+class Event_Loop_Thread;
+
+static Event_Loop_Thread *global_event_loop_thread_variable = 0;
+
+class Sender : public ACE_Event_Handler
+{
+public:
+
+ Sender (ACE_HANDLE handle,
+ Connection_Cache &connection_cache);
+
+ ~Sender (void);
+
+ int handle_input (ACE_HANDLE);
+
+ ssize_t send_message (void);
+
+ void close (void);
+
+ ACE_HANDLE handle_;
+
+ Connection_Cache &connection_cache_;
+
+};
+
+class Connection_Cache
+{
+public:
+
+ Connection_Cache (void);
+
+ ~Connection_Cache (void);
+
+ void add_connection (Sender *sender);
+
+ void remove_connection (Sender *sender);
+
+ Sender *acquire_connection (void);
+
+ void release_connection (Sender *sender);
+
+ int find (Sender *sender);
+
+ ACE_SYNCH_MUTEX &lock (void);
+
+ enum State
+ {
+ IDLE,
+ BUSY,
+ NOT_IN_CACHE
+ };
+
+ struct Entry
+ {
+ Sender *sender_;
+ State state_;
+ };
+
+ Entry *entries_;
+
+ ACE_SYNCH_MUTEX lock_;
+};
+
+Sender::Sender (ACE_HANDLE handle,
+ Connection_Cache &connection_cache)
+ : handle_ (handle),
+ connection_cache_ (connection_cache)
+{
+ // Enable reference counting.
+ this->reference_counting_policy ().value
+ (ACE_Event_Handler::Reference_Counting_Policy::ENABLED);
+
+ if (debug)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Reference count in Sender::Sender() is %d\n"),
+ this->reference_count_.value ()));
+}
+
+Sender::~Sender (void)
+{
+ if (debug)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Reference count in ~Sender::Sender() is %d\n"),
+ this->reference_count_.value ()));
+
+ // Close the socket that we are responsible for.
+ ACE_OS::closesocket (this->handle_);
+}
+
+int
+Sender::handle_input (ACE_HANDLE)
+{
+ if (debug)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Reference count in Sender::handle_input() is %d\n"),
+ this->reference_count_.value ()));
+
+ //
+ // In this test, this method is only called when the connection has
+ // been closed. Remove self from Reactor.
+ //
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Event loop thread calling Sender::close() ")
+ ACE_TEXT ("for handle %d\n"),
+ this->handle_));
+
+ this->close ();
+
+ return 0;
+}
+
+void
+Sender::close (void)
+{
+ // Remove socket from Reactor (may fail if another thread has already
+ // removed the handle from the Reactor).
+ this->reactor ()->remove_handler (this->handle_,
+ ACE_Event_Handler::ALL_EVENTS_MASK);
+
+ // Remove self from connection cache (may fail if another thread has
+ // already removed "this" from the cache).
+ this->connection_cache_.remove_connection (this);
+}
+
+ssize_t
+Sender::send_message (void)
+{
+ return ACE::send_n (this->handle_,
+ message,
+ message_size);
+}
+
+class Event_Loop_Thread : public ACE_Task_Base
+{
+public:
+
+ Event_Loop_Thread (ACE_Thread_Manager &thread_manager,
+ ACE_Reactor &reactor);
+
+ int svc (void);
+
+ ACE_Reactor &reactor_;
+
+};
+
+class Receiver : public ACE_Task_Base
+{
+public:
+
+ Receiver (ACE_Thread_Manager &thread_manager,
+ ACE_HANDLE handle,
+ int nested_upcalls);
+
+ ~Receiver (void);
+
+ int svc (void);
+
+ int close (u_long flags);
+
+ int handle_input (ACE_HANDLE);
+
+ int resume_handler (void);
+
+ ACE_HANDLE handle_;
+
+ int counter_;
+
+ int nested_upcalls_;
+
+ int nested_upcalls_level_;
+
+};
+
+Receiver::Receiver (ACE_Thread_Manager &thread_manager,
+ ACE_HANDLE handle,
+ int nested_upcalls)
+ : ACE_Task_Base (&thread_manager),
+ handle_ (handle),
+ counter_ (1),
+ nested_upcalls_ (nested_upcalls),
+ nested_upcalls_level_ (0)
+{
+ // Enable reference counting.
+ this->reference_counting_policy ().value
+ (ACE_Event_Handler::Reference_Counting_Policy::ENABLED);
+
+ if (debug)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Reference count in Receiver::Receiver() is %d\n"),
+ this->reference_count_.value ()));
+}
+
+Receiver::~Receiver (void)
+{
+ if (debug)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Reference count in ~Receiver::Receiver() is %d\n"),
+ this->reference_count_.value ()));
+
+ // Close the socket that we are responsible for.
+ ACE_OS::closesocket (this->handle_);
+}
+
+int
+Receiver::svc (void)
+{
+ //
+ // Continuously receive messages from the Sender. On error, exit
+ // thread.
+ //
+
+ int result = 0;
+
+ while (result != -1)
+ {
+ result =
+ this->handle_input (this->handle_);
+ }
+
+ return 0;
+}
+
+int
+Receiver::handle_input (ACE_HANDLE handle)
+{
+ char buf[message_size + 1];
+
+ // Receive message.
+ ssize_t result =
+ ACE::recv_n (handle,
+ buf,
+ sizeof buf - 1);
+
+ if (this->reactor ())
+ this->reactor ()->resume_handler (handle);
+
+ if (result == message_size)
+ {
+ if (debug)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Message %d received on handle %d\n"),
+ this->counter_++,
+ handle));
+
+ if (this->thr_count () == 0 &&
+ this->nested_upcalls_)
+ {
+ this->nested_upcalls_level_++;
+
+ if (debug)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Nesting level %d\n"),
+ this->nested_upcalls_level_));
+
+ if ((this->nested_upcalls_level_ != max_nested_upcall_level) &&
+ (global_event_loop_thread_variable != 0))
+ global_event_loop_thread_variable->svc ();
+
+ this->nested_upcalls_level_--;
+ return 0;
+ }
+ else
+ return 0;
+ }
+ else
+ {
+ if (debug)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("/*** Problem in receiving message %d on handle")
+ ACE_TEXT (" %d: shutting down receiving thread ***/\n"),
+ this->counter_,
+ handle));
+
+ return -1;
+ }
+}
+
+int
+Receiver::resume_handler (void)
+{
+ /// The application takes responsibility of resuming the handler.
+ return ACE_APPLICATION_RESUMES_HANDLER;
+}
+
+int
+Receiver::close (u_long)
+{
+ // If threaded, we are responsible for deleting this instance when
+ // the thread completes. If not threaded, Reactor reference
+ // counting will handle the deletion of this instance.
+ delete this;
+ return 0;
+}
+
+class Connector
+{
+public:
+
+ Connector (ACE_Thread_Manager &thread_manager,
+ ACE_Reactor &reactor,
+ int nested_upcalls);
+
+ int connect (ACE_HANDLE &client_handle,
+ ACE_HANDLE &server_handle,
+ int run_receiver_thread);
+
+ ACE_Thread_Manager &thread_manager_;
+
+ ACE_Reactor &reactor_;
+
+ int nested_upcalls_;
+
+};
+
+Connector::Connector (ACE_Thread_Manager &thread_manager,
+ ACE_Reactor &reactor,
+ int nested_upcalls)
+ : thread_manager_ (thread_manager),
+ reactor_ (reactor),
+ nested_upcalls_ (nested_upcalls)
+{
+}
+
+int
+Connector::connect (ACE_HANDLE &client_handle,
+ ACE_HANDLE &server_handle,
+ int run_receiver_thread)
+{
+ //
+ // Create a connection and a receiver to receive messages on the
+ // connection.
+ //
+
+ Pipe pipe;
+ int result = 0;
+
+ for (int i = 0; i < pipe_open_attempts; ++i)
+ {
+ result =
+ pipe.open ();
+
+ if (result == 0)
+ break;
+
+ if (result == -1)
+ ACE_OS::sleep (pipe_retry_timeout);
+ }
+
+ ACE_ASSERT (result == 0);
+ ACE_UNUSED_ARG (result);
+
+ Receiver *receiver =
+ new Receiver (this->thread_manager_,
+ pipe.write_handle (),
+ this->nested_upcalls_);
+
+ // Either the receiver is threaded or register it with the Reactor.
+ if (run_receiver_thread)
+ result =
+ receiver->activate ();
+ else
+ {
+ result =
+ this->reactor_.register_handler (pipe.write_handle (),
+ receiver,
+ ACE_Event_Handler::READ_MASK);
+
+ // The reference count on the receiver was increased by the
+ // Reactor.
+ ACE_Event_Handler_var safe_receiver (receiver);
+ }
+
+ ACE_ASSERT (result == 0);
+ ACE_UNUSED_ARG (result);
+
+ client_handle =
+ pipe.read_handle ();
+
+ server_handle =
+ pipe.write_handle ();
+
+ if (debug)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("New connection: client handle = %d, ")
+ ACE_TEXT ("server handle = %d\n"),
+ client_handle, server_handle));
+
+ return 0;
+}
+
+Connection_Cache::Connection_Cache (void)
+{
+ // Initialize the connection cache.
+ this->entries_ =
+ new Entry[number_of_connections];
+
+ for (int i = 0; i < number_of_connections; ++i)
+ {
+ this->entries_[i].sender_ = 0;
+ this->entries_[i].state_ = NOT_IN_CACHE;
+ }
+}
+
+int
+Connection_Cache::find (Sender *sender)
+{
+ for (int i = 0; i < number_of_connections; ++i)
+ {
+ if (this->entries_[i].sender_ == sender)
+ return i;
+ }
+
+ return -1;
+}
+
+void
+Connection_Cache::add_connection (Sender *sender)
+{
+ ACE_GUARD (ACE_SYNCH_MUTEX, ace_mon, this->lock_);
+
+ // Make sure that the state of the connection cache is as
+ // expected. <sender> should not be already in the cache.
+ ACE_ASSERT (this->find (sender) == -1);
+
+ int empty_index =
+ this->find (0);
+
+ sender->add_reference ();
+ this->entries_[empty_index].sender_ = sender;
+ this->entries_[empty_index].state_ = BUSY;
+}
+
+void
+Connection_Cache::remove_connection (Sender *sender)
+{
+ ACE_GUARD (ACE_SYNCH_MUTEX, ace_mon, this->lock_);
+
+ // Make sure that the state of the connection cache is as expected.
+ // remove_connection() may already have been called.
+ int index =
+ this->find (sender);
+
+ if (index == -1)
+ return;
+
+ // If we still have the sender, remove it.
+ sender->remove_reference ();
+ this->entries_[index].sender_ = 0;
+ this->entries_[index].state_ = NOT_IN_CACHE;
+}
+
+Sender *
+Connection_Cache::acquire_connection (void)
+{
+ ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, ace_mon, this->lock_, 0);
+
+ // Find a valid and IDLE sender.
+
+ int index = -1;
+
+ for (int i = 0; i < number_of_connections; ++i)
+ {
+ if (this->entries_[i].sender_ &&
+ this->entries_[i].state_ == IDLE)
+ index = i;
+ }
+
+ if (index == -1)
+ return 0;
+
+ this->entries_[index].sender_->add_reference ();
+ this->entries_[index].state_ = BUSY;
+
+ return this->entries_[index].sender_;
+}
+
+void
+Connection_Cache::release_connection (Sender *sender)
+{
+ ACE_GUARD (ACE_SYNCH_MUTEX, ace_mon, this->lock_);
+
+ // Make sure that the state of the connection cache is as expected.
+ // remove_connection() may have already removed the connection from
+ // the cache.
+ int index =
+ this->find (sender);
+
+ if (index == -1)
+ return;
+
+ // If we still have the sender, idle it.
+ this->entries_[index].state_ = IDLE;
+}
+
+ACE_SYNCH_MUTEX &
+Connection_Cache::lock (void)
+{
+ return this->lock_;
+}
+
+Connection_Cache::~Connection_Cache (void)
+{
+ for (int i = 0; i < number_of_connections; ++i)
+ {
+ if (this->entries_[i].sender_)
+ this->remove_connection (this->entries_[i].sender_);
+ }
+
+ delete[] this->entries_;
+}
+
+class Invocation_Thread : public ACE_Task_Base
+{
+public:
+
+ Invocation_Thread (ACE_Thread_Manager &thread_manager,
+ ACE_Reactor &reactor,
+ Connection_Cache &connection_cache,
+ ACE_Auto_Event &new_connection_event,
+ int make_invocations,
+ int run_receiver_thread,
+ int nested_upcalls);
+
+ int svc (void);
+
+ Sender *create_connection (void);
+
+ Connection_Cache &connection_cache_;
+
+ ACE_Reactor &reactor_;
+
+ ACE_Thread_Manager &thread_manager_;
+
+ ACE_Auto_Event &new_connection_event_;
+
+ int make_invocations_;
+
+ int run_receiver_thread_;
+
+ int nested_upcalls_;
+
+};
+
+Invocation_Thread::Invocation_Thread (ACE_Thread_Manager &thread_manager,
+ ACE_Reactor &reactor,
+ Connection_Cache &connection_cache,
+ ACE_Auto_Event &new_connection_event,
+ int make_invocations,
+ int run_receiver_thread,
+ int nested_upcalls)
+ : ACE_Task_Base (&thread_manager),
+ connection_cache_ (connection_cache),
+ reactor_ (reactor),
+ thread_manager_ (thread_manager),
+ new_connection_event_ (new_connection_event),
+ make_invocations_ (make_invocations),
+ run_receiver_thread_ (run_receiver_thread),
+ nested_upcalls_ (nested_upcalls)
+{
+}
+
+Sender *
+Invocation_Thread::create_connection (void)
+{
+ int result = 0;
+
+ // Connector for creating new connections.
+ Connector connector (this->thread_manager_,
+ this->reactor_,
+ this->nested_upcalls_);
+
+ // <server_handle> is a global variable. It will be used later by
+ // the Close_Socket_Thread.
+ result =
+ connector.connect (client_handle,
+ server_handle,
+ this->run_receiver_thread_);
+ ACE_ASSERT (result == 0);
+ ACE_UNUSED_ARG (result);
+
+ // Create a new sender.
+ Sender *sender =
+ new Sender (client_handle,
+ this->connection_cache_);
+
+ // Register it with the cache.
+ this->connection_cache_.add_connection (sender);
+
+ //
+ // There might be a race condition here. The sender has been added
+ // to the cache and is potentially available to other threads
+ // accessing the cache. Therefore, the other thread may use this
+ // sender and potentially close the sender before it even gets
+ // registered with the Reactor.
+ //
+ // This is resolved by marking the connection as busy when it is
+ // first added to the cache. And only once the thread creating the
+ // connection is done with it, it is marked a available in the
+ // cache.
+ //
+ // This order of registration is important.
+ //
+
+ // Register the handle with the Reactor.
+ result =
+ this->reactor_.register_handler (client_handle,
+ sender,
+ ACE_Event_Handler::READ_MASK);
+#if 0
+ ACE_ASSERT (result == 0);
+ ACE_UNUSED_ARG (result);
+#else
+ if (result != 0)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%t) create_connection h %d, %p\n"),
+ client_handle,
+ ACE_TEXT ("register_handler")));
+#endif
+ return sender;
+}
+
+int
+Invocation_Thread::svc (void)
+{
+ int connection_counter = 0;
+ for (int message_counter = 1;; ++message_counter)
+ {
+ // Get a connection from the cache.
+ Sender *sender =
+ this->connection_cache_.acquire_connection ();
+
+ // If no connection is available in the cache, create a new one.
+ if (sender == 0)
+ {
+ if (connection_counter < number_of_connections)
+ {
+ sender = this->create_connection ();
+
+ // This lets the Close_Socket_Thread know that the new
+ // connection has been created.
+ int result =
+ this->new_connection_event_.signal ();
+ ACE_ASSERT (result == 0);
+ ACE_UNUSED_ARG (result);
+
+ ++connection_counter;
+ message_counter = 1;
+ }
+ else
+ // Stop the thread, if the maximum number of connections
+ // for the test has been reached.
+ break;
+ }
+
+ // The reference count on the sender was increased by the cache
+ // before it was returned to us.
+ ACE_Event_Handler_var safe_sender (sender);
+
+ // If the test does not require making invocations, immediately
+ // release the connection.
+ if (!this->make_invocations_)
+ {
+ this->connection_cache_.release_connection (sender);
+
+ // Sleep for a short while
+ ACE_OS::sleep (ACE_Time_Value (0, 10 * 1000));
+ }
+ else
+ {
+ // Make invocation.
+ ssize_t result =
+ sender->send_message ();
+
+ // If successful, release connection.
+ if (result == message_size)
+ {
+ if (debug)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Message %d:%d delivered on handle %d\n"),
+ connection_counter,
+ message_counter,
+ sender->handle_));
+
+ this->connection_cache_.release_connection (sender);
+ }
+ else
+ {
+ // If failure in making invocation, close the sender.
+ if (debug)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("/*** Problem in delivering message ")
+ ACE_TEXT ("%d:%d on handle %d: shutting down ")
+ ACE_TEXT ("invocation thread ***/\n"),
+ connection_counter,
+ message_counter,
+ sender->handle_));
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Invocation thread calling ")
+ ACE_TEXT ("Sender::close() for handle %d\n"),
+ sender->handle_));
+
+ sender->close ();
+ }
+ }
+ }
+
+ // Close the Reactor event loop.
+ this->reactor_.end_reactor_event_loop ();
+
+ return 0;
+}
+
+class Close_Socket_Thread : public ACE_Task_Base
+{
+public:
+
+ Close_Socket_Thread (ACE_Thread_Manager &thread_manager,
+ ACE_Reactor &reactor,
+ ACE_Auto_Event &new_connection_event,
+ int make_invocations,
+ int run_receiver_thread);
+
+ int svc (void);
+
+ ACE_Auto_Event &new_connection_event_;
+
+ ACE_Reactor &reactor_;
+
+ int make_invocations_;
+
+ int run_receiver_thread_;
+
+};
+
+Close_Socket_Thread::Close_Socket_Thread (ACE_Thread_Manager &thread_manager,
+ ACE_Reactor &reactor,
+ ACE_Auto_Event &new_connection_event,
+ int make_invocations,
+ int run_receiver_thread)
+ : ACE_Task_Base (&thread_manager),
+ new_connection_event_ (new_connection_event),
+ reactor_ (reactor),
+ make_invocations_ (make_invocations),
+ run_receiver_thread_ (run_receiver_thread)
+{
+}
+
+int
+Close_Socket_Thread::svc (void)
+{
+ ACE_OS::srand ((u_int) ACE_OS::time ());
+ ACE_Time_Value timeout (0, close_timeout * 1000);
+
+ for (; !this->reactor_.reactor_event_loop_done ();)
+ {
+ // Wait for the new connection to be established.
+ int result =
+ this->new_connection_event_.wait (&timeout,
+ 0);
+ ACE_ASSERT (result == 0 ||
+ (result == -1 && errno == ETIME));
+
+ if (result == -1 &&
+ errno == ETIME)
+ continue;
+
+ // Sleep for half a second.
+ ACE_OS::sleep (timeout);
+
+ int close_client = 0;
+
+ // If the invocation thread is making invocations and if the
+ // receiver is threaded, either socket can be closed.
+ if (this->make_invocations_ &&
+ this->run_receiver_thread_)
+ // Randomize which socket to close.
+ close_client = ACE_OS::rand () % 2;
+
+ // If the invocation thread is making invocations, only close
+ // the client socket.
+ else if (this->make_invocations_)
+ close_client = 1;
+ else
+ // If the receiver is threaded, only close the server socket.
+ close_client = 0;
+
+ if (close_client)
+ {
+ // Close the client socket.
+ if (debug)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Close socket thread closing client ")
+ ACE_TEXT ("handle %d\n"),
+ client_handle));
+
+ ACE_OS::shutdown (client_handle, ACE_SHUTDOWN_BOTH);
+ ACE_OS::closesocket (client_handle);
+ }
+ else
+ {
+ // Close the server socket.
+ if (debug)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Close socket thread closing server ")
+ ACE_TEXT ("handle %d\n"),
+ server_handle));
+ ACE_OS::shutdown (server_handle, ACE_SHUTDOWN_BOTH);
+ ACE_OS::closesocket (server_handle);
+ }
+ }
+
+ return 0;
+}
+
+Event_Loop_Thread::Event_Loop_Thread (ACE_Thread_Manager &thread_manager,
+ ACE_Reactor &reactor)
+ : ACE_Task_Base (&thread_manager),
+ reactor_ (reactor)
+{
+}
+
+int
+Event_Loop_Thread::svc (void)
+{
+ // Simply run the event loop.
+ this->reactor_.owner (ACE_Thread::self ());
+
+ while (!this->reactor_.reactor_event_loop_done ())
+ {
+ this->reactor_.handle_events ();
+ }
+
+ return 0;
+}
+
+class Purger_Thread : public ACE_Task_Base
+{
+public:
+
+ Purger_Thread (ACE_Thread_Manager &thread_manager,
+ ACE_Reactor &reactor,
+ Connection_Cache &connection_cache);
+
+ int svc (void);
+
+ ACE_Reactor &reactor_;
+
+ Connection_Cache &connection_cache_;
+
+};
+
+Purger_Thread::Purger_Thread (ACE_Thread_Manager &thread_manager,
+ ACE_Reactor &reactor,
+ Connection_Cache &connection_cache)
+ : ACE_Task_Base (&thread_manager),
+ reactor_ (reactor),
+ connection_cache_ (connection_cache)
+{
+}
+
+int
+Purger_Thread::svc (void)
+{
+ for (; !this->reactor_.reactor_event_loop_done ();)
+ {
+ // Get a connection from the cache.
+ Sender *sender =
+ this->connection_cache_.acquire_connection ();
+
+ // If no connection is available in the cache, sleep for a while.
+ if (sender == 0)
+ ACE_OS::sleep (ACE_Time_Value (0, 10 * 1000));
+ else
+ {
+ // The reference count on the sender was increased by the
+ // cache before it was returned to us.
+ ACE_Event_Handler_var safe_sender (sender);
+
+ // Actively close the connection.
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Purger thread calling Sender::close() ")
+ ACE_TEXT ("for handle %d\n"),
+ sender->handle_));
+
+ sender->close ();
+ }
+ }
+
+ return 0;
+}
+
+void
+testing (ACE_Reactor *reactor,
+ int make_invocations,
+ int run_event_loop_thread,
+ int run_purger_thread,
+ int run_receiver_thread,
+ int nested_upcalls)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\nConfiguration: \n")
+ ACE_TEXT ("\tInvocation thread = %d\n")
+ ACE_TEXT ("\tEvent Loop thread = %d\n")
+ ACE_TEXT ("\tPurger thread = %d\n")
+ ACE_TEXT ("\tReceiver thread = %d\n")
+ ACE_TEXT ("\tNested Upcalls = %d\n\n"),
+ make_invocations,
+ run_event_loop_thread,
+ run_purger_thread,
+ run_receiver_thread,
+ nested_upcalls));
+
+ ACE_Thread_Manager thread_manager;
+
+ int result = 0;
+
+ // Create the connection cache.
+ Connection_Cache connection_cache;
+ ACE_Auto_Event new_connection_event;
+
+ // Create the invocation thread.
+ Invocation_Thread invocation_thread (thread_manager,
+ *reactor,
+ connection_cache,
+ new_connection_event,
+ make_invocations,
+ run_receiver_thread,
+ nested_upcalls);
+
+ result =
+ invocation_thread.activate ();
+ ACE_ASSERT (result == 0);
+
+ // Create the thread for closing the server socket.
+ Close_Socket_Thread close_socket_thread (thread_manager,
+ *reactor,
+ new_connection_event,
+ make_invocations,
+ run_receiver_thread);
+ result =
+ close_socket_thread.activate ();
+ ACE_ASSERT (result == 0);
+
+ global_event_loop_thread_variable = 0;
+
+ // Create a thread to run the event loop.
+ Event_Loop_Thread event_loop_thread (thread_manager,
+ *reactor);
+ if (run_event_loop_thread)
+ {
+ global_event_loop_thread_variable =
+ &event_loop_thread;
+
+ result =
+ event_loop_thread.activate ();
+ ACE_ASSERT (result == 0);
+ }
+
+ // Create a thread to run the purger.
+ Purger_Thread purger_thread (thread_manager,
+ *reactor,
+ connection_cache);
+ if (run_purger_thread)
+ {
+ result =
+ purger_thread.activate ();
+ ACE_ASSERT (result == 0);
+ }
+
+ // Wait for threads to exit.
+ result = thread_manager.wait ();
+ ACE_ASSERT (result == 0);
+
+ // Set the global variable to zero again because the
+ // event_loop_thread exists on the stack and now
+ // gets destructed.
+ global_event_loop_thread_variable = 0;
+}
+
+template <class REACTOR_IMPL>
+class test
+{
+public:
+ test (int ignore_nested_upcalls,
+ int require_event_loop_thread);
+};
+
+template <class REACTOR_IMPL>
+test<REACTOR_IMPL>::test (int ignore_nested_upcalls,
+ int require_event_loop_thread)
+{
+ for (int i = 0;
+ i < (int) (sizeof test_configs / (sizeof (int) * number_of_options));
+ i++)
+ {
+ if ((make_invocations == -1 ||
+ make_invocations == test_configs[i][0]) &&
+ (run_event_loop_thread == -1 ||
+ run_event_loop_thread == test_configs[i][1]) &&
+ (run_purger_thread == -1 ||
+ run_purger_thread == test_configs[i][2]) &&
+ (run_receiver_thread == -1 ||
+ run_receiver_thread == test_configs[i][3]) &&
+ (nested_upcalls == -1 ||
+ nested_upcalls == test_configs[i][4]))
+ {
+
+#if 0 // defined (linux)
+
+ // @@ I am not sure why but when <make_invocations> is 0 and
+ // there is no purger thread, the receiver thread does not
+ // notice that the connection has been closed.
+ if (!test_configs[i][0] && !test_configs[i][2])
+ continue;
+
+ // @@ Linux also does not work correctly in the following
+ // case: Invocation thread starts and sends messages filling
+ // the socket buffer. It then blocks in write(). In the
+ // meantime, the close connection thread closes the socket
+ // used by invocation thread. However, the invocation thread
+ // does not notice this as it does not return from write().
+ // Meanwhile, the event loop thread notices that a socket in
+ // it's wait set has been closed, and starts to spin in
+ // handle_events() since the invocation thread is not taking
+ // out the closed handle from the Reactor's wait set.
+ if (test_configs[i][0] && test_configs[i][1] && !test_configs[i][3])
+ continue;
+
+#endif /* linux */
+
+ if (test_configs[i][4] && ignore_nested_upcalls)
+ continue;
+
+ if (!test_configs[i][1] && require_event_loop_thread)
+ continue;
+
+ ACE_Reactor reactor (new REACTOR_IMPL,
+ 1);
+
+ testing (&reactor,
+ test_configs[i][0],
+ test_configs[i][1],
+ test_configs[i][2],
+ test_configs[i][3],
+ test_configs[i][4]);
+ }
+ }
+}
+
+static int
+parse_args (int argc, ACE_TCHAR *argv[])
+{
+ ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("a:b:c:d:f:g:k:l:m:n:o:uz:"));
+
+ int cc;
+ while ((cc = get_opt ()) != -1)
+ {
+ switch (cc)
+ {
+ case 'a':
+ test_select_reactor = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'b':
+ test_tp_reactor = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'c':
+ test_wfmo_reactor = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'd':
+ test_dev_poll_reactor = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'f':
+ number_of_connections = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'g':
+ close_timeout = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'k':
+ make_invocations = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'l':
+ run_event_loop_thread = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'm':
+ run_purger_thread = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'n':
+ run_receiver_thread = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'o':
+ nested_upcalls = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'z':
+ debug = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'u':
+ default:
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("\nusage: %s \n\n")
+ ACE_TEXT ("\t[-a test Select Reactor] (defaults to %d)\n")
+ ACE_TEXT ("\t[-b test TP Reactor] (defaults to %d)\n")
+ ACE_TEXT ("\t[-c test WFMO Reactor] (defaults to %d)\n")
+ ACE_TEXT ("\t[-d test Dev Poll Reactor] (defaults to %d)\n")
+ ACE_TEXT ("\t[-f number of connections] (defaults to %d)\n")
+ ACE_TEXT ("\t[-g close timeout] (defaults to %d)\n")
+ ACE_TEXT ("\t[-k make invocations] (defaults to %d)\n")
+ ACE_TEXT ("\t[-l run event loop thread] (defaults to %d)\n")
+ ACE_TEXT ("\t[-m run purger thread] (defaults to %d)\n")
+ ACE_TEXT ("\t[-n run receiver thread] (defaults to %d)\n")
+ ACE_TEXT ("\t[-o nested upcalls] (defaults to %d)\n")
+ ACE_TEXT ("\t[-z debug] (defaults to %d)\n")
+ ACE_TEXT ("\n"),
+ argv[0],
+ test_select_reactor,
+ test_tp_reactor,
+ test_wfmo_reactor,
+ test_dev_poll_reactor,
+ number_of_connections,
+ close_timeout,
+ make_invocations,
+ run_event_loop_thread,
+ run_purger_thread,
+ run_receiver_thread,
+ nested_upcalls,
+ debug));
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+int
+run_main (int argc, ACE_TCHAR *argv[])
+{
+ ACE_START_TEST (ACE_TEXT ("MT_Reference_Counted_Event_Handler_Test"));
+
+ // Validate options.
+ int result =
+ parse_args (argc, argv);
+ if (result != 0)
+ return result;
+
+#if defined (SIGPIPE) && !defined (ACE_LACKS_UNIX_SIGNALS)
+ // There's really no way to deal with this in a portable manner, so
+ // we just have to suck it up and get preprocessor conditional and
+ // ugly.
+ //
+ // Impractical to have each call to the ORB protect against the
+ // implementation artifact of potential writes to dead connections,
+ // as it'd be way expensive. Do it here; who cares about SIGPIPE in
+ // these kinds of applications, anyway?
+ (void) ACE_OS::signal (SIGPIPE, (ACE_SignalHandler) SIG_IGN);
+#endif /* SIGPIPE */
+
+ int ignore_nested_upcalls = 1;
+ int perform_nested_upcalls = 0;
+
+ int event_loop_thread_required = 1;
+ int event_loop_thread_not_required = 0;
+
+ if (test_select_reactor)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\n\nTesting Select Reactor....\n\n")));
+
+ test<ACE_Select_Reactor> test (ignore_nested_upcalls,
+ event_loop_thread_not_required);
+ ACE_UNUSED_ARG (test);
+ }
+
+ if (test_tp_reactor)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\n\nTesting TP Reactor....\n\n")));
+
+ test<ACE_TP_Reactor> test (perform_nested_upcalls,
+ event_loop_thread_not_required);
+ ACE_UNUSED_ARG (test);
+ }
+
+#if defined (ACE_HAS_EVENT_POLL)
+
+ if (test_dev_poll_reactor)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\n\nTesting Dev Poll Reactor....\n\n")));
+
+ test<ACE_Dev_Poll_Reactor> test (perform_nested_upcalls,
+ event_loop_thread_not_required);
+ ACE_UNUSED_ARG (test);
+ }
+
+#endif
+
+#if defined (ACE_WIN32)
+
+ if (test_wfmo_reactor)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\n\nTesting WFMO Reactor....\n\n")));
+
+ test<ACE_WFMO_Reactor> test (ignore_nested_upcalls,
+ event_loop_thread_required);
+ ACE_UNUSED_ARG (test);
+ }
+
+#else /* ACE_WIN32 */
+
+ ACE_UNUSED_ARG (event_loop_thread_required);
+
+#endif /* ACE_WIN32 */
+
+ ACE_END_TEST;
+
+ return 0;
+}
+
+#else /* ACE_HAS_THREADS */
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("MT_Reference_Counted_Event_Handler_Test"));
+
+ ACE_ERROR ((LM_INFO,
+ ACE_TEXT ("threads not supported on this platform\n")));
+
+ ACE_END_TEST;
+
+ return 0;
+}
+
+#endif /* ACE_HAS_THREADS */
diff --git a/ACE/tests/MT_Reference_Counted_Notify_Test.cpp b/ACE/tests/MT_Reference_Counted_Notify_Test.cpp
new file mode 100644
index 00000000000..713e81d6a5e
--- /dev/null
+++ b/ACE/tests/MT_Reference_Counted_Notify_Test.cpp
@@ -0,0 +1,463 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// MT_Reference_Counted_Notify_Test.cpp
+//
+// = DESCRIPTION
+// This test is used to check reference counting of the event
+// handlers when it interacts with the reactor notification
+// mechanism.
+//
+// = AUTHOR
+// Irfan Pyarali <irfan@oomworks.com>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/OS_NS_unistd.h"
+#include "ace/Reactor.h"
+#include "ace/Select_Reactor.h"
+#include "ace/TP_Reactor.h"
+#include "ace/WFMO_Reactor.h"
+#include "ace/Dev_Poll_Reactor.h"
+#include "ace/Task.h"
+#include "ace/Get_Opt.h"
+
+ACE_RCSID(tests, MT_Reference_Counted_Notify_Test, "$Id$")
+
+#if defined (ACE_HAS_THREADS)
+
+static int test_select_reactor = 1;
+static int test_tp_reactor = 1;
+static int test_wfmo_reactor = 1;
+static int test_dev_poll_reactor = 1;
+static int test_empty_notify = 1;
+static int test_simple_notify = 1;
+static int test_reference_counted_notify = 1;
+static int iterations = 5;
+static int debug = 1;
+
+class Reference_Counted_Event_Handler : public ACE_Event_Handler
+{
+public:
+
+ Reference_Counted_Event_Handler (void);
+
+ ~Reference_Counted_Event_Handler (void);
+
+ int handle_input (ACE_HANDLE);
+
+ ACE_Event_Handler::Reference_Count add_reference (void);
+
+ ACE_Event_Handler::Reference_Count remove_reference (void);
+
+};
+
+Reference_Counted_Event_Handler::Reference_Counted_Event_Handler (void)
+{
+ this->reference_counting_policy ().value
+ (ACE_Event_Handler::Reference_Counting_Policy::ENABLED);
+
+ if (debug)
+ ACE_DEBUG
+ ((LM_DEBUG,
+ ACE_TEXT ("Reference count in Reference_Counted_Event_Handler() ")
+ ACE_TEXT ("is %d\n"),
+ this->reference_count_.value ()));
+}
+
+Reference_Counted_Event_Handler::~Reference_Counted_Event_Handler (void)
+{
+ if (debug)
+ ACE_DEBUG
+ ((LM_DEBUG,
+ ACE_TEXT ("Reference count in ~Reference_Counted_Event_Handler() ")
+ ACE_TEXT ("is %d\n"),
+ this->reference_count_.value ()));
+
+ if (0 != this->reference_count_.value ())
+ ACE_ERROR
+ ((LM_ERROR,
+ ACE_TEXT ("Reference count in ~Reference_Counted_Event_Handler() ")
+ ACE_TEXT ("should be 0 but is %d\n"),
+ this->reference_count_.value ()));
+}
+
+int
+Reference_Counted_Event_Handler::handle_input (ACE_HANDLE)
+{
+ if (debug)
+ ACE_DEBUG
+ ((LM_DEBUG,
+ ACE_TEXT ("Reference count in Reference_Counted_Event_Handler::")
+ ACE_TEXT ("handle_input() is %d\n"),
+ this->reference_count_.value ()));
+
+ if (2 != this->reference_count_.value ())
+ ACE_ERROR
+ ((LM_ERROR,
+ ACE_TEXT ("Reference count in Reference_Counted_Event_Handler::")
+ ACE_TEXT ("handle_input() should be 2 but is %d\n"),
+ this->reference_count_.value ()));
+
+ return 0;
+}
+
+ACE_Event_Handler::Reference_Count
+Reference_Counted_Event_Handler::add_reference (void)
+{
+ ACE_Event_Handler::Reference_Count reference_count =
+ this->ACE_Event_Handler::add_reference ();
+
+ if (debug)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Reference count after add_reference() is %d\n"),
+ this->reference_count_.value ()));
+
+ return reference_count;
+}
+
+ACE_Event_Handler::Reference_Count
+Reference_Counted_Event_Handler::remove_reference (void)
+{
+ ACE_Event_Handler::Reference_Count reference_count =
+ this->ACE_Event_Handler::remove_reference ();
+
+ if (debug)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Reference count after remove_reference() is %d\n"),
+ reference_count));
+
+ return reference_count;
+}
+
+class Simple_Event_Handler : public ACE_Event_Handler
+{
+public:
+
+ Simple_Event_Handler (int notifies);
+
+ ~Simple_Event_Handler (void);
+
+ int handle_input (ACE_HANDLE);
+
+ int notifies_;
+};
+
+Simple_Event_Handler::Simple_Event_Handler (int notifies)
+ : notifies_ (notifies)
+{
+ if (debug)
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Simple_Event_Handler()\n")));
+}
+
+Simple_Event_Handler::~Simple_Event_Handler (void)
+{
+ if (debug)
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("~Simple_Event_Handler()\n")));
+}
+
+int
+Simple_Event_Handler::handle_input (ACE_HANDLE)
+{
+ if (debug)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Simple_Event_Handler::handle_input()\n")));
+
+ this->notifies_--;
+
+ if (this->notifies_ == 0)
+ delete this;
+
+ return 0;
+}
+
+class Event_Loop_Thread : public ACE_Task_Base
+{
+public:
+
+ Event_Loop_Thread (ACE_Thread_Manager &thread_manager,
+ ACE_Reactor &reactor,
+ int extra_iterations_needed);
+
+ int svc (void);
+
+ ACE_Reactor &reactor_;
+
+ int extra_iterations_needed_;
+};
+
+Event_Loop_Thread::Event_Loop_Thread (ACE_Thread_Manager &thread_manager,
+ ACE_Reactor &reactor,
+ int extra_iterations_needed)
+ : ACE_Task_Base (&thread_manager),
+ reactor_ (reactor),
+ extra_iterations_needed_ (extra_iterations_needed)
+{
+}
+
+int
+Event_Loop_Thread::svc (void)
+{
+ int counter = 0;
+
+ // Simply run the event loop.
+ this->reactor_.owner (ACE_Thread::self ());
+
+ while (1)
+ {
+ counter++;
+
+ if (debug)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Event Loop iteration %d....\n"),
+ counter));
+
+ this->reactor_.handle_events ();
+
+ if (counter ==
+ iterations + this->extra_iterations_needed_)
+ break;
+ }
+
+ return 0;
+}
+
+void
+notify (ACE_Reactor &reactor,
+ ACE_Event_Handler *event_handler,
+ int extra_iterations_needed)
+{
+ ACE_Thread_Manager thread_manager;
+
+ // Create a thread to run the event loop.
+ Event_Loop_Thread event_loop_thread (thread_manager,
+ reactor,
+ extra_iterations_needed);
+
+ int result =
+ event_loop_thread.activate ();
+ ACE_ASSERT (result == 0);
+
+ for (int i = 0;
+ i < iterations;
+ ++i)
+ {
+ ACE_OS::sleep (ACE_Time_Value (0, 500 * 1000));
+
+ result = reactor.notify (event_handler,
+ ACE_Event_Handler::READ_MASK);
+
+ ACE_ASSERT (result == 0);
+ }
+
+ thread_manager.wait ();
+}
+
+template <class REACTOR_IMPLEMENTATION>
+class test
+{
+public:
+ test (int extra_iterations_needed);
+};
+
+template <class REACTOR_IMPLEMENTATION>
+test<REACTOR_IMPLEMENTATION>::test (int extra_iterations_needed)
+{
+ if (test_empty_notify)
+ {
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\n\nTesting empty notifies...\n\n")));
+
+ REACTOR_IMPLEMENTATION impl;
+ ACE_Reactor reactor (&impl, 0);
+
+ notify (reactor,
+ 0,
+ extra_iterations_needed);
+ }
+
+
+ if (test_simple_notify)
+ {
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\n\nTesting simple notifies...\n\n")));
+
+ REACTOR_IMPLEMENTATION impl;
+ ACE_Reactor reactor (&impl, 0);
+
+ Simple_Event_Handler *simple_event_handler =
+ new Simple_Event_Handler (iterations);
+
+ notify (reactor,
+ simple_event_handler,
+ extra_iterations_needed);
+ }
+
+ if (test_reference_counted_notify)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\n\nTesting reference counted notifies...\n\n")));
+
+ REACTOR_IMPLEMENTATION impl;
+ ACE_Reactor reactor (&impl, 0);
+
+ Reference_Counted_Event_Handler *reference_counted_event_handler =
+ new Reference_Counted_Event_Handler;
+
+ ACE_Event_Handler_var safe_event_handler (reference_counted_event_handler);
+
+ notify (reactor,
+ reference_counted_event_handler,
+ extra_iterations_needed);
+ }
+}
+
+static int
+parse_args (int argc, ACE_TCHAR *argv[])
+{
+ ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("a:b:c:d:e:f:g:z:"));
+
+ int cc;
+ while ((cc = get_opt ()) != -1)
+ {
+ switch (cc)
+ {
+ case 'a':
+ test_select_reactor = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'b':
+ test_tp_reactor = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'c':
+ test_wfmo_reactor = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'd':
+ test_dev_poll_reactor = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'e':
+ test_empty_notify = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'f':
+ test_simple_notify = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'g':
+ test_reference_counted_notify = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'z':
+ debug = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ default:
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("\nusage: %s \n\n")
+ ACE_TEXT ("\t[-a test Select Reactor] (defaults to %d)\n")
+ ACE_TEXT ("\t[-b test TP Reactor] (defaults to %d)\n")
+ ACE_TEXT ("\t[-c test WFMO Reactor] (defaults to %d)\n")
+ ACE_TEXT ("\t[-d test Dev Poll Reactor] (defaults to %d)\n")
+ ACE_TEXT ("\t[-e test empty notify] (defaults to %d)\n")
+ ACE_TEXT ("\t[-f test simple notify] (defaults to %d)\n")
+ ACE_TEXT ("\t[-g test reference counted notify] (defaults to %d)\n")
+ ACE_TEXT ("\t[-z debug] (defaults to %d)\n")
+ ACE_TEXT ("\n"),
+ argv[0],
+ test_select_reactor,
+ test_tp_reactor,
+ test_wfmo_reactor,
+ test_dev_poll_reactor,
+ test_empty_notify,
+ test_simple_notify,
+ test_reference_counted_notify,
+ debug));
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+int
+run_main (int argc, ACE_TCHAR *argv[])
+{
+ ACE_START_TEST (ACE_TEXT ("MT_Reference_Counted_Notify_Test"));
+
+ // Validate options.
+ int result =
+ parse_args (argc, argv);
+ if (result != 0)
+ return result;
+
+ int extra_iterations_needed = 1;
+ int extra_iterations_not_needed = 0;
+
+ if (test_select_reactor)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ "\n\nTesting Select Reactor....\n\n"));
+
+ test<ACE_Select_Reactor> test (extra_iterations_not_needed);
+ ACE_UNUSED_ARG (test);
+ }
+
+ if (test_tp_reactor)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ "\n\nTesting TP Reactor....\n\n"));
+
+ test<ACE_TP_Reactor> test (extra_iterations_not_needed);
+ ACE_UNUSED_ARG (test);
+ }
+
+#if defined (ACE_HAS_EVENT_POLL)
+
+ if (test_dev_poll_reactor)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ "\n\nTesting Dev Poll Reactor....\n\n"));
+
+ test<ACE_Dev_Poll_Reactor> test (extra_iterations_not_needed);
+ ACE_UNUSED_ARG (test);
+ }
+
+#endif
+
+#if defined (ACE_WIN32)
+
+ if (test_wfmo_reactor)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ "\n\nTesting WFMO Reactor....\n\n"));
+
+ test<ACE_WFMO_Reactor> test (extra_iterations_needed);
+ ACE_UNUSED_ARG (test);
+ }
+
+#else /* ACE_WIN32 */
+
+ ACE_UNUSED_ARG (extra_iterations_needed);
+
+#endif /* ACE_WIN32 */
+
+ ACE_END_TEST;
+
+ return 0;
+}
+
+#else /* ACE_HAS_THREADS */
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("MT_Reference_Counted_Notify_Test"));
+
+ ACE_ERROR ((LM_INFO,
+ ACE_TEXT ("threads not supported on this platform\n")));
+
+ ACE_END_TEST;
+
+ return 0;
+}
+
+#endif /* ACE_HAS_THREADS */
diff --git a/ACE/tests/MT_SOCK_Test.cpp b/ACE/tests/MT_SOCK_Test.cpp
new file mode 100644
index 00000000000..eb407f5f596
--- /dev/null
+++ b/ACE/tests/MT_SOCK_Test.cpp
@@ -0,0 +1,440 @@
+/* -*- C++ -*- */
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// MT_SOCK_Test.cpp
+//
+// = DESCRIPTION
+// This is a multi-threaded torture test of the
+// <ACE_SOCK_Acceptor> and <ACE_SOCK_Connector> classes. The test
+// forks 30 processes or spawns 30 threads (depending upon the
+// platform) and then executes client and server allowing them to
+// connect and exchange data. Note that most of the connections
+// will fail since we're overrunning the size of the listen queue
+// for the acceptor-mode socket.
+//
+// = AUTHOR
+// Doug Schmidt <schmidt@cs.wustl.edu>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/OS_NS_sys_select.h"
+#include "ace/OS_NS_sys_wait.h"
+#include "ace/OS_NS_unistd.h"
+#include "ace/Thread.h"
+#include "ace/Thread_Manager.h"
+#include "ace/SOCK_Connector.h"
+#include "ace/SOCK_Acceptor.h"
+#include "ace/Handle_Set.h"
+#include "ace/Time_Value.h"
+
+ACE_RCSID(tests, MT_SOCK_Test, "$Id$")
+
+static const char ACE_ALPHABET[] = "abcdefghijklmnopqrstuvwxyz";
+
+// Normally the test will have BACKLOG < NUM_CLIENTS to force some
+// of the connections to fail.
+// Do NOT use ACE_DEFAULT_BACKLOG here, because that will likely
+// be set to some other value. (i.e. Win32 = SOMAXCONN)
+static const int BACKLOG = 5;
+static const int NUM_CLIENTS = 30;
+
+#if !defined (ACE_LACKS_FORK) || defined (ACE_HAS_THREADS)
+
+static void *
+client (void *arg)
+{
+ ACE_INET_Addr *remote_addr = (ACE_INET_Addr *) arg;
+ ACE_INET_Addr server_addr (remote_addr->get_port_number (),
+ ACE_DEFAULT_SERVER_HOST);
+ ACE_INET_Addr client_addr;
+ ACE_SOCK_Stream cli_stream;
+ ACE_SOCK_Connector con;
+#if defined (ACE_HAS_BROKEN_NON_BLOCKING_CONNECTS)
+ ACE_Time_Value *timeout = 0;
+#else
+ ACE_Time_Value tv (ACE_DEFAULT_TIMEOUT);
+ ACE_Time_Value *timeout = &tv;
+#endif /* ACE_HAS_BROKEN_NON_BLOCKING_CONNECTS */
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) client: Connecting...\n")));
+ // Initiate timed connection with server.
+
+ // Attempt a timed connect to the server.
+ if (con.connect (cli_stream,
+ server_addr,
+ timeout) == -1)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) %p\n"),
+ ACE_TEXT ("client: Connection timed out.")));
+ return 0;
+ }
+
+ if (cli_stream.get_local_addr (client_addr) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n"),
+ ACE_TEXT ("client: get_local_addr")),
+ 0);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) client: Connected at %d\n"),
+ client_addr.get_port_number ()));
+
+ if (cli_stream.disable (ACE_NONBLOCK) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n"),
+ ACE_TEXT ("client: disable")));
+
+ // Send data to server (correctly handles "incomplete writes").
+
+ ACE_DEBUG ((LM_DEBUG, "(%P|%t) client: Sending data...\n"));
+
+ for (const char *c = ACE_ALPHABET; *c != '\0'; c++)
+ if (cli_stream.send_n (c, 1) == -1)
+ {
+ // This is, I believe, more of an issue with WinXP-64 _server_
+ // side, but we can trap it here since we know we're connecting
+ // to localhost. It appears, though I haven't found documentation
+ // stating, that WinXP-64 will appear to accept connections at the
+ // TCP level past the listen backlog but if data arrives before the
+ // actual application-level accept() occurs, the connection is reset.
+ // So, if we get a reset on the first send, don't flag the error -
+ // just note it and act like the connection was refused.
+ if (c == ACE_ALPHABET && errno == ECONNRESET) // First byte sent
+ {
+ ACE_DEBUG
+ ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) client: Connection refused (delayed)\n")));
+ cli_stream.close ();
+ return 0;
+ }
+
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) (errno %d) %p\n"), errno,
+ ACE_TEXT ("client: send_n")));
+ ACE_ERROR ((LM_ERROR, "client: Closing stream.\n"));
+ cli_stream.close();
+ return 0;
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) client: Closing writer...\n")));
+
+ // Explicitly close the writer-side of the connection.
+ if (cli_stream.close_writer () == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n"),
+ ACE_TEXT ("client: close_writer")));
+ char buf[1];
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) client: Waiting for server handshake...\n")));
+
+ // Wait for handshake with server.
+ if (cli_stream.recv_n (buf, 1) != 1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n"),
+ ACE_TEXT ("client: recv_n")));
+
+ ACE_DEBUG
+ ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) client: Handshake received. Closing stream.\n")));
+
+ // Close the connection completely.
+ if (cli_stream.close () == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n"),
+ ACE_TEXT ("client: close")));
+ return 0;
+}
+
+static void *
+server (void *arg)
+{
+ ACE_SOCK_Acceptor *peer_acceptor =
+ static_cast<ACE_SOCK_Acceptor *> (arg);
+
+ if (peer_acceptor->enable (ACE_NONBLOCK) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n"),
+ ACE_TEXT ("server: enable acceptor")));
+
+ // Keep these objects out here to prevent excessive constructor
+ // calls...
+ ACE_SOCK_Stream new_stream;
+ ACE_INET_Addr cli_addr;
+ ACE_Handle_Set handle_set;
+ const ACE_Time_Value def_timeout (ACE_DEFAULT_TIMEOUT);
+ ACE_Time_Value tv (def_timeout);
+
+ // We want some of the clients to get connection failures, but on
+ // a really fast machine with a good network card and multiple
+ // processors this may never happen.
+ // Add a sleep() to allow the client threads to complete.
+ ACE_OS::sleep(def_timeout);
+
+ int num_clients_connected = 0;
+
+ // Performs the iterative server activities.
+ for (;;)
+ {
+ char buf[BUFSIZ];
+
+ handle_set.reset ();
+ handle_set.set_bit (peer_acceptor->get_handle ());
+
+ ACE_DEBUG((LM_DEBUG, "(%P|%t) server: Waiting for connection...\n"));
+
+ int select_width;
+# if defined (ACE_WIN64)
+ // This arg is ignored on Windows and causes pointer truncation
+ // warnings on 64-bit compiles.
+ select_width = 0;
+# else
+ select_width = int (peer_acceptor->get_handle ()) + 1;
+# endif /* ACE_WIN64 */
+ int result = ACE_OS::select (select_width, handle_set, 0, 0, &tv);
+ ACE_ASSERT (tv == def_timeout);
+
+ if (result == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n"),
+ ACE_TEXT ("server: select acceptor")),
+ 0);
+ else if (result == 0)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) server: Test finished.\n")));
+ // The meaning of the backlog parameter for listen() varies by
+ // platform. For some reason lost to history, the specified value
+ // is typically backlog * 1.5, backlog * 1.5 + 1, or event taken
+ // literally as on Windows. We'll accept any number less than
+ // backlog * 2 as valid.
+ if (num_clients_connected >= BACKLOG * 2)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) server: Incorrect # client ")
+ ACE_TEXT ("connections. Expected:%d-%d Actual:%d\n"),
+ BACKLOG, BACKLOG * 2, num_clients_connected));
+ return 0;
+ }
+
+ // Create a new ACE_SOCK_Stream endpoint (note automatic restart
+ // if errno == EINTR).
+
+ while ((result = peer_acceptor->accept (new_stream,
+ &cli_addr)) != -1)
+ {
+ const char *t = ACE_ALPHABET;
+
+ ++num_clients_connected;
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) server: Client %C connected from %d\n"),
+ cli_addr.get_host_name (),
+ cli_addr.get_port_number ()));
+
+ // Enable non-blocking I/O.
+ if (new_stream.enable (ACE_NONBLOCK) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n"),
+ ACE_TEXT ("server: enable non blocking i/o")),
+ 0);
+ handle_set.reset ();
+ handle_set.set_bit (new_stream.get_handle ());
+
+ // Read data from client (terminate on error).
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) server: Waiting for data...\n")));
+
+ for (ssize_t r_bytes; ;)
+ {
+ int select_width;
+# if defined (ACE_WIN64)
+ // This arg is ignored on Windows and causes pointer truncation
+ // warnings on 64-bit compiles.
+ select_width = 0;
+# else
+ select_width = int (new_stream.get_handle ()) + 1;
+# endif /* ACE_WIN64 */
+ if (ACE_OS::select (select_width,
+ handle_set,
+ 0, 0, 0) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n"),
+ ACE_TEXT ("select")),
+ 0);
+
+ ACE_DEBUG ((LM_DEBUG, "(%P|%t) server: Receiving data...\n"));
+
+ while ((r_bytes = new_stream.recv (buf, 1)) > 0)
+ {
+ ACE_ASSERT (*t == buf[0]);
+ t++;
+ }
+
+ ACE_DEBUG((LM_DEBUG, "(%P|%t) server: Received data.\n"));
+
+ if (r_bytes == 0)
+ {
+ // Handshake back with client.
+ ACE_DEBUG
+ ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) server: Connection closed by client.\n")));
+
+ ACE_DEBUG
+ ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) server: Sending handshake.\n")));
+
+ if (new_stream.send_n ("", 1) != 1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n"),
+ ACE_TEXT ("server: send_n")));
+
+ ACE_DEBUG ((LM_DEBUG, "(%P|%t) server: Closing stream.\n"));
+
+ // Close endpoint.
+ if (new_stream.close () == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n"),
+ ACE_TEXT ("server: close")));
+ break;
+ }
+ else if (r_bytes == -1)
+ {
+ if (errno == EWOULDBLOCK || errno == EAGAIN)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) server: (EWOULDBLOCK) Waiting for more data...\n")));
+ else
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n"),
+ ACE_TEXT ("server: recv_n")),
+ 0);
+ }
+ }
+ }
+ if (result == -1)
+ {
+ if (errno == EWOULDBLOCK)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) server: No more connections pending.\n")));
+ else
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n"),
+ ACE_TEXT ("server: accept")));
+ }
+ }
+ ACE_NOTREACHED (return 0);
+}
+
+#endif /* !ACE_LACKS_FORK || ACE_HAS_THREADS */
+
+static void
+spawn (int num_clients)
+{
+ // Acceptor
+ ACE_SOCK_Acceptor peer_acceptor;
+
+ // Create a server address.
+ ACE_INET_Addr server_addr;
+
+ // Bind listener to any port and then find out what the port was.
+ if (peer_acceptor.open (ACE_Addr::sap_any, 0, PF_UNSPEC, BACKLOG) == -1
+ || peer_acceptor.get_local_addr (server_addr) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n"),
+ ACE_TEXT ("spawn: open")));
+ else
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) starting server at port %d\n"),
+ server_addr.get_port_number ()));
+
+#if !defined (ACE_LACKS_FORK)
+ for (int i = 0; i < num_clients; i++)
+ {
+ switch (ACE_OS::fork (ACE_TEXT ("child")))
+ {
+ case -1:
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n"), "spawn: fork failed"));
+ i = num_clients;
+ // Break out of 'for' loop.
+ break;
+ case 0:
+ client (&server_addr);
+ exit (0);
+ /* NOTREACHED */
+ default:
+ break;
+ }
+ }
+
+ server ((void *) &peer_acceptor);
+
+ peer_acceptor.close();
+
+ // Reap the child pids.
+ for (pid_t pid; (pid = ACE_OS::wait ()) != -1; )
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) spawn: reaping pid %d\n"), pid));
+
+#elif defined (ACE_HAS_THREADS)
+
+ ACE_DEBUG((LM_DEBUG, "Spawning server...\n"));
+
+ if (ACE_Thread_Manager::instance ()->spawn
+ (ACE_THR_FUNC (server),
+ (void *) &peer_acceptor,
+ THR_BOUND | THR_DETACHED) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n%a"),
+ ACE_TEXT ("spawn: failed"),
+ 1));
+
+ ACE_DEBUG((LM_DEBUG, "Spawning %d clients...\n", num_clients));
+
+ if (ACE_Thread_Manager::instance ()->spawn_n
+ (num_clients,
+ ACE_THR_FUNC (client),
+ (void *) &server_addr,
+ THR_BOUND | THR_DETACHED) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n%a"),
+ ACE_TEXT ("spawn: failed 2"),
+ 1));
+
+ ACE_DEBUG((LM_DEBUG, "Waiting for threads to finish...\n"));
+
+ // Wait for the threads to exit.
+ ACE_Thread_Manager::instance ()->wait ();
+#else
+ ACE_ERROR ((LM_INFO,
+ ACE_TEXT ("(%P|%t) ")
+ ACE_TEXT ("spawn: only one thread may be run")
+ ACE_TEXT (" in a process on this platform\n")));
+#endif /* !ACE_LACKS_FORK */
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Threads complete. Closing Acceptor.\n")));
+
+ peer_acceptor.close ();
+ }
+}
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("MT_SOCK_Test"));
+
+ spawn (NUM_CLIENTS);
+
+ ACE_END_TEST;
+ return 0;
+}
diff --git a/ACE/tests/Main.cpp b/ACE/tests/Main.cpp
new file mode 100644
index 00000000000..44b92128394
--- /dev/null
+++ b/ACE/tests/Main.cpp
@@ -0,0 +1,30 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Main.cpp
+//
+// = DESCRIPTION
+// This is a wrapper for the test programs. It obviates the test cpp's
+// from having to always include OS.h.
+//
+// = AUTHOR
+// Don Hinton <dhinton@dresystems.com>
+//
+// ============================================================================
+
+#include "ace/OS_main.h"
+#if defined (ACE_HAS_WINCE)
+# include "ace/ACE.h"
+#endif /* ACE_HAS_WINCE */
+int run_main (int argc, ACE_TCHAR *argv[]);
+
+int
+ACE_TMAIN (int argc, ACE_TCHAR *argv[])
+{
+ return run_main (argc, argv);
+}
diff --git a/ACE/tests/Makefile.am b/ACE/tests/Makefile.am
new file mode 100644
index 00000000000..82a7bd50dc5
--- /dev/null
+++ b/ACE/tests/Makefile.am
@@ -0,0 +1,3004 @@
+## Process this file with automake to create Makefile.in
+##
+## $Id$
+##
+## This file was generated by MPC. Any changes made directly to
+## this file will be lost the next time it is generated.
+##
+## MPC Command:
+## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu
+
+ACE_BUILDDIR = $(top_builddir)
+ACE_ROOT = $(top_srcdir)
+
+SUBDIRS = \
+ . \
+ HTBP \
+ SSL
+
+
+## Makefile.Test_Output.am
+
+noinst_SCRIPTS = run_test.pl run_test.lst
+
+dist_check_SCRIPTS = run_test.pl run_test.lst
+TESTS = $(noinst_PROGRAMS)
+TESTS_ENVIRONMENT = $(srcdir)/run_test.pl -t
+
+noinst_LTLIBRARIES = libTest_Output.la
+
+libTest_Output_la_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR) \
+ -DTEST_OUTPUT_BUILD_DLL
+
+libTest_Output_la_SOURCES = \
+ Test_Output.cpp
+
+noinst_HEADERS = \
+ Test_Output_Export.h \
+ test_config.h
+
+## Makefile.ACE_Init_Test.am
+noinst_PROGRAMS = ACE_Init_Test
+
+ACE_Init_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+ACE_Init_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ ACE_Init_Test.cpp \
+ ACE_Init_Test.h
+
+ACE_Init_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+EXTRA_DIST = \
+ ACE_Init_Test.rc
+
+
+## Makefile.ACE_Test.am
+noinst_PROGRAMS += ACE_Test
+
+ACE_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+ACE_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ ACE_Test.cpp
+
+ACE_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.ARGV_Test.am
+noinst_PROGRAMS += ARGV_Test
+
+ARGV_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+ARGV_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ ARGV_Test.cpp
+
+ARGV_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.Aio_Platform_Test.am
+noinst_PROGRAMS += Aio_Platform_Test
+
+Aio_Platform_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Aio_Platform_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Aio_Platform_Test.cpp
+
+Aio_Platform_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.Arg_Shifter_Test.am
+noinst_PROGRAMS += Arg_Shifter_Test
+
+Arg_Shifter_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Arg_Shifter_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Arg_Shifter_Test.cpp
+
+Arg_Shifter_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.Array_Map_Test.am
+noinst_PROGRAMS += Array_Map_Test
+
+Array_Map_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Array_Map_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Array_Map_Test.cpp
+
+Array_Map_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.Atomic_Op_Test.am
+noinst_PROGRAMS += Atomic_Op_Test
+
+Atomic_Op_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Atomic_Op_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Atomic_Op_Test.cpp
+
+Atomic_Op_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.Auto_Event_Test.am
+noinst_PROGRAMS += Auto_Event_Test
+
+Auto_Event_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Auto_Event_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Auto_Event_Test.cpp
+
+Auto_Event_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.Auto_IncDec_Test.am
+noinst_PROGRAMS += Auto_IncDec_Test
+
+Auto_IncDec_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Auto_IncDec_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Auto_IncDec_Test.cpp
+
+Auto_IncDec_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.Barrier_Test.am
+noinst_PROGRAMS += Barrier_Test
+
+Barrier_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Barrier_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Barrier_Test.cpp
+
+Barrier_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.Based_Pointer_Test_Lib.am
+
+if !BUILD_ACE_FOR_TAO
+
+noinst_LTLIBRARIES += libBased_Pointer_Test_Lib.la
+
+libBased_Pointer_Test_Lib_la_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR) \
+ -DACE_SVC_BUILD_DLL
+
+libBased_Pointer_Test_Lib_la_SOURCES = \
+ Based_Pointer_Test_Lib.cpp
+
+noinst_HEADERS += \
+ ACE_Init_Test.h \
+ ACE_Init_TestDlg.h \
+ ACE_Init_Test_Resource.h \
+ ACE_Init_Test_StdAfx.h \
+ Bound_Ptr_Test.h \
+ CE_fostream.h \
+ Cache_Map_Manager_Test.h \
+ Cached_Accept_Conn_Test.h \
+ Cached_Conn_Test.h \
+ Collection_Test.h \
+ Config_Test.h \
+ Conn_Test.h \
+ DLL_Test.h \
+ DLL_Test_Impl.h \
+ DLL_Test_Parent.h \
+ DLL_Test_Parent_Export.h \
+ Framework_Component_DLL.h \
+ Framework_Component_DLL_Export.h \
+ Framework_Component_Test.h \
+ MEM_Stream_Test.h \
+ MT_Reactor_Timer_Test.h \
+ Malloc_Test.h \
+ Map_Test.h \
+ Max_Default_Port_Test.h \
+ Message_Queue_Test_Ex.h \
+ Network_Adapters_Test.h \
+ NonBlocking_Conn_Test.h \
+ Priority_Reactor_Test.h \
+ Proactor_Test.h \
+ Process_Strategy_Test.h \
+ QtReactor_Test.h \
+ RB_Tree_Test.h \
+ Reactor_Performance_Test.h \
+ Refcounted_Auto_Ptr_Test.h \
+ Service_Config_DLL.h \
+ Service_Config_DLL_Export.h \
+ TP_Reactor_Test.h \
+ TSS_Test_Errno.h \
+ Task_Ex_Test.h \
+ Test_Output_Export.h \
+ Thread_Pool_Reactor_Resume_Test.h \
+ Thread_Pool_Reactor_Test.h \
+ Upgradable_RW_Test.h \
+ test_config.h
+
+endif !BUILD_ACE_FOR_TAO
+
+## Makefile.Based_Pointer_Test.am
+
+if !BUILD_ACE_FOR_TAO
+noinst_PROGRAMS += Based_Pointer_Test
+
+Based_Pointer_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Based_Pointer_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Based_Pointer_Test.cpp
+
+Based_Pointer_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_ACE_FOR_TAO
+
+## Makefile.Basic_Types_Test.am
+noinst_PROGRAMS += Basic_Types_Test
+
+Basic_Types_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Basic_Types_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Basic_Types_Test.cpp
+
+Basic_Types_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.Bound_Ptr_Test.am
+
+if !BUILD_ACE_FOR_TAO
+noinst_PROGRAMS += Bound_Ptr_Test
+
+Bound_Ptr_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Bound_Ptr_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Bound_Ptr_Test.cpp \
+ Bound_Ptr_Test.h
+
+Bound_Ptr_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_ACE_FOR_TAO
+
+## Makefile.Buffer_Stream_Test.am
+noinst_PROGRAMS += Buffer_Stream_Test
+
+Buffer_Stream_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Buffer_Stream_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Buffer_Stream_Test.cpp
+
+Buffer_Stream_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.Bug_1576_Regression_Test.am
+noinst_PROGRAMS += Bug_1576_Regression_Test
+
+Bug_1576_Regression_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Bug_1576_Regression_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Bug_1576_Regression_Test.cpp
+
+Bug_1576_Regression_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.Bug_2368_Regression_Test.am
+noinst_PROGRAMS += Bug_2368_Regression_Test
+
+Bug_2368_Regression_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Bug_2368_Regression_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Bug_2368_Regression_Test.cpp
+
+Bug_2368_Regression_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.Bug_2497_Regression_Test.am
+noinst_PROGRAMS += Bug_2497_Regression_Test
+
+Bug_2497_Regression_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Bug_2497_Regression_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Bug_2497_Regression_Test.cpp
+
+Bug_2497_Regression_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.CDR_Array_Test.am
+
+if !BUILD_ACE_FOR_TAO
+noinst_PROGRAMS += CDR_Array_Test
+
+CDR_Array_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+CDR_Array_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ CDR_Array_Test.cpp
+
+CDR_Array_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_ACE_FOR_TAO
+
+## Makefile.CDR_File_Test.am
+
+if !BUILD_ACE_FOR_TAO
+noinst_PROGRAMS += CDR_File_Test
+
+CDR_File_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+CDR_File_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ CDR_File_Test.cpp \
+ CE_fostream.cpp \
+ CE_fostream.h
+
+CDR_File_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_ACE_FOR_TAO
+
+## Makefile.CDR_Test.am
+noinst_PROGRAMS += CDR_Test
+
+CDR_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+CDR_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ CDR_Test.cpp
+
+CDR_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.Cache_Map_Manager_Test.am
+noinst_PROGRAMS += Cache_Map_Manager_Test
+
+Cache_Map_Manager_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Cache_Map_Manager_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Cache_Map_Manager_Test.cpp \
+ Cache_Map_Manager_Test.h
+
+Cache_Map_Manager_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.Cached_Accept_Conn_Test.am
+
+if !BUILD_ACE_FOR_TAO
+noinst_PROGRAMS += Cached_Accept_Conn_Test
+
+Cached_Accept_Conn_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Cached_Accept_Conn_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Cached_Accept_Conn_Test.cpp \
+ Cached_Accept_Conn_Test.h
+
+Cached_Accept_Conn_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_ACE_FOR_TAO
+
+## Makefile.Cached_Allocator_Test.am
+
+if !BUILD_ACE_FOR_TAO
+noinst_PROGRAMS += Cached_Allocator_Test
+
+Cached_Allocator_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Cached_Allocator_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Cached_Allocator_Test.cpp
+
+Cached_Allocator_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_ACE_FOR_TAO
+
+## Makefile.Cached_Conn_Test.am
+
+if !BUILD_ACE_FOR_TAO
+noinst_PROGRAMS += Cached_Conn_Test
+
+Cached_Conn_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Cached_Conn_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Cached_Conn_Test.cpp \
+ Cached_Conn_Test.h
+
+Cached_Conn_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_ACE_FOR_TAO
+
+## Makefile.Capabilities_Test.am
+
+if !BUILD_ACE_FOR_TAO
+noinst_PROGRAMS += Capabilities_Test
+
+Capabilities_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Capabilities_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Capabilities_Test.cpp
+
+Capabilities_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_ACE_FOR_TAO
+
+## Makefile.Codecs_Test.am
+
+if BUILD_ACE_CODECS
+if !BUILD_ACE_FOR_TAO
+noinst_PROGRAMS += Codecs_Test
+
+Codecs_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Codecs_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Codecs_Test.cpp
+
+Codecs_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_ACE_FOR_TAO
+endif BUILD_ACE_CODECS
+
+## Makefile.Collection_Test.am
+noinst_PROGRAMS += Collection_Test
+
+Collection_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Collection_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Collection_Test.cpp \
+ Collection_Test.h
+
+Collection_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.Config_Test.am
+
+if !BUILD_ACE_FOR_TAO
+noinst_PROGRAMS += Config_Test
+
+Config_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Config_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Config_Test.cpp \
+ Config_Test.h
+
+Config_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_ACE_FOR_TAO
+
+## Makefile.Conn_Test.am
+
+if !BUILD_ACE_FOR_TAO
+noinst_PROGRAMS += Conn_Test
+
+Conn_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Conn_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Conn_Test.cpp \
+ Conn_Test.h
+
+Conn_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_ACE_FOR_TAO
+
+## Makefile.DLL_Test_Parent_Lib.am
+
+noinst_LTLIBRARIES += libDLL_Test_Parent.la
+
+libDLL_Test_Parent_la_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR) \
+ -DDLL_TEST_PARENT_BUILD_DLL
+
+libDLL_Test_Parent_la_SOURCES = \
+ DLL_Test_Parent.cpp
+
+noinst_HEADERS += \
+ DLL_Test_Parent.h \
+ DLL_Test_Parent_Export.h \
+ test_config.h
+
+## Makefile.DLL_Test_Lib.am
+
+noinst_LTLIBRARIES += libDLL_Test_Lib.la
+
+libDLL_Test_Lib_la_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR) \
+ -DACE_SVC_BUILD_DLL
+
+libDLL_Test_Lib_la_SOURCES = \
+ DLL_Test_Impl.cpp
+
+noinst_HEADERS += \
+ DLL_Test_Impl.h \
+ test_config.h
+
+## Makefile.DLL_Test.am
+noinst_PROGRAMS += DLL_Test
+
+DLL_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+DLL_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ DLL_Test.cpp \
+ DLL_Test.h
+
+DLL_Test_LDADD = \
+ libDLL_Test_Lib.la \
+ libDLL_Test_Parent.la \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.DLList_Test.am
+
+if !BUILD_ACE_FOR_TAO
+noinst_PROGRAMS += DLList_Test
+
+DLList_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+DLList_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ DLList_Test.cpp
+
+DLList_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_ACE_FOR_TAO
+
+## Makefile.Date_Time_Test.am
+
+if !BUILD_ACE_FOR_TAO
+noinst_PROGRAMS += Date_Time_Test
+
+Date_Time_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Date_Time_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Date_Time_Test.cpp
+
+Date_Time_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_ACE_FOR_TAO
+
+## Makefile.Dev_Poll_Reactor_Test.am
+noinst_PROGRAMS += Dev_Poll_Reactor_Test
+
+Dev_Poll_Reactor_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Dev_Poll_Reactor_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Dev_Poll_Reactor_Test.cpp
+
+Dev_Poll_Reactor_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.Dirent_Test.am
+noinst_PROGRAMS += Dirent_Test
+
+Dirent_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Dirent_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Dirent_Test.cpp
+
+Dirent_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.Dynamic_Priority_Test.am
+noinst_PROGRAMS += Dynamic_Priority_Test
+
+Dynamic_Priority_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Dynamic_Priority_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Dynamic_Priority_Test.cpp
+
+Dynamic_Priority_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.Enum_Interfaces_Test.am
+noinst_PROGRAMS += Enum_Interfaces_Test
+
+Enum_Interfaces_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Enum_Interfaces_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Enum_Interfaces_Test.cpp
+
+Enum_Interfaces_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.Env_Value_Test.am
+noinst_PROGRAMS += Env_Value_Test
+
+Env_Value_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Env_Value_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Env_Value_Test.cpp
+
+Env_Value_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.FIFO_Test.am
+
+if !BUILD_ACE_FOR_TAO
+noinst_PROGRAMS += FIFO_Test
+
+FIFO_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+FIFO_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ FIFO_Test.cpp
+
+FIFO_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_ACE_FOR_TAO
+
+## Makefile.FlReactor_Test.am
+
+if BUILD_ACE_FLREACTOR
+if BUILD_FL
+if BUILD_GL
+if BUILD_X11
+
+noinst_PROGRAMS += FlReactor_Test
+
+FlReactor_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR) \
+ $(ACE_FLTK_CPPFLAGS)
+
+FlReactor_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ FlReactor_Test.cpp
+
+FlReactor_Test_LDFLAGS = \
+ $(ACE_FLTK_LDFLAGS)
+
+FlReactor_Test_LDADD = \
+ $(ACE_BUILDDIR)/ace/libACE_FlReactor.la \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la \
+ $(ACE_FLTK_LIBS)
+
+endif BUILD_X11
+endif BUILD_GL
+endif BUILD_FL
+endif BUILD_ACE_FLREACTOR
+
+## Makefile.Framework_Component_DLL.am
+
+noinst_LTLIBRARIES += libFramework_Component_DLL.la
+
+libFramework_Component_DLL_la_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR) \
+ -DFRAMEWORK_COMPONENT_DLL_BUILD_DLL
+
+libFramework_Component_DLL_la_SOURCES = \
+ Framework_Component_DLL.cpp
+
+noinst_HEADERS += \
+ Framework_Component_DLL.h \
+ Framework_Component_DLL_Export.h
+
+## Makefile.Framework_Component_Test.am
+noinst_PROGRAMS += Framework_Component_Test
+
+Framework_Component_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Framework_Component_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Framework_Component_Test.cpp \
+ Framework_Component_Test.h
+
+Framework_Component_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.Future_Set_Test.am
+
+if !BUILD_ACE_FOR_TAO
+noinst_PROGRAMS += Future_Set_Test
+
+Future_Set_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Future_Set_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Future_Set_Test.cpp
+
+Future_Set_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_ACE_FOR_TAO
+
+## Makefile.Future_Test.am
+
+if !BUILD_ACE_FOR_TAO
+noinst_PROGRAMS += Future_Test
+
+Future_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Future_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Future_Test.cpp
+
+Future_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_ACE_FOR_TAO
+
+## Makefile.Get_Opt_Test.am
+noinst_PROGRAMS += Get_Opt_Test
+
+Get_Opt_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Get_Opt_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Get_Opt_Test.cpp
+
+Get_Opt_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.Handle_Set_Test.am
+
+if !BUILD_ACE_FOR_TAO
+noinst_PROGRAMS += Handle_Set_Test
+
+Handle_Set_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Handle_Set_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Handle_Set_Test.cpp
+
+Handle_Set_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_ACE_FOR_TAO
+
+## Makefile.Hash_Map_Bucket_Iterator_Test.am
+noinst_PROGRAMS += Hash_Map_Bucket_Iterator_Test
+
+Hash_Map_Bucket_Iterator_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Hash_Map_Bucket_Iterator_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Hash_Map_Bucket_Iterator_Test.cpp
+
+Hash_Map_Bucket_Iterator_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.Hash_Map_Manager_Test.am
+noinst_PROGRAMS += Hash_Map_Manager_Test
+
+Hash_Map_Manager_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Hash_Map_Manager_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Hash_Map_Manager_Test.cpp
+
+Hash_Map_Manager_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.High_Res_Timer_Test.am
+
+if !BUILD_ACE_FOR_TAO
+noinst_PROGRAMS += High_Res_Timer_Test
+
+High_Res_Timer_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+High_Res_Timer_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ High_Res_Timer_Test.cpp
+
+High_Res_Timer_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_ACE_FOR_TAO
+
+## Makefile.INET_Addr_Test.am
+noinst_PROGRAMS += INET_Addr_Test
+
+INET_Addr_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+INET_Addr_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ INET_Addr_Test.cpp
+
+INET_Addr_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.INET_Addr_Test_IPV6.am
+noinst_PROGRAMS += INET_Addr_Test_IPV6
+
+INET_Addr_Test_IPV6_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+INET_Addr_Test_IPV6_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ INET_Addr_Test_IPV6.cpp
+
+INET_Addr_Test_IPV6_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.IOStream_Test.am
+noinst_PROGRAMS += IOStream_Test
+
+IOStream_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+IOStream_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ IOStream_Test.cpp
+
+IOStream_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.Lazy_Map_Manager_Test.am
+noinst_PROGRAMS += Lazy_Map_Manager_Test
+
+Lazy_Map_Manager_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Lazy_Map_Manager_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Lazy_Map_Manager_Test.cpp
+
+Lazy_Map_Manager_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.Library_Unload.am
+noinst_PROGRAMS += UnloadLibACE
+
+UnloadLibACE_SOURCES = \
+ Unload_libACE.cpp \
+ ACE_Init_Test.h \
+ ACE_Init_TestDlg.h \
+ ACE_Init_Test_Resource.h \
+ ACE_Init_Test_StdAfx.h \
+ Bound_Ptr_Test.h \
+ CE_fostream.h \
+ Cache_Map_Manager_Test.h \
+ Cached_Accept_Conn_Test.h \
+ Cached_Conn_Test.h \
+ Collection_Test.h \
+ Config_Test.h \
+ Conn_Test.h \
+ DLL_Test.h \
+ DLL_Test_Impl.h \
+ DLL_Test_Parent.h \
+ DLL_Test_Parent_Export.h \
+ Framework_Component_DLL.h \
+ Framework_Component_DLL_Export.h \
+ Framework_Component_Test.h \
+ MEM_Stream_Test.h \
+ MT_Reactor_Timer_Test.h \
+ Malloc_Test.h \
+ Map_Test.h \
+ Max_Default_Port_Test.h \
+ Message_Queue_Test_Ex.h \
+ Network_Adapters_Test.h \
+ NonBlocking_Conn_Test.h \
+ Priority_Reactor_Test.h \
+ Proactor_Test.h \
+ Process_Strategy_Test.h \
+ QtReactor_Test.h \
+ RB_Tree_Test.h \
+ Reactor_Performance_Test.h \
+ Refcounted_Auto_Ptr_Test.h \
+ Service_Config_DLL.h \
+ Service_Config_DLL_Export.h \
+ TP_Reactor_Test.h \
+ TSS_Test_Errno.h \
+ Task_Ex_Test.h \
+ Test_Output_Export.h \
+ Thread_Pool_Reactor_Resume_Test.h \
+ Thread_Pool_Reactor_Test.h \
+ Upgradable_RW_Test.h \
+ test_config.h
+
+## Makefile.Log_Msg_Test.am
+
+if !BUILD_ACE_FOR_TAO
+noinst_PROGRAMS += Log_Msg_Test
+
+Log_Msg_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Log_Msg_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Log_Msg_Test.cpp
+
+Log_Msg_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_ACE_FOR_TAO
+
+## Makefile.Logging_Strategy_Test.am
+noinst_PROGRAMS += Logging_Strategy_Test
+
+Logging_Strategy_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Logging_Strategy_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Logging_Strategy_Test.cpp
+
+Logging_Strategy_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.MEM_Stream_Test.am
+
+if !BUILD_ACE_FOR_TAO
+noinst_PROGRAMS += MEM_Stream_Test
+
+MEM_Stream_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+MEM_Stream_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ MEM_Stream_Test.cpp \
+ MEM_Stream_Test.h
+
+MEM_Stream_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_ACE_FOR_TAO
+
+## Makefile.MM_Shared_Memory_Test.am
+
+if !BUILD_ACE_FOR_TAO
+noinst_PROGRAMS += MM_Shared_Memory_Test
+
+MM_Shared_Memory_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+MM_Shared_Memory_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ MM_Shared_Memory_Test.cpp
+
+MM_Shared_Memory_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_ACE_FOR_TAO
+
+## Makefile.MT_Reactor_Timer_Test.am
+noinst_PROGRAMS += MT_Reactor_Timer_Test
+
+MT_Reactor_Timer_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+MT_Reactor_Timer_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ MT_Reactor_Timer_Test.cpp \
+ MT_Reactor_Timer_Test.h
+
+MT_Reactor_Timer_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.MT_Reactor_Upcall_Test.am
+noinst_PROGRAMS += MT_Reactor_Upcall_Test
+
+MT_Reactor_Upcall_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+MT_Reactor_Upcall_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ MT_Reactor_Upcall_Test.cpp
+
+MT_Reactor_Upcall_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.MT_Ref_Counted_Event_Handler_Test.am
+noinst_PROGRAMS += MT_Reference_Counted_Event_Handler_Test
+
+MT_Reference_Counted_Event_Handler_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+MT_Reference_Counted_Event_Handler_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ MT_Reference_Counted_Event_Handler_Test.cpp
+
+MT_Reference_Counted_Event_Handler_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.MT_Reference_Counted_Notify_Test.am
+noinst_PROGRAMS += MT_Reference_Counted_Notify_Test
+
+MT_Reference_Counted_Notify_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+MT_Reference_Counted_Notify_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ MT_Reference_Counted_Notify_Test.cpp
+
+MT_Reference_Counted_Notify_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.MT_SOCK_Test.am
+noinst_PROGRAMS += MT_SOCK_Test
+
+MT_SOCK_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+MT_SOCK_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ MT_SOCK_Test.cpp
+
+MT_SOCK_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.Malloc_Test.am
+
+if !BUILD_ACE_FOR_TAO
+noinst_PROGRAMS += Malloc_Test
+
+Malloc_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Malloc_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Malloc_Test.cpp \
+ Malloc_Test.h
+
+Malloc_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_ACE_FOR_TAO
+
+## Makefile.Manual_Event_Test.am
+noinst_PROGRAMS += Manual_Event_Test
+
+Manual_Event_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Manual_Event_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Manual_Event_Test.cpp
+
+Manual_Event_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.Map_Manager_Test.am
+
+if !BUILD_ACE_FOR_TAO
+noinst_PROGRAMS += Map_Manager_Test
+
+Map_Manager_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Map_Manager_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Map_Manager_Test.cpp
+
+Map_Manager_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_ACE_FOR_TAO
+
+## Makefile.Map_Test.am
+
+if !BUILD_ACE_FOR_TAO
+noinst_PROGRAMS += Map_Test
+
+Map_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Map_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Map_Test.cpp \
+ Map_Test.h
+
+Map_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_ACE_FOR_TAO
+
+## Makefile.Max_Default_Port_Test.am
+noinst_PROGRAMS += Max_Default_Port_Test
+
+Max_Default_Port_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Max_Default_Port_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Max_Default_Port_Test.cpp \
+ Max_Default_Port_Test.h
+
+Max_Default_Port_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.Max_Default_Port_Test_IPV6.am
+noinst_PROGRAMS += Max_Default_Port_Test_IPV6
+
+Max_Default_Port_Test_IPV6_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Max_Default_Port_Test_IPV6_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Max_Default_Port_Test_IPV6.cpp
+
+Max_Default_Port_Test_IPV6_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.Mem_Map_Test.am
+
+if !BUILD_ACE_FOR_TAO
+noinst_PROGRAMS += Mem_Map_Test
+
+Mem_Map_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Mem_Map_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Mem_Map_Test.cpp
+
+Mem_Map_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_ACE_FOR_TAO
+
+## Makefile.Memcpy_Test.am
+
+if !BUILD_ACE_FOR_TAO
+noinst_PROGRAMS += Memcpy_Test
+
+Memcpy_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Memcpy_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Memcpy_Test.cpp
+
+Memcpy_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_ACE_FOR_TAO
+
+## Makefile.Message_Block_Test.am
+
+if !BUILD_ACE_FOR_TAO
+noinst_PROGRAMS += Message_Block_Test
+
+Message_Block_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Message_Block_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Message_Block_Test.cpp
+
+Message_Block_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_ACE_FOR_TAO
+
+## Makefile.Message_Queue_Notifications_Test.am
+noinst_PROGRAMS += Message_Queue_Notifications_Test
+
+Message_Queue_Notifications_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Message_Queue_Notifications_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Message_Queue_Notifications_Test.cpp
+
+Message_Queue_Notifications_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.Message_Queue_Test.am
+
+if !BUILD_ACE_FOR_TAO
+noinst_PROGRAMS += Message_Queue_Test
+
+Message_Queue_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Message_Queue_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Message_Queue_Test.cpp
+
+Message_Queue_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_ACE_FOR_TAO
+
+## Makefile.Message_Queue_Test_Ex.am
+
+if !BUILD_ACE_FOR_TAO
+noinst_PROGRAMS += Message_Queue_Test_Ex
+
+Message_Queue_Test_Ex_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Message_Queue_Test_Ex_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Message_Queue_Test_Ex.cpp \
+ Message_Queue_Test_Ex.h
+
+Message_Queue_Test_Ex_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_ACE_FOR_TAO
+
+## Makefile.Multicast_Test.am
+noinst_PROGRAMS += Multicast_Test
+
+Multicast_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Multicast_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Multicast_Test.cpp
+
+Multicast_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.Multicast_Test_IPV6.am
+noinst_PROGRAMS += Multicast_Test_IPV6
+
+Multicast_Test_IPV6_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Multicast_Test_IPV6_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Multicast_Test_IPV6.cpp
+
+Multicast_Test_IPV6_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.Multihomed_INET_Addr_Test.am
+
+if !BUILD_ACE_FOR_TAO
+noinst_PROGRAMS += Multihomed_INET_Addr_Test
+
+Multihomed_INET_Addr_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Multihomed_INET_Addr_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Multihomed_INET_Addr_Test.cpp
+
+Multihomed_INET_Addr_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_ACE_FOR_TAO
+
+## Makefile.Multihomed_INET_Addr_Test_IPV6.am
+
+if !BUILD_ACE_FOR_TAO
+noinst_PROGRAMS += Multihomed_INET_Addr_Test_IPV6
+
+Multihomed_INET_Addr_Test_IPV6_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Multihomed_INET_Addr_Test_IPV6_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Multihomed_INET_Addr_Test_IPV6.cpp
+
+Multihomed_INET_Addr_Test_IPV6_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_ACE_FOR_TAO
+
+## Makefile.Naming_Test.am
+
+if BUILD_ACE_OTHER
+if !BUILD_ACE_FOR_TAO
+noinst_PROGRAMS += Naming_Test
+
+Naming_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Naming_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Naming_Test.cpp
+
+Naming_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_ACE_FOR_TAO
+endif BUILD_ACE_OTHER
+
+## Makefile.Network_Adapters_Test.am
+noinst_PROGRAMS += Network_Adapters_Test
+
+Network_Adapters_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Network_Adapters_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Network_Adapters_Test.cpp \
+ Network_Adapters_Test.h
+
+Network_Adapters_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.New_Fail_Test.am
+noinst_PROGRAMS += New_Fail_Test
+
+New_Fail_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+New_Fail_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ New_Fail_Test.cpp
+
+New_Fail_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.NonBlocking_Conn_Test.am
+noinst_PROGRAMS += NonBlocking_Conn_Test
+
+NonBlocking_Conn_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+NonBlocking_Conn_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ NonBlocking_Conn_Test.cpp \
+ NonBlocking_Conn_Test.h
+
+NonBlocking_Conn_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.Notify_Performance_Test.am
+
+if !BUILD_ACE_FOR_TAO
+noinst_PROGRAMS += Notify_Performance_Test
+
+Notify_Performance_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Notify_Performance_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Notify_Performance_Test.cpp
+
+Notify_Performance_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_ACE_FOR_TAO
+
+## Makefile.OS_Test.am
+noinst_PROGRAMS += OS_Test
+
+OS_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+OS_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ OS_Test.cpp
+
+OS_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.Object_Manager_Test.am
+noinst_PROGRAMS += Object_Manager_Test
+
+Object_Manager_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Object_Manager_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Object_Manager_Test.cpp
+
+Object_Manager_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.Obstack_Test.am
+noinst_PROGRAMS += Obstack_Test
+
+Obstack_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Obstack_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Obstack_Test.cpp
+
+Obstack_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.OrdMultiSet_Test.am
+noinst_PROGRAMS += OrdMultiSet_Test
+
+OrdMultiSet_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+OrdMultiSet_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ OrdMultiSet_Test.cpp
+
+OrdMultiSet_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.Pipe_Test.am
+noinst_PROGRAMS += Pipe_Test
+
+Pipe_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Pipe_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Pipe_Test.cpp
+
+Pipe_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.Priority_Buffer_Test.am
+noinst_PROGRAMS += Priority_Buffer_Test
+
+Priority_Buffer_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Priority_Buffer_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Priority_Buffer_Test.cpp
+
+Priority_Buffer_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.Priority_Reactor_Test.am
+
+if !BUILD_ACE_FOR_TAO
+noinst_PROGRAMS += Priority_Reactor_Test
+
+Priority_Reactor_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Priority_Reactor_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Priority_Reactor_Test.cpp \
+ Priority_Reactor_Test.h
+
+Priority_Reactor_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_ACE_FOR_TAO
+
+## Makefile.Priority_Task_Test.am
+noinst_PROGRAMS += Priority_Task_Test
+
+Priority_Task_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Priority_Task_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Priority_Task_Test.cpp
+
+Priority_Task_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.Proactor_Scatter_Gather_Test.am
+
+if !BUILD_ACE_FOR_TAO
+noinst_PROGRAMS += Proactor_Scatter_Gather_Test
+
+Proactor_Scatter_Gather_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Proactor_Scatter_Gather_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Proactor_Scatter_Gather_Test.cpp
+
+Proactor_Scatter_Gather_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_ACE_FOR_TAO
+
+## Makefile.Proactor_Test.am
+
+if !BUILD_ACE_FOR_TAO
+noinst_PROGRAMS += Proactor_Test
+
+Proactor_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Proactor_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Proactor_Test.cpp \
+ Proactor_Test.h
+
+Proactor_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_ACE_FOR_TAO
+
+## Makefile.Proactor_Test_IPV6.am
+
+if !BUILD_ACE_FOR_TAO
+noinst_PROGRAMS += Proactor_Test_IPV6
+
+Proactor_Test_IPV6_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Proactor_Test_IPV6_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Proactor_Test_IPV6.cpp
+
+Proactor_Test_IPV6_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_ACE_FOR_TAO
+
+## Makefile.Proactor_Timer_Test.am
+
+if !BUILD_ACE_FOR_TAO
+noinst_PROGRAMS += Proactor_Timer_Test
+
+Proactor_Timer_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Proactor_Timer_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Proactor_Timer_Test.cpp
+
+Proactor_Timer_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_ACE_FOR_TAO
+
+## Makefile.Process_Manager_Test.am
+
+if !BUILD_ACE_FOR_TAO
+noinst_PROGRAMS += Process_Manager_Test
+
+Process_Manager_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Process_Manager_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Process_Manager_Test.cpp
+
+Process_Manager_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_ACE_FOR_TAO
+
+## Makefile.Process_Manual_Event_Test.am
+noinst_PROGRAMS += Process_Manual_Event_Test
+
+Process_Manual_Event_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Process_Manual_Event_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Process_Manual_Event_Test.cpp
+
+Process_Manual_Event_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.Process_Mutex_Test.am
+
+if !BUILD_ACE_FOR_TAO
+noinst_PROGRAMS += Process_Mutex_Test
+
+Process_Mutex_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Process_Mutex_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Process_Mutex_Test.cpp
+
+Process_Mutex_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_ACE_FOR_TAO
+
+## Makefile.Process_Semaphore_Test.am
+
+if !BUILD_ACE_FOR_TAO
+noinst_PROGRAMS += Process_Semaphore_Test
+
+Process_Semaphore_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Process_Semaphore_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Process_Semaphore_Test.cpp
+
+Process_Semaphore_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_ACE_FOR_TAO
+
+## Makefile.Process_Strategy_Test.am
+
+if !BUILD_ACE_FOR_TAO
+noinst_PROGRAMS += Process_Strategy_Test
+
+Process_Strategy_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Process_Strategy_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Process_Strategy_Test.cpp \
+ Process_Strategy_Test.h
+
+Process_Strategy_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_ACE_FOR_TAO
+
+## Makefile.QtReactor_Test.am
+
+if BUILD_ACE_QTREACTOR
+if BUILD_QT
+
+BUILT_SOURCES = \
+ QtReactor_Test_moc.cpp
+
+CLEANFILES = \
+ QtReactor_Test_moc.cpp
+
+QtReactor_Test_moc.cpp: $(srcdir)/QtReactor_Test.h
+ $(QTDIR)/bin/moc -o QtReactor_Test_moc.cpp $(srcdir)/QtReactor_Test.h
+
+noinst_PROGRAMS += QtReactor_Test
+
+QtReactor_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR) \
+ $(ACE_QT_CPPFLAGS)
+
+QtReactor_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ QtReactor_Test.cpp \
+ QtReactor_Test_moc.cpp \
+ QtReactor_Test.h
+
+QtReactor_Test_LDFLAGS = \
+ $(ACE_QT_LDFLAGS)
+
+QtReactor_Test_LDADD = \
+ $(ACE_BUILDDIR)/ace/libACE_QtReactor.la \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la \
+ $(ACE_QT_LIBS)
+
+endif BUILD_QT
+endif BUILD_ACE_QTREACTOR
+
+## Makefile.RB_Tree_Test.am
+noinst_PROGRAMS += RB_Tree_Test
+
+RB_Tree_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+RB_Tree_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ RB_Tree_Test.cpp \
+ RB_Tree_Test.h
+
+RB_Tree_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.Reactor_Dispatch_Order_Test.am
+noinst_PROGRAMS += Reactor_Dispatch_Order_Test
+
+Reactor_Dispatch_Order_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Reactor_Dispatch_Order_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Reactor_Dispatch_Order_Test.cpp
+
+Reactor_Dispatch_Order_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.Reactor_Exceptions_Test.am
+noinst_PROGRAMS += Reactor_Exceptions_Test
+
+Reactor_Exceptions_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Reactor_Exceptions_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Reactor_Exceptions_Test.cpp
+
+Reactor_Exceptions_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.Reactor_Notification_Queue_Test.am
+noinst_PROGRAMS += Reactor_Notification_Queue_Test
+
+Reactor_Notification_Queue_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Reactor_Notification_Queue_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Reactor_Notification_Queue_Test.cpp
+
+Reactor_Notification_Queue_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.Reactor_Notify_Test.am
+
+if !BUILD_ACE_FOR_TAO
+noinst_PROGRAMS += Reactor_Notify_Test
+
+Reactor_Notify_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Reactor_Notify_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Reactor_Notify_Test.cpp
+
+Reactor_Notify_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_ACE_FOR_TAO
+
+## Makefile.Reactor_Performance_Test.am
+
+if !BUILD_ACE_FOR_TAO
+noinst_PROGRAMS += Reactor_Performance_Test
+
+Reactor_Performance_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Reactor_Performance_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Reactor_Performance_Test.cpp \
+ Reactor_Performance_Test.h
+
+Reactor_Performance_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_ACE_FOR_TAO
+
+## Makefile.Reactor_Registration_Test.am
+noinst_PROGRAMS += Reactor_Registration_Test
+
+Reactor_Registration_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Reactor_Registration_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Reactor_Registration_Test.cpp
+
+Reactor_Registration_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.Reactor_Timer_Test.am
+
+if !BUILD_ACE_FOR_TAO
+noinst_PROGRAMS += Reactor_Timer_Test
+
+Reactor_Timer_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Reactor_Timer_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Reactor_Timer_Test.cpp
+
+Reactor_Timer_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_ACE_FOR_TAO
+
+## Makefile.Reactors_Test.am
+noinst_PROGRAMS += Reactors_Test
+
+Reactors_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Reactors_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Reactors_Test.cpp
+
+Reactors_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.Reader_Writer_Test.am
+noinst_PROGRAMS += Reader_Writer_Test
+
+Reader_Writer_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Reader_Writer_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Reader_Writer_Test.cpp
+
+Reader_Writer_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.Recursive_Condition_Bug_Test.am
+noinst_PROGRAMS += Recursive_Condition_Bug_Test
+
+Recursive_Condition_Bug_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Recursive_Condition_Bug_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Recursive_Condition_Bug_Test.cpp
+
+Recursive_Condition_Bug_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.Recursive_Condition_Test.am
+noinst_PROGRAMS += Recursive_Condition_Test
+
+Recursive_Condition_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Recursive_Condition_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Recursive_Condition_Test.cpp
+
+Recursive_Condition_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.Recursive_Mutex_Test.am
+noinst_PROGRAMS += Recursive_Mutex_Test
+
+Recursive_Mutex_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Recursive_Mutex_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Recursive_Mutex_Test.cpp
+
+Recursive_Mutex_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.Refcounted_Auto_Ptr_Test.am
+
+if !BUILD_ACE_FOR_TAO
+noinst_PROGRAMS += Refcounted_Auto_Ptr_Test
+
+Refcounted_Auto_Ptr_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Refcounted_Auto_Ptr_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Refcounted_Auto_Ptr_Test.cpp \
+ Refcounted_Auto_Ptr_Test.h
+
+Refcounted_Auto_Ptr_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_ACE_FOR_TAO
+
+## Makefile.Reference_Counted_Event_Handler_Test.am
+noinst_PROGRAMS += Reference_Counted_Event_Handler_Test
+
+Reference_Counted_Event_Handler_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Reference_Counted_Event_Handler_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Reference_Counted_Event_Handler_Test.cpp
+
+Reference_Counted_Event_Handler_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.Reverse_Lock_Test.am
+noinst_PROGRAMS += Reverse_Lock_Test
+
+Reverse_Lock_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Reverse_Lock_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Reverse_Lock_Test.cpp
+
+Reverse_Lock_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.SOCK_Connector_Test.am
+noinst_PROGRAMS += SOCK_Connector_Test
+
+SOCK_Connector_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+SOCK_Connector_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ SOCK_Connector_Test.cpp
+
+SOCK_Connector_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.SOCK_Dgram_Bcast_Test.am
+
+if !BUILD_ACE_FOR_TAO
+noinst_PROGRAMS += SOCK_Dgram_Bcast_Test
+
+SOCK_Dgram_Bcast_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+SOCK_Dgram_Bcast_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ SOCK_Dgram_Bcast_Test.cpp
+
+SOCK_Dgram_Bcast_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_ACE_FOR_TAO
+
+## Makefile.SOCK_Dgram_Test.am
+noinst_PROGRAMS += SOCK_Dgram_Test
+
+SOCK_Dgram_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+SOCK_Dgram_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ SOCK_Dgram_Test.cpp
+
+SOCK_Dgram_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.SOCK_SEQPACK_SCTP_Test.am
+
+if !BUILD_ACE_FOR_TAO
+noinst_PROGRAMS += SOCK_SEQPACK_SCTP_Test
+
+SOCK_SEQPACK_SCTP_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+SOCK_SEQPACK_SCTP_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ SOCK_SEQPACK_SCTP_Test.cpp
+
+SOCK_SEQPACK_SCTP_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_ACE_FOR_TAO
+
+## Makefile.SOCK_Send_Recv_Test.am
+noinst_PROGRAMS += SOCK_Send_Recv_Test
+
+SOCK_Send_Recv_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+SOCK_Send_Recv_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ SOCK_Send_Recv_Test.cpp
+
+SOCK_Send_Recv_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.SOCK_Send_Recv_Test_IPV6.am
+noinst_PROGRAMS += SOCK_Send_Recv_Test_IPV6
+
+SOCK_Send_Recv_Test_IPV6_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+SOCK_Send_Recv_Test_IPV6_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ SOCK_Send_Recv_Test_IPV6.cpp
+
+SOCK_Send_Recv_Test_IPV6_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.SOCK_Test.am
+noinst_PROGRAMS += SOCK_Test
+
+SOCK_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+SOCK_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ SOCK_Test.cpp
+
+SOCK_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.SOCK_Test_IPv6.am
+noinst_PROGRAMS += SOCK_Test_IPv6
+
+SOCK_Test_IPv6_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+SOCK_Test_IPv6_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ SOCK_Test_IPv6.cpp
+
+SOCK_Test_IPv6_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.SPIPE_Test.am
+
+if !BUILD_ACE_FOR_TAO
+noinst_PROGRAMS += SPIPE_Test
+
+SPIPE_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+SPIPE_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ SPIPE_Test.cpp
+
+SPIPE_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_ACE_FOR_TAO
+
+## Makefile.SString_Test.am
+noinst_PROGRAMS += SString_Test
+
+SString_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+SString_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ SString_Test.cpp
+
+SString_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.SV_Shared_Memory_Test.am
+
+if !BUILD_ACE_FOR_TAO
+noinst_PROGRAMS += SV_Shared_Memory_Test
+
+SV_Shared_Memory_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+SV_Shared_Memory_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ SV_Shared_Memory_Test.cpp
+
+SV_Shared_Memory_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_ACE_FOR_TAO
+
+## Makefile.Semaphore_Test.am
+
+if !BUILD_ACE_FOR_TAO
+noinst_PROGRAMS += Semaphore_Test
+
+Semaphore_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Semaphore_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Semaphore_Test.cpp
+
+Semaphore_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_ACE_FOR_TAO
+
+## Makefile.Sendfile_Test.am
+noinst_PROGRAMS += Sendfile_Test
+
+Sendfile_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Sendfile_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Sendfile_Test.cpp
+
+Sendfile_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.Service_Config_DLL.am
+
+noinst_LTLIBRARIES += libService_Config_DLL.la
+
+libService_Config_DLL_la_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR) \
+ -DSERVICE_CONFIG_DLL_BUILD_DLL
+
+libService_Config_DLL_la_SOURCES = \
+ Service_Config_DLL.cpp
+
+noinst_HEADERS += \
+ Service_Config_DLL.h \
+ Service_Config_DLL_Export.h
+
+## Makefile.Service_Config_Test.am
+noinst_PROGRAMS += Service_Config_Test
+
+Service_Config_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Service_Config_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Service_Config_Test.cpp
+
+Service_Config_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.Signal_Test.am
+noinst_PROGRAMS += Signal_Test
+
+Signal_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Signal_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Signal_Test.cpp
+
+Signal_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.Sigset_Ops_Test.am
+noinst_PROGRAMS += Sigset_Ops_Test
+
+Sigset_Ops_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Sigset_Ops_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Sigset_Ops_Test.cpp
+
+Sigset_Ops_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.Simple_Message_Block_Test.am
+noinst_PROGRAMS += Simple_Message_Block_Test
+
+Simple_Message_Block_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Simple_Message_Block_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Simple_Message_Block_Test.cpp
+
+Simple_Message_Block_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.Svc_Handler_Test.am
+
+if !BUILD_ACE_FOR_TAO
+noinst_PROGRAMS += Svc_Handler_Test
+
+Svc_Handler_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Svc_Handler_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Svc_Handler_Test.cpp
+
+Svc_Handler_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_ACE_FOR_TAO
+
+## Makefile.TP_Reactor_Test.am
+
+if !BUILD_ACE_FOR_TAO
+noinst_PROGRAMS += TP_Reactor_Test
+
+TP_Reactor_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+TP_Reactor_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ TP_Reactor_Test.cpp \
+ TP_Reactor_Test.h
+
+TP_Reactor_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_ACE_FOR_TAO
+
+## Makefile.TSS_Static_Test.am
+noinst_PROGRAMS += TSS_Static_Test
+
+TSS_Static_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+TSS_Static_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ TSS_Static_Test.cpp
+
+TSS_Static_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.TSS_Test.am
+noinst_PROGRAMS += TSS_Test
+
+TSS_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+TSS_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ TSS_Test.cpp
+
+TSS_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.Task_Ex_Test.am
+noinst_PROGRAMS += Task_Ex_Test
+
+Task_Ex_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Task_Ex_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Task_Ex_Test.cpp \
+ Task_Ex_Test.h
+
+Task_Ex_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.Task_Test.am
+noinst_PROGRAMS += Task_Test
+
+Task_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Task_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Task_Test.cpp
+
+Task_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.Thread_Manager_Test.am
+noinst_PROGRAMS += Thread_Manager_Test
+
+Thread_Manager_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Thread_Manager_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Thread_Manager_Test.cpp
+
+Thread_Manager_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.Thread_Mutex_Test.am
+noinst_PROGRAMS += Thread_Mutex_Test
+
+Thread_Mutex_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Thread_Mutex_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Thread_Mutex_Test.cpp
+
+Thread_Mutex_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.Thread_Pool_Reactor_Resume_Test.am
+
+if BUILD_ACE_OTHER
+noinst_PROGRAMS += Thread_Pool_Reactor_Resume_Test
+
+Thread_Pool_Reactor_Resume_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Thread_Pool_Reactor_Resume_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Thread_Pool_Reactor_Resume_Test.cpp \
+ Thread_Pool_Reactor_Resume_Test.h
+
+Thread_Pool_Reactor_Resume_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif BUILD_ACE_OTHER
+
+## Makefile.Thread_Pool_Reactor_Test.am
+
+if BUILD_ACE_OTHER
+noinst_PROGRAMS += Thread_Pool_Reactor_Test
+
+Thread_Pool_Reactor_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Thread_Pool_Reactor_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Thread_Pool_Reactor_Test.cpp \
+ Thread_Pool_Reactor_Test.h
+
+Thread_Pool_Reactor_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif BUILD_ACE_OTHER
+
+## Makefile.Thread_Pool_Test.am
+noinst_PROGRAMS += Thread_Pool_Test
+
+Thread_Pool_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Thread_Pool_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Thread_Pool_Test.cpp
+
+Thread_Pool_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.Time_Service_Test.am
+noinst_PROGRAMS += Time_Service_Test
+
+Time_Service_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Time_Service_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Time_Service_Test.cpp
+
+Time_Service_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.Time_Value_Test.am
+noinst_PROGRAMS += Time_Value_Test
+
+Time_Value_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Time_Value_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Time_Value_Test.cpp
+
+Time_Value_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.Timeprobe_Test.am
+noinst_PROGRAMS += Timeprobe_Test
+
+Timeprobe_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Timeprobe_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Timeprobe_Test.cpp
+
+Timeprobe_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.Timer_Cancellation_Test.am
+noinst_PROGRAMS += Timer_Cancellation_Test
+
+Timer_Cancellation_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Timer_Cancellation_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Timer_Cancellation_Test.cpp
+
+Timer_Cancellation_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.Timer_Queue_Reference_Counting_Test.am
+noinst_PROGRAMS += Timer_Queue_Reference_Counting_Test
+
+Timer_Queue_Reference_Counting_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Timer_Queue_Reference_Counting_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Timer_Queue_Reference_Counting_Test.cpp
+
+Timer_Queue_Reference_Counting_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.Timer_Queue_Test.am
+
+if !BUILD_ACE_FOR_TAO
+noinst_PROGRAMS += Timer_Queue_Test
+
+Timer_Queue_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Timer_Queue_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Timer_Queue_Test.cpp
+
+Timer_Queue_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_ACE_FOR_TAO
+
+## Makefile.TkReactor_Test.am
+
+if BUILD_ACE_TKREACTOR
+if BUILD_TK
+
+noinst_PROGRAMS += TkReactor_Test
+
+TkReactor_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR) \
+ $(ACE_TK_CPPFLAGS) \
+ $(ACE_TCL_CPPFLAGS)
+
+TkReactor_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ TkReactor_Test.cpp
+
+TkReactor_Test_LDFLAGS = \
+ $(ACE_TK_LDFLAGS) $(ACE_TCL_LDFLAGS)
+
+TkReactor_Test_LDADD = \
+ $(ACE_BUILDDIR)/ace/libACE_TkReactor.la \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la \
+ $(ACE_TK_LIBS) \
+ $(ACE_TCL_LIBS)
+
+endif BUILD_TK
+endif BUILD_ACE_TKREACTOR
+
+## Makefile.Token_Strategy_Test.am
+noinst_PROGRAMS += Token_Strategy_Test
+
+Token_Strategy_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Token_Strategy_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Token_Strategy_Test.cpp
+
+Token_Strategy_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.Tokens_Test.am
+
+if BUILD_ACE_TOKEN
+noinst_PROGRAMS += Tokens_Test
+
+Tokens_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Tokens_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Tokens_Test.cpp
+
+Tokens_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif BUILD_ACE_TOKEN
+
+## Makefile.UPIPE_SAP_Test.am
+
+if !BUILD_ACE_FOR_TAO
+noinst_PROGRAMS += UPIPE_SAP_Test
+
+UPIPE_SAP_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+UPIPE_SAP_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ UPIPE_SAP_Test.cpp
+
+UPIPE_SAP_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_ACE_FOR_TAO
+
+## Makefile.UUIDTest.am
+
+if BUILD_ACE_UUID
+if !BUILD_ACE_FOR_TAO
+noinst_PROGRAMS += UUIDTest
+
+UUIDTest_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+UUIDTest_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ UUIDTest.cpp
+
+UUIDTest_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_ACE_FOR_TAO
+endif BUILD_ACE_UUID
+
+## Makefile.Unbounded_Set_Test.am
+noinst_PROGRAMS += Unbounded_Set_Test
+
+Unbounded_Set_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Unbounded_Set_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Unbounded_Set_Test.cpp
+
+Unbounded_Set_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.Upgradable_RW_Test.am
+
+if !BUILD_ACE_FOR_TAO
+noinst_PROGRAMS += Upgradable_RW_Test
+
+Upgradable_RW_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Upgradable_RW_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Upgradable_RW_Test.cpp \
+ Upgradable_RW_Test.h
+
+Upgradable_RW_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_ACE_FOR_TAO
+
+## Makefile.Vector_Test.am
+noinst_PROGRAMS += Vector_Test
+
+Vector_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+Vector_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Vector_Test.cpp
+
+Vector_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.WFMO_Reactor_Test.am
+noinst_PROGRAMS += WFMO_Reactor_Test
+
+WFMO_Reactor_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+WFMO_Reactor_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ WFMO_Reactor_Test.cpp
+
+WFMO_Reactor_Test_LDADD = \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.XtAthenaReactor_Test.am
+
+if BUILD_ACE_XTREACTOR
+if BUILD_ATHENA
+if BUILD_X11
+if BUILD_XT
+
+noinst_PROGRAMS += XtAthenaReactor_Test
+
+XtAthenaReactor_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR) \
+ $(ACE_X11_CPPFLAGS) \
+ $(ACE_XT_CPPFLAGS)
+
+XtAthenaReactor_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ XtAthenaReactor_Test.cpp
+
+XtAthenaReactor_Test_LDFLAGS = \
+ $(ACE_X11_LDFLAGS) $(ACE_XT_LDFLAGS)
+
+XtAthenaReactor_Test_LDADD = \
+ $(ACE_BUILDDIR)/ace/libACE_XtReactor.la \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la \
+ -lXaw \
+ $(ACE_XT_LIBS) \
+ $(ACE_X11_LIBS)
+
+endif BUILD_XT
+endif BUILD_X11
+endif BUILD_ATHENA
+endif BUILD_ACE_XTREACTOR
+
+## Makefile.XtMotifReactor_Test.am
+
+if BUILD_ACE_XTREACTOR
+if BUILD_MOTIF
+if BUILD_X11
+if BUILD_XT
+
+noinst_PROGRAMS += XtMotifReactor_Test
+
+XtMotifReactor_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR) \
+ $(ACE_X11_CPPFLAGS) \
+ $(ACE_XT_CPPFLAGS)
+
+XtMotifReactor_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ XtMotifReactor_Test.cpp
+
+XtMotifReactor_Test_LDFLAGS = \
+ $(ACE_X11_LDFLAGS) $(ACE_XT_LDFLAGS)
+
+XtMotifReactor_Test_LDADD = \
+ $(ACE_BUILDDIR)/ace/libACE_XtReactor.la \
+ libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la \
+ -lXm \
+ $(ACE_XT_LIBS) \
+ $(ACE_X11_LIBS)
+
+endif BUILD_XT
+endif BUILD_X11
+endif BUILD_MOTIF
+endif BUILD_ACE_XTREACTOR
+
+## Clean up template repositories, etc.
+clean-local:
+ -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.*
+ -rm -f gcctemp.c gcctemp so_locations *.ics
+ -rm -rf cxx_repository ptrepository ti_files
+ -rm -rf templateregistry ir.out
+ -rm -rf ptrepository SunWS_cache Templates.DB
diff --git a/ACE/tests/Malloc_Test.cpp b/ACE/tests/Malloc_Test.cpp
new file mode 100644
index 00000000000..88c2bd5e669
--- /dev/null
+++ b/ACE/tests/Malloc_Test.cpp
@@ -0,0 +1,437 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Malloc_Test.cpp
+//
+// = DESCRIPTION
+// This is a test of the position-independent <ACE_Malloc> memory
+// manager using the <ACE_MMAP_Memory_Pool> and <ACE_Process_Mutex>.
+//
+// = AUTHOR
+// Douglas C. Schmidt <schmidt@cs.wustl.edu>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "Malloc_Test.h"
+
+#include "ace/Malloc_T.h"
+#include "ace/MMAP_Memory_Pool.h"
+#include "ace/Process.h"
+#include "ace/Auto_Ptr.h"
+#include "ace/Process_Mutex.h"
+#include "ace/PI_Malloc.h"
+#include "ace/RW_Thread_Mutex.h"
+#include "ace/Time_Value.h"
+#include "ace/OS_NS_unistd.h"
+
+ACE_RCSID(tests, Malloc_Test, "Malloc_Test.cpp,v 4.22 1999/12/13 22:24:42 nanbor Exp")
+
+#if defined (ACE_HAS_PROCESS_SPAWN)
+
+#if (ACE_HAS_POSITION_INDEPENDENT_POINTERS == 1)
+typedef ACE_Malloc_T<ACE_MMAP_MEMORY_POOL, ACE_Process_Mutex, ACE_PI_Control_Block> MALLOC;
+#else
+typedef ACE_Malloc<ACE_MMAP_MEMORY_POOL, ACE_Process_Mutex> MALLOC;
+#endif /* ACE_HAS_POSITION_INDEPENDENT_POINTERS == 1 */
+#define MMAP_FILENAME ACE_TEXT ("test_file")
+#define MUTEX_NAME ACE_TEXT ("test_lock")
+
+#if !defined (linux) && !defined (ACE_OPENVMS) \
+ && !(defined (ACE_WIN32) \
+ && (defined (ghs) \
+ || defined (__MINGW32__) \
+ || (!defined(ACE_HAS_WINNT4) || (ACE_HAS_WINNT4 == 0)))) \
+ && !(defined (__OpenBSD__) && defined (ACE_HAS_PTHREADS))
+#define ACE_TEST_REMAP_ON_FAULT
+// Linux seems to have problem when calling mmap from the signal handler.
+// The Green Hills Native x86 compiler does not support structural exceptions.
+// Mingw's gcc does not support structural exceptions.
+// Win9x doesn't support remaps.
+// OpenBSD causes this test to hang in the child when pthreads are enabled.
+// On these plarforms, we make sure the remapping will never occur.
+#endif /* linux && Win32 GHS*/
+
+#if defined (ACE_WIN32)
+// When looking for the file to execute a process on Win32, the directory from
+// containing the parent process file is searched first. Since certain Win32
+// configurations (e.g. Borland C++Builder) put the output files in a different
+// directory we will use this feature rather than specifying '.\'.
+# define EXE_LOCATION ACE_TEXT ("")
+#else
+# define EXE_LOCATION ACE_TEXT (".") ACE_DIRECTORY_SEPARATOR_STR
+#endif /*ACE_WIN32*/
+
+// Parents <ACE_Malloc> base address in shared memory.
+static const void *PARENT_BASE_ADDR = ACE_DEFAULT_BASE_ADDR;
+
+// If the platform supports position-independent malloc, choose
+// another base address that's 1M higher so that <ACE_Malloc> will be
+// mapped into a different address in the child's virtual memory.
+// Note that on HP-UX on PA-RISC hardware, a single range of a file
+// cannot be mapped into multiple virtual address ranges, even across
+// processes. So, though the whole PI pointer thing is tested here,
+// it isn't actually using multiple address ranges. Also, on Win9x,
+// you need to map shared views to the same address.
+
+#if (ACE_HAS_POSITION_INDEPENDENT_POINTERS == 1 && !defined (HPUX)) \
+ && !(defined (ACE_WIN32) \
+ && (!defined (ACE_HAS_WINNT4) || (ACE_HAS_WINNT4 == 0)))
+# define CHILD_ADDR_DELTA (1024*1024)
+#else
+# define CHILD_ADDR_DELTA 0
+#endif /* CHILD_ADDR_DELTA */
+
+static const void *CHILD_BASE_ADDR = CHILD_ADDR_DELTA + ACE_DEFAULT_BASE_ADDR;
+
+// Shared memory allocator. Hide the allocator inside this function
+// so that it doesn't get constructed until after the
+// <ACE_Object_Manager> gets constructed, even with
+// <ACE_HAS_NONSTATIC_OBJECT_MANAGER>.
+
+static MALLOC *
+myallocator (const void *base_addr = 0)
+{
+ static auto_ptr<MALLOC> static_allocator;
+
+ if (static_allocator.get () == 0)
+ {
+
+#if defined (ACE_HAS_WINCE) || defined (ACE_OPENVMS)
+ // WinCE cannot do fixed base, ever.
+ ACE_MMAP_Memory_Pool_Options options
+ (0,
+ ACE_MMAP_Memory_Pool_Options::NEVER_FIXED);
+#else
+ ACE_MMAP_Memory_Pool_Options options (base_addr);
+#endif /* ACE_HAS_WINCE */
+
+#if !defined (ACE_TEST_REMAP_ON_FAULT)
+ options.minimum_bytes_ = 512 * 1024;
+#endif /* ACE_TEST_REMAP_ON_FAULT */
+
+ MALLOC *ptr = new MALLOC (MMAP_FILENAME,
+ MUTEX_NAME,
+ &options);
+ ACE_AUTO_PTR_RESET(static_allocator, ptr, MALLOC);
+ }
+ return static_allocator.get ();
+}
+
+static void
+init_test (const void *base_addr = 0)
+{
+ // Cleanup the MMAP file so we won't trip over the leftover mmap
+ // file from the previous crash.
+#if defined (ACE_HAS_WINCE) || defined (ACE_OPENVMS)
+ // WinCE cannot do fixed base, ever.
+ ACE_MMAP_Memory_Pool_Options options
+ (0,
+ ACE_MMAP_Memory_Pool_Options::NEVER_FIXED);
+#else
+ ACE_MMAP_Memory_Pool_Options options (base_addr);
+#endif /* ACE_HAS_WINCE */
+ ACE_MMAP_Memory_Pool mmap (MMAP_FILENAME, &options);
+
+ size_t rbyte = 0;
+ int ft = 0;
+ mmap.init_acquire (1024, rbyte, ft);
+ mmap.release ();
+}
+
+static Test_Data *
+initialize (MALLOC *allocator)
+{
+ double *temp = 0;
+ ACE_ALLOCATOR_RETURN (temp,
+ (double *) allocator->malloc (sizeof (double)),
+ 0);
+ // Make sure that doubles work!
+ *temp = 5.0;
+ allocator->free (temp);
+
+ void *ptr;
+ ACE_ALLOCATOR_RETURN (ptr,
+ allocator->malloc (sizeof (Test_Data)),
+ 0);
+ Test_Data *data1 = new (ptr) Test_Data;
+
+ data1->i1_ = 111;
+ data1->i2_ = 222;
+ data1->i3_ = 333;
+ data1->d1_ = 87.5;
+
+ void *gap = 0;
+ ACE_ALLOCATOR_RETURN (gap,
+ allocator->malloc (sizeof (256)),
+ 0);
+ allocator->free (gap);
+
+
+ ACE_ALLOCATOR_RETURN (ptr,
+ allocator->malloc (sizeof (Test_Data)),
+ 0);
+ Test_Data *data2 = new (ptr) Test_Data;
+
+ data1->next_ = 0;
+ data2->next_ = data1;
+ data2->i1_ = -111;
+ data2->i2_ = -222;
+ data2->i3_ = -333;
+ data2->d1_ = 77.34;
+
+ // Test in shared memory using long (array/pointer)
+ ACE_ALLOCATOR_RETURN (ptr,
+ allocator->malloc (sizeof (Long_Test)),
+ 0);
+ Long_Test *lt = new (ptr) Long_Test;
+
+ lt->array_[0] = 1000;
+ lt->array_[1] = 1001;
+ lt->array_[2] = 1002;
+ lt->array_[3] = 1003;
+ lt->array_[4] = 1004;
+ lt->bpl_ = lt->array_;
+
+ data1->long_test_= lt;
+
+ long long_cont_1 = *lt->bpl_;
+ long long_cont_2 = lt->bpl_[3];
+
+ ACE_ASSERT (long_cont_1 == 1000);
+ ACE_ASSERT (long_cont_2 == 1003);
+
+ ACE_ALLOCATOR_RETURN (ptr,
+ allocator->malloc (sizeof (Long_Test)),
+ 0);
+ lt = new (ptr) Long_Test;
+
+ lt->array_[0] = 2000;
+ lt->array_[1] = 2001;
+ lt->array_[2] = 2002;
+ lt->array_[3] = 2003;
+ lt->array_[4] = 2004;
+ lt->bpl_ = lt->array_;
+
+ data2->long_test_= lt;
+
+ long long_cont_3 = *lt->bpl_;
+ long long_cont_4 = lt->bpl_[4];
+
+ ACE_ASSERT (long_cont_3 == 2000);
+ ACE_ASSERT (long_cont_4 == 2004);
+
+ return data2;
+}
+
+static void
+print (const char *process_name,
+ Test_Data *data)
+{
+ for (Test_Data *t = data; t != 0; t = t->next_)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("<<<< (%P) %s\ni1_ = %d, i2_ = %d, i3_ = %d, d1_ = %f\n"),
+ process_name,
+ t->i1_,
+ t->i2_,
+ t->i3_,
+ t->d1_));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("*t->bpl_ = %d, t->long_test_->array_[0] = ")
+ ACE_TEXT ("%d\n>>>>\n"),
+ *t->long_test_->bpl_,
+ t->long_test_->array_[0]));
+ }
+}
+
+static int
+parent (Test_Data *data)
+{
+ MALLOC *myalloc = myallocator ();
+
+ {
+ ACE_GUARD_RETURN (ACE_Process_Mutex, guard, myalloc->mutex (), -1);
+ print ("parent", data);
+ }
+
+ // Sleep for a 200 msecs so that the child will have a chance to spin!
+ ACE_OS::sleep (ACE_Time_Value (0, 200 * 1000));
+
+#if defined (ACE_TEST_REMAP_ON_FAULT)
+ char *small_buf[1024];
+ int cntr;
+
+ for (cntr = 0 ; cntr < 1024; ++cntr)
+ small_buf[cntr] = (char *) myalloc->malloc (1);
+ char *big_buf = (char *) myalloc->malloc (1024 * 4069);
+#endif /* ACE_TEST_REMAP_ON_FAULT */
+
+ int result = myalloc->bind ("bar", data);
+
+#if defined (ACE_TEST_REMAP_ON_FAULT)
+ myalloc->free (big_buf);
+ for (cntr = 0 ; cntr < 1024; ++cntr)
+ myalloc->free (small_buf[cntr]);
+#endif /* ACE_TEST_REMAP_ON_FAULT */
+
+ ACE_ASSERT (result != -1);
+ return 0;
+}
+
+static int
+child (void)
+{
+ void *bar;
+ // Perform "busy waiting" here until the parent stores data under a
+ // new name called "bar" in <ACE_Malloc>. This isn't a good design
+ // -- it's just to test that synchronization is working across
+ // processes via <ACE_Malloc>.
+ for (ACE_Time_Value timeout (0, 1000 * 10);
+ myallocator ()->find ("bar",
+ bar) == -1;
+ )
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P) sleeping for 10 milliseconds!\n")));
+ ACE_OS::sleep (timeout);
+ }
+
+ print ("child",
+ reinterpret_cast<Test_Data *> (bar));
+ return 0;
+}
+
+#if defined (ACE_WIN32) \
+ && (!defined (ACE_HAS_WINNT4) || (ACE_HAS_WINNT4 == 0))
+// On Win9x/Me, a shared address needs to be on the shared arena,
+// betweeen the second and third megabyte in the virtual address space
+// of the process. Also, a mapped view of a file is shared on the same
+// virtual address on every 32 bit process. On WinNT/2k, memory above
+// 2Gb is reserved for the system. So, we need to check at runtime
+// (we want an ACE_HAS_WINNT4 == 0 ace to run on either).
+static void
+get_base_addrs (void)
+{
+ OSVERSIONINFO vinfo;
+ vinfo.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
+ if (::GetVersionEx(&vinfo) == 0)
+ return;
+
+ if (vinfo.dwPlatformId == VER_PLATFORM_WIN32_NT)
+ PARENT_BASE_ADDR = (char*) (64 * 1024*1024);
+ else
+ PARENT_BASE_ADDR = (char*) ((2048UL + 512UL)*(1024UL*1024UL));
+
+ CHILD_BASE_ADDR = CHILD_ADDR_DELTA + (char*) PARENT_BASE_ADDR;
+}
+#endif /* defined (ACE_WIN32) && (!defined (ACE_HAS_WINNT4) || (ACE_HAS_WINNT4 == 0)) */
+
+int
+run_main (int argc, ACE_TCHAR *[])
+{
+#if defined (ACE_WIN32) \
+ && (!defined (ACE_HAS_WINNT4) || (ACE_HAS_WINNT4 == 0))
+ get_base_addrs();
+#endif
+
+ if (argc == 1)
+ {
+ ACE_START_TEST (ACE_TEXT ("Malloc_Test"));
+ ACE_INIT_LOG (ACE_TEXT ("Malloc_Test-child"));
+
+ init_test (PARENT_BASE_ADDR);
+
+ ACE_Control_Block::print_alignment_info ();
+# if (ACE_HAS_POSITION_INDEPENDENT_POINTERS == 1)
+ ACE_PI_Control_Block::print_alignment_info ();
+# endif /* ACE_HAS_POSITION_INDEPENDENT_POINTERS == 1 */
+
+ // No arguments means we're the parent process.
+ ACE_Process_Options options (1);
+
+ options.command_line (EXE_LOCATION
+ ACE_TEXT ("Malloc_Test")
+ ACE_PLATFORM_EXE_SUFFIX
+ ACE_TEXT (" run_as_test"));
+
+#ifdef ACE_HAS_WINCE
+ // \Windows\Start Menu is where Malloc_Test.exe will be downloaded to.
+ // Check project setting for the directory information if needs to be changed.
+ options.process_name(ACE_TEXT("\\Windows\\Start Menu\\Malloc_Test.exe"));
+#endif
+
+ MALLOC *myalloc = myallocator (PARENT_BASE_ADDR);
+
+ Test_Data *data = initialize (myalloc);
+ ACE_ASSERT (data != 0);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P) PARENT allocator at = %@, ")
+ ACE_TEXT ("data allocated at %@\n"),
+ myalloc,
+ data));
+ myalloc->dump ();
+ int result = myalloc->bind ("foo", data);
+ ACE_ASSERT (result != -1);
+
+ ACE_Process p;
+ pid_t pid = p.spawn (options);
+ if (pid == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("spawn")), 1);
+
+ parent (data);
+
+ // Synchronize on the exit of the child.
+ result = p.wait ();
+ if (result == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("wait")), 1);
+ ACE_ASSERT (myalloc->ref_counter () == 1);
+ myalloc->remove ();
+ ACE_END_TEST;
+ return 0;
+ }
+ else
+ {
+ // In this case we're the child process.
+ ACE_APPEND_LOG (ACE_TEXT ("Malloc_Test-child"));
+
+ void *data = 0;
+ MALLOC *myalloc = myallocator (CHILD_BASE_ADDR);
+ int result = myalloc->find ("foo", data);
+ ACE_ASSERT (result != -1);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P) CHILD allocator at = %@, ")
+ ACE_TEXT ("data allocated at %@\n"),
+ myalloc,
+ data));
+ myalloc->dump ();
+ child ();
+ myalloc->release ();
+ ACE_END_LOG;
+ return 0;
+ }
+}
+
+#else
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("Malloc_Test"));
+ ACE_ERROR ((LM_INFO,
+ ACE_TEXT ("process creation is not supported on this ")
+ ACE_TEXT ("platform\n")));
+ ACE_END_TEST;
+ return 0;
+}
+#endif /* ACE_HAS_PROCESS_SPAWN */
diff --git a/ACE/tests/Malloc_Test.h b/ACE/tests/Malloc_Test.h
new file mode 100644
index 00000000000..8fda7368ee4
--- /dev/null
+++ b/ACE/tests/Malloc_Test.h
@@ -0,0 +1,44 @@
+// $Id$
+//
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Malloc_Test.h
+//
+// = DESCRIPTION
+// This class gets its own header file to work around AIX C++
+// compiler "features" related to template instantiation... It is
+// only used by Malloc_Test.cpp.
+//
+// = AUTHOR
+// Douglas C. Schmidt <schmidt@cs.wustl.edu>
+
+// ============================================================================
+
+#ifndef ACE_TESTS_MALLOC_TEST_H
+#define ACE_TESTS_MALLOC_TEST_H
+
+#include "ace/Based_Pointer_T.h"
+
+// Some test data.
+struct Long_Test
+{
+ ACE_Based_Pointer_Basic<long> bpl_;
+ long array_[10];
+};
+
+// Some more test data.
+struct Test_Data
+{
+ int i1_;
+ int i2_;
+ int i3_;
+ double d1_;
+ ACE_Based_Pointer<Test_Data> next_;
+ ACE_Based_Pointer<Long_Test> long_test_;
+};
+
+#endif /* ACE_TESTS_MALLOC_TEST_H */
diff --git a/ACE/tests/Manual_Event_Test.cpp b/ACE/tests/Manual_Event_Test.cpp
new file mode 100644
index 00000000000..1b28d846a71
--- /dev/null
+++ b/ACE/tests/Manual_Event_Test.cpp
@@ -0,0 +1,205 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Manual_Event Test
+//
+// = DESCRIPTION
+// This test verifies the functionality of the <ACE_Manual_Event>
+// implementation.
+//
+// = AUTHOR
+// Martin Corino <mcorino@remedy.nl>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/Manual_Event.h"
+#include "ace/Thread.h"
+#include "ace/Thread_Manager.h"
+#include "ace/Get_Opt.h"
+#include "ace/OS_NS_sys_time.h"
+#include "ace/OS_NS_time.h"
+#include "ace/OS_NS_unistd.h"
+#include "ace/Atomic_Op.h"
+
+ACE_RCSID(tests, Manual_Event_Test, "$Id$")
+
+// msec that times are allowed to differ before test fails.
+#if defined (ACE_HAS_HI_RES_TIMER) || defined (ACE_HAS_AIX_HI_RES_TIMER) || \
+ defined (ACE_HAS_PENTIUM) || defined (ACE_HAS_ALPHA_TIMER) || \
+ defined (ACE_HAS_POWERPC_TIMER)
+# define ACE_ALLOWED_SLACK 100
+#else /* don't have a high-res timer */
+# define ACE_ALLOWED_SLACK 1100
+#endif /* don't have a high-res timer */
+
+// Test results, 'success' is 0
+static int test_result = 0;
+
+#if defined (ACE_HAS_THREADS)
+
+// Event used in the tests. Start it "unsignalled" (i.e., its initial
+// state is 0).
+static ACE_Manual_Event evt ((unsigned int) 0);
+
+// Default number of iterations.
+static int n_iterations = 10;
+
+// Number of worker threads.
+static long n_workers = 10;
+
+// Number of wakeups.
+#if defined (ACE_HAS_BUILTIN_ATOMIC_OP)
+static ACE_Atomic_Op<ACE_Thread_Mutex, long> n_awoken;
+static ACE_Atomic_Op<ACE_Thread_Mutex, long> n_awoken2;
+#else
+static long n_awoken;
+static long n_awoken2;
+#endif
+
+// Explain usage and exit.
+static void
+print_usage_and_die (void)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("usage: %n [-w n_workers] [-n iteration_count]\n")));
+ ACE_OS::exit (1);
+}
+
+static void
+parse_args (int argc, ACE_TCHAR *argv[])
+{
+ ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("w:n:"));
+
+ int c;
+
+ while ((c = get_opt ()) != -1)
+ switch (c)
+ {
+ case 'w':
+ n_workers = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'n':
+ n_iterations = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ default:
+ print_usage_and_die ();
+ break;
+ }
+}
+
+// Worker tries to acquire the semaphore, hold it for a while, and
+// then manually releases it.
+
+static void *
+worker (void *)
+{
+ if (evt.wait() == -1)
+ {
+ ACE_DEBUG ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Failed waiting for pulse()\n")));
+ return 0;
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) awake\n")));
+
+ if (++n_awoken < n_workers)
+ {
+ ACE_Time_Value wait (1, 0); // Wait 10 sec
+ ACE_Time_Value tv = ACE_OS::gettimeofday () + wait;
+
+ if (evt.wait (&tv) == -1)
+ {
+ // verify that we have ETIME
+ ACE_ASSERT(ACE_OS::last_error() == ETIME);
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) timeout\n")));
+ }
+ else
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) awake in time\n")));
+
+ if (++n_awoken2 >= (n_workers/2))
+ evt.reset(); // reset signal (rest times out)
+ }
+ }
+ else
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) last awake; send signal\n")));
+ // last one wakes others
+ evt.signal();
+
+ ACE_OS::sleep (ACE_Time_Value(0, 200 * 1000 * 100)); // 200 msec
+ }
+
+ if (evt.wait() == -1)
+ {
+ ACE_DEBUG ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Failed waiting for signal()\n")));
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) worker finished\n")));
+
+ return 0;
+}
+
+#endif /* ACE_HAS_THREADS */
+
+// Test event functionality.
+
+int run_main (int argc, ACE_TCHAR *argv[])
+{
+ ACE_START_TEST (ACE_TEXT ("Manual_Event_Test"));
+
+#if defined (ACE_HAS_THREADS)
+ parse_args (argc, argv);
+
+ if (ACE_Thread_Manager::instance ()->spawn_n
+ (static_cast<size_t> (n_workers),
+ ACE_THR_FUNC (worker),
+ 0,
+ THR_NEW_LWP) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("spawn_n")),
+ 1);
+
+ // gives all workers chance to start
+ ACE_OS::sleep (5);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("sending pulse()\n")));
+
+ // Release the all workers.
+ evt.pulse ();
+
+ // Wait 2 sec
+ ACE_OS::sleep (2);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("sending signal()\n")));
+
+ // Signal
+ evt.signal();
+
+ ACE_Thread_Manager::instance ()->wait ();
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Manual_Event Test successful\n")));
+#else
+ ACE_UNUSED_ARG (argc);
+ ACE_UNUSED_ARG (argv);
+ ACE_ERROR ((LM_INFO,
+ ACE_TEXT ("Threads not supported on this platform\n")));
+#endif /* ACE_HAS_THREADS */
+ ACE_END_TEST;
+ return test_result;
+}
diff --git a/ACE/tests/Map_Manager_Test.cpp b/ACE/tests/Map_Manager_Test.cpp
new file mode 100644
index 00000000000..2f90f2bb16b
--- /dev/null
+++ b/ACE/tests/Map_Manager_Test.cpp
@@ -0,0 +1,956 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Map_Manager_Test.cpp
+//
+// = DESCRIPTION
+// This is a simple test of the <ACE_Map_Manager> and
+// <ACE_Hash_Map_Manager> that illustrates how to use the forward
+// and reverse iterators.
+//
+// = AUTHOR
+// Irfan Pyarali <irfan@cs.wustl.edu>,
+// Douglas C. Schmidt <schmidt@cs.wustl.edu>, and
+// Kirthika Parameswaran <kirthika@cs.wustl.edu>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/Map_Manager.h"
+#include "ace/Hash_Map_Manager.h"
+#include "ace/Active_Map_Manager.h"
+#include "ace/Profile_Timer.h"
+#include "ace/Hash_Cache_Map_Manager_T.h"
+#include "ace/Caching_Strategies_T.h"
+#include "ace/Pair_T.h"
+
+ACE_RCSID(tests, Map_Manager_Test, "$Id$")
+
+typedef ACE_Null_Mutex MUTEX;
+typedef ACE_UINT32 TYPE;
+typedef ACE_Active_Map_Manager_Key
+ ACTIVE_KEY;
+typedef ACE_Hash<TYPE>
+ HASH_KEY;
+typedef ACE_Equal_To<TYPE>
+ COMPARE_KEYS;
+
+typedef ACE_Map_Manager <TYPE, TYPE, MUTEX>
+ MAP_MANAGER;
+typedef ACE_Map_Iterator <TYPE, TYPE, MUTEX>
+ ITERATOR;
+typedef ACE_Map_Reverse_Iterator <TYPE, TYPE, MUTEX>
+ REVERSE_ITERATOR;
+typedef ACE_Map_Entry <TYPE, TYPE>
+ MAP_ENTRY;
+typedef ACE_Hash_Map_Manager_Ex <TYPE, TYPE, HASH_KEY, COMPARE_KEYS, MUTEX>
+ HASH_MAP_MANAGER;
+typedef ACE_Hash_Map_Iterator_Ex <TYPE, TYPE, HASH_KEY, COMPARE_KEYS, MUTEX>
+ HASH_ITERATOR;
+typedef ACE_Hash_Map_Reverse_Iterator_Ex <TYPE, TYPE, HASH_KEY, COMPARE_KEYS, MUTEX>
+ HASH_REVERSE_ITERATOR;
+typedef ACE_Hash_Map_Entry <TYPE, TYPE>
+ HASH_ENTRY;
+typedef ACE_Active_Map_Manager <TYPE>
+ ACTIVE_MAP_MANAGER;
+
+typedef ACE_Hash_Map_Manager_Ex<TYPE, ACE_Pair<TYPE, int>, HASH_KEY, COMPARE_KEYS, MUTEX>
+ CACHE_MAP_IMPL;
+typedef ACE_Hash_Map_Iterator_Ex<TYPE, ACE_Pair<TYPE, int>, HASH_KEY, COMPARE_KEYS, MUTEX>
+ CACHE_ITER_IMPL;
+typedef ACE_Hash_Map_Reverse_Iterator_Ex<TYPE, ACE_Pair<TYPE, int>, HASH_KEY, COMPARE_KEYS, MUTEX>
+ CACHE_REV_ITER_IMPL;
+typedef int ATTR;
+typedef ACE_Null_Cleanup_Strategy<TYPE, TYPE, CACHE_MAP_IMPL>
+ NULL_CLEANUP;
+typedef ACE_Null_Caching_Utility <TYPE, TYPE, CACHE_MAP_IMPL, CACHE_ITER_IMPL, ATTR>
+ NULL_UTILITY;
+typedef ACE_Null_Caching_Strategy<ATTR, NULL_UTILITY>
+ NULL_CACHING_STRATEGY;
+typedef ACE_Cache_Map_Manager<TYPE, TYPE, CACHE_MAP_IMPL, CACHE_ITER_IMPL, CACHE_REV_ITER_IMPL, NULL_CACHING_STRATEGY, ATTR>
+ CACHE_MAP_MANAGER;
+typedef ACE_Hash_Cache_Map_Manager<TYPE, TYPE, HASH_KEY, COMPARE_KEYS, NULL_CACHING_STRATEGY, ATTR>
+ HASH_CACHE_MAP_MANAGER;
+
+static void
+test_cache_map_manager (size_t table_size,
+ size_t iterations,
+ int test_iterators)
+{
+ NULL_CACHING_STRATEGY null_caching_strategy;
+ CACHE_MAP_MANAGER map (null_caching_strategy,
+ table_size);
+ TYPE i;
+ TYPE j;
+ ssize_t k;
+
+ for (i = 0; i < iterations; i++)
+ ACE_ASSERT (map.bind (i, i) != -1);
+
+ if (test_iterators)
+ {
+ {
+ i = 0;
+
+ CACHE_MAP_MANAGER::ITERATOR end = map.end ();
+
+ for (CACHE_MAP_MANAGER::ITERATOR iter = map.begin ();
+ iter != end;
+ ++iter)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%d|%d|%d)"),
+ i,
+ (*iter).first (),
+ (*iter).second ()));
+ ++i;
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\n")));
+ ACE_ASSERT (i == iterations);
+ }
+
+
+ {
+ k = iterations - 1;
+
+ CACHE_MAP_MANAGER::REVERSE_ITERATOR rend = map.rend ();
+
+ for (CACHE_MAP_MANAGER::REVERSE_ITERATOR iter = map.rbegin ();
+ iter != rend;
+ ++iter)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%d|%d|%d)"),
+ k,
+ (*iter).first (),
+ (*iter).second ()));
+ k--;
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\n")));
+ ACE_ASSERT (k == -1);
+ }
+
+
+ {
+ i = 0;
+
+ CACHE_MAP_MANAGER::iterator end = map.end ();
+
+ for (CACHE_MAP_MANAGER::iterator iter = map.begin ();
+ iter != end;
+ ++iter)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%d|%d|%d)"),
+ i,
+ (*iter).first (),
+ (*iter).second ()));
+ ++i;
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\n")));
+ ACE_ASSERT (i == iterations);
+ }
+
+
+ {
+ k = iterations - 1;
+
+ CACHE_MAP_MANAGER::reverse_iterator rend = map.rend ();
+
+ for (CACHE_MAP_MANAGER::reverse_iterator iter = map.rbegin ();
+ iter != rend;
+ ++iter)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%d|%d|%d)"),
+ k,
+ (*iter).first (),
+ (*iter).second ()));
+ k--;
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\n")));
+ ACE_ASSERT (k == -1);
+ }
+
+
+ }
+
+ for (i = 0; i < iterations; ++i)
+ {
+ ACE_ASSERT (map.find (i, j) != -1);
+ ACE_ASSERT (i == j);
+ }
+
+ size_t remaining_entries = iterations;
+ for (i = 0; i < iterations; ++i)
+ {
+ ACE_ASSERT (map.unbind (i) != -1);
+ --remaining_entries;
+ ACE_ASSERT (map.current_size () == remaining_entries);
+ }
+
+}
+
+static void
+test_hash_cache_map_manager (size_t table_size,
+ size_t iterations,
+ int test_iterators)
+{
+ NULL_CACHING_STRATEGY null_caching_strategy;
+ HASH_CACHE_MAP_MANAGER map (null_caching_strategy,
+ table_size);
+ TYPE i;
+ TYPE j = 0;
+ ssize_t k;
+
+ for (i = 0; i < iterations; i++)
+ ACE_ASSERT (map.bind (i, i) != -1);
+
+ if (test_iterators)
+ {
+ {
+ i = 0;
+
+ HASH_CACHE_MAP_MANAGER::ITERATOR end = map.end ();
+
+ for (HASH_CACHE_MAP_MANAGER::ITERATOR iter = map.begin ();
+ iter != end;
+ ++iter)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%d|%d|%d)"),
+ i,
+ (*iter).first (),
+ (*iter).second ()));
+ ++i;
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\n")));
+ ACE_ASSERT (i == iterations);
+ }
+
+
+ {
+ k = iterations - 1;
+
+ HASH_CACHE_MAP_MANAGER::REVERSE_ITERATOR rend = map.rend ();
+
+ for (HASH_CACHE_MAP_MANAGER::REVERSE_ITERATOR iter = map.rbegin ();
+ iter != rend;
+ ++iter)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%d|%d|%d)"),
+ k,
+ (*iter).first (),
+ (*iter).second ()));
+ k--;
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\n")));
+ ACE_ASSERT (k == -1);
+ }
+
+
+ {
+ i = 0;
+
+ HASH_CACHE_MAP_MANAGER::iterator end = map.end ();
+
+ for (HASH_CACHE_MAP_MANAGER::iterator iter = map.begin ();
+ iter != end;
+ ++iter)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%d|%d|%d)"),
+ i,
+ (*iter).first (),
+ (*iter).second ()));
+ ++i;
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\n")));
+ ACE_ASSERT (i == iterations);
+ }
+
+
+ {
+ k = iterations - 1;
+
+ HASH_CACHE_MAP_MANAGER::reverse_iterator rend = map.rend ();
+
+ for (HASH_CACHE_MAP_MANAGER::reverse_iterator iter = map.rbegin ();
+ iter != rend;
+ ++iter)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%d|%d|%d)"),
+ k,
+ (*iter).first (),
+ (*iter).second ()));
+ k--;
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\n")));
+ ACE_ASSERT (k == -1);
+ }
+
+
+ }
+
+ for (i = 0; i < iterations; ++i)
+ {
+ ACE_ASSERT (map.find (i, j) != -1);
+ ACE_ASSERT (i == j);
+ }
+
+ size_t remaining_entries = iterations;
+ for (i = 0; i < iterations; ++i)
+ {
+ ACE_ASSERT (map.unbind (i) != -1);
+ --remaining_entries;
+ ACE_ASSERT (map.current_size () == remaining_entries);
+ }
+}
+
+
+static void
+test_active_map_manager (size_t table_size,
+ size_t iterations,
+ int test_iterators)
+{
+ ACTIVE_MAP_MANAGER map (table_size);
+ TYPE i;
+ TYPE j = 0;
+ ssize_t k;
+
+ ACTIVE_MAP_MANAGER::key_type *active_keys;
+
+ ACE_NEW (active_keys,
+ ACTIVE_MAP_MANAGER::key_type[iterations]);
+
+ for (i = 0;
+ i < iterations;
+ i++)
+ ACE_ASSERT (map.bind (i, active_keys[i]) != -1);
+
+ if (test_iterators)
+ {
+ {
+ i = 0;
+
+ ACTIVE_MAP_MANAGER::iterator end = map.end ();
+
+ for (ACTIVE_MAP_MANAGER::iterator iter = map.begin ();
+ iter != end;
+ ++iter)
+ {
+ ACTIVE_MAP_MANAGER::ENTRY &entry = *iter;
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%d|%d-%d|%d)"),
+ i,
+ entry.ext_id_.slot_index (),
+ entry.ext_id_.slot_generation (),
+ entry.int_id_));
+ ++i;
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\n")));
+ ACE_ASSERT (i == iterations);
+ }
+
+ {
+ k = iterations - 1;
+
+ ACTIVE_MAP_MANAGER::reverse_iterator rend = map.rend ();
+
+ for (ACTIVE_MAP_MANAGER::reverse_iterator iter = map.rbegin ();
+ iter != rend;
+ ++iter)
+ {
+ ACTIVE_MAP_MANAGER::ENTRY &entry = *iter;
+ ACE_UNUSED_ARG (entry);
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%d|%d-%d|%d)"),
+ k,
+ entry.ext_id_.slot_index (),
+ entry.ext_id_.slot_generation (),
+ entry.int_id_));
+ k--;
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\n")));
+ ACE_ASSERT (k == -1);
+ }
+ }
+
+ for (i = 0; i < iterations; ++i)
+ {
+ ACE_ASSERT (map.find (active_keys[i], j) != -1);
+ ACE_ASSERT (i == j);
+ }
+
+ size_t remaining_entries = iterations;
+ for (i = 0; i < iterations; ++i)
+ {
+ ACE_ASSERT (map.unbind (active_keys[i]) != -1);
+ --remaining_entries;
+ ACE_ASSERT (map.current_size () == remaining_entries);
+ }
+
+ delete [] active_keys;
+}
+
+static void
+test_hash_map_manager (size_t table_size,
+ size_t iterations,
+ int test_iterators)
+{
+ HASH_MAP_MANAGER map (table_size);
+ TYPE i;
+ TYPE j = 0;
+ ssize_t k;
+
+ for (i = 0; i < iterations; i++)
+ ACE_ASSERT (map.bind (i, i) != -1);
+
+ if (test_iterators)
+ {
+ {
+ i = 0;
+
+ HASH_ITERATOR end = map.end ();
+ for (HASH_ITERATOR iter = map.begin ();
+ iter != end;
+ ++iter)
+ {
+ HASH_ENTRY &entry = *iter;
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%d|%d|%d)"),
+ i,
+ entry.ext_id_,
+ entry.int_id_));
+ ++i;
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\n")));
+ ACE_ASSERT (i == iterations);
+ }
+
+ {
+ i = 0;
+ HASH_ENTRY *entry = 0;
+
+ for (HASH_ITERATOR iterator (map);
+ iterator.next (entry) != 0;
+ iterator.advance ())
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%d|%d|%d)"),
+ i,
+ entry->ext_id_,
+ entry->int_id_));
+ ++i;
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\n")));
+ ACE_ASSERT (i == iterations);
+ }
+
+ {
+ k = iterations - 1;
+ HASH_REVERSE_ITERATOR rend = map.rend ();
+
+ for (HASH_REVERSE_ITERATOR iter = map.rbegin ();
+ iter != rend;
+ ++iter)
+ {
+ HASH_ENTRY &entry = *iter;
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%d|%d|%d)"),
+ k,
+ entry.ext_id_,
+ entry.int_id_));
+ k--;
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\n")));
+ ACE_ASSERT (k == -1);
+ }
+
+ {
+ k = iterations - 1;
+ HASH_ENTRY *entry = 0;
+
+ for (HASH_REVERSE_ITERATOR iterator (map);
+ iterator.next (entry) != 0;
+ iterator.advance ())
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%d|%d|%d)"),
+ k,
+ entry->ext_id_,
+ entry->int_id_));
+ k--;
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\n")));
+ ACE_ASSERT (k == -1);
+ }
+
+ {
+ i = 0;
+
+ HASH_MAP_MANAGER::iterator end = map.end ();
+ for (HASH_MAP_MANAGER::iterator iter = map.begin ();
+ iter != end;
+ ++iter)
+ {
+ HASH_MAP_MANAGER::ENTRY &entry = *iter;
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%d|%d|%d)"),
+ i,
+ entry.ext_id_,
+ entry.int_id_));
+ ++i;
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\n")));
+ ACE_ASSERT (i == iterations);
+ }
+
+ {
+ i = 0;
+ HASH_MAP_MANAGER::ENTRY *entry = 0;
+
+ for (HASH_MAP_MANAGER::ITERATOR iterator (map);
+ iterator.next (entry) != 0;
+ iterator.advance ())
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%d|%d|%d)"),
+ i,
+ entry->ext_id_,
+ entry->int_id_));
+ ++i;
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\n")));
+ ACE_ASSERT (i == iterations);
+ }
+
+ {
+ k = iterations - 1;
+ HASH_MAP_MANAGER::reverse_iterator rend = map.rend ();
+
+ for (HASH_MAP_MANAGER::reverse_iterator iter = map.rbegin ();
+ iter != rend;
+ ++iter)
+ {
+ HASH_MAP_MANAGER::ENTRY &entry = *iter;
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%d|%d|%d)"),
+ k,
+ entry.ext_id_,
+ entry.int_id_));
+ k--;
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\n")));
+ ACE_ASSERT (k == -1);
+ }
+
+ {
+ k = iterations - 1;
+ HASH_MAP_MANAGER::ENTRY *entry = 0;
+
+ for (HASH_MAP_MANAGER::REVERSE_ITERATOR iterator (map);
+ iterator.next (entry) != 0;
+ iterator.advance ())
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%d|%d|%d)"),
+ k,
+ entry->ext_id_,
+ entry->int_id_));
+ k--;
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\n")));
+ ACE_ASSERT (k == -1);
+ }
+ }
+
+ for (i = 0; i < iterations; ++i)
+ {
+ ACE_ASSERT (map.find (i, j) != -1);
+ ACE_ASSERT (i == j);
+ }
+
+ size_t remaining_entries = iterations;
+ for (i = 0; i < iterations; ++i)
+ {
+ ACE_ASSERT (map.unbind (i) != -1);
+ --remaining_entries;
+ ACE_ASSERT (map.current_size () == remaining_entries);
+ }
+}
+
+static void
+test_map_manager (size_t table_size,
+ size_t iterations,
+ int test_iterators)
+{
+ MAP_MANAGER map (table_size);
+ TYPE i;
+ TYPE j = 0;
+ ssize_t k;
+
+ for (i = 0; i < iterations; ++i)
+ ACE_ASSERT (map.bind (i, i) != -1);
+
+ if (test_iterators)
+ {
+ {
+ i = 0;
+
+ ITERATOR end = map.end ();
+ for (ITERATOR iter = map.begin ();
+ iter != end;
+ ++iter)
+ {
+ MAP_ENTRY &entry = *iter;
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%d|%d|%d)"),
+ i,
+ entry.ext_id_,
+ entry.int_id_));
+ ++i;
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\n")));
+ ACE_ASSERT (i == iterations);
+ }
+
+ {
+ i = 0;
+ MAP_ENTRY *entry = 0;
+
+ for (ITERATOR iterator (map);
+ iterator.next (entry) != 0;
+ iterator.advance ())
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%d|%d|%d)"),
+ i,
+ entry->ext_id_,
+ entry->int_id_));
+ ++i;
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\n")));
+ ACE_ASSERT (i == iterations);
+ }
+
+ {
+ k = iterations - 1;
+ REVERSE_ITERATOR rend = map.rend ();
+
+ for (REVERSE_ITERATOR iter = map.rbegin ();
+ iter != rend;
+ ++iter)
+ {
+ MAP_ENTRY &entry = *iter;
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%d|%d|%d)"),
+ k,
+ entry.ext_id_,
+ entry.int_id_));
+ k--;
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\n")));
+ ACE_ASSERT (k == -1);
+ }
+
+ {
+ k = iterations - 1;
+ MAP_ENTRY *entry = 0;
+
+ for (REVERSE_ITERATOR iterator (map);
+ iterator.next (entry) != 0;
+ iterator.advance ())
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%d|%d|%d)"),
+ k,
+ entry->ext_id_,
+ entry->int_id_));
+ k--;
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\n")));
+ ACE_ASSERT (k == -1);
+ }
+
+ {
+ i = 0;
+
+ MAP_MANAGER::iterator end = map.end ();
+ for (MAP_MANAGER::iterator iter = map.begin ();
+ iter != end;
+ ++iter)
+ {
+ MAP_MANAGER::ENTRY &entry = *iter;
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%d|%d|%d)"),
+ i,
+ entry.ext_id_,
+ entry.int_id_));
+ ++i;
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\n")));
+ ACE_ASSERT (i == iterations);
+ }
+
+ {
+ i = 0;
+ MAP_MANAGER::ENTRY *entry = 0;
+
+ for (MAP_MANAGER::ITERATOR iterator (map);
+ iterator.next (entry) != 0;
+ iterator.advance ())
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%d|%d|%d)"),
+ i,
+ entry->ext_id_,
+ entry->int_id_));
+ ++i;
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\n")));
+ ACE_ASSERT (i == iterations);
+ }
+
+ {
+ k = iterations - 1;
+ MAP_MANAGER::reverse_iterator rend = map.rend ();
+
+ for (MAP_MANAGER::reverse_iterator iter = map.rbegin ();
+ iter != rend;
+ ++iter)
+ {
+ MAP_ENTRY &entry = *iter;
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%d|%d|%d)"),
+ k,
+ entry.ext_id_,
+ entry.int_id_));
+ k--;
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\n")));
+ ACE_ASSERT (k == -1);
+ }
+
+ {
+ k = iterations - 1;
+ MAP_MANAGER::ENTRY *entry = 0;
+
+ for (MAP_MANAGER::REVERSE_ITERATOR iterator (map);
+ iterator.next (entry) != 0;
+ iterator.advance ())
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%d|%d|%d)"),
+ k,
+ entry->ext_id_,
+ entry->int_id_));
+ k--;
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\n")));
+ ACE_ASSERT (k == -1);
+ }
+ }
+
+ for (i = 0; i < iterations; ++i)
+ {
+ ACE_ASSERT (map.find (i, j) != -1);
+ ACE_ASSERT (i == j);
+ }
+
+ size_t remaining_entries = iterations;
+ for (i = 0; i < iterations; ++i)
+ {
+ ACE_ASSERT (map.unbind (i) != -1);
+ --remaining_entries;
+ ACE_ASSERT (map.current_size () == remaining_entries);
+ }
+
+ //
+ // This is extra for the map manager.
+ //
+ for (i = 0; i < iterations; ++i)
+ ACE_ASSERT (map.bind (i, i) != -1);
+
+ // Unbind in one swoop.
+ map.unbind_all ();
+ ACE_ASSERT (map.current_size () == 0);
+
+ for (i = 0; i < iterations; ++i)
+ ACE_ASSERT (map.bind (i, i) != -1);
+
+ // Unbind one at a time.
+ MAP_MANAGER::iterator end = map.end ();
+ while (1)
+ {
+ MAP_MANAGER::iterator iter = map.begin ();
+ if (iter == end)
+ break;
+ ACE_ASSERT (map.unbind ((*iter).ext_id_) != -1);
+ }
+
+ ACE_ASSERT (map.current_size () == 0);
+}
+
+static void
+run_test (void (*ptf) (size_t, size_t, int),
+ size_t table_size,
+ size_t iterations,
+ int test_iterators,
+ const ACE_TCHAR *test_name)
+{
+ ACE_Profile_Timer timer;
+ timer.start ();
+
+ (*ptf) (table_size, iterations, test_iterators);
+
+ timer.stop ();
+
+ ACE_Profile_Timer::ACE_Elapsed_Time et;
+
+ timer.elapsed_time (et);
+
+ ACE_TCHAR *test_iterators_string = 0;
+
+ if (test_iterators)
+ test_iterators_string =
+ const_cast<ACE_TCHAR*> (ACE_TEXT ( "includes executing iterators"));
+ else
+ test_iterators_string =
+ const_cast<ACE_TCHAR*> (ACE_TEXT ("doesn't include executing iterators"));
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("time to test a map of size %d for %d iterations using %s (%s)\n"),
+ table_size,
+ iterations,
+ test_name,
+ test_iterators_string));
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("real time = %f secs, user time = %f secs, system time = %f secs\n"),
+ et.real_time,
+ et.user_time,
+ et.system_time));
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("time per call = %f usecs\n"),
+ (et.real_time / ACE_timer_t (iterations)) * 1000000));
+}
+
+int
+run_main (int argc, ACE_TCHAR *argv[])
+{
+ ACE_START_TEST (ACE_TEXT ("Map_Manager_Test"));
+ ACE_LOG_MSG->clr_flags (ACE_Log_Msg::VERBOSE_LITE);
+
+ size_t table_size = ACE_MAX_ITERATIONS / 2;
+ size_t iterations = ACE_MAX_ITERATIONS;
+ int test_iterators = 1;
+
+ if (argc > 1)
+ table_size = ACE_OS::atoi (argv[1]);
+
+ if (argc > 2)
+ iterations = ACE_OS::atoi (argv[2]);
+
+ if (argc > 3)
+ test_iterators = ACE_OS::atoi (argv[3]);
+
+ // Test the <ACE_Map_Manager>.
+ run_test (&test_map_manager,
+ table_size,
+ iterations,
+ test_iterators,
+ ACE_TEXT ("Map_Manager"));
+
+ // Test the <ACE_Hash_Map_Manager>.
+ run_test (&test_hash_map_manager,
+ table_size,
+ iterations,
+ test_iterators,
+ ACE_TEXT ("Hash_Map_Manager"));
+
+ // Test the <ACE_Hash_Map_Manager>.
+ run_test (&test_active_map_manager,
+ table_size,
+ iterations,
+ test_iterators,
+ ACE_TEXT ("Active_Map_Manager"));
+
+ // Test the <ACE_Cache_Map_Manager>.
+ run_test (&test_cache_map_manager,
+ table_size,
+ iterations,
+ test_iterators,
+ ACE_TEXT ("Cache_Map_Manager"));
+
+ // Test the <ACE_Hash_Cache_Map_Manager>.
+ run_test (&test_hash_cache_map_manager,
+ table_size,
+ iterations,
+ test_iterators,
+ ACE_TEXT ("Hash_Cache_Map_Manager"));
+ ACE_LOG_MSG->set_flags (ACE_Log_Msg::VERBOSE_LITE);
+ ACE_END_TEST;
+ return 0;
+}
+
diff --git a/ACE/tests/Map_Test.cpp b/ACE/tests/Map_Test.cpp
new file mode 100644
index 00000000000..b27ef4083b3
--- /dev/null
+++ b/ACE/tests/Map_Test.cpp
@@ -0,0 +1,369 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Map_Test.cpp
+//
+// = DESCRIPTION
+// This is a simple test of the <ACE_Map> and illustrates how to
+// use the forward and reverse iterators.
+//
+// = AUTHOR
+// Irfan Pyarali <irfan@cs.wustl.edu>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "Map_Test.h"
+#include "ace/Map_T.h"
+#include "ace/Profile_Timer.h"
+
+ACE_RCSID(tests, Map_Test, "$Id$")
+
+// Value type.
+typedef size_t VALUE;
+
+// Generic map type.
+typedef ACE_Map<KEY, VALUE> TEST_MAP;
+
+// Manager Manager adapter.
+typedef ACE_Map_Manager_Adapter<KEY, VALUE, Key_Generator> MAP_MANAGER_ADAPTER;
+
+// Hash Manager Manager adapter.
+typedef ACE_Hash_Map_Manager_Ex_Adapter<KEY, VALUE, Hash_Key, ACE_Equal_To<KEY>, Key_Generator> HASH_MAP_MANAGER_ADAPTER;
+
+// Active Manager Manager adapter.
+typedef ACE_Active_Map_Manager_Adapter<KEY, VALUE, Key_Adapter> ACTIVE_MAP_MANAGER_ADAPTER;
+
+static void
+functionality_test (TEST_MAP &map,
+ size_t iterations)
+{
+ size_t counter;
+ VALUE i;
+ KEY *original_keys = new KEY[iterations];
+ KEY *modified_keys = new KEY[iterations];
+
+ // Setup the keys to have some initial data.
+ for (i = 0;
+ i < iterations;
+ ++i)
+ {
+ original_keys[i].size (sizeof i / sizeof (KEY::TYPE));
+ ACE_OS::memcpy (&original_keys[i][0],
+ &i,
+ sizeof i);
+ }
+
+ // Make a copy of the keys so that we can compare with the original
+ // keys later.
+ for (i = 0; i < iterations; ++i)
+ {
+ modified_keys[i] = original_keys[i];
+ }
+
+ // Add to the map, allowing keys to be modified.
+ counter = 0;
+ for (i = 0; i < iterations; ++i)
+ {
+ ACE_ASSERT (map.bind_modify_key (i, modified_keys[i]) == 0);
+ ++counter;
+ ACE_ASSERT (map.current_size () == counter);
+ }
+
+ // Forward iteration...
+ {
+ counter = 0;
+ TEST_MAP::iterator end = map.end ();
+
+ for (TEST_MAP::iterator iter = map.begin ();
+ iter != end;
+ ++iter, ++counter)
+ {
+ TEST_MAP::value_type entry = *iter;
+
+ // Recover original key.
+ KEY original_key;
+ ACE_ASSERT (map.recover_key (entry.first (),
+ original_key) == 0);
+
+ // Make sure recovering keys work.
+ ACE_ASSERT (original_keys[entry.second ()] == original_key);
+
+ // Obtain value from key.
+ VALUE original_value;
+ ACE_OS::memcpy (&original_value,
+ &original_key[0],
+ sizeof original_value);
+
+ // Debugging info.
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%d|%d|%d)"),
+ counter,
+ original_value,
+ entry.second ()));
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\n")));
+ ACE_ASSERT (counter == iterations);
+ }
+
+ // Reverse iteration...
+ {
+ counter = iterations;
+ TEST_MAP::reverse_iterator end = map.rend ();
+
+ for (TEST_MAP::reverse_iterator iter = map.rbegin ();
+ iter != end;
+ ++iter)
+ {
+ --counter;
+ TEST_MAP::value_type entry = *iter;
+
+ // Recover original key.
+ KEY original_key;
+ ACE_ASSERT (map.recover_key (entry.first (),
+ original_key) == 0);
+
+ // Make sure recovering keys work.
+ ACE_ASSERT (original_keys[entry.second ()] == original_key);
+
+ // Obtain value from key.
+ VALUE original_value;
+ ACE_OS::memcpy (&original_value,
+ &original_key[0],
+ sizeof original_value);
+
+ // Debugging info.
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%d|%d|%d)"),
+ counter,
+ original_value,
+ entry.second ()));
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\n")));
+ ACE_ASSERT (counter == 0);
+ }
+
+ // Search using the modified keys.
+ for (i = 0; i < iterations; ++i)
+ {
+ VALUE j;
+ ACE_ASSERT (map.find (modified_keys[i], j) != -1);
+ ACE_ASSERT (i == j);
+ }
+
+ // Rmoved keys from map.
+ counter = iterations;
+ for (i = 0; i < iterations; ++i)
+ {
+ ACE_ASSERT (map.unbind (modified_keys[i]) != -1);
+ --counter;
+ ACE_ASSERT (map.current_size () == counter);
+ }
+
+ // Cleanup.
+ delete[] modified_keys;
+ delete[] original_keys;
+}
+
+static void
+insert_test (TEST_MAP &map,
+ size_t iterations,
+ KEY *keys)
+{
+ // Add to the map, allowing keys to be created by the map.
+ size_t counter = 0;
+ for (VALUE i = 0; i < iterations; ++i)
+ {
+ ACE_ASSERT (map.bind_create_key (i, keys[i]) == 0);
+ ++counter;
+ ACE_ASSERT (map.current_size () == counter);
+ }
+}
+
+static void
+find_test (TEST_MAP &map,
+ size_t iterations,
+ KEY *keys)
+{
+ // Find system generated keys.
+ for (VALUE i = 0; i < iterations; ++i)
+ {
+ VALUE j;
+ ACE_ASSERT (map.find (keys[i], j) != -1);
+ ACE_ASSERT (i == j);
+ }
+}
+
+static void
+unbind_test (TEST_MAP &map,
+ size_t iterations,
+ KEY *keys)
+{
+ // Remove system generated keys.
+ size_t counter = iterations;
+ for (VALUE i = 0; i < iterations; ++i)
+ {
+ ACE_ASSERT (map.unbind (keys[i]) != -1);
+ --counter;
+ ACE_ASSERT (map.current_size () == counter);
+ }
+}
+
+static void
+performance_test (void (*ptf) (TEST_MAP &, size_t, KEY *),
+ TEST_MAP &map,
+ size_t iterations,
+ KEY *keys,
+ size_t table_size,
+ const ACE_TCHAR *test_name)
+{
+ ACE_Profile_Timer timer;
+ timer.start ();
+
+ (*ptf) (map, iterations, keys);
+
+ timer.stop ();
+
+ ACE_Profile_Timer::ACE_Elapsed_Time et;
+
+ timer.elapsed_time (et);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("time to run %s of size %d for %d iterations\n"),
+ test_name,
+ table_size,
+ iterations));
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("real time = %f secs, user time = %f secs, system time = %f secs\n"),
+ et.real_time,
+ et.user_time,
+ et.system_time));
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("time per call = %f usecs\n"),
+ (et.real_time / ACE_timer_t (iterations)) * 1000000));
+}
+
+int
+run_main (int argc, ACE_TCHAR *argv[])
+{
+ ACE_START_TEST (ACE_TEXT ("Map_Test"));
+ ACE_LOG_MSG->clr_flags (ACE_Log_Msg::VERBOSE_LITE);
+
+ size_t table_size = ACE_MAX_ITERATIONS / 2;
+ size_t iterations = ACE_MAX_ITERATIONS;
+ size_t functionality_tests = 1;
+
+ if (argc > 1)
+ functionality_tests = ACE_OS::atoi (argv[1]);
+
+ if (argc > 2)
+ table_size = ACE_OS::atoi (argv[2]);
+
+ if (argc > 3)
+ iterations = ACE_OS::atoi (argv[3]);
+
+ MAP_MANAGER_ADAPTER map1 (table_size);
+ HASH_MAP_MANAGER_ADAPTER map2 (table_size);
+ ACTIVE_MAP_MANAGER_ADAPTER map3 (table_size);
+
+ if (functionality_tests)
+ {
+ // Functionality test of the maps.
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\nMap Manager functionality test\n")));
+ functionality_test (map1, iterations);
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\nHash Map Manager functionality test\n")));
+ functionality_test (map2, iterations);
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\nActive Map Manager functionality test\n")));
+ functionality_test (map3, iterations);
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\n")));
+ }
+
+ // Performance test of the maps.
+ KEY *keys = new KEY[iterations];
+
+ // Map Manager
+ performance_test (&insert_test,
+ map1,
+ iterations,
+ keys,
+ table_size,
+ ACE_TEXT ("Map Manager (insert test)"));
+ performance_test (&find_test,
+ map1,
+ iterations,
+ keys,
+ table_size,
+ ACE_TEXT ("Map Manager (find test)"));
+ performance_test (&unbind_test,
+ map1,
+ iterations,
+ keys,
+ table_size,
+ ACE_TEXT ("Map Manager (unbind test)"));
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\n")));
+
+ // Hash Map Manager
+ performance_test (&insert_test,
+ map2,
+ iterations,
+ keys,
+ table_size,
+ ACE_TEXT ("Hash Map Manager (insert test)"));
+ performance_test (&find_test,
+ map2,
+ iterations,
+ keys,
+ table_size,
+ ACE_TEXT ("Hash Map Manager (find test)"));
+ performance_test (&unbind_test,
+ map2,
+ iterations,
+ keys,
+ table_size,
+ ACE_TEXT ("Hash Map Manager (unbind test)"));
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\n")));
+
+ // Active Map Manager
+ performance_test (&insert_test,
+ map3,
+ iterations,
+ keys,
+ table_size,
+ ACE_TEXT ("Active Map Manager (insert test)"));
+ performance_test (&find_test,
+ map3,
+ iterations,
+ keys,
+ table_size,
+ ACE_TEXT ("Active Map Manager (find test)"));
+ performance_test (&unbind_test,
+ map3,
+ iterations,
+ keys,
+ table_size,
+ ACE_TEXT ("Active Map Manager (unbind test)"));
+
+ delete[] keys;
+
+ ACE_LOG_MSG->set_flags (ACE_Log_Msg::VERBOSE_LITE);
+ ACE_END_TEST;
+
+ return 0;
+}
+
diff --git a/ACE/tests/Map_Test.h b/ACE/tests/Map_Test.h
new file mode 100644
index 00000000000..c881a3f7645
--- /dev/null
+++ b/ACE/tests/Map_Test.h
@@ -0,0 +1,151 @@
+/* -*- C++ -*- */
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Map_Test.h
+//
+// = DESCRIPTION
+// This file has the class definitions needed for template generation in
+// Map_Test.cpp. They have to be in a separate file so AIX xlC can
+// find them at auto-instantiate time.
+//
+// = AUTHOR
+// Irfan Pyarali <irfan@cs.wustl.edu>
+//
+// ============================================================================
+
+#ifndef ACE_TESTS_MAP_TEST_H
+#define ACE_TESTS_MAP_TEST_H
+
+#include "ace/OS_NS_string.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "ace/Active_Map_Manager.h"
+#include "ace/Containers.h"
+
+// Key data type.
+typedef ACE_Array<char> KEY;
+
+class Key_Generator
+{
+ // = TITLE
+ // Defines a key generator.
+ //
+ // = DESCRIPTION
+ // This class is used in adapters of maps that do not produce keys.
+public:
+
+ Key_Generator (void)
+ : counter_ (0)
+ {
+ }
+
+ int operator() (KEY &key)
+ {
+ // Keep original information in the key intact.
+ size_t original_size = key.size ();
+
+ // Size of this counter key.
+ size_t counter_key_size = sizeof this->counter_;
+
+ // Resize to accommodate both the original data and the new key.
+ key.size (counter_key_size + original_size);
+
+ // Add new key data.
+ ACE_OS::memcpy (&key[original_size],
+ &++this->counter_,
+ sizeof this->counter_);
+
+ // Success.
+ return 0;
+ }
+
+private:
+ u_long counter_;
+};
+
+class Hash_Key
+{
+public:
+ u_long operator () (const KEY &key) const
+ {
+ // Recover system generated part of key.
+ u_long value;
+ size_t counter_key_size = sizeof (u_long);
+
+ // Copy system key from user key.
+ ACE_OS::memcpy (&value,
+ &key[key.size () - counter_key_size],
+ sizeof value);
+
+ // Return the system key value as the hash value.
+ return value;
+ }
+};
+
+class Key_Adapter
+{
+public:
+
+ int encode (const KEY &original_key,
+ const ACE_Active_Map_Manager_Key &active_key,
+ KEY &modified_key)
+ {
+ // Keep original information in the key intact.
+ modified_key = original_key;
+ size_t original_size = modified_key.size ();
+
+ // Size of active key.
+ size_t active_key_size = active_key.size ();
+
+ // Resize to accommodate both the original data and the new active key.
+ modified_key.size (active_key_size + original_size);
+
+ // Copy active key data into user key.
+ active_key.encode (&modified_key[original_size]);
+
+ // Success.
+ return 0;
+ }
+
+ int decode (const KEY &modified_key,
+ ACE_Active_Map_Manager_Key &active_key)
+ {
+ // Read the active key data from the back of the key.
+ size_t active_key_size = active_key.size ();
+ size_t original_size = modified_key.size () - active_key_size;
+
+ // Read off value of index and generation.
+ active_key.decode (&modified_key[original_size]);
+
+ // Success.
+ return 0;
+ }
+
+ int decode (const KEY &modified_key,
+ KEY &original_key)
+ {
+ // Read the original user key data from the front of the
+ // modified key.
+ size_t active_key_size = ACE_Active_Map_Manager_Key::size ();
+
+ // Copy all the data.
+ original_key = modified_key;
+
+ // Resize to ignore active key data.
+ original_key.size (original_key.size () - active_key_size);
+
+ // Success.
+ return 0;
+ }
+};
+
+#endif /* ACE_TESTS_MAP_TEST_H */
diff --git a/ACE/tests/Max_Default_Port_Test.cpp b/ACE/tests/Max_Default_Port_Test.cpp
new file mode 100644
index 00000000000..5a07a0abb35
--- /dev/null
+++ b/ACE/tests/Max_Default_Port_Test.cpp
@@ -0,0 +1,292 @@
+// $Id$
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Max_Default_Port_Test.cpp
+//
+// = DESCRIPTION
+// This is a test for ACE_MAX_DEFAULT_PORT value. The test tests the
+// highest value of the port number at which an event handler can be
+// registered and a Connector can be connected to.
+//
+// Some weird behaviour has been reported on Windows NT (sp 3) when
+// the port number exceeds 65279 resulting ACE_MAX_DEFAULT_PORT to set
+// to zero on that platform.
+//
+// In this test, the event handler is started at the port value
+// USHRT_MAX and decremented for 300 port values and tested if the
+// highest port number used agrees with ACE_MAX_DEFAULT_PORT value.
+//
+//
+// = AUTHOR
+// Chanaka Liyanaarachchi <chanaka@ociweb.com>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/Reactor.h"
+#include "ace/SOCK_Connector.h"
+#include "ace/Thread_Manager.h"
+#include "ace/OS_NS_unistd.h"
+#include "ace/Time_Value.h"
+
+#include "Max_Default_Port_Test.h"
+
+// implement a retry and recuperation mechanism for VxWorks because test will otherwise fail
+// on a non-optimized kernel with several ETIME errors on the client connects.
+#if defined (ACE_VXWORKS)
+int retry_port_ = 0;
+#endif
+
+My_Accept_Handler::My_Accept_Handler (ACE_INET_Addr &addr)
+ : addr_ (addr)
+{
+ if (addr.get_port_number() != 0)
+ this->open (addr);
+}
+
+
+My_Accept_Handler::~My_Accept_Handler ()
+{
+ this->peer_acceptor_.close (); // Prevent handle leaks
+}
+
+
+int
+My_Accept_Handler::open (ACE_INET_Addr &addr)
+{
+
+ if (this->peer_acceptor_.open (addr, 1) == -1)
+ {
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"),
+ ACE_TEXT ("My_Accept_Handler open")));
+ ACE_OS::exit (1);
+ }
+
+ return 0;
+
+}
+
+ACE_HANDLE
+My_Accept_Handler::get_handle () const
+{
+ return this->peer_acceptor_.get_handle ();
+}
+
+int
+My_Accept_Handler::handle_input (ACE_HANDLE)
+{
+
+ if (this->peer_acceptor_.accept(this->stream_, 0) == -1) {
+ ACE_ERROR((LM_ERROR, ACE_TEXT ("%p\n"),
+ ACE_TEXT ("peer_acceptor.accept")));
+ ACE_OS::exit(1);
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("My_Accept_Handler::handle_input \n")));
+
+ // Close the opened stream, else it'll leak a handle. Don't close
+ // the acceptor here, though, because get_handle() needs it to
+ // correctly allow removal from the reactor later. It gets closed
+ // in the destructor.
+ this->stream_.close ();
+
+ return 0;
+}
+
+u_short
+My_Accept_Handler::port ()
+{
+ return this->addr_.get_port_number();
+}
+
+long max_connected_port = 0;
+
+static void *
+client (void *arg)
+{
+ ACE_INET_Addr *remote_addr = reinterpret_cast<ACE_INET_Addr *> (arg);
+
+ ACE_INET_Addr server_addr (remote_addr->get_port_number (),
+ ACE_LOCALHOST,
+ AF_INET);
+
+ ACE_SOCK_Stream cli_stream;
+ ACE_SOCK_Connector con;
+ ACE_Time_Value timeout (ACE_DEFAULT_TIMEOUT);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Connecting to port %d\n"),
+ server_addr.get_port_number()));
+
+ // Initiate connection with server; don't wait forever
+ if (con.connect (cli_stream,
+ server_addr,
+ &timeout) == -1)
+ {
+#if defined (ACE_VXWORKS)
+ if (errno == ETIME)
+ {
+ if ( ++retry_port_<6 )
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Going to retry port %d\n"),
+ server_addr.get_port_number()));
+ }
+ }
+ if ( retry_port_>5 )
+ {
+ retry_port_ = 0;
+#endif
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n"),
+ ACE_TEXT ("connection failed")));
+
+#if defined (ACE_VXWORKS)
+ }
+#endif
+ return 0;
+ }
+
+#if defined (ACE_VXWORKS)
+ retry_port_ = 0;
+#endif
+
+ // if connect succesful, what is the max port number we connected
+ // up to now.
+ int connected_port = server_addr.get_port_number ();
+
+ if (connected_port > max_connected_port)
+ max_connected_port = connected_port;
+
+ cli_stream.close ();
+
+ return 0;
+}
+
+int
+run_main (int argc, ACE_TCHAR *argv[])
+{
+
+ ACE_START_TEST (ACE_TEXT ("Max_Default_Port_Test"));
+
+ ACE_UNUSED_ARG (argc);
+ ACE_UNUSED_ARG (argv);
+
+ u_short max_listened_port = 0;
+
+ //Ports beyond 65279 were said to bad on NT sp 3.
+ for (u_short idx = USHRT_MAX; idx != USHRT_MAX - 300; --idx)
+ {
+#if defined (ACE_VXWORKS)
+ if (retry_port_>0)
+ {
+ ++idx;
+ ACE_OS::sleep (ACE_Time_Value (2*ACE_DEFAULT_TIMEOUT));
+ }
+#endif
+
+ ACE_INET_Addr addr (idx);
+
+ My_Accept_Handler *eh = new My_Accept_Handler (addr);
+
+
+ if ( ACE_Reactor::instance()->register_handler (
+ eh,
+ ACE_Event_Handler::ACCEPT_MASK) == -1)
+ {
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("Failed to register event handler")),
+ 1);
+ }
+
+ ACE_DEBUG ((LM_DEBUG, "Registered event handler at %d\n", idx));
+
+ ACE_Time_Value tv (1);
+
+#if defined (ACE_HAS_THREADS)
+
+ if (ACE_Thread_Manager::instance ()->spawn_n
+ (1,
+ ACE_THR_FUNC (client),
+ reinterpret_cast <void *> (&addr),
+ THR_NEW_LWP | THR_DETACHED) == -1)
+
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n"),
+ ACE_TEXT ("thread create failed")),
+ 1);
+
+ ACE_Thread_Manager::instance ()->wait ();
+
+#else
+ ACE_UNUSED_ARG (client);
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) only one thread may be run in a process on this platform\n%a"),
+ 1));
+#endif //ACE_HAS_THREADS
+
+ if (ACE_Reactor::instance()->handle_events (tv) == -1 )
+ {
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"),
+ ACE_TEXT ("Reactor::handle_events")),
+ 1);
+ }
+
+ // see if I can register a reactor at this port.
+ if (eh->port () == idx)
+ {
+ if (idx > max_listened_port)
+ max_listened_port = idx;
+ }
+ else
+ {
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("Test Fail, listening port %d\n"),
+ eh->port()),
+ 1);
+ }
+
+ ACE_Reactor::instance()->remove_handler (
+ eh,
+ ACE_Event_Handler::ACCEPT_MASK |
+ ACE_Event_Handler::DONT_CALL);
+ delete eh;
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ "Value of ACE_MAX_DEFAULT_PORT %d\n",
+ ACE_MAX_DEFAULT_PORT));
+
+ ACE_DEBUG ((LM_DEBUG,
+ "Highest port value I can listen at %d\n",
+ max_listened_port));
+
+ ACE_DEBUG ((LM_DEBUG,
+ "Highest port value I can connect to %d\n",
+ max_connected_port));
+
+ if ((max_listened_port == ACE_MAX_DEFAULT_PORT) &&
+ (max_connected_port == ACE_MAX_DEFAULT_PORT))
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Valid ACE_MAX_DEFAULT_PORT value: %d\n"),
+ max_listened_port));
+ }
+ else
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Invalid ACE_MAX_DEFAULT_PORT ")
+ ACE_TEXT ("or %d port may be busy; got to %d\n"),
+ ACE_MAX_DEFAULT_PORT, max_listened_port));
+
+ }
+
+ ACE_END_TEST;
+ return 0;
+}
diff --git a/ACE/tests/Max_Default_Port_Test.h b/ACE/tests/Max_Default_Port_Test.h
new file mode 100644
index 00000000000..78969cf05e1
--- /dev/null
+++ b/ACE/tests/Max_Default_Port_Test.h
@@ -0,0 +1,53 @@
+// $Id$
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Max_Default_Port_Test.h
+//
+// = DESCRIPTION
+// This is a test to verify ACE_MAX_DEFAULT_PORT is correct.
+//
+// = AUTHOR
+// Chanaka Liyanaarachchi <chanaka@ociweb.com>
+//
+// ===========================================================================
+
+
+#ifndef ACE_TESTS_MAX_DEFAULT_PORT_TEST
+#define ACE_TESTS_MAX_DEFAULT_PORT_TEST
+
+#include "ace/Event_Handler.h"
+#include "ace/SOCK_Acceptor.h"
+#include "ace/SOCK_Stream.h"
+#include "ace/INET_Addr.h"
+
+class My_Accept_Handler : public ACE_Event_Handler
+{
+ // = Title
+ // A simple event handler
+
+public:
+ My_Accept_Handler (ACE_INET_Addr &addr);
+ ~My_Accept_Handler ();
+
+ int open (ACE_INET_Addr &addr);
+
+ ACE_HANDLE get_handle () const;
+
+ int handle_input (ACE_HANDLE handle);
+
+ u_short port ();
+ // Returns the port the event handler is listening at.
+
+private:
+ ACE_SOCK_Acceptor peer_acceptor_;
+
+ ACE_SOCK_Stream stream_;
+
+ ACE_INET_Addr addr_;
+};
+
+#endif /* ACE_TESTS_MAX_DEFAULT_PORT_TEST */
diff --git a/ACE/tests/Max_Default_Port_Test_IPV6.cpp b/ACE/tests/Max_Default_Port_Test_IPV6.cpp
new file mode 100644
index 00000000000..bc0e9809ee0
--- /dev/null
+++ b/ACE/tests/Max_Default_Port_Test_IPV6.cpp
@@ -0,0 +1,255 @@
+// $Id$
+// ============================================================================
+/**
+ * @file Max_Default_Port_Test_IPV6.cpp
+ *
+ * @brief This is a test for ACE_MAX_DEFAULT_PORT value.
+ *
+ * The test tests the highest value of the port number at which an
+ * event handler can be registered and a Connector can be connected
+ * to.
+ *
+ * Some weird behaviour has been reported on Windows NT (sp 3) when
+ * the port number exceeds 65279 resulting ACE_MAX_DEFAULT_PORT to set
+ * to zero on that platform.
+ *
+ * In this test, the event handler is started at the port value
+ * USHRT_MAX and decremented for 300 port values and tested if the
+ * highest port number used agrees with ACE_MAX_DEFAULT_PORT value.
+ *
+ * @author Chanaka Liyanaarachchi <chanaka@ociweb.com>
+ * Brian Buesker <bbuesker@qualcomm.com>
+ */
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/Reactor.h"
+#include "ace/SOCK_Connector.h"
+#include "ace/Thread_Manager.h"
+
+#include "Max_Default_Port_Test.h"
+
+My_Accept_Handler::My_Accept_Handler (ACE_INET_Addr &addr)
+ : addr_ (addr)
+{
+ if (addr.get_port_number() != 0)
+ this->open (addr);
+}
+
+
+My_Accept_Handler::~My_Accept_Handler ()
+{
+ this->peer_acceptor_.close (); // Prevent handle leaks
+}
+
+
+int
+My_Accept_Handler::open (ACE_INET_Addr &addr)
+{
+
+ if (this->peer_acceptor_.open (addr, 1) == -1)
+ {
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"),
+ ACE_TEXT ("My_Accept_Handler open")));
+ ACE_OS::exit (1);
+ }
+
+ return 0;
+
+}
+
+ACE_HANDLE
+My_Accept_Handler::get_handle () const
+{
+ return this->peer_acceptor_.get_handle ();
+}
+
+int
+My_Accept_Handler::handle_input (ACE_HANDLE)
+{
+
+ if (this->peer_acceptor_.accept(this->stream_, 0) == -1) {
+ ACE_ERROR((LM_ERROR, ACE_TEXT ("%p\n"),
+ ACE_TEXT ("peer_acceptor.accept")));
+ ACE_OS::exit(1);
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("My_Accept_Handler::handle_input \n")));
+
+ // Close the opened stream, else it'll leak a handle. Don't close
+ // the acceptor here, though, because get_handle() needs it to
+ // correctly allow removal from the reactor later. It gets closed
+ // in the destructor.
+ this->stream_.close ();
+
+ return 0;
+}
+
+u_short
+My_Accept_Handler::port ()
+{
+ return this->addr_.get_port_number();
+}
+
+long max_connected_port = 0;
+
+#if defined (ACE_HAS_IPV6)
+static void *
+client (void *arg)
+{
+ ACE_INET_Addr *remote_addr = reinterpret_cast<ACE_INET_Addr *> (arg);
+
+ ACE_INET_Addr server_addr (remote_addr->get_port_number (),
+ "::1");
+
+ ACE_SOCK_Stream cli_stream;
+
+ ACE_SOCK_Connector con;
+ ACE_Time_Value timeout (ACE_DEFAULT_TIMEOUT);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Connecting to port %d\n"),
+ server_addr.get_port_number()));
+
+ // Initiate connection with server; don't wait forever
+ if (con.connect (cli_stream,
+ server_addr,
+ &timeout) == -1)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n"),
+ ACE_TEXT ("connection failed")));
+
+ return 0;
+ }
+
+ // if connect succesful, what is the max port number we connected
+ // up to now.
+ int connected_port = server_addr.get_port_number ();
+
+ if (connected_port > max_connected_port)
+ max_connected_port = connected_port;
+
+ cli_stream.close ();
+
+ return 0;
+}
+#endif /*ACE_HAS_IPV6*/
+
+int
+run_main (int argc, ACE_TCHAR *argv[])
+{
+ ACE_START_TEST (ACE_TEXT ("Max_Default_Port_Test_IPV6"));
+
+ ACE_UNUSED_ARG (argc);
+ ACE_UNUSED_ARG (argv);
+
+#if defined (ACE_HAS_IPV6)
+ u_short max_listened_port = 0;
+
+ //Ports beyond 65279 were said to bad on NT sp 3.
+ for (u_short idx = USHRT_MAX; idx != USHRT_MAX - 300; --idx)
+ {
+ ACE_INET_Addr addr (idx, "::");
+
+ My_Accept_Handler *eh = new My_Accept_Handler (addr);
+
+
+ if ( ACE_Reactor::instance()->register_handler (
+ eh,
+ ACE_Event_Handler::ACCEPT_MASK) == -1)
+ {
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("Failed to register event handler")),
+ 1);
+ }
+
+ ACE_DEBUG ((LM_DEBUG, "Registered event handler at %d\n", idx));
+
+ ACE_Time_Value tv (1);
+
+#if defined (ACE_HAS_THREADS)
+
+ if (ACE_Thread_Manager::instance ()->spawn_n
+ (1,
+ ACE_THR_FUNC (client),
+ reinterpret_cast<void *> (&addr),
+ THR_NEW_LWP | THR_DETACHED) == -1)
+
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n"),
+ ACE_TEXT ("thread create failed")),
+ 1);
+
+ ACE_Thread_Manager::instance ()->wait ();
+
+#else
+ ACE_UNUSED_ARG (client);
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) only one thread may be run in a process on this platform\n%a"),
+ 1));
+#endif //ACE_HAS_THREADS
+
+ if (ACE_Reactor::instance()->handle_events (tv) == -1 )
+ {
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"),
+ ACE_TEXT ("Reactor::handle_events")),
+ 1);
+ }
+
+ // see if I can register a reactor at this port.
+ if (eh->port () == idx)
+ {
+ if (idx > max_listened_port)
+ max_listened_port = idx;
+ }
+ else
+ {
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("Test Fail, listening port %d\n"),
+ eh->port()),
+ 1);
+ }
+
+ ACE_Reactor::instance()->remove_handler (
+ eh,
+ ACE_Event_Handler::ACCEPT_MASK |
+ ACE_Event_Handler::DONT_CALL);
+ delete eh;
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ "Value of ACE_MAX_DEFAULT_PORT %d\n",
+ ACE_MAX_DEFAULT_PORT));
+
+ ACE_DEBUG ((LM_DEBUG,
+ "Highest port value I can listen at %d\n",
+ max_listened_port));
+
+ ACE_DEBUG ((LM_DEBUG,
+ "Highest port value I can connect to %d\n",
+ max_connected_port));
+
+ if ((max_listened_port == ACE_MAX_DEFAULT_PORT) &&
+ (max_connected_port == ACE_MAX_DEFAULT_PORT))
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Valid ACE_MAX_DEFAULT_PORT value: %d\n"),
+ max_listened_port));
+ }
+ else
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Invalid ACE_MAX_DEFAULT_PORT ")
+ ACE_TEXT ("or %d port may be busy; got to %d\n"),
+ ACE_MAX_DEFAULT_PORT, max_listened_port));
+
+ }
+
+#endif /* ACE_HAS_IPV6 */
+
+ ACE_END_TEST;
+ return 0;
+}
diff --git a/ACE/tests/Mem_Map_Test.cpp b/ACE/tests/Mem_Map_Test.cpp
new file mode 100644
index 00000000000..8deba91d1a6
--- /dev/null
+++ b/ACE/tests/Mem_Map_Test.cpp
@@ -0,0 +1,280 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Mem_Map_Test.cpp
+//
+// = DESCRIPTION
+// This test illustrates the use of ACE_Mem_Map to reverse a
+// file. The test first creates a dummy file for testing, then
+// reverses the file and then reverses it again to get back the
+// original file.
+//
+// = AUTHOR
+// Prashant Jain <pjain@cs.wustl.edu>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/Mem_Map.h"
+#include "ace/ACE.h"
+#include "ace/OS_NS_string.h"
+#include "ace/OS_NS_unistd.h"
+#include "ace/OS_NS_fcntl.h"
+#include "ace/OS_Memory.h"
+
+ACE_RCSID(tests, Mem_Map_Test, "Mem_Map_Test.cpp,v 4.36 2003/11/01 11:15:25 dhinton Exp")
+
+#if !defined (ACE_LACKS_MMAP)
+
+static const char ACE_ALPHABET[] = "abcdefghijklmnopqrstuvwxyz";
+static const int LINE_LENGTH = 10;
+static const int NUM_LINES = 15;
+
+static void
+reverse_file (ACE_HANDLE file_handle,
+ char *array,
+ size_t size)
+{
+ int count = 0;
+ // LynxOS 3.0.0/PowerPC needs the volatile qualifier, with -O2
+ // optimization enabled and without ACE_HAS_INLINE.
+ volatile size_t i = size;
+ --i;
+
+ if (array[i] == '\0')
+ array[i] = '\n';
+
+ while (i-- > 0)
+ {
+ if (array[i] == '\n')
+ {
+ ACE_OS::write (file_handle, array + i + 1, count);
+ ACE_OS::write (file_handle, ACE_TEXT ("\n"), 1);
+ count = 0;
+ }
+ else
+ count++;
+ }
+ ACE_OS::write (file_handle, array, count+1);
+}
+
+static int
+create_test_file (ACE_TCHAR *filename, int line_length, int num_lines)
+{
+ char *mybuf = 0;
+
+ ACE_NEW_RETURN (mybuf, char[line_length + 1], -1);
+ const char *c = ACE_ALPHABET;
+ const char *d = c;
+#if defined (__QNXNTO__)
+ // For NTO has to applied to open the file, as Mem_Map can map only shared memory
+ ACE_Mem_Map mmap_4_open;
+ mmap_4_open.open (filename, O_RDWR | O_CREAT | O_TRUNC, ACE_DEFAULT_FILE_PERMS);
+ ACE_HANDLE file_handle = mmap_4_open.handle();
+#else
+ ACE_HANDLE file_handle = ACE_OS::open (filename,
+ O_RDWR | O_CREAT | O_TRUNC,
+ ACE_DEFAULT_FILE_PERMS);
+#endif
+ if (file_handle == ACE_INVALID_HANDLE)
+ {
+ delete [] mybuf;
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("Open failed\n")),
+ -1);
+ }
+
+ for (int j = 0; j < num_lines; j++)
+ {
+ for (int i = 0; i < line_length; i++)
+ {
+ mybuf[i] = *c;
+ c++;
+ }
+
+ mybuf[line_length] = '\0';
+
+ c = ++d;
+
+ if (ACE_OS::write (file_handle, mybuf, line_length) != line_length)
+ {
+ delete [] mybuf;
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("write to file failed: %p (%d)\n"),
+ errno,
+ errno),
+ -1);
+ }
+
+ if (ACE_OS::write (file_handle, ACE_TEXT ("\n"), 1) != 1)
+ {
+ delete [] mybuf;
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("write to file failed\n")),
+ -1);
+ }
+ }
+#if defined (__QNXNTO__)
+ mmap_4_open.close();
+#else
+ ACE_OS::close (file_handle);
+#endif
+
+ delete [] mybuf;
+ return 0;
+}
+
+#endif /* !ACE_LACKS_MMAP */
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("Mem_Map_Test"));
+
+#if !defined (ACE_LACKS_MMAP)
+
+#if defined (__QNXNTO__)
+ ACE_ERROR ((LM_INFO,
+ ACE_TEXT ("mmap on QNX Neutrino can map only shared memory files\n")));
+#endif
+
+ // = Initialize the temporary variable names
+
+ ACE_TCHAR test_file[MAXPATHLEN + 1];
+ ACE_TCHAR temp_file1[MAXPATHLEN + 1];
+ ACE_TCHAR temp_file2[MAXPATHLEN + 1];
+
+ // Get the temporary directory
+ // - 18 is for the filenames, ace_mem_map_temp_1 is the longest
+ if (ACE::get_temp_dir (test_file, MAXPATHLEN - 18) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("Temporary path too long\n")),
+ -1);
+
+ // Copy the temp directory to the other variables
+ ACE_OS::strcpy (temp_file1, test_file);
+ ACE_OS::strcpy (temp_file2, test_file);
+
+ // Add the filenames to the end
+ ACE_OS::strcat (test_file,
+ ACE_TEXT ("ace_mem_map_test"));
+ ACE_OS::strcat (temp_file1,
+ ACE_TEXT ("ace_mem_map_temp_1"));
+ ACE_OS::strcat (temp_file2,
+ ACE_TEXT ("ace_mem_map_temp_2"));
+
+ // First create a test file to work on
+ if (create_test_file (test_file, LINE_LENGTH, NUM_LINES) != 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("Create test file failed\n")),
+ -1);
+ ACE_Mem_Map mmap;
+
+ // First memory map the test file
+ if (mmap.map (test_file) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%n: %p\n%a"),
+ ACE_TEXT ("mmap")),
+ -1);
+
+ // Now create a temporary file for intermediate processing
+#if defined (__QNXNTO__)
+ ACE_Mem_Map mmap_4_open;
+ mmap_4_open.open(temp_file1,
+ O_RDWR | O_TRUNC | O_CREAT,
+ ACE_DEFAULT_FILE_PERMS);
+ ACE_HANDLE temp_file_handle = mmap_4_open.handle();
+#else
+ ACE_HANDLE temp_file_handle = ACE_OS::open (temp_file1,
+ O_RDWR | O_TRUNC | O_CREAT,
+ ACE_DEFAULT_FILE_PERMS);
+#endif
+
+ if (temp_file_handle == ACE_INVALID_HANDLE)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("Open failed\n")),
+ -1);
+
+ // Reverse the original file and write the output to the temporary
+ // file.
+ reverse_file (temp_file_handle,
+ (char *) mmap.addr (),
+ mmap.size ());
+#if defined (__QNXNTO__)
+ mmap_4_open.close();
+#else
+ ACE_OS::close (temp_file_handle);
+#endif
+
+ ACE_Mem_Map temp_mmap;
+
+ // Now memory map the temporary file
+ if (temp_mmap.map (temp_file1) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%n: %p\n%a"),
+ ACE_TEXT ("mmap")),
+ -1);
+#if defined (__QNXNTO__)
+ mmap_4_open.open(temp_file2,
+ O_RDWR | O_TRUNC | O_CREAT,
+ ACE_DEFAULT_FILE_PERMS);
+ temp_file_handle = mmap_4_open.handle();
+#else
+ temp_file_handle = ACE_OS::open (temp_file2,
+ O_RDWR | O_TRUNC | O_CREAT,
+ ACE_DEFAULT_FILE_PERMS);
+#endif
+ if ( temp_file_handle == ACE_INVALID_HANDLE)
+
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("Open failed\n")), -1);
+
+ // Now reverse the temporary file and write everything to the second
+ // temporary file.
+ reverse_file (temp_file_handle,
+ (char *) temp_mmap.addr (),
+ temp_mmap.size ());
+#if defined (__QNXNTO__)
+ mmap_4_open.close();
+#else
+ ACE_OS::close (temp_file_handle);
+#endif
+
+ // Memory map the second temporary file
+ ACE_Mem_Map temp_mmap2;
+
+ if (temp_mmap2.map (temp_file2) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%n: %p\n%a"),
+ ACE_TEXT ("mmap")),
+ -1);
+
+ // Now do a memcmp -- the orig file and the second temporary file
+ // should be identical.
+ ACE_ASSERT (ACE_OS::memcmp (temp_mmap2.addr (),
+ mmap.addr (),
+ mmap.size ()) == 0);
+
+ // Delete the test file
+ mmap.remove ();
+
+ // Delete ACE_TEMP_TEST_FILE
+ temp_mmap.remove ();
+
+ // Delete ACE_TEMP_TEST_FILE_2
+ temp_mmap2.remove ();
+
+#else /* !ACE_LACKS_MMAP */
+
+ ACE_ERROR ((LM_INFO,
+ ACE_TEXT ("mmap is not supported on this platform\n")));
+
+#endif /* !ACE_LACKS_MMAP */
+
+ ACE_END_TEST;
+ return 0;
+}
diff --git a/ACE/tests/Memcpy_Test.cpp b/ACE/tests/Memcpy_Test.cpp
new file mode 100644
index 00000000000..46fb2c381e5
--- /dev/null
+++ b/ACE/tests/Memcpy_Test.cpp
@@ -0,0 +1,103 @@
+//=============================================================================
+/**
+ * @file Memcpy_Test.cpp
+ *
+ * $Id$
+ *
+ * @author Mike Marinez <mmartinez@oci.com>
+ *
+ * This test compares the performance of ACE_OS::memcpy with
+ * that of smemcpy which unrolls the memcpy loop upto size = 16.
+ * This test is also run via autoconf and if smemcpy is faster,
+ * ACE_HAS_MEMCPY_LOOP_UNROLL flag is set.
+ *
+ */
+//=============================================================================
+
+#include "ace/OS_NS_string.h"
+#include "ace/High_Res_Timer.h"
+
+#include "test_config.h"
+
+void *
+smemcpy (void *dest, const void *src, const size_t n)
+{
+ unsigned char *to = static_cast<unsigned char*> (dest);
+ const unsigned char *from = static_cast<const unsigned char*> (src);
+ // Unroll the loop...
+ switch (n) {
+ case 16: to[ 15] = from[ 15];
+ case 15: to[ 14] = from[ 14];
+ case 14: to[ 13] = from[ 13];
+ case 13: to[ 12] = from[ 12];
+ case 12: to[ 11] = from[ 11];
+ case 11: to[ 10] = from[ 10];
+ case 10: to[ 9] = from[ 9];
+ case 9: to[ 8] = from[ 8];
+ case 8: to[ 7] = from[ 7];
+ case 7: to[ 6] = from[ 6];
+ case 6: to[ 5] = from[ 5];
+ case 5: to[ 4] = from[ 4];
+ case 4: to[ 3] = from[ 3];
+ case 3: to[ 2] = from[ 2];
+ case 2: to[ 1] = from[ 1];
+ case 1: to[ 0] = from[ 0];
+ case 0: return dest;
+ default: return ACE_OS::memcpy (dest, src, n);
+ }
+}
+
+void
+testit (int type)
+{
+ char buffer[16];
+ size_t size = 16;
+
+ switch (type)
+ {
+ case 0: smemcpy ((void*)buffer, (void*)" THIS IS A TEST", size); break;
+ case 1: ACE_OS::memcpy ((void*)buffer, (void*)" THIS IS A TEST", size); break;
+ }
+
+}
+
+namespace { enum { ITERATIONS = 100000000 }; }
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("Memcpy_Test"));
+
+ //ACE_Time_Value start, now;
+ struct timeval start, now;
+
+ for (int i = ITERATIONS; i > 0; --i)
+ testit (0);
+
+ start = ACE_High_Res_Timer::gettimeofday_hr ();
+ for (int j = ITERATIONS; j > 0; --j)
+ testit (0);
+
+ now = ACE_High_Res_Timer::gettimeofday_hr ();
+
+ double fast = 1000000 *(now.tv_sec - start.tv_sec) +
+ now.tv_usec - start.tv_usec;
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%f uSec per iteration for fast version.\n"),
+ fast / ITERATIONS));
+
+ start = ACE_High_Res_Timer::gettimeofday_hr ();
+ for (int k = ITERATIONS; k > 0; --k)
+ testit (1);
+
+ now = ACE_High_Res_Timer::gettimeofday_hr ();
+
+ double slow = 1000000 * (now.tv_sec-start.tv_sec) + now.tv_usec - start.tv_usec;
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%f uSec per iteration for slow version.\n"),
+ slow / ITERATIONS));
+
+ ACE_END_TEST;
+
+ return 0;
+}
diff --git a/ACE/tests/Message_Block_Test.cpp b/ACE/tests/Message_Block_Test.cpp
new file mode 100644
index 00000000000..3757c3c9f2c
--- /dev/null
+++ b/ACE/tests/Message_Block_Test.cpp
@@ -0,0 +1,347 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Message_Block_Test.cpp
+//
+// = DESCRIPTION
+// This test program is a torture test that illustrates how
+// <ACE_Message_Block> reference counting works in multi-threaded
+// code.
+//
+// = AUTHOR
+// Doug Schmidt <schmidt@cs.wustl.edu> and Nanbor Wang <nanbor@cs.wustl.edu>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/OS_NS_stdio.h"
+#include "ace/OS_NS_string.h"
+#include "ace/Task.h"
+#include "ace/Malloc_T.h"
+#include "ace/Profile_Timer.h"
+#include "ace/Free_List.h"
+
+ACE_RCSID (tests,
+ Message_Block_Test,
+ "$Id$")
+
+// Number of memory allocation strategies used in this test.
+static const int ACE_ALLOC_STRATEGY_NO = 2;
+
+// Size of a memory block (multiple of ACE_MALLOC_ALIGN).
+static const int ACE_ALLOC_SIZE = 5;
+
+// Amount of memory block preallocated.
+static const size_t ACE_ALLOC_AMOUNT = 48;
+
+#if defined (ACE_HAS_THREADS)
+
+#include "ace/Lock_Adapter_T.h"
+#include "ace/Synch_Traits.h"
+
+// Number of iterations to run the test.
+static size_t n_iterations = ACE_MAX_ITERATIONS;
+
+static ACE_Lock_Adapter<ACE_SYNCH_MUTEX> lock_adapter_;
+// Serialize access to <ACE_Message_Block> reference count, which will
+// be decremented from multiple threads.
+
+class Worker_Task : public ACE_Task<ACE_MT_SYNCH>
+{
+public:
+ Worker_Task (void);
+ // Activate the task.
+
+ virtual int svc (void);
+ // Iterate <n_iterations> time printing off a message and "waiting"
+ // for all other threads to complete this iteration.
+
+ virtual int put (ACE_Message_Block *mb, ACE_Time_Value *tv = 0);
+ // Allows the producer to pass messages to the <Message_Block>.
+
+private:
+ virtual int close (u_long);
+ // Close hook.
+};
+
+int
+Worker_Task::close (u_long)
+{
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) close of worker\n")));
+ return 0;
+}
+
+// Simply enqueue the Worker_Task into the end of the queue.
+
+int
+Worker_Task::put (ACE_Message_Block *mb, ACE_Time_Value *tv)
+{
+ return this->msg_queue ()->enqueue_prio (mb, tv);
+}
+
+// Iterate <n_iterations> printing off a message and "waiting" for all
+// other threads to complete this iteration.
+
+int
+Worker_Task::svc (void)
+{
+ // The <ACE_Task::svc_run()> method automatically adds us to the
+ // process-wide <ACE_Thread_Manager> when the thread begins.
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) starting svc() method\n")));
+
+ // Keep looping, reading a message out of the queue, until we get a
+ // message with a length == 0, which signals us to quit.
+
+ for (int count = 0; ; count++)
+ {
+ ACE_Message_Block *mb = 0;
+
+ int dequeue_results = this->msg_queue ()->dequeue_head (mb);
+
+ ACE_ASSERT (dequeue_results != -1);
+
+ size_t length = mb->length ();
+
+ // If there's a next() Task then "logically" copy the message by
+ // calling <duplicate> and send it on down the pipeline. Note
+ // that this doesn't actually make a copy of the message
+ // contents (i.e., the Data_Block portion), it just makes a copy
+ // of the header and reference counts the data.
+ if (this->next () != 0)
+ {
+ int duplicate_result = this->put_next (mb->duplicate ());
+ ACE_ASSERT (duplicate_result != -1);
+ }
+
+ // If there's no next() Task to send to, then we'll consume the
+ // message here.
+ else if (length > 0)
+ {
+ int current_count = ACE_OS::atoi (ACE_TEXT_CHAR_TO_TCHAR (mb->rd_ptr ()));
+ int i;
+
+ ACE_ASSERT (count == current_count);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) enqueueing %d duplicates\n"),
+ current_count));
+
+ ACE_Message_Block *dup;
+
+ // Enqueue <current_count> duplicates with msg_priority == 1.
+ for (i = current_count; i > 0; i--)
+ {
+ ACE_ALLOCATOR_RETURN (dup,
+ mb->duplicate (),
+ -1);
+ // Set the priority to be greater than "normal"
+ // messages. Therefore, all of these messages should go
+ // to the "front" of the queue, i.e., ahead of all the
+ // other messages that are being enqueued by other
+ // threads.
+ dup->msg_priority (ACE_DEFAULT_MESSAGE_BLOCK_PRIORITY + 1);
+
+ int enqueue_prio_result =
+ this->msg_queue ()->enqueue_prio
+ (dup,
+ // Don't block indefinitely if we flow control...
+ (ACE_Time_Value *) &ACE_Time_Value::zero);
+
+ ACE_ASSERT (enqueue_prio_result != -1);
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) dequeueing %d duplicates\n"),
+ current_count));
+
+ // Dequeue the same <current_count> duplicates.
+ for (i = current_count; i > 0; i--)
+ {
+ int deqresult = this->msg_queue ()->dequeue_head (dup);
+ ACE_ASSERT (deqresult != -1);
+ ACE_ASSERT (count == ACE_OS::atoi (ACE_TEXT_CHAR_TO_TCHAR (dup->rd_ptr ())));
+ ACE_ASSERT (ACE_OS::strcmp (mb->rd_ptr (), dup->rd_ptr ()) == 0);
+ ACE_ASSERT (dup->msg_priority () == ACE_DEFAULT_MESSAGE_BLOCK_PRIORITY + 1);
+ dup->release ();
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) in iteration %d, length = %d, prio = %d, text = \"%*s\"\n"),
+ count,
+ length,
+ mb->msg_priority (),
+ length - 2, // remove the trailing "\n\0"
+ mb->rd_ptr ()));
+ }
+
+ // We're responsible for deallocating this.
+ mb->release ();
+
+ if (length == 0)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) in iteration %d, queue len = %d, got NULL message, exiting\n"),
+ count, this->msg_queue ()->message_count ()));
+ break;
+ }
+ }
+
+ // Note that the ACE_Task::svc_run () method automatically removes
+ // us from the Thread_Manager when the thread exits.
+ return 0;
+}
+
+Worker_Task::Worker_Task (void)
+{
+ // Make us an Active Object.
+ if (this->activate (THR_NEW_LWP) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("activate failed")));
+}
+
+static int
+produce (Worker_Task &worker_task,
+ ACE_Allocator *alloc_strategy)
+{
+ ACE_Message_Block *mb;
+
+ // Send <n_iteration> messages through the pipeline.
+ for (size_t count = 0; count < n_iterations; count++)
+ {
+ ACE_TCHAR buf[BUFSIZ];
+ ACE_OS::sprintf (buf, ACE_SIZE_T_FORMAT_SPECIFIER, count);
+
+ size_t n = (ACE_OS::strlen (buf) + 1) * sizeof (ACE_TCHAR);
+
+ // Allocate a new message.
+ ACE_NEW_RETURN (mb,
+ ACE_Message_Block (n, // size
+ ACE_Message_Block::MB_DATA, // type
+ 0, // cont
+ 0, // data
+ alloc_strategy, // allocator
+ &lock_adapter_, // locking strategy
+ ACE_DEFAULT_MESSAGE_BLOCK_PRIORITY), // priority
+ -1);
+
+ // Copy buf into the Message_Block and update the wr_ptr ().
+ mb->copy ((char *) buf, n);
+
+ // Pass the message to the Worker_Task.
+ if (worker_task.put (mb,
+ // Don't block indefinitely if we flow control...
+ (ACE_Time_Value *) &ACE_Time_Value::zero) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT (" (%t) %p\n"),
+ ACE_TEXT ("put")));
+ }
+
+ // Send a shutdown message to the waiting threads and exit.
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\n(%t) sending shutdown message\n")));
+
+ ACE_NEW_RETURN (mb,
+ ACE_Message_Block (0,
+ ACE_Message_Block::MB_DATA,
+ 0,
+ 0,
+ alloc_strategy,
+ &lock_adapter_),
+ -1);
+
+ if (worker_task.put (mb) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT (" (%t) %p\n"),
+ ACE_TEXT ("put")));
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\n(%t) end producer\n")));
+ return 0;
+}
+
+typedef ACE_TCHAR MEMORY_CHUNK[ACE_MALLOC_ALIGN * ACE_ALLOC_SIZE];
+
+ACE_Cached_Allocator<MEMORY_CHUNK,
+ ACE_SYNCH_MUTEX>
+ mem_allocator (ACE_ALLOC_AMOUNT);
+struct alloc_struct_type
+{
+ ACE_Allocator *strategy_;
+ const ACE_TCHAR *name_;
+ ACE_Profile_Timer::ACE_Elapsed_Time et_;
+};
+
+alloc_struct_type alloc_struct[ACE_ALLOC_STRATEGY_NO] =
+{
+ { 0, ACE_TEXT ("Default"), {0,0,0} },
+ { &mem_allocator, ACE_TEXT ("Cached Memory"), {0,0,0} }
+};
+
+#endif /* ACE_HAS_THREADS */
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("Message_Block_Test"));
+#if defined (ACE_HAS_THREADS)
+ int n_threads = ACE_MAX_THREADS;
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) threads = %d\n"), n_threads));
+
+ ACE_Profile_Timer ptime;
+
+ int i;
+
+ for (i = 0; i < ACE_ALLOC_STRATEGY_NO; i++)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Start Message_Block_Test using %s allocation strategy\n"),
+ alloc_struct[i].name_));
+
+ // Create the worker tasks.
+ Worker_Task worker_task[ACE_MAX_THREADS] ;
+
+ // Link all the tasks together into a simple pipeline.
+ for (size_t j = 1; j < ACE_MAX_THREADS; j++)
+ worker_task[j - 1].next (&worker_task[j]);
+
+ ptime.start ();
+ // Generate messages and pass them through the pipeline.
+ produce (worker_task[0], alloc_struct[i].strategy_);
+
+ // Wait for all the threads to reach their exit point.
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) waiting for worker tasks to finish...\n")));
+
+ ACE_Thread_Manager::instance ()->wait ();
+ ptime.stop ();
+ ptime.elapsed_time (alloc_struct[i].et_);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) destroying worker tasks\n")));
+ }
+
+ for (i = 0; i < ACE_ALLOC_STRATEGY_NO; i++)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Elapsed time using %s allocation strategy: %f sec\n"),
+ alloc_struct[i].name_,
+ alloc_struct[i].et_.real_time));
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Exiting...\n")));
+#else
+ ACE_ERROR ((LM_INFO,
+ ACE_TEXT ("threads not supported on this platform\n")));
+#endif /* ACE_HAS_THREADS */
+ ACE_END_TEST;
+ return 0;
+}
diff --git a/ACE/tests/Message_Queue_Notifications_Test.cpp b/ACE/tests/Message_Queue_Notifications_Test.cpp
new file mode 100644
index 00000000000..51fe8c261b3
--- /dev/null
+++ b/ACE/tests/Message_Queue_Notifications_Test.cpp
@@ -0,0 +1,367 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Message_Queue_Notification_Test.cpp
+//
+// = DESCRIPTION
+// There are two tests that test 2 different notification
+// mechanisms in Message Queue.
+//
+// The first test illustrates the notification mechanisms in
+// Message_Queue and its integration with Reactor.
+//
+// Note the following things about this part of the test:
+//
+// 1. Multiple threads are not required.
+// 2. You do not have to explicitly notify the Reactor
+// 3. This code will work the same with any Reactor Implementation
+// 4. handle_input, handle_exception, handle_output are the only
+// callbacks supported by this mechanism
+// 5. The notification mechanism need not notify the Reactor. You can
+// write your own strategy classes that can do whatever application
+// specific behavior you want.
+//
+// The second test also makes sure the high/low water mark
+// signaling mechanism works flawlessly.
+//
+// = AUTHOR
+// Irfan Pyarali <irfan@cs.wustl.edu> and Nanbor Wang <nanbor@cs.wustl.edu>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/Reactor.h"
+#include "ace/Task.h"
+#include "ace/Reactor_Notification_Strategy.h"
+#include "ace/Atomic_Op.h"
+#include "ace/Barrier.h"
+#include "ace/Synch_Traits.h"
+#include "ace/Null_Condition.h"
+#include "ace/Null_Mutex.h"
+#include "ace/OS_NS_string.h"
+#include "ace/OS_NS_unistd.h"
+
+ACE_RCSID(tests, Message_Queue_Notifications_Test, "$Id$")
+
+static int iterations = 10;
+
+static const size_t worker_threads = 2;
+static const char * default_message = "ACE RULES";
+static const size_t default_high_water_mark = 20;
+static const size_t default_low_water_mark = 10;
+static const int watermark_iterations = 2 * default_high_water_mark;
+
+class Message_Handler : public ACE_Task<ACE_NULL_SYNCH>
+{
+ // = TITLE
+ // This class implements a notification strategy for the Reactor.
+public:
+ // = Initialization and termination.
+ Message_Handler (ACE_Reactor &reactor);
+ // Constructor.
+
+ // = Demuxing hooks.
+ virtual int handle_input (ACE_HANDLE);
+ virtual int handle_output (ACE_HANDLE fd = ACE_INVALID_HANDLE);
+ virtual int handle_exception (ACE_HANDLE fd = ACE_INVALID_HANDLE);
+
+private:
+ int process_message (void);
+ void make_message (void);
+
+ ACE_Reactor_Notification_Strategy notification_strategy_;
+};
+
+class Watermark_Test : public ACE_Task<ACE_SYNCH>
+{
+ // = TITLE
+ // This class test the correct functioning of build-in flow
+ // control machanism in ACE_Task.
+public:
+ Watermark_Test (void);
+
+ virtual int svc (void);
+
+ int consumer (void);
+ int producer (void);
+ int put_message (ACE_Time_Value* timeout = 0);
+ int get_message (void);
+ void print_producer_debug_message (void);
+
+private:
+ const size_t len_;
+ const size_t hwm_;
+ const size_t lwm_;
+ ACE_Atomic_Op <ACE_SYNCH_MUTEX, int> role_;
+#if defined (ACE_HAS_THREADS)
+ ACE_Barrier mq_full_;
+ ACE_Barrier mq_low_water_mark_hit_;
+#endif /* ACE_HAS_THREADS */
+};
+
+Message_Handler::Message_Handler (ACE_Reactor &reactor)
+ // First time handle_input will be called
+ : notification_strategy_ (&reactor,
+ this,
+ ACE_Event_Handler::READ_MASK)
+{
+ this->msg_queue ()->notification_strategy (&this->notification_strategy_);
+ this->make_message ();
+}
+
+int
+Message_Handler::handle_input (ACE_HANDLE)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Message_Handler::handle_input\n")));
+
+ // Next time handle_output will be called.
+ this->notification_strategy_.mask (ACE_Event_Handler::WRITE_MASK);
+
+ return process_message ();
+}
+
+int
+Message_Handler::handle_output (ACE_HANDLE fd)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Message_Handler::handle_output\n")));
+ ACE_UNUSED_ARG (fd);
+
+ // Next time handle_exception will be called.
+ this->notification_strategy_.mask (ACE_Event_Handler::EXCEPT_MASK);
+
+ return process_message ();
+}
+
+int
+Message_Handler::handle_exception (ACE_HANDLE fd)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Message_Handler::handle_exception\n")));
+ ACE_UNUSED_ARG (fd);
+
+ // Next time handle_input will be called.
+ this->notification_strategy_.mask (ACE_Event_Handler::READ_MASK);
+
+ return this->process_message ();
+}
+
+int
+Message_Handler::process_message (void)
+{
+ ACE_Message_Block *mb;
+
+ if (this->getq (mb,
+ (ACE_Time_Value *) &ACE_Time_Value::zero) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("dequeue_head")),
+ -1);
+ else
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("message received = %s\n"),
+ mb->rd_ptr ()));
+ mb->release ();
+ }
+
+ this->make_message ();
+ return 0;
+}
+
+void
+Message_Handler::make_message (void)
+{
+ if (--iterations > 0)
+ {
+ ACE_Message_Block *mb;
+ ACE_NEW (mb,
+ ACE_Message_Block ((char *) ACE_TEXT ("hello")));
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("sending message\n")));
+ this->putq (mb);
+ }
+}
+
+Watermark_Test::Watermark_Test (void)
+ : len_ (ACE_OS::strlen (default_message) + 1),
+ hwm_ (this->len_ * default_high_water_mark),
+ lwm_ (this->len_ * default_low_water_mark),
+ role_ (0)
+#if defined (ACE_HAS_THREADS)
+ , mq_full_ (worker_threads),
+ mq_low_water_mark_hit_ (worker_threads)
+#endif /* ACE_HAS_THREADS */
+{
+ this->water_marks (ACE_IO_Cntl_Msg::SET_LWM,
+ this->lwm_);
+ this->water_marks (ACE_IO_Cntl_Msg::SET_HWM,
+ this->hwm_);
+}
+
+int
+Watermark_Test::producer (void)
+{
+ int i = watermark_iterations;
+
+ for (ssize_t hwm = this->hwm_;
+ hwm >= 0 ;
+ hwm -= this->len_)
+ {
+ this->put_message ();
+ this->print_producer_debug_message ();
+ i--;
+ if (this->msg_queue ()->is_full ())
+ break;
+
+ }
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Producer: High water mark hit ---- \n")));
+
+ ACE_MT (this->mq_full_.wait ());
+
+ // The following put_message should block until the message queue
+ // has dropped under the lwm.
+ this->put_message ();
+
+ ACE_ASSERT (this->msg_queue ()-> message_bytes () <= this->lwm_ + this->len_);
+
+ this->print_producer_debug_message ();
+
+ for (i--; i >= 0 ; i--)
+ {
+ this->put_message ();
+ this->print_producer_debug_message ();
+ }
+
+ return 0;
+}
+
+int
+Watermark_Test::consumer (void)
+{
+ ACE_MT (this->mq_full_.wait ());
+
+ ACE_OS::sleep (1);
+
+ // Let producer proceed and block in putq.
+
+ for (int i = watermark_iterations; i >= 0; i--)
+ {
+ this->get_message ();
+ ACE_OS::sleep (0);
+ }
+
+ return 0;
+}
+
+int
+Watermark_Test::get_message (void)
+{
+ ACE_Message_Block *mb;
+
+ if (this->getq (mb) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("dequeue_head")),
+ -1);
+ else
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Consumer: message size = %3d, ")
+ ACE_TEXT ("message count = %3d\n"),
+ this->msg_queue ()-> message_bytes (),
+ this->msg_queue ()-> message_count ()));
+ mb->release ();
+ }
+
+ return 0;
+}
+
+int
+Watermark_Test::put_message (ACE_Time_Value *timeout)
+{
+ ACE_Message_Block *mb;
+
+ ACE_NEW_RETURN (mb,
+ ACE_Message_Block (default_message,
+ this->len_),
+ -1);
+
+ return this->putq (mb, timeout);
+}
+
+void
+Watermark_Test::print_producer_debug_message (void)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Producer: message size = %3d, ")
+ ACE_TEXT ("message count = %3d\n"),
+ this->msg_queue ()-> message_bytes (),
+ this->msg_queue ()-> message_count ()));
+}
+
+int
+Watermark_Test::svc (void)
+{
+ // this->role_ is an Atomic_Op object.
+ int role = this->role_++;
+
+ switch (role)
+ {
+ case 0:
+ this->producer ();
+ break;
+ case 1:
+ this->consumer ();
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("Message_Queue_Notifications_Test"));
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Starting message queue reactive notification test...\n")));
+
+ ACE_Reactor reactor;
+ Message_Handler mh (reactor);
+
+ while (iterations > 0)
+ reactor.handle_events ();
+
+#if defined (ACE_HAS_THREADS)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Starting message queue watermark test...\n")));
+ Watermark_Test watermark_test;
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("High water mark is %d\n")
+ ACE_TEXT ("Low water mark is %d\n"),
+ default_high_water_mark,
+ default_low_water_mark));
+
+ watermark_test.activate (THR_NEW_LWP,
+ worker_threads);
+
+ ACE_Thread_Manager::instance ()->wait ();
+#else
+ ACE_DEBUG ((LM_INFO,
+ ACE_TEXT ("Message queue watermark test not performed because threads are not supported\n")));
+#endif /* ACE_HAS_THREADS */
+
+ ACE_END_TEST;
+ return 0;
+}
+
diff --git a/ACE/tests/Message_Queue_Test.cpp b/ACE/tests/Message_Queue_Test.cpp
new file mode 100644
index 00000000000..4198ca5b6fd
--- /dev/null
+++ b/ACE/tests/Message_Queue_Test.cpp
@@ -0,0 +1,688 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Message_Queue_Test.cpp
+//
+// = DESCRIPTION
+// This is:
+// 0) a test that ensures key ACE_Message_Queue features are
+// working properly, including timeouts and priorities.
+// 1) a simple test of the ACE_Message_Queue that illustrates how to
+// use the forward and reverse iterators;
+// 2) a simple performance measurement test for both single-threaded
+// (null synch) and thread-safe ACE_Message_Queues, and
+// ACE_Message_Queue_Vx, which wraps VxWorks message queues; and
+// 3) a test/usage example of ACE_Message_Queue_Vx.
+//
+// = AUTHORS
+// Irfan Pyarali <irfan@cs.wustl.edu>,
+// David L. Levine <levine@cs.wustl.edu>, and
+// Douglas C. Schmidt <schmidt@vanderbilt.edu>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/Thread_Manager.h"
+#include "ace/Message_Queue.h"
+#include "ace/Synch_Traits.h"
+#include "ace/Null_Mutex.h"
+#include "ace/Null_Condition.h"
+#include "ace/High_Res_Timer.h"
+#include "ace/OS_NS_stdio.h"
+#include "ace/OS_NS_string.h"
+#include "ace/OS_NS_sys_time.h"
+
+ACE_RCSID(tests, Message_Queue_Test, "$Id$")
+
+const ACE_TCHAR usage[] = ACE_TEXT ("usage: Message_Queue_Test <number of messages>\n");
+
+typedef ACE_Message_Queue<ACE_NULL_SYNCH> QUEUE;
+typedef ACE_Message_Queue_Iterator<ACE_NULL_SYNCH> ITERATOR;
+typedef ACE_Message_Queue_Reverse_Iterator<ACE_NULL_SYNCH> REVERSE_ITERATOR;
+
+static const int MAX_MESSAGES = 10000;
+static const int MAX_MESSAGE_SIZE = 32;
+static const char test_message[] = "ACE_Message_Queue Test Message";
+
+static int max_messages = MAX_MESSAGES;
+
+// Dynamically allocate to avoid a static.
+static ACE_High_Res_Timer *timer = 0;
+
+#if defined (ACE_HAS_THREADS)
+typedef ACE_Message_Queue<ACE_MT_SYNCH> SYNCH_QUEUE;
+
+struct Queue_Wrapper
+{
+ // = TITLE
+ // Container for data passed to sender and receiver in
+ // performance test.
+ //
+ // = DESCRIPTION
+ // For use in multithreaded performance test.
+
+ ACE_Message_Queue_Base *q_;
+ // The message queue.
+
+ ACE_Message_Block **send_block_;
+ // Pointer to messages blocks for sender to send to reciever.
+
+ Queue_Wrapper (void)
+ : q_ (0), send_block_ (0)
+ {
+ }
+ // Default constructor.
+};
+
+#endif /* ACE_HAS_THREADS */
+
+#if !defined (VXWORKS)
+static int
+iterator_test (void)
+{
+ const int ITERATIONS = 5;
+ ACE_TCHAR buffer[ITERATIONS][BUFSIZ];
+ // Use queue size from of 32 Kb (more if using wide-char), instead of the
+ // default of 16 Kb (defined by ACE_Message_Queue_Base::DEFAULT_HWM),
+ // so that the test runs on machines with 8Kb pagesizes.
+#if !defined(_UNICOS)
+ // QUEUE queue (32 * 1024 * sizeof (ACE_TCHAR));
+ QUEUE queue (sizeof(buffer));
+#else
+ // this works on the Cray, where BUFSIZ is defined as 32Kb
+ QUEUE queue (ITERATIONS * BUFSIZ - 1);
+#endif
+
+ int i;
+
+ for (i = 0; i < ITERATIONS; i++)
+ {
+ ACE_OS::sprintf (buffer[i],
+ ACE_TEXT ("%d"),
+ i + 1);
+
+ ACE_Message_Block *entry;
+ ACE_NEW_RETURN (entry,
+ ACE_Message_Block ((char *) buffer[i],
+ sizeof buffer[i]),
+ -1);
+
+ if (queue.is_full ())
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("QUEUE:: the message queue is full on iteration %u!\n"),
+ i + 1),
+ -1);
+
+ if (queue.enqueue (entry) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("QUEUE::enqueue\n")),
+ -1);
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\nForward Iterations\n")));
+ {
+ ITERATOR iterator (queue);
+
+ for (ACE_Message_Block *entry = 0;
+ iterator.next (entry) != 0;
+ iterator.advance ())
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%s\n"),
+ entry->base ()));
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\nReverse Iterations\n")));
+ {
+ REVERSE_ITERATOR iterator (queue);
+
+ for (ACE_Message_Block *entry = 0;
+ iterator.next (entry) != 0;
+ iterator.advance ())
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%s\n"),
+ entry->base ()));
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\nForward Iterations\n")));
+ {
+ QUEUE::ITERATOR iterator (queue);
+
+ for (ACE_Message_Block *entry = 0;
+ iterator.next (entry) != 0;
+ iterator.advance ())
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%s\n"),
+ entry->base ()));
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\nReverse Iterations\n")));
+ {
+ QUEUE::REVERSE_ITERATOR iterator (queue);
+
+ for (ACE_Message_Block *entry = 0;
+ iterator.next (entry) != 0;
+ iterator.advance ())
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%s\n"),
+ entry->base ()));
+ }
+
+ return 0;
+}
+#endif /* ! VXWORKS */
+
+#if defined (ACE_HAS_THREADS)
+
+static int
+chained_block_test (void)
+{
+
+ QUEUE q;
+ const char * s = "123456789"; // Will be length 10 when copied to block
+ const size_t slen = 10;
+ const size_t num_blks = 10;
+ ACE_Message_Block b[num_blks];
+ size_t i;
+ int status = 0;
+
+ for (i = 0; i < num_blks; ++i)
+ {
+ b[i].init (slen);
+ b[i].copy (s);
+ }
+
+ // Test enqueueing single and chained blocks and be sure they end up with
+ // the proper enqueued block count and sizes. Then be sure they are dequeued
+ // in the proper order.
+ b[0].next (&b[1]);
+ b[1].next (&b[2]);
+ // b[3] and b[4] are unchained.
+ b[5].next (&b[6]);
+ b[6].next (&b[7]);
+ b[7].next (&b[8]);
+ // b[9] is unchained
+ q.enqueue_tail (&b[3]);
+ q.enqueue_tail (&b[4]);
+ int num = q.enqueue_head (&b[0]);
+ if (num != 5)
+ {
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("Chained enqueue expected 5; has %d\n"),
+ num));
+ status = -1;
+ }
+ num = q.enqueue_tail (&b[5]);
+ if (num != 9)
+ {
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("Chained enqueue expected 9; has %d\n"),
+ num));
+ status = -1;
+ }
+ num = q.enqueue_tail (&b[9]);
+ if (num != 10)
+ {
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("Chained enqueue expected 10; has %d\n"),
+ num));
+ status = -1;
+ }
+ size_t msgs, bytes;
+ msgs = q.message_count ();
+ bytes = q.message_bytes ();
+ if (msgs != 10 || bytes != 100)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Chained enqueue totals: %d msgs, %d bytes; ")
+ ACE_TEXT ("should be 10 msgs, 100 bytes\n"),
+ (int)msgs, (int)bytes));
+ status = -1;
+ }
+
+ // Now see if we can dequeue them, checking the order.
+ ACE_Time_Value nowait (ACE_OS::gettimeofday ());
+ ACE_Message_Block *bp;
+ int qstat;
+ for (i = 0; i < num_blks; ++i)
+ {
+ qstat = q.dequeue_head (bp, &nowait);
+ if (qstat == -1)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Checking chained blocks, pass %d: %p\n"),
+ (int)i, ACE_TEXT ("dequeue_head")));
+ status = -1;
+ }
+ else if (bp != &b[i])
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Checking chained blocks, pass %d: ")
+ ACE_TEXT ("block out of order\n"),
+ (int)i));
+ status = -1;
+ }
+ }
+
+ if (status == 0)
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Chained block test OK\n")));
+ return status;
+}
+
+static int
+single_thread_performance_test (int queue_type = 0)
+{
+ const char test_message[] =
+ "ACE_Message_Queue Test Message";
+ const ACE_TCHAR *message =
+ ACE_TEXT ("ACE_Message_Queue<ACE_NULL_SYNCH>, single thread");
+ int i = 0;
+
+ // Create a message queue.
+ ACE_Message_Queue_Base *msgq = 0;
+
+ if (queue_type == 0)
+ ACE_NEW_RETURN (msgq,
+ QUEUE,
+ -1);
+#if defined (VXWORKS)
+ else
+ {
+ ACE_NEW_RETURN (msgq,
+ ACE_Message_Queue_Vx (max_messages,
+ MAX_MESSAGE_SIZE),
+ -1);
+ message = "ACE_Message_Queue_Vx, single thread test";
+ }
+#elif defined (ACE_WIN32) && (ACE_HAS_WINNT4 != 0)
+ else
+ {
+ ACE_NEW_RETURN (msgq,
+ ACE_Message_Queue_NT,
+ -1);
+ message = ACE_TEXT ("ACE_Message_Queue_NT, single thread test");
+ }
+#endif /* VXWORKS */
+
+ // Create the messages. Allocate off the heap in case messages
+ // is large relative to the amount of stack space available.
+ ACE_Message_Block **send_block = 0;
+ ACE_NEW_RETURN (send_block,
+ ACE_Message_Block *[max_messages],
+ -1);
+
+ for (i = 0; i < max_messages; ++i)
+ ACE_NEW_RETURN (send_block[i],
+ ACE_Message_Block (test_message,
+ MAX_MESSAGE_SIZE),
+ -1);
+
+ ACE_Message_Block **receive_block_p = 0;
+ ACE_NEW_RETURN (receive_block_p,
+ ACE_Message_Block *[max_messages],
+ -1);
+
+#if defined (VXWORKS)
+ // Set up blocks to receive the messages. Allocate these off the
+ // heap in case messages is large relative to the amount of
+ // stack space available.
+ ACE_Message_Block *receive_block;
+ ACE_NEW_RETURN (receive_block,
+ ACE_Message_Block[max_messages],
+ -1);
+
+ for (i = 0; i < max_messages; ++i)
+ {
+ receive_block[i].init (MAX_MESSAGE_SIZE);
+
+ // For VxWorks Message Queues, the receive block pointer must be
+ // assigned. It will be used by dequeue_head ().
+ receive_block_p[i] = &receive_block[i];
+ }
+#endif /* VXWORKS */
+
+ timer->start ();
+
+ // Send/receive the messages.
+ for (i = 0; i < max_messages; ++i)
+ {
+ if (msgq->enqueue_tail (send_block[i]) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("enqueue")),
+ -1);
+
+ if (msgq->dequeue_head (receive_block_p[i]) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("dequeue_head")),
+ -1);
+ }
+
+ timer->stop ();
+
+ ACE_Time_Value tv;
+ timer->elapsed_time (tv);
+ ACE_DEBUG ((LM_INFO,
+ ACE_TEXT ("%s: %u messages took %u msec (%f msec/message)\n"),
+ message,
+ max_messages,
+ tv.msec (),
+ (double) tv.msec () / max_messages));
+ timer->reset ();
+
+ delete [] receive_block_p;
+#if defined (VXWORKS)
+ delete [] receive_block;
+#endif /* VXWORKS */
+
+ for (i = 0; i < max_messages; ++i)
+ delete send_block[i];
+ delete [] send_block;
+ delete msgq;
+
+ return 0;
+}
+
+static void *
+receiver (void *arg)
+{
+ Queue_Wrapper *queue_wrapper =
+ reinterpret_cast<Queue_Wrapper *> (arg);
+ int i;
+
+ ACE_Message_Block **receive_block_p = 0;
+ ACE_NEW_RETURN (receive_block_p,
+ ACE_Message_Block *[max_messages],
+ (void *) -1);
+
+#if defined (VXWORKS)
+ // Set up blocks to receive the messages. Allocate these off the
+ // heap in case messages is large relative to the amount of stack
+ // space available.
+ ACE_Message_Block *receive_block;
+ ACE_NEW_RETURN (receive_block,
+ ACE_Message_Block[max_messages],
+ (void *) -1);
+
+ for (i = 0; i < max_messages; ++i)
+ {
+ receive_block[i].init (MAX_MESSAGE_SIZE);
+
+ // For VxWorks Message Queues, the receive block pointer must be
+ // assigned. It will be used by <dequeue_head>.
+ receive_block_p[i] = &receive_block[i];
+ }
+#endif /* VXWORKS */
+
+ for (i = 0; i < max_messages; ++i)
+ if (queue_wrapper->q_->dequeue_head (receive_block_p[i]) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("dequeue_head")),
+ 0);
+ timer->stop ();
+
+ delete [] receive_block_p;
+#if defined (VXWORKS)
+ delete [] receive_block;
+#endif /* VXWORKS */
+
+ return 0;
+}
+
+static void *
+sender (void *arg)
+{
+ Queue_Wrapper *queue_wrapper =
+ reinterpret_cast<Queue_Wrapper *> (arg);
+ int i;
+
+ timer->start ();
+
+ // Send the messages.
+ for (i = 0; i < max_messages; ++i)
+ if (queue_wrapper->q_->
+ enqueue_tail (queue_wrapper->send_block_[i]) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("enqueue")),
+ 0);
+ return 0;
+}
+
+static
+int
+performance_test (int queue_type = 0)
+{
+ Queue_Wrapper queue_wrapper;
+ const ACE_TCHAR *message =
+ ACE_TEXT ("ACE_Message_Queue<ACE_SYNCH>");
+ int i = 0;
+
+ // Create the messages. Allocate off the heap in case messages is
+ // large relative to the amount of stack space available. Allocate
+ // it here instead of in the sender, so that we can delete it after
+ // the _receiver_ is done.
+ ACE_Message_Block **send_block = 0;
+ ACE_NEW_RETURN (send_block,
+ ACE_Message_Block *[max_messages],
+ -1);
+
+ for (i = 0; i < max_messages; ++i)
+ ACE_NEW_RETURN (send_block[i],
+ ACE_Message_Block (test_message,
+ MAX_MESSAGE_SIZE),
+ -1);
+
+ queue_wrapper.send_block_ = send_block;
+
+ if (queue_type == 0)
+ ACE_NEW_RETURN (queue_wrapper.q_,
+ SYNCH_QUEUE,
+ -1);
+#if defined (VXWORKS)
+ else
+ {
+ ACE_NEW_RETURN (queue_wrapper.q_,
+ ACE_Message_Queue_Vx (max_messages,
+ MAX_MESSAGE_SIZE),
+ -1);
+ message = "ACE_Message_Queue_Vx";
+ }
+#elif defined (ACE_WIN32) && (ACE_HAS_WINNT4 != 0)
+ else
+ {
+ ACE_NEW_RETURN (queue_wrapper.q_,
+ ACE_Message_Queue_NT,
+ -1);
+ message = ACE_TEXT ("ACE_Message_Queue_NT");
+ }
+#endif /* VXWORKS */
+
+ if (ACE_Thread_Manager::instance ()->spawn ((ACE_THR_FUNC) sender,
+ &queue_wrapper,
+ THR_BOUND) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("spawning sender thread")),
+ -1);
+
+ if (ACE_Thread_Manager::instance ()->spawn ((ACE_THR_FUNC) receiver,
+ &queue_wrapper,
+ THR_BOUND) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("spawning receiver thread")),
+ -1);
+
+ ACE_Thread_Manager::instance ()->wait ();
+ ACE_Time_Value tv;
+ timer->elapsed_time (tv);
+ ACE_DEBUG ((LM_INFO, ACE_TEXT ("%s: %u messages took %u msec (%f msec/message)\n"),
+ message,
+ max_messages,
+ tv.msec (),
+ (double) tv.msec () / max_messages));
+ timer->reset ();
+
+ delete queue_wrapper.q_;
+ queue_wrapper.q_ = 0;
+
+ for (i = 0; i < max_messages; ++i)
+ delete send_block[i];
+ delete [] send_block;
+
+ return 0;
+}
+
+// Ensure that the timedout dequeue_head() sets errno code properly.
+
+static int
+timeout_test (void)
+{
+ SYNCH_QUEUE mq;
+ int status = 0;
+
+ if (!mq.is_empty ())
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("New queue is not empty!\n")));
+ status = 1;
+ }
+ else
+ {
+ ACE_Message_Block *b;
+ ACE_Time_Value tv (ACE_OS::gettimeofday ()); // Now
+
+ if (mq.dequeue_head (b, &tv) != -1)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Dequeued from empty queue!\n")));
+ status = 1;
+ }
+ else if (errno != EWOULDBLOCK)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("Dequeue timeout should be EWOULDBLOCK, got")));
+ status = 1;
+ }
+ else
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Timed dequeue test: OK\n")));
+ status = 0; // All is well
+ }
+ }
+
+ return status;
+}
+#endif /* ACE_HAS_THREADS */
+
+// Check to make sure that dequeue_prio() respects FIFO ordering.
+// @@ At some point, this function should be enhanced to do a more
+// thorough check...
+
+static int
+prio_test (void)
+{
+ const char S1[] = "first";
+ const char S2[] = "second";
+ const int PRIORITY = 50;
+ QUEUE mq;
+ int status;
+
+ ACE_Message_Block mb1 (S1, sizeof S1, PRIORITY);
+ ACE_Message_Block mb2 (S2, sizeof S2, PRIORITY);
+
+ mq.enqueue_prio (&mb1);
+ mq.enqueue_prio (&mb2);
+
+ ACE_Message_Block *mb1p;
+ ACE_Message_Block *mb2p;
+
+ mq.dequeue_prio (mb1p);
+ mq.dequeue_prio (mb2p);
+
+ ACE_DEBUG ((LM_DEBUG, "message 1 = %s\nmessage 2 = %s\n",
+ mb1p->rd_ptr (),
+ mb2p->rd_ptr ()));
+
+ if (ACE_OS_String::strcmp (mb1p->rd_ptr (), S1) == 0
+ && ACE_OS_String::strcmp (mb2p->rd_ptr (), S2) == 0)
+ status = 0;
+ else
+ status = 1;
+
+ return status;
+}
+
+int
+run_main (int argc, ACE_TCHAR *argv[])
+{
+ ACE_START_TEST (ACE_TEXT ("Message_Queue_Test"));
+
+ if (argc == 2)
+ if (!ACE_OS::strcmp (argv[1], ACE_TEXT ("-?")))
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("%s/n"),
+ usage));
+ else
+ max_messages = ACE_OS::atoi (argv[1]);
+
+ int status = prio_test ();
+
+#if !defined (VXWORKS)
+ // The iterator test occasionally causes a page fault or a hang on
+ // VxWorks.
+ if (status == 0)
+ status = iterator_test ();
+#endif /* ! VXWORKS */
+
+ ACE_NEW_RETURN (timer,
+ ACE_High_Res_Timer,
+ -1);
+
+#if defined (ACE_HAS_THREADS)
+ if (status == 0)
+ status = timeout_test ();
+
+ if (status == 0)
+ status = chained_block_test ();
+
+ if (status == 0)
+ status = single_thread_performance_test ();
+
+# if defined (VXWORKS) || (defined (ACE_WIN32) && (ACE_HAS_WINNT4 != 0))
+ // Test ACE_Message_Queue_Vx. or ACE_Message_Queue_NT
+ if (status == 0)
+ status = single_thread_performance_test (1);
+# endif /* VXWORKS */
+
+ if (status == 0)
+ status = performance_test ();
+
+# if defined (VXWORKS) || (defined (ACE_WIN32) && (ACE_HAS_WINNT4 != 0))
+ // Test ACE_Message_Queue_Vx or ACE_Message_Queue_NT
+ if (status == 0)
+ status = performance_test (1);
+# endif /* VXWORKS */
+#endif /* ACE_HAS_THREADS */
+
+ if (status != 0)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("test failed")));
+ delete timer;
+ timer = 0;
+
+ ACE_END_TEST;
+ return status;
+}
+
diff --git a/ACE/tests/Message_Queue_Test_Ex.cpp b/ACE/tests/Message_Queue_Test_Ex.cpp
new file mode 100644
index 00000000000..fd4f714a42b
--- /dev/null
+++ b/ACE/tests/Message_Queue_Test_Ex.cpp
@@ -0,0 +1,677 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Message_Queue_Test_Ex.cpp
+//
+// = DESCRIPTION
+// This is:
+// 1. A simple test of the ACE_Message_Queue_Ex that executes
+// a performance measurement test for both single-threaded
+// (null synch) and thread-safe ACE_Message_Queue_Ex
+// instantiations.
+// 2. An example of using a user-defined class to parameterize
+// ACE_Message_Queue_Ex.
+//
+// = AUTHORS
+// Michael Vitlo <mvitalo@sprynet.com>, copied the code from:
+// Irfan Pyarali <irfan@cs.wustl.edu> and
+// David L. Levine <levine@cs.wustl.edu>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/Thread_Manager.h"
+
+#include "ace/Message_Queue.h"
+#include "ace/Synch_Traits.h"
+#include "ace/Null_Mutex.h"
+#include "ace/Null_Condition.h"
+#include "ace/High_Res_Timer.h"
+#include "ace/Message_Block.h"
+#include "ace/OS_NS_sys_time.h"
+#include "ace/Barrier.h"
+#include "Message_Queue_Test_Ex.h" // Declares User_Class
+
+const ACE_TCHAR usage[] =
+ ACE_TEXT ("usage: Message_Queue_Test_Ex <number of messages>\n");
+
+typedef ACE_Message_Queue_Ex<User_Class, ACE_NULL_SYNCH> QUEUE;
+
+static const int MAX_MESSAGES = 10000;
+static const char test_message[] = "ACE_Message_Queue_Ex Test Message";
+
+static int max_messages = MAX_MESSAGES;
+static int chain_limit = 4;
+static ACE_Barrier tester_barrier (2);
+
+// Dynamically allocate to avoid a static.
+static ACE_High_Res_Timer *timer = 0;
+
+// Helper printing function
+static void
+print_message (const ACE_TCHAR *message)
+{
+ ACE_Time_Value tv;
+ timer->elapsed_time (tv);
+ ACE_DEBUG ((LM_INFO,
+ ACE_TEXT ("%s: %u messages took %u msec (%f msec/message)\n"),
+ message,
+ max_messages,
+ tv.msec (),
+ (double) tv.msec () / max_messages));
+}
+
+#if defined (ACE_HAS_THREADS)
+typedef ACE_Message_Queue_Ex<User_Class, ACE_MT_SYNCH> SYNCH_QUEUE;
+
+struct Queue_Wrapper
+{
+ // = TITLE
+ // Container for data passed to sender and receiver in
+ // performance test.
+ //
+ // = DESCRIPTION
+ // For use in multithreaded performance test.
+
+ SYNCH_QUEUE *q_;
+ // The message queue.
+
+ User_Class **send_block_;
+ // Pointer to messages blocks for sender to send to reciever.
+
+ Queue_Wrapper (void)
+ : q_ (0), send_block_ (0)
+ {
+ }
+ // Default constructor.
+};
+
+struct MQ_Ex_N_Tester_Wrapper
+{
+ // = TITLE
+ // Container for data passed to sender in the MQ_Ex_N_Tester
+ // performance test.
+ //
+ // = DESCRIPTION
+ // For use in multithreaded performance test.
+ MQ_Ex_N_Tester *tester_;
+ User_Class *head_send_block_;
+};
+
+#endif /* ACE_HAS_THREADS */
+
+// Encapsulates the sent messages creation and destruction
+struct Send_Messages
+{
+ Send_Messages (int number_of_messages, int chain_limit):
+ send_block_ (0),
+ number_of_messages_ (number_of_messages),
+ chain_limit_ (chain_limit)
+ {
+ }
+
+ int create_messages (const char test_message[])
+ {
+ int limit = this->number_of_messages_ / this->chain_limit_;
+ ACE_NEW_RETURN (this->send_block_,
+ User_Class *[limit],
+ -1);
+
+ int i, j;
+ for (i = 0; i < limit; ++i)
+ {
+ User_Class *&temp1 = this->send_block_[i];
+ ACE_NEW_RETURN (temp1,
+ User_Class (test_message),
+ -1);
+ User_Class *tail = temp1;
+ for (j = 1; j < this->chain_limit_; ++j)
+ {
+ User_Class *temp2 = 0;
+ ACE_NEW_RETURN (temp2,
+ User_Class (test_message),
+ -1);
+ tail->next (temp2);
+ tail = temp2;
+ }
+ }
+ this->head_send_block_ = this->send_block_[0];
+ return 0;
+ }
+
+ ~Send_Messages ()
+ {
+ int j, i = 0;
+ int limit = this->number_of_messages_ / this->chain_limit_;
+ for (; i < limit; ++i)
+ {
+ User_Class *&temp1 = this->send_block_[i];
+ for (j = 0; j < this->chain_limit_; ++j)
+ {
+ User_Class *temp2 = temp1->next ();
+ delete temp1;
+ temp1 = temp2;
+ }
+ }
+ delete [] this->send_block_;
+ }
+
+ User_Class * head_send_block_;
+ User_Class ** send_block_;
+ int number_of_messages_;
+ int chain_limit_;
+};
+
+// Encapsulates the received messages creation and destruction
+struct Receive_Messages
+{
+ Receive_Messages (int number_of_messages) :
+ receive_block_ (0),
+ number_of_messages_ (number_of_messages)
+ {
+ }
+
+ int create (void)
+ {
+ ACE_NEW_RETURN (this->receive_block_,
+ User_Class *[this->number_of_messages_],
+ -1);
+ return 0;
+ }
+
+ ~Receive_Messages ()
+ {
+ delete [] this->receive_block_;
+ }
+
+ User_Class **receive_block_;
+ int number_of_messages_;
+};
+
+static int
+single_thread_performance_test (void)
+{
+ const char test_message[] =
+ "ACE_Message_Queue_Ex Test Message";
+ const ACE_TCHAR *message =
+ ACE_TEXT ("ACE_Message_Queue_Ex<ACE_NULL_SYNCH>, single thread");
+
+ // Create a message queue.
+ QUEUE *msgq = 0;
+
+ ACE_NEW_RETURN (msgq,
+ QUEUE,
+ -1);
+
+ // Create the messages. Allocate off the heap in case messages is
+ // large relative to the amount of stack space available.
+ User_Class **send_block = 0;
+ ACE_NEW_RETURN (send_block,
+ User_Class *[max_messages],
+ -1);
+
+ int i = 0;
+
+ for (i = 0; i < max_messages; ++i)
+ ACE_NEW_RETURN (send_block[i],
+ User_Class (test_message),
+ -1);
+
+ User_Class **receive_block_p = 0;
+ ACE_NEW_RETURN (receive_block_p,
+ User_Class *[max_messages],
+ -1);
+
+ timer->start ();
+
+ // Send/receive the messages.
+ for (i = 0; i < max_messages; ++i)
+ {
+ if (msgq->enqueue_tail (send_block[i]) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("enqueue")),
+ -1);
+
+ if (msgq->dequeue_head (receive_block_p[i]) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("dequeue_head")),
+ -1);
+ }
+
+ timer->stop ();
+ print_message (message);
+ timer->reset ();
+
+ delete [] receive_block_p;
+
+ for (i = 0; i < max_messages; ++i)
+ delete send_block[i];
+ delete [] send_block;
+ delete msgq;
+
+ return 0;
+}
+
+int
+MQ_Ex_N_Tester::single_thread_performance_test (void)
+{
+ // Create the messages. Allocate off the heap in case messages is
+ // large relative to the amount of stack space available.
+
+ if ((0 != this->test_enqueue_tail ()) ||
+ (0 != this->test_enqueue_head ()) )
+ {
+ return -1;
+ }
+
+ return 0;
+}
+
+int
+MQ_Ex_N_Tester::test_enqueue_tail (void)
+{
+ const ACE_TCHAR *message =
+ ACE_TEXT ("ACE_Message_Queue_Ex_N<ACE_NULL_SYNCH>, test_enqueue_tail");
+
+ // Send_Messages creates messages and deletes them when it gets out of scope
+ Send_Messages messages (max_messages, chain_limit);
+ if (-1 == messages.create_messages (test_message))
+ {
+ return -1;
+ }
+ Receive_Messages r_messages (max_messages);
+ if (-1 == r_messages.create ())
+ {
+ return -1;
+ }
+
+ // prepare
+ int limit = max_messages / chain_limit;
+ timer->start ();
+ // Send with just one call
+ for (int i = 0; i < limit; ++i)
+ {
+ if (-1 == this->st_queue_.enqueue_tail (messages.send_block_[i]))
+ {
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("enqueue_tail_n")),
+ -1);
+ }
+
+ for (int j = 0, k = 0; j < chain_limit; ++j, ++k)
+ {
+ if (this->st_queue_.dequeue_head (r_messages.receive_block_[k]) == -1)
+ {
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("dequeue_head")),
+ -1);
+ }
+ }
+ }
+ timer->stop ();
+
+ print_message (message);
+
+ timer->reset ();
+
+ return 0;
+}
+
+int
+MQ_Ex_N_Tester::test_enqueue_head (void)
+{
+ const ACE_TCHAR *message =
+ ACE_TEXT ("ACE_Message_Queue_Ex_N<ACE_NULL_SYNCH>, test_enqueue_head");
+
+ // Send_Messages creates messages and deletes them when it gets out of scope
+ Send_Messages messages (max_messages, chain_limit);
+ if (-1 == messages.create_messages (test_message))
+ {
+ return -1;
+ }
+ Receive_Messages r_messages (max_messages);
+ if (-1 == r_messages.create ())
+ {
+ return -1;
+ }
+
+ // prepare
+ int i, j, k = 0;
+
+ int limit = max_messages / chain_limit;
+ timer->start ();
+
+ // Send/receive the messages.
+ // Send with just one call
+ for (i = 0; i < limit; ++i)
+ {
+ if (-1 == this->st_queue_.enqueue_head (messages.send_block_[i]))
+ {
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("enqueue_tail_n")),
+ -1);
+ }
+
+ for (j = 0; j < chain_limit; ++j, ++k)
+ {
+ if (this->st_queue_.dequeue_head (r_messages.receive_block_[k]) == -1)
+ {
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("dequeue_head")),
+ -1);
+ }
+ }
+ }
+ timer->stop ();
+
+ print_message (message);
+
+ timer->reset ();
+
+ return 0;
+
+}
+
+#if defined (ACE_HAS_THREADS)
+
+static void *
+receiver (void *arg)
+{
+ Queue_Wrapper *queue_wrapper = reinterpret_cast<Queue_Wrapper *> (arg);
+ int i;
+
+ User_Class **receive_block_p = 0;
+ ACE_NEW_RETURN (receive_block_p,
+ User_Class *[max_messages],
+ (void *) -1);
+
+ for (i = 0; i < max_messages; ++i)
+ if (queue_wrapper->q_->dequeue_head (receive_block_p[i]) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("dequeue_head")),
+ 0);
+ timer->stop ();
+
+ delete [] receive_block_p;
+
+ return 0;
+}
+
+static void *
+sender (void *arg)
+{
+ Queue_Wrapper *queue_wrapper = reinterpret_cast<Queue_Wrapper *> (arg);
+ int i;
+
+ timer->start ();
+
+ // Send the messages.
+ for (i = 0; i < max_messages; ++i)
+ if (queue_wrapper->q_->
+ enqueue_tail (queue_wrapper->send_block_[i]) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("enqueue")),
+ 0);
+ return 0;
+}
+
+static int
+performance_test (void)
+{
+ Queue_Wrapper queue_wrapper;
+ const ACE_TCHAR *message =
+ ACE_TEXT ("ACE_Message_Queue_Ex<ACE_SYNCH>");
+ int i = 0;
+
+ // Create the messages. Allocate off the heap in case messages is
+ // large relative to the amount of stack space available. Allocate
+ // it here instead of in the sender, so that we can delete it after
+ // the _receiver_ is done.
+ User_Class **send_block = 0;
+ ACE_NEW_RETURN (send_block,
+ User_Class *[max_messages],
+ -1);
+
+ for (i = 0; i < max_messages; ++i)
+ ACE_NEW_RETURN (send_block[i],
+ User_Class (test_message),
+ -1);
+
+ queue_wrapper.send_block_ = send_block;
+
+ ACE_NEW_RETURN (queue_wrapper.q_,
+ SYNCH_QUEUE,
+ -1);
+
+ if (ACE_Thread_Manager::instance ()->spawn ((ACE_THR_FUNC) sender,
+ &queue_wrapper,
+ THR_BOUND) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("spawning sender thread")),
+ -1);
+
+ if (ACE_Thread_Manager::instance ()->spawn ((ACE_THR_FUNC) receiver,
+ &queue_wrapper,
+ THR_BOUND) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("spawning receiver thread")),
+ -1);
+
+ ACE_Thread_Manager::instance ()->wait ();
+ print_message (message);
+ timer->reset ();
+
+ delete queue_wrapper.q_;
+ queue_wrapper.q_ = 0;
+
+ for (i = 0; i < max_messages; ++i)
+ delete send_block[i];
+ delete [] send_block;
+
+ return 0;
+}
+
+int
+MQ_Ex_N_Tester::performance_test (void)
+{
+ const ACE_TCHAR *message =
+ ACE_TEXT ("ACE_Message_Queue_Ex_N<ACE_SYNCH>");
+
+ Send_Messages messages (max_messages, chain_limit);
+ if (-1 == messages.create_messages (test_message))
+ {
+ return -1;
+ }
+
+ MQ_Ex_N_Tester_Wrapper tester_wrapper;
+ tester_wrapper.head_send_block_ = messages.head_send_block_;
+ tester_wrapper.tester_ = this;
+
+ if (ACE_Thread_Manager::instance ()->spawn ((ACE_THR_FUNC) &MQ_Ex_N_Tester::sender,
+ &tester_wrapper,
+ THR_BOUND) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("spawning sender thread")),
+ -1);
+
+ if (ACE_Thread_Manager::instance ()->spawn ((ACE_THR_FUNC) &MQ_Ex_N_Tester::receiver,
+ this,
+ THR_BOUND) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("spawning receiver thread")),
+ -1);
+
+ ACE_Thread_Manager::instance ()->wait ();
+
+ print_message (message);
+
+ timer->reset ();
+
+ return 0;
+}
+
+ACE_THR_FUNC_RETURN
+MQ_Ex_N_Tester::receiver (void *args)
+{
+ MQ_Ex_N_Tester *tester = reinterpret_cast<MQ_Ex_N_Tester *> (args);
+
+ User_Class **receive_block_p = 0;
+ ACE_NEW_RETURN (receive_block_p,
+ User_Class *[max_messages],
+ (ACE_THR_FUNC_RETURN) -1);
+
+ int i;
+ tester_barrier.wait ();
+ for (i = 0; i < max_messages; ++i)
+ {
+ if (tester->mt_queue_.dequeue_head (receive_block_p[i]) == -1)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("dequeue_head")));
+ return (ACE_THR_FUNC_RETURN) -1;
+ }
+ }
+ timer->stop ();
+
+ delete [] receive_block_p;
+
+ return 0;
+}
+
+ACE_THR_FUNC_RETURN
+MQ_Ex_N_Tester::sender (void *args)
+{
+ MQ_Ex_N_Tester_Wrapper *tester_wrapper =
+ reinterpret_cast<MQ_Ex_N_Tester_Wrapper *> (args);
+ MQ_Ex_N_Tester *tester = tester_wrapper->tester_;
+
+ Send_Messages messages (max_messages, chain_limit);
+ if (-1 == messages.create_messages (test_message))
+ {
+ return (ACE_THR_FUNC_RETURN) -1;
+ }
+ int limit = max_messages / chain_limit;
+ tester_barrier.wait ();
+ timer->start ();
+ // Send/receive the messages.
+ timer->start ();
+ // Send with just one call
+ for (int i = 0; i < limit; ++i)
+ {
+ if (-1 == tester->mt_queue_.enqueue_tail (messages.send_block_[i]))
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("enqueue_tail_n")));
+ return (ACE_THR_FUNC_RETURN) -1;
+ }
+ }
+ return 0;
+}
+
+#endif /* ACE_HAS_THREADS */
+
+int basic_queue_test (ACE_Message_Queue_Ex<User_Class, ACE_SYNCH>& q)
+{
+ int status = 0;
+ if (!q.is_empty ())
+ {
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("New queue is not empty!\n")));
+ status = 1;
+ }
+ else
+ {
+ User_Class *b;
+ ACE_Time_Value tv (ACE_OS::gettimeofday ()); // Now
+ if (q.dequeue_head (b, &tv) != -1)
+ {
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("Dequeued from empty queue!\n")));
+ status = 1;
+ }
+ else if (errno != EWOULDBLOCK)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("Dequeue timeout should be EWOULDBLOCK, got")));
+ status = 1;
+ }
+ else
+ {
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Timed dequeue test: OK\n")));
+ status = 0; // All is well
+ }
+ }
+
+ return status;
+}
+
+int
+run_main (int argc, ACE_TCHAR *argv[])
+{
+ ACE_START_TEST (ACE_TEXT ("Message_Queue_Test_Ex"));
+
+ if (argc == 2)
+ if (! ACE_OS::strcmp (argv[1], ACE_TEXT ("-?")))
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("%s/n"),
+ usage));
+ else
+ max_messages = ACE_OS::atoi (argv[1]);
+
+ int status = 0;
+
+ // Be sure that the a timed out get sets the error code properly.
+ ACE_Message_Queue_Ex<User_Class, ACE_SYNCH> q1;
+ ACE_Message_Queue_Ex_N<User_Class, ACE_SYNCH> q2;
+ if (0 != basic_queue_test (q1) ||
+ 0 != basic_queue_test (q2))
+ {
+ ++status;
+ }
+
+ ACE_NEW_RETURN (timer,
+ ACE_High_Res_Timer,
+ -1);
+
+ status += single_thread_performance_test ();
+
+#if defined (ACE_HAS_THREADS)
+ status += performance_test ();
+#endif /* ACE_HAS_THREADS */
+
+ {
+ MQ_Ex_N_Tester ex_n_tester;
+ status += ex_n_tester.single_thread_performance_test ();
+#if defined (ACE_HAS_THREADS)
+ status += ex_n_tester.performance_test ();
+#endif /* ACE_HAS_THREADS */
+ }
+
+ if (status != 0)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("test failed")));
+ delete timer;
+ timer = 0;
+
+ ACE_END_TEST;
+ return status;
+}
diff --git a/ACE/tests/Message_Queue_Test_Ex.h b/ACE/tests/Message_Queue_Test_Ex.h
new file mode 100644
index 00000000000..408d62277d2
--- /dev/null
+++ b/ACE/tests/Message_Queue_Test_Ex.h
@@ -0,0 +1,84 @@
+// -*- C++ -*-
+
+//=============================================================================
+/**
+ * @file Message_Queue_Test_Ex.h
+ *
+ * $Id$
+ *
+ * Define class needed for generating templates. IBM C++ requires this
+ * to be in its own file for auto template instantiation.
+ *
+ * @author Michael Vitlo <mvitalo@sprynet.com>
+ * @author Irfan Pyarali <irfan@cs.wustl.edu>
+ * @author David L. Levine <levine@cs.wustl.edu>
+ * @author Guy Peleg <guy.peleg@amdocs.com>
+ */
+//=============================================================================
+
+#ifndef ACE_TESTS_MESSAGE_QUEUE_TEST_EX_H
+#define ACE_TESTS_MESSAGE_QUEUE_TEST_EX_H
+
+#include "ace/OS_NS_string.h"
+
+// User-defined class used for queue data.
+class User_Class
+{
+public:
+ User_Class (const char inputMsg[])
+ : message_ (0),
+ next_(0)
+ {
+ ACE_NEW (this->message_, char[ACE_OS::strlen (inputMsg) + 1]);
+ ACE_OS::strcpy (this->message_, inputMsg);
+ }
+
+ ~User_Class (void) { delete [] this->message_; }
+
+ // This is for checking the ACE_Message_Queue_Ex_N
+ User_Class *next () const
+ {
+ return this->next_;
+ }
+
+ void next (User_Class *uc)
+ {
+ this->next_ = uc;
+ }
+
+private:
+ char *message_;
+ User_Class *next_;
+};
+
+// The main tests for the ACE_Message_Queue_Ex_N
+struct Receive_Messages;
+
+class MQ_Ex_N_Tester
+{
+public:
+ int single_thread_performance_test (void);
+
+#if defined (ACE_HAS_THREADS)
+ int performance_test (void);
+
+ /// Sender runs with an autonomous thread
+ static ACE_THR_FUNC_RETURN sender (void *);
+
+ /// Receiver runs with an autonomous thread
+ static ACE_THR_FUNC_RETURN receiver (void *);
+
+ /// Multi threaded tests use this queue
+ ACE_Message_Queue_Ex_N<User_Class, ACE_MT_SYNCH> mt_queue_;
+#endif /* ACE_HAS_THREADS */
+
+ /// Single threaded tests use this queue
+ ACE_Message_Queue_Ex_N<User_Class, ACE_NULL_SYNCH> st_queue_;
+
+private:
+ /// Helper methods
+ int test_enqueue_head (void);
+ int test_enqueue_tail (void);
+};
+
+#endif /* ACE_TESTS_MESSAGE_QUEUE_TEST_EX_H */
diff --git a/ACE/tests/Multicast_Test.cpp b/ACE/tests/Multicast_Test.cpp
new file mode 100644
index 00000000000..8613c1a498b
--- /dev/null
+++ b/ACE/tests/Multicast_Test.cpp
@@ -0,0 +1,944 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = DESCRIPTION
+// This program tests ACE_SOCK_Dgram_Mcast class.
+// It specifically tests subscribing to multiple groups on the same socket
+// on one or more physical interfaces (if available).
+//
+// The test can be run as a producer, consumer, or both producer/consumer
+// (default). The test requires at least two (2) multicast groups which can
+// be configured as command line options. The consumer subscribes to a
+// single group per instance and an additional instance tries to subscribe
+// to all groups on a single socket (if the ACE_SOCK_Dgram_Mcast instance
+// bind()'s the first address to the socket, additional joins will fail).
+// The producer iterates through the list of group addresses and sends a
+// single message containing the destination address and port to each one.
+// It also sends messages to five (5) additional groups and a message to an
+// additional port for each group in order to produce a bit of "noise" in
+// order to help validate how well the multicast filtering works on a
+// particular platform.
+//
+// The list of destination groups start at 239.255.0.1 (default) and
+// increment by 1 up to 5 (default) groups. Both of these values, as well
+// as others, can be overridden via command-line options. Use the -?
+// option to display the usage message...
+//
+// = AUTHOR
+// Don Hinton <dhinton@dresystems.com>
+//
+// ============================================================================
+
+#include "tests/test_config.h"
+#include "ace/Get_Opt.h"
+#include "ace/Vector_T.h"
+#include "ace/SOCK_Dgram_Mcast.h"
+#include "ace/ACE.h"
+#include "ace/Reactor.h"
+#include "ace/OS_NS_stdio.h"
+#include "ace/OS_NS_string.h"
+#include "ace/OS_NS_strings.h"
+#include "ace/OS_NS_sys_time.h"
+#include "ace/Task.h"
+#include "ace/Atomic_Op.h"
+#include "ace/SString.h"
+#include "ace/Signal.h"
+#include "ace/Min_Max.h"
+
+ACE_RCSID(tests, Multicast_Test, "$Id$")
+
+#if defined (ACE_HAS_IP_MULTICAST) && defined (ACE_HAS_THREADS)
+
+/*
+ * The 'finished' flag is used to break out of an infninite loop in the
+ * task::svc () method. The 'handler' will set the flag in respose to
+ * SIGINT (CTRL-C).
+ */
+static sig_atomic_t finished = 0;
+extern "C" void handler (int)
+{
+ finished = 1;
+}
+
+static const int MCT_ITERATIONS = 10;
+static const int MCT_GROUPS = 5;
+static const int MCT_MIN_GROUPS = 2;
+
+static const char MCT_START_GROUP[] = "239.255.0.1";
+static const int MCT_START_PORT = 16000;
+
+static const size_t MAX_STRING_SIZE = 200;
+
+int advance_addr (ACE_INET_Addr &addr);
+
+// Keep track of errors so we can report them on exit.
+static sig_atomic_t error = 0;
+
+/*
+ * MCast_Config holds configuration data for this test.
+ */
+class MCT_Config
+{
+public:
+
+ enum
+ {
+ PRODUCER = 1,
+ CONSUMER = 2,
+ BOTH = PRODUCER | CONSUMER
+ };
+
+ MCT_Config (void)
+ : group_start_ (MCT_START_PORT, MCT_START_GROUP),
+ groups_ (0),
+ debug_ (0),
+ role_ (BOTH),
+ sdm_opts_ (ACE_SOCK_Dgram_Mcast::DEFOPTS),
+ iterations_ (MCT_ITERATIONS),
+ ttl_ (1),
+ wait_ (2)
+ {
+ if (IP_MAX_MEMBERSHIPS == 0)
+ this->groups_ = MCT_GROUPS;
+ else
+ this->groups_ = ACE_MIN (IP_MAX_MEMBERSHIPS, MCT_GROUPS);
+ }
+ ~MCT_Config (void)
+ {}
+
+ int open (int argc, ACE_TCHAR *argv[]);
+ int debug (void) const { return this->debug_;}
+ void dump (void) const;
+ int groups (void) const { return this->groups_;}
+ const ACE_INET_Addr group_start (void) const { return this->group_start_;}
+ u_long role (void) const { return this->role_;}
+ int iterations (void) const { return this->iterations_;}
+ int ttl (void) const { return this->ttl_;}
+ int wait (void) const { return this->wait_;}
+ ACE_SOCK_Dgram_Mcast::options options (void) const
+ {
+ return static_cast<ACE_SOCK_Dgram_Mcast::options> (this->sdm_opts_);
+ }
+
+private:
+ // Starting group address. (only IPv4 capable right now...)
+ ACE_INET_Addr group_start_;
+
+ // Number of groups we will try to use in the test.
+ int groups_;
+
+ // Debug flag.
+ int debug_;
+
+ // Role, i.e., PRODUCER, CONSUMER, BOTH: defaults to BOTH
+ u_long role_;
+
+ // ACE_SOCK_Dgram_Mcast ctor options
+ u_long sdm_opts_;
+
+ // Producer iterations
+ int iterations_;
+
+ // TTL, time to live, for use over routers.
+ int ttl_;
+
+ // Time to wait on CONSUMER threads to end before killing test.
+ int wait_;
+};
+
+int
+MCT_Config::open (int argc, ACE_TCHAR *argv[])
+{
+ int retval = 0;
+ int help = 0;
+
+ ACE_Get_Opt getopt (argc, argv, ACE_TEXT (":?"), 1, 1);
+
+ if (getopt.long_option (ACE_TEXT ("GroupStart"),
+ 'g',
+ ACE_Get_Opt::ARG_REQUIRED) != 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT (" Unable to add GroupStart option.\n")),
+ 1);
+
+ if (getopt.long_option (ACE_TEXT ("Groups"),
+ 'n',
+ ACE_Get_Opt::ARG_REQUIRED) != 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT (" Unable to add Groups option.\n")), 1);
+
+ if (getopt.long_option (ACE_TEXT ("Debug"),
+ 'd',
+ ACE_Get_Opt::NO_ARG) != 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT (" Unable to add Debug option.\n")), 1);
+
+ if (getopt.long_option (ACE_TEXT ("Role"),
+ 'r',
+ ACE_Get_Opt::ARG_REQUIRED) != 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT (" Unable to add Role option.\n")), 1);
+
+ if (getopt.long_option (ACE_TEXT ("SDM_options"),
+ 'm',
+ ACE_Get_Opt::ARG_REQUIRED) != 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT (" Unable to add Multicast_Options option.\n")),
+ 1);
+
+ if (getopt.long_option (ACE_TEXT ("Iterations"),
+ 'i',
+ ACE_Get_Opt::ARG_REQUIRED) != 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT (" Unable to add iterations option.\n")),
+ 1);
+
+ if (getopt.long_option (ACE_TEXT ("TTL"),
+ 't',
+ ACE_Get_Opt::ARG_REQUIRED) != 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT (" Unable to add TTL option.\n")),
+ 1);
+
+ if (getopt.long_option (ACE_TEXT ("Wait"),
+ 'w',
+ ACE_Get_Opt::ARG_REQUIRED) != 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT (" Unable to add wait option.\n")),
+ 1);
+
+ if (getopt.long_option (ACE_TEXT ("help"),
+ 'h',
+ ACE_Get_Opt::NO_ARG) != 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT (" Unable to add help option.\n")),
+ 1);
+
+ // Now, let's parse it...
+ int c = 0;
+ while ((c = getopt ()) != EOF)
+ {
+ switch (c)
+ {
+ case 0:
+ // Long Option. This should never happen.
+ retval = -1;
+ break;
+ case 'g':
+ {
+ // @todo validate all these, i.e., must be within range
+ // 224.255.0.0 to 238.255.255.255, but we only allow the
+ // administrative "site local" range, 239.255.0.0 to
+ // 239.255.255.255.
+ ACE_TCHAR *group = getopt.opt_arg ();
+ if (this->group_start_.set (group) != 0)
+ {
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("Bad group address:%s\n"),
+ group));
+ }
+ }
+ break;
+ case 'i':
+ this->iterations_ = ACE_OS::atoi (getopt.opt_arg ());
+ break;
+ case 'n':
+ {
+ int n = ACE_OS::atoi (getopt.opt_arg ());
+ // I'm assuming 0 means unlimited, so just use whatever the
+ // user provides. Seems to work okay on Solaris 5.8.
+ if (IP_MAX_MEMBERSHIPS == 0)
+ this->groups_ = n;
+ else
+ this->groups_ = ACE_MIN (ACE_MAX (n, MCT_MIN_GROUPS),
+ IP_MAX_MEMBERSHIPS);
+ break;
+ }
+ case 'd':
+ this->debug_ = 1;
+ break;
+ case 'r':
+ {
+ ACE_TCHAR *c = getopt.opt_arg ();
+ if (ACE_OS::strcasecmp (c, ACE_TEXT ("CONSUMER")) == 0)
+ this->role_ = CONSUMER;
+ else if (ACE_OS::strcasecmp (c, ACE_TEXT ("PRODUCER")) == 0)
+ this->role_ = PRODUCER;
+ else
+ {
+ help = 1;
+ retval = -1;
+ }
+ }
+ break;
+ case 'm':
+ {
+ //@todo add back OPT_BINDADDR_NO...
+ ACE_TCHAR *c = getopt.opt_arg ();
+ if (ACE_OS::strcasecmp (c, ACE_TEXT ("OPT_BINDADDR_YES")) == 0)
+ ACE_SET_BITS (this->sdm_opts_,
+ ACE_SOCK_Dgram_Mcast::OPT_BINDADDR_YES);
+ else if (ACE_OS::strcasecmp (c, ACE_TEXT ("OPT_BINDADDR_NO")) == 0)
+ ACE_CLR_BITS (this->sdm_opts_,
+ ACE_SOCK_Dgram_Mcast::OPT_BINDADDR_YES);
+ else if (ACE_OS::strcasecmp (c, ACE_TEXT ("DEFOPT_BINDADDR")) == 0)
+ {
+ ACE_CLR_BITS (this->sdm_opts_,
+ ACE_SOCK_Dgram_Mcast::OPT_BINDADDR_YES);
+ ACE_SET_BITS (this->sdm_opts_,
+ ACE_SOCK_Dgram_Mcast::DEFOPT_BINDADDR);
+ }
+ else if (ACE_OS::strcasecmp (c, ACE_TEXT ("OPT_NULLIFACE_ALL")) == 0)
+ ACE_SET_BITS (this->sdm_opts_,
+ ACE_SOCK_Dgram_Mcast::OPT_NULLIFACE_ALL);
+ else if (ACE_OS::strcasecmp (c, ACE_TEXT ("OPT_NULLIFACE_ONE")) == 0)
+ ACE_CLR_BITS (this->sdm_opts_,
+ ACE_SOCK_Dgram_Mcast::OPT_NULLIFACE_ALL);
+ else if (ACE_OS::strcasecmp (c, ACE_TEXT ("DEFOPT_NULLIFACE")) == 0)
+ {
+ ACE_CLR_BITS (this->sdm_opts_,
+ ACE_SOCK_Dgram_Mcast::OPT_NULLIFACE_ALL);
+ ACE_SET_BITS (this->sdm_opts_,
+ ACE_SOCK_Dgram_Mcast::DEFOPT_NULLIFACE);
+ }
+ else if (ACE_OS::strcasecmp (c, ACE_TEXT ("DEFOPTS")) == 0)
+ this->sdm_opts_ = ACE_SOCK_Dgram_Mcast::DEFOPTS;
+ else
+ {
+ help = 1;
+ retval = -1;
+ }
+ }
+ break;
+ case 't':
+ this->ttl_ = ACE_OS::atoi (getopt.opt_arg ());
+ break;
+ case 'w':
+ this->wait_ = ACE_OS::atoi (getopt.opt_arg ());
+ break;
+ case ':':
+ // This means an option requiring an argument didn't have one.
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT (" Option '%c' requires an argument but ")
+ ACE_TEXT ("none was supplied\n"),
+ getopt.opt_opt ()));
+ help = 1;
+ retval = -1;
+ break;
+ case '?':
+ case 'h':
+ default:
+ if (ACE_OS::strcmp (argv[getopt.opt_ind () - 1], ACE_TEXT ("-?")) != 0
+ && getopt.opt_opt () != 'h')
+ // Don't allow unknown options.
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT (" Found an unknown option (%c) ")
+ ACE_TEXT ("we couldn't handle.\n"),
+ getopt.opt_opt ()));
+ // getopt.last_option ())); //readd with "%s" when
+ // last_option() is available.
+ help = 1;
+ retval = -1;
+ break;
+ }
+ }
+
+ if (retval == -1)
+ {
+ if (help)
+ // print usage here
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("usage: %s [options]\n")
+ ACE_TEXT ("Options:\n")
+ ACE_TEXT (" -g {STRING} --GroupStart={STRING} ")
+ ACE_TEXT ("starting multicast group address\n")
+ ACE_TEXT (" ")
+ ACE_TEXT ("(default=239.255.0.1:16000)\n")
+ ACE_TEXT (" -n {#} --Groups={#} ")
+ ACE_TEXT ("number of groups (default=5)\n")
+ ACE_TEXT (" -d --Debug ")
+ ACE_TEXT ("debug flag (default=off)\n")
+ ACE_TEXT (" -r {STRING} --Role={STRING} ")
+ ACE_TEXT ("role {PRODUCER|CONSUMER|BOTH}\n")
+ ACE_TEXT (" ")
+ ACE_TEXT ("(default=BOTH)\n")
+ ACE_TEXT (" -m {STRING} --SDM_options={STRING} ")
+ ACE_TEXT ("ACE_SOCK_Dgram_Mcast ctor options\n")
+ ACE_TEXT (" ")
+ ACE_TEXT ("(default=DEFOPTS)\n")
+ ACE_TEXT (" -i {#} --Iterations={#} ")
+ ACE_TEXT ("number of iterations (default=100)\n")
+ ACE_TEXT (" -t {#} --TTL={#} ")
+ ACE_TEXT ("time to live (default=1)\n")
+ ACE_TEXT (" -w {#} --Wait={#} ")
+ ACE_TEXT ("number of seconds to wait on CONSUMER\n")
+ ACE_TEXT (" ")
+ ACE_TEXT ("(default=2)\n")
+ ACE_TEXT (" -h/? --help ")
+ ACE_TEXT ("show this message\n"),
+ argv[0]));
+
+ return -1;
+ }
+
+ return 0;
+}
+
+void
+MCT_Config::dump (void) const
+{
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT (" Dumping MCT_Config\n")));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\tIP_MAX_MEMBERSHIPS = %d\n"),
+ IP_MAX_MEMBERSHIPS));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\tgroups_ = %d\n"),
+ this->groups_));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\trole_ = %s\n"),
+ (ACE_BIT_ENABLED (this->role_, PRODUCER)
+ && ACE_BIT_ENABLED (this->role_, CONSUMER))
+ ? ACE_TEXT ("PRODUCER/CONSUMER")
+ : ACE_BIT_ENABLED (this->role_, PRODUCER)
+ ? ACE_TEXT ("PRODUCER")
+ : ACE_TEXT ("CONSUMER")));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\tsdm_options_ = %d\n"),
+ this->sdm_opts_));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\titerations_ = %d\n"),
+ this->iterations_));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\tttl_ = %d\n"),
+ this->ttl_));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\twait_ = %d\n"),
+ this->wait_));
+ // Note that this call to get_host_addr is the non-reentrant
+ // version, but it's okay for us.
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\tgroups_start_ = %s:%d\n"),
+ this->group_start_.get_host_addr (),
+ this->group_start_.get_port_number ()));
+
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+/******************************************************************************/
+
+class MCT_Event_Handler : public ACE_Event_Handler
+{
+public:
+ MCT_Event_Handler (ACE_SOCK_Dgram_Mcast::options options
+ = ACE_SOCK_Dgram_Mcast::DEFOPTS);
+ virtual ~MCT_Event_Handler (void);
+
+ int join (const ACE_INET_Addr &mcast_addr,
+ int reuse_addr = 1,
+ const ACE_TCHAR *net_if = 0);
+ int leave (const ACE_INET_Addr &mcast_addr,
+ const ACE_TCHAR *net_if = 0);
+
+ // = Event Handler hooks.
+ virtual int handle_input (ACE_HANDLE handle);
+ virtual int handle_close (ACE_HANDLE fd, ACE_Reactor_Mask close_mask);
+
+ virtual ACE_HANDLE get_handle (void) const;
+
+protected:
+ ACE_SOCK_Dgram_Mcast *mcast (void);
+ int find (const char *buf);
+
+private:
+ ACE_SOCK_Dgram_Mcast mcast_;
+
+ // List of groups we've joined
+ ACE_Vector<ACE_CString*> address_vec_;
+
+ // Flag used to set the 'finished' flag when the last event handler
+ // gets removed from the reactor.
+ static ACE_Atomic_Op<ACE_SYNCH_MUTEX, long> active_handlers_;
+};
+
+ACE_Atomic_Op<ACE_SYNCH_MUTEX, long> MCT_Event_Handler::active_handlers_ = 0;
+
+MCT_Event_Handler::MCT_Event_Handler (ACE_SOCK_Dgram_Mcast::options options)
+ : mcast_ (options)
+{
+ // Increment the number of active handlers in the reactor. Note this isn't
+ // really correct, but it should work for our simple example.
+ ++MCT_Event_Handler::active_handlers_;
+}
+
+MCT_Event_Handler::~MCT_Event_Handler (void)
+{
+ size_t size = this->address_vec_.size ();
+ for (size_t i = 0; i < size; ++i)
+ {
+ delete this->address_vec_[i];
+ this->address_vec_[i] = 0;
+ }
+ mcast_.close ();
+}
+
+
+ACE_SOCK_Dgram_Mcast *
+MCT_Event_Handler::mcast (void)
+{
+ return &this->mcast_;
+}
+
+int
+MCT_Event_Handler::find (const char *buf)
+{
+ size_t size = this->address_vec_.size ();
+ size_t i;
+ for (i = 0; i < size; ++i)
+ {
+ if (ACE_OS::strcasecmp (buf, this->address_vec_[i]->c_str ()) == 0)
+ return 0;
+ }
+
+ // Not found, so output message we received along with a list of groups
+ // we've joined for debugging.
+ ACE_CString local;
+ for (i = 0; i < size; ++i)
+ {
+ local += "\t";
+ local += this->address_vec_[i]->c_str ();
+ local += "\n";
+ }
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("%C not in:\n%C"),
+ buf, local.c_str ()));
+
+ return -1;
+}
+
+
+int
+MCT_Event_Handler::join (const ACE_INET_Addr &mcast_addr,
+ int reuse_addr,
+ const ACE_TCHAR *net_if)
+{
+ if (this->mcast_.join (mcast_addr, reuse_addr, net_if) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("MCT_Event_Handler::join - %p\n"),
+ ACE_TEXT ("Could not join group")),
+ -1);
+
+ char buf[MAX_STRING_SIZE];
+ ACE_OS::sprintf (buf, "%s/%d",
+ mcast_addr.get_host_addr (),
+ mcast_addr.get_port_number ());
+ ACE_CString *str;
+ ACE_NEW_RETURN (str, ACE_CString (buf), -1);
+ this->address_vec_.push_back (str);
+ return 0;
+}
+
+int
+MCT_Event_Handler::leave (const ACE_INET_Addr &mcast_addr,
+ const ACE_TCHAR *net_if)
+{
+ if (this->mcast_.leave (mcast_addr, net_if) == 0)
+ {
+ char buf[MAX_STRING_SIZE];
+ size_t size = this->address_vec_.size ();
+ for (size_t i = 0; i < size; ++i)
+ {
+ ACE_OS::sprintf (buf, "%s/%d",
+ mcast_addr.get_host_addr (),
+ mcast_addr.get_port_number ());
+ if (ACE_OS::strcasecmp (buf, this->address_vec_[i]->c_str ()) == 0)
+ {
+ this->address_vec_[i]->set ("");
+ break;
+ }
+ }
+ return 0;
+ }
+ return -1;
+}
+
+int
+MCT_Event_Handler::handle_input (ACE_HANDLE /*handle*/)
+{
+ char buf[MAX_STRING_SIZE];
+ ACE_OS::memset (buf, 0, sizeof buf);
+ ACE_INET_Addr addr;
+
+ if (this->mcast ()->recv (buf, sizeof buf, addr) == -1)
+ {
+ ++error;
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("MCT_Event_Handler::handle_input - ")
+ ACE_TEXT ("calling recv\n")), -1);
+ }
+
+ // Zero length buffer means we are done.
+ if (ACE_OS::strlen (buf) == 0)
+ return -1;
+ else if (this->find (buf) == -1)
+ {
+ ++error;
+ ACE_DEBUG ((LM_ERROR,
+ ACE_TEXT ("MCT_Event_Handler::handle_input - ")
+ ACE_TEXT ("Received dgram for a group we didn't join ")
+ ACE_TEXT ("(%s) \n"),
+ buf));
+ }
+ return 0;
+}
+
+int
+MCT_Event_Handler::handle_close (ACE_HANDLE /*fd*/,
+ ACE_Reactor_Mask /*close_mask*/)
+{
+ // If this is the last handler, use the finished flag to signal
+ // the task to exit.
+ if (--MCT_Event_Handler::active_handlers_ == 0)
+ finished = 1;
+
+ // The DONT_CALL flag keeps the reactor from calling handle_close ()
+ // again, since we commit suicide below.
+ this->reactor ()->remove_handler (this,
+ ACE_Event_Handler::ALL_EVENTS_MASK |
+ ACE_Event_Handler::DONT_CALL);
+ this->reactor (0);
+ delete this;
+ return 0;
+}
+
+ACE_HANDLE
+MCT_Event_Handler::get_handle (void) const
+{
+ return this->mcast_.get_handle ();
+}
+
+/******************************************************************************/
+
+/*
+ * Our MCT_Task object will be an Active Object if we are running the Consumer
+ * side of the test. open() calls active() which creates a thread and calls
+ * the svc() method that calls runs the reactor event loop.
+ */
+class MCT_Task : public ACE_Task<ACE_NULL_SYNCH>
+{
+public:
+ MCT_Task (const MCT_Config &config,
+ ACE_Reactor *reactor = ACE_Reactor::instance ());
+ ~MCT_Task (void);
+
+ // = Task hooks.
+ virtual int open (void *args = 0);
+ virtual int svc (void);
+
+private:
+ const MCT_Config &config_;
+ int iterations_;
+};
+
+MCT_Task::MCT_Task (const MCT_Config &config,
+ ACE_Reactor *reactor)
+ : config_ (config)
+{
+ this->reactor (reactor);
+}
+
+MCT_Task::~MCT_Task (void)
+{}
+
+int
+MCT_Task::open (void *)
+{
+ MCT_Event_Handler *handler;
+
+ ACE_INET_Addr addr = this->config_.group_start ();
+ int groups = this->config_.groups ();
+ for (int i = 0; i < groups; ++i)
+ {
+ ACE_NEW_RETURN (handler,
+ MCT_Event_Handler (this->config_.options ()), -1);
+ // We subscribe to all groups for the first one and one each for
+ // all the others.
+ if (i == 0)
+ {
+ // go ahead and hide the other one since we want our own.
+ ACE_INET_Addr addr = this->config_.group_start ();
+ for (int j = 0; j < groups; ++j)
+ {
+ // If OPT_BINDADDR_YES is set, this will fail after the first
+ // join, so just break and keep on going, otherwise it's a
+ // real error.
+ if (j > 0
+ && ACE_BIT_ENABLED (ACE_SOCK_Dgram_Mcast::OPT_BINDADDR_YES,
+ this->config_.options ()))
+ break;
+
+ if (handler->join (addr) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("MCT_Task::open - join error\n")),
+ -1);
+ advance_addr (addr);
+ }
+ }
+ else
+ {
+ if (handler->join (addr) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("MCT_Task::open - join error\n")),
+ -1);
+ }
+
+ advance_addr (addr);
+
+ if (this->reactor ()->register_handler (handler, READ_MASK) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("MCT_Task::open - cannot register ")
+ ACE_TEXT ("handler\n")),
+ -1);
+ }
+
+ if (this->activate (THR_NEW_LWP) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("MCT_TASK:open - activate failed")),
+ -1);
+ return 0;
+}
+
+int
+MCT_Task::svc (void)
+{
+ // make sure this thread owns the reactor or handle_events () won't do
+ // anything.
+ this->reactor ()->owner (ACE_Thread::self ());
+
+ // loop and call handle_events...
+ while (!finished)
+ this->reactor ()->handle_events ();
+
+ return 0;
+}
+
+/******************************************************************************/
+
+int send_dgram (ACE_SOCK_Dgram &socket, ACE_INET_Addr addr, int done = 0)
+{
+
+ // Send each message twice, once to the right port, and once to the "wrong"
+ // port. This helps generate noise and lets us see if port filtering is
+ // working properly.
+ const char *address = addr.get_host_addr ();
+ int port = addr.get_port_number ();
+
+ for (int i = 0; i < 2; ++i)
+ {
+ char buf[MAX_STRING_SIZE];
+ if (done)
+ buf[0] = 0;
+ else
+ ACE_OS::sprintf (buf, "%s/%d", address, port);
+ //ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("sending (%s)\n"), buf));
+ if (socket.send (buf, ACE_OS::strlen (buf),addr) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"),
+ ACE_TEXT ("send_dgram - error calling send on ")
+ ACE_TEXT ("ACE_SOCK_Dgram.")), -1);
+ addr.set_port_number (++port);
+ }
+ return 0;
+}
+
+int producer (MCT_Config &config)
+{
+ int retval = 0;
+
+ ACE_DEBUG ((LM_INFO, ACE_TEXT ("Starting producer...\n")));
+ ACE_SOCK_Dgram socket (ACE_sap_any_cast (ACE_INET_Addr &), PF_INET);
+
+ // Note that is is IPv4 specific and needs to be changed once
+ //
+ if (config.ttl () > 1)
+ {
+ int ttl = config.ttl ();
+ if (socket.set_option (IPPROTO_IP,
+ IP_MULTICAST_TTL,
+ (void*) &ttl,
+ sizeof ttl) != 0)
+ ACE_DEBUG ((LM_ERROR,
+ ACE_TEXT ("could net set socket option IP_MULTICAST_TTL ")
+ ACE_TEXT ("= %d\n"),
+ ttl));
+ else
+ ACE_DEBUG ((LM_INFO, ACE_TEXT ("set IP_MULTICAST_TTL = %d\n"), ttl));
+ }
+
+ int iterations = config.iterations ();
+ // we add an extra 5 groups for noise.
+ int groups = config.groups () + 5;
+ for (int i = 0; (i < iterations || iterations == 0) && !finished; ++i)
+ {
+ ACE_INET_Addr addr = config.group_start ();
+ for (int j = 0; j < groups && !finished; ++j)
+ {
+ if ((retval += send_dgram (socket, addr,
+ ((i + 1) == iterations))) == -1)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("Calling send_dgram.\n")));
+ if ((retval += advance_addr (addr)) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Calling advance_addr.\n")));
+ }
+ // Give the task thread a chance to run.
+ ACE_Thread::yield ();
+ }
+ socket.close ();
+ return retval;
+}
+
+/*
+ * Advance the address by 1, e.g., 239.255.0.1 => 239.255.0.2
+ * Note that the algorithm is somewhat simplistic, but sufficient for our
+ * purpose.
+ */
+int advance_addr (ACE_INET_Addr &addr)
+{
+ int a, b, c, d;
+ ::sscanf (addr.get_host_addr (), "%d.%d.%d.%d", &a, &b, &c, &d);
+ if (d < 255)
+ ++d;
+ else if (c < 255)
+ {
+ d = 1;
+ ++c;
+ }
+ else if (b < 255)
+ {
+ d = 1;
+ c = 0;
+ ++b;
+ }
+ else if (a < 239)
+ {
+ d = 1;
+ c = 0;
+ b = 0;
+ ++a;
+ }
+ else
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("advance_addr - Cannot advance multicast ")
+ ACE_TEXT ("group address past %s\n"),
+ addr.get_host_addr ()),
+ -1);
+
+ ACE_TCHAR buf[MAX_STRING_SIZE];
+ ACE_OS::sprintf (buf, ACE_TEXT ("%d.%d.%d.%d:%d"),
+ a, b, c, d, addr.get_port_number ());
+ addr.set (buf);
+ return 0;
+}
+
+int
+run_main (int argc, ACE_TCHAR *argv[])
+{
+ int retval = 0;
+ MCT_Config config;
+ retval = config.open (argc, argv);
+ if (retval != 0)
+ return 1;
+
+ const ACE_TCHAR *temp = ACE_TEXT ("Multicast_Test");
+ ACE_TString test = temp;
+
+ u_long role = config.role ();
+ if (ACE_BIT_DISABLED (role, MCT_Config::PRODUCER)
+ || ACE_BIT_DISABLED (role, MCT_Config::CONSUMER))
+ {
+ if (ACE_BIT_ENABLED (role, MCT_Config::PRODUCER))
+ test += ACE_TEXT ("-PRODUCER");
+ else
+ test += ACE_TEXT ("-CONSUMER");
+ }
+
+ // Start test only if options are valid.
+ ACE_START_TEST (test.c_str ());
+
+ // Register a signal handler to close down application gracefully.
+ ACE_Sig_Action sa ((ACE_SignalHandler) handler, SIGINT);
+
+ // Dump the configuration info to the log if caller passed debug option.
+ if (config.debug ())
+ config.dump ();
+
+ ACE_Reactor *reactor = ACE_Reactor::instance ();
+
+ MCT_Task *task = new MCT_Task (config, reactor);
+
+ if (ACE_BIT_ENABLED (role, MCT_Config::CONSUMER))
+ {
+ ACE_DEBUG ((LM_INFO, ACE_TEXT ("Starting consumer...\n")));
+ // Open makes it an active object.
+ retval += task->open ();
+ }
+
+ // now produce the datagrams...
+ if (ACE_BIT_ENABLED (role, MCT_Config::PRODUCER))
+ retval += producer (config);
+
+ if (ACE_BIT_ENABLED (role, MCT_Config::CONSUMER))
+ {
+ // and wait for everything to finish
+ ACE_DEBUG ((LM_INFO,
+ ACE_TEXT ("start waiting for consumer to finish...\n")));
+ // Wait for the threads to exit.
+ // But, wait for a limited time since we could hang if the last udp
+ // message isn't received.
+ ACE_Time_Value max_wait ( config.wait ()/* seconds */);
+ ACE_Time_Value wait_time (ACE_OS::gettimeofday () + max_wait);
+ ACE_Time_Value *ptime = ACE_BIT_ENABLED (role, MCT_Config::PRODUCER)
+ ? &wait_time : 0;
+ if (ACE_Thread_Manager::instance ()->wait (ptime) == -1)
+ {
+ // We will no longer wait for this thread, so we must
+ // force it to exit otherwise the thread will be referencing
+ // deleted memory.
+ finished = 1;
+ reactor->end_reactor_event_loop ();
+
+ if (errno == ETIME)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("maximum wait time of %d msec exceeded\n"),
+ max_wait.msec ()));
+ else
+ ACE_OS::perror (ACE_TEXT ("wait"));
+
+ ++error;
+
+ // This should exit now that we ended the reactor loop.
+ task->wait ();
+ }
+ }
+
+ delete task;
+ ACE_END_TEST;
+ return (retval == 0 && error == 0) ? 0 : 1;
+}
+
+#else
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("Multicast_Test"));
+
+ ACE_ERROR ((LM_INFO,
+ ACE_TEXT ("This test must be run on a platform ")
+ ACE_TEXT ("that support IP multicast.\n")));
+
+ ACE_END_TEST;
+ return 1;
+}
+#endif /* ACE_HAS_IP_MULTICAST && ACE_HAS_THREADS */
diff --git a/ACE/tests/Multicast_Test_IPV6.cpp b/ACE/tests/Multicast_Test_IPV6.cpp
new file mode 100644
index 00000000000..fd7d1705a92
--- /dev/null
+++ b/ACE/tests/Multicast_Test_IPV6.cpp
@@ -0,0 +1,1004 @@
+// $Id$
+// ============================================================================
+/**
+ * @file Multicast_Test_IPV6.cpp
+ *
+ * @brief This program tests ACE_SOCK_Dgram_Mcast class.
+ *
+ * It specifically tests subscribing to multiple groups on the same
+ * socket on one or more physical interfaces (if available).
+ *
+ * The test can be run as a producer, consumer, or both
+ * producer/consumer (default). The test requires at least two (2)
+ * multicast groups which can be configured as command line options.
+ * The consumer subscribes to a single group per instance and an
+ * additional instance tries to subscribe to all groups on a single
+ * socket (if the ACE_SOCK_Dgram_Mcast instance bind()'s the first
+ * address to the socket, additional joins will fail). The producer
+ * iterates through the list of group addresses and sends a single
+ * message containing the destination address and port to each one. It
+ * also sends messages to five (5) additional groups and a message to
+ * an additional port for each group in order to produce a bit of
+ * "noise" in order to help validate how well the multicast filtering
+ * works on a particular platform.
+ *
+ * The list of destination groups start at ff01::1 (default) and
+ * increment by 1 up to 5 (default) groups. Both of these values, as
+ * well as others, can be overridden via command-line options. Use
+ * the -? option to display the usage message...
+ *
+ * @author Don Hinton <dhinton@dresystems.com>
+ * Brian Buesker <bbuesker@qualcomm.com>
+ */
+// ============================================================================
+
+#include "tests/test_config.h"
+#include "ace/Get_Opt.h"
+#include "ace/Vector_T.h"
+#include "ace/SOCK_Dgram_Mcast.h"
+#include "ace/ACE.h"
+#include "ace/Reactor.h"
+#include "ace/OS_NS_string.h"
+#include "ace/OS_NS_strings.h"
+#include "ace/Task.h"
+#include "ace/Atomic_Op.h"
+#include "ace/SString.h"
+#include "ace/Signal.h"
+#include "ace/Min_Max.h"
+
+#if defined (ACE_HAS_IP_MULTICAST) && defined (ACE_HAS_THREADS)
+
+/*
+ * The 'finished' flag is used to break out of an infninite loop in the
+ * task::svc () method. The 'handler' will set the flag in respose to
+ * SIGINT (CTRL-C).
+ */
+static sig_atomic_t finished = 0;
+extern "C" void handler (int)
+{
+ finished = 1;
+}
+
+static const int MCT_ITERATIONS = 10;
+static const int MCT_GROUPS = 5;
+static const int MCT_MIN_GROUPS = 2;
+
+#if defined (ACE_HAS_IPV6)
+static const char MCT_START_GROUP[] = "ff01::1";
+#else
+// an IPv4 address that will ensure an error message is not printed when
+// IPv6 is not enabled
+static const char MCT_START_GROUP[] = "239.255.0.1";
+#endif /* ACE_HAS_IPV6 */
+static const int MCT_START_PORT = 16000;
+
+static const size_t MAX_STRING_SIZE = 200;
+
+int advance_addr (ACE_INET_Addr &addr);
+
+// Keep track of errors so we can report them on exit.
+static sig_atomic_t error = 0;
+
+/*
+ * MCast_Config holds configuration data for this test.
+ */
+class MCT_Config
+{
+public:
+
+ enum
+ {
+ PRODUCER = 1,
+ CONSUMER = 2,
+ BOTH = PRODUCER | CONSUMER
+ };
+
+ MCT_Config (void)
+ : group_start_ (MCT_START_PORT, MCT_START_GROUP),
+ groups_ (0),
+ debug_ (0),
+ role_ (BOTH),
+ sdm_opts_ (ACE_SOCK_Dgram_Mcast::DEFOPTS),
+ iterations_ (MCT_ITERATIONS),
+ ttl_ (1),
+ wait_ (2)
+ {
+ if (IP_MAX_MEMBERSHIPS == 0)
+ this->groups_ = MCT_GROUPS;
+ else
+ this->groups_ = ACE_MIN (IP_MAX_MEMBERSHIPS, MCT_GROUPS);
+ }
+
+ ~MCT_Config (void)
+ {}
+
+ int open (int argc, ACE_TCHAR *argv[]);
+ int debug (void) const { return this->debug_;}
+ void dump (void) const;
+ int groups (void) const { return this->groups_;}
+ const ACE_INET_Addr group_start (void) const { return this->group_start_;}
+ u_long role (void) const { return this->role_;}
+ int iterations (void) const { return this->iterations_;}
+ int ttl (void) const { return this->ttl_;}
+ int wait (void) const { return this->wait_;}
+ ACE_SOCK_Dgram_Mcast::options options (void) const
+ {
+ return static_cast<ACE_SOCK_Dgram_Mcast::options> (this->sdm_opts_);
+ }
+
+ int set_group (int port, const char *group);
+
+private:
+ // Starting group address.
+ ACE_INET_Addr group_start_;
+
+ // Number of groups we will try to use in the test.
+ int groups_;
+
+ // Debug flag.
+ int debug_;
+
+ // Role, i.e., PRODUCER, CONSUMER, BOTH: defaults to BOTH
+ u_long role_;
+
+ // ACE_SOCK_Dgram_Mcast ctor options
+ u_long sdm_opts_;
+
+ // Producer iterations
+ int iterations_;
+
+ // TTL, time to live, for use over routers.
+ int ttl_;
+
+ // Time to wait on CONSUMER threads to end before killing test.
+ int wait_;
+};
+
+int
+MCT_Config::open (int argc, ACE_TCHAR *argv[])
+{
+ int retval = 0;
+ int help = 0;
+
+ ACE_Get_Opt getopt (argc, argv, ACE_TEXT (":?"), 1, 1);
+
+ if (getopt.long_option (ACE_TEXT ("GroupStart"),
+ 'g',
+ ACE_Get_Opt::ARG_REQUIRED) != 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT (" Unable to add GroupStart option.\n")),
+ 1);
+
+ if (getopt.long_option (ACE_TEXT ("Groups"),
+ 'n',
+ ACE_Get_Opt::ARG_REQUIRED) != 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT (" Unable to add Groups option.\n")), 1);
+
+ if (getopt.long_option (ACE_TEXT ("Debug"),
+ 'd',
+ ACE_Get_Opt::NO_ARG) != 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT (" Unable to add Debug option.\n")), 1);
+
+ if (getopt.long_option (ACE_TEXT ("Role"),
+ 'r',
+ ACE_Get_Opt::ARG_REQUIRED) != 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT (" Unable to add Role option.\n")), 1);
+
+ if (getopt.long_option (ACE_TEXT ("SDM_options"),
+ 'm',
+ ACE_Get_Opt::ARG_REQUIRED) != 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT (" Unable to add Multicast_Options option.\n")),
+ 1);
+
+ if (getopt.long_option (ACE_TEXT ("Iterations"),
+ 'i',
+ ACE_Get_Opt::ARG_REQUIRED) != 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT (" Unable to add iterations option.\n")),
+ 1);
+
+ if (getopt.long_option (ACE_TEXT ("TTL"),
+ 't',
+ ACE_Get_Opt::ARG_REQUIRED) != 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT (" Unable to add TTL option.\n")),
+ 1);
+
+ if (getopt.long_option (ACE_TEXT ("Wait"),
+ 'w',
+ ACE_Get_Opt::ARG_REQUIRED) != 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT (" Unable to add wait option.\n")),
+ 1);
+
+ if (getopt.long_option (ACE_TEXT ("help"),
+ 'h',
+ ACE_Get_Opt::NO_ARG) != 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT (" Unable to add help option.\n")),
+ 1);
+
+ // Now, let's parse it...
+ int c = 0;
+ while ((c = getopt ()) != EOF)
+ {
+ switch (c)
+ {
+ case 0:
+ // Long Option. This should never happen.
+ retval = -1;
+ break;
+ case 'g':
+ {
+ // @todo validate all these, i.e., must be within range
+ // 224.255.0.0 to 238.255.255.255, but we only allow the
+ // administrative "site local" range, 239.255.0.0 to
+ // 239.255.255.255.
+ ACE_TCHAR *group = getopt.opt_arg ();
+ if (this->group_start_.set (group) != 0)
+ {
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("Bad group address:%s\n"),
+ group));
+ }
+ }
+ break;
+ case 'i':
+ this->iterations_ = ACE_OS::atoi (getopt.opt_arg ());
+ break;
+ case 'n':
+ {
+ int n = ACE_OS::atoi (getopt.opt_arg ());
+ // I'm assuming 0 means unlimited, so just use whatever the
+ // user provides. Seems to work okay on Solaris 5.8.
+ if (IP_MAX_MEMBERSHIPS == 0)
+ this->groups_ = n;
+ else
+ this->groups_ = ACE_MIN (ACE_MAX (n, MCT_MIN_GROUPS),
+ IP_MAX_MEMBERSHIPS);
+ break;
+ }
+ case 'd':
+ this->debug_ = 1;
+ break;
+ case 'r':
+ {
+ ACE_TCHAR *c = getopt.opt_arg ();
+ if (ACE_OS::strcasecmp (c, ACE_TEXT ("CONSUMER")) == 0)
+ this->role_ = CONSUMER;
+ else if (ACE_OS::strcasecmp (c, ACE_TEXT ("PRODUCER")) == 0)
+ this->role_ = PRODUCER;
+ else
+ {
+ help = 1;
+ retval = -1;
+ }
+ }
+ break;
+ case 'm':
+ {
+ //@todo add back OPT_BINDADDR_NO...
+ ACE_TCHAR *c = getopt.opt_arg ();
+ if (ACE_OS::strcasecmp (c, ACE_TEXT ("OPT_BINDADDR_YES")) == 0)
+ ACE_SET_BITS (this->sdm_opts_,
+ ACE_SOCK_Dgram_Mcast::OPT_BINDADDR_YES);
+ else if (ACE_OS::strcasecmp (c, ACE_TEXT ("OPT_BINDADDR_NO")) == 0)
+ ACE_CLR_BITS (this->sdm_opts_,
+ ACE_SOCK_Dgram_Mcast::OPT_BINDADDR_YES);
+ else if (ACE_OS::strcasecmp (c, ACE_TEXT ("DEFOPT_BINDADDR")) == 0)
+ {
+ ACE_CLR_BITS (this->sdm_opts_,
+ ACE_SOCK_Dgram_Mcast::OPT_BINDADDR_YES);
+ ACE_SET_BITS (this->sdm_opts_,
+ ACE_SOCK_Dgram_Mcast::DEFOPT_BINDADDR);
+ }
+ else if (ACE_OS::strcasecmp (c, ACE_TEXT ("OPT_NULLIFACE_ALL")) == 0)
+ ACE_SET_BITS (this->sdm_opts_,
+ ACE_SOCK_Dgram_Mcast::OPT_NULLIFACE_ALL);
+ else if (ACE_OS::strcasecmp (c, ACE_TEXT ("OPT_NULLIFACE_ONE")) == 0)
+ ACE_CLR_BITS (this->sdm_opts_,
+ ACE_SOCK_Dgram_Mcast::OPT_NULLIFACE_ALL);
+ else if (ACE_OS::strcasecmp (c, ACE_TEXT ("DEFOPT_NULLIFACE")) == 0)
+ {
+ ACE_CLR_BITS (this->sdm_opts_,
+ ACE_SOCK_Dgram_Mcast::OPT_NULLIFACE_ALL);
+ ACE_SET_BITS (this->sdm_opts_,
+ ACE_SOCK_Dgram_Mcast::DEFOPT_NULLIFACE);
+ }
+ else if (ACE_OS::strcasecmp (c, ACE_TEXT ("DEFOPTS")) == 0)
+ this->sdm_opts_ = ACE_SOCK_Dgram_Mcast::DEFOPTS;
+ else
+ {
+ help = 1;
+ retval = -1;
+ }
+ }
+ break;
+ case 't':
+ this->ttl_ = ACE_OS::atoi (getopt.opt_arg ());
+ break;
+ case 'w':
+ this->wait_ = ACE_OS::atoi (getopt.opt_arg ());
+ break;
+ case ':':
+ // This means an option requiring an argument didn't have one.
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT (" Option '%c' requires an argument but ")
+ ACE_TEXT ("none was supplied\n"),
+ getopt.opt_opt ()));
+ help = 1;
+ retval = -1;
+ break;
+ case '?':
+ case 'h':
+ default:
+ if (ACE_OS::strcmp (argv[getopt.opt_ind () - 1], ACE_TEXT ("-?")) != 0
+ && getopt.opt_opt () != 'h')
+ // Don't allow unknown options.
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT (" Found an unknown option (%c) ")
+ ACE_TEXT ("we couldn't handle.\n"),
+ getopt.opt_opt ()));
+ // getopt.last_option ())); //readd with "%s" when
+ // last_option() is available.
+ help = 1;
+ retval = -1;
+ break;
+ }
+ }
+
+ if (retval == -1)
+ {
+ if (help)
+ // print usage here
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("usage: %s [options]\n")
+ ACE_TEXT ("Options:\n")
+ ACE_TEXT (" -g {STRING} --GroupStart={STRING} ")
+ ACE_TEXT ("starting multicast group address\n")
+ ACE_TEXT (" ")
+ ACE_TEXT ("(default=239.255.0.1:16000)\n")
+ ACE_TEXT (" -n {#} --Groups={#} ")
+ ACE_TEXT ("number of groups (default=5)\n")
+ ACE_TEXT (" -d --Debug ")
+ ACE_TEXT ("debug flag (default=off)\n")
+ ACE_TEXT (" -r {STRING} --Role={STRING} ")
+ ACE_TEXT ("role {PRODUCER|CONSUMER|BOTH}\n")
+ ACE_TEXT (" ")
+ ACE_TEXT ("(default=BOTH)\n")
+ ACE_TEXT (" -m {STRING} --SDM_options={STRING} ")
+ ACE_TEXT ("ACE_SOCK_Dgram_Mcast ctor options\n")
+ ACE_TEXT (" ")
+ ACE_TEXT ("(default=DEFOPTS)\n")
+ ACE_TEXT (" -i {#} --Iterations={#} ")
+ ACE_TEXT ("number of iterations (default=100)\n")
+ ACE_TEXT (" -t {#} --TTL={#} ")
+ ACE_TEXT ("time to live (default=1)\n")
+ ACE_TEXT (" -w {#} --Wait={#} ")
+ ACE_TEXT ("number of seconds to wait on CONSUMER\n")
+ ACE_TEXT (" ")
+ ACE_TEXT ("(default=2)\n")
+ ACE_TEXT (" -h/? --help ")
+ ACE_TEXT ("show this message\n"),
+ argv[0]));
+
+ return -1;
+ }
+
+ return 0;
+}
+
+void
+MCT_Config::dump (void) const
+{
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT (" Dumping MCT_Config\n")));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\tIP_MAX_MEMBERSHIPS = %d\n"),
+ IP_MAX_MEMBERSHIPS));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\tgroups_ = %d\n"),
+ this->groups_));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\trole_ = %s\n"),
+ (ACE_BIT_ENABLED (this->role_, PRODUCER)
+ && ACE_BIT_ENABLED (this->role_, CONSUMER))
+ ? ACE_TEXT ("PRODUCER/CONSUMER")
+ : ACE_BIT_ENABLED (this->role_, PRODUCER)
+ ? ACE_TEXT ("PRODUCER")
+ : ACE_TEXT ("CONSUMER")));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\tsdm_options_ = %d\n"),
+ this->sdm_opts_));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\titerations_ = %d\n"),
+ this->iterations_));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\tttl_ = %d\n"),
+ this->ttl_));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\twait_ = %d\n"),
+ this->wait_));
+ // Note that this call to get_host_addr is the non-reentrant
+ // version, but it's okay for us.
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\tgroups_start_ = %s:%d\n"),
+ this->group_start_.get_host_addr (),
+ this->group_start_.get_port_number ()));
+
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+int
+MCT_Config::set_group (int port, const char *group)
+{
+ return group_start_.set (port, group);
+}
+
+/******************************************************************************/
+
+class MCT_Event_Handler : public ACE_Event_Handler
+{
+public:
+ MCT_Event_Handler (ACE_SOCK_Dgram_Mcast::options options
+ = ACE_SOCK_Dgram_Mcast::DEFOPTS);
+ virtual ~MCT_Event_Handler (void);
+
+ int join (const ACE_INET_Addr &mcast_addr,
+ int reuse_addr = 1,
+ const ACE_TCHAR *net_if = 0);
+ int leave (const ACE_INET_Addr &mcast_addr,
+ const ACE_TCHAR *net_if = 0);
+
+ // = Event Handler hooks.
+ virtual int handle_input (ACE_HANDLE handle);
+ virtual int handle_close (ACE_HANDLE fd, ACE_Reactor_Mask close_mask);
+
+ virtual ACE_HANDLE get_handle (void) const;
+
+protected:
+ ACE_SOCK_Dgram_Mcast *mcast (void);
+ int find (const char *buf);
+
+private:
+ ACE_SOCK_Dgram_Mcast mcast_;
+
+ // List of groups we've joined
+ ACE_Vector<ACE_CString*> address_vec_;
+
+ // Flag used to set the 'finished' flag when the last event handler
+ // gets removed from the reactor.
+ static ACE_Atomic_Op<ACE_SYNCH_MUTEX, long> active_handlers_;
+};
+
+ACE_Atomic_Op<ACE_SYNCH_MUTEX, long> MCT_Event_Handler::active_handlers_ = 0;
+
+MCT_Event_Handler::MCT_Event_Handler (ACE_SOCK_Dgram_Mcast::options options)
+ : mcast_ (options)
+{
+ // Increment the number of active handlers in the reactor. Note this isn't
+ // really correct, but it should work for our simple example.
+ ++MCT_Event_Handler::active_handlers_;
+}
+
+MCT_Event_Handler::~MCT_Event_Handler (void)
+{
+ size_t size = this->address_vec_.size ();
+ for (size_t i = 0; i < size; ++i)
+ {
+ delete this->address_vec_[i];
+ this->address_vec_[i] = 0;
+ }
+}
+
+
+ACE_SOCK_Dgram_Mcast *
+MCT_Event_Handler::mcast (void)
+{
+ return &this->mcast_;
+}
+
+int
+MCT_Event_Handler::find (const char *buf)
+{
+ size_t size = this->address_vec_.size ();
+ size_t i;
+ for (i = 0; i < size; ++i)
+ {
+ if (ACE_OS::strcasecmp (buf, this->address_vec_[i]->c_str ()) == 0)
+ return 0;
+ }
+
+ // Not found, so output message we received along with a list of groups
+ // we've joined for debugging.
+ ACE_CString local;
+ for (i = 0; i < size; ++i)
+ {
+ local += "\t";
+ local += this->address_vec_[i]->c_str ();
+ local += "\n";
+ }
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("%s not in:\n%s"),
+ buf, local.c_str ()));
+
+ return -1;
+}
+
+
+int
+MCT_Event_Handler::join (const ACE_INET_Addr &mcast_addr,
+ int reuse_addr,
+ const ACE_TCHAR *net_if)
+{
+ if (this->mcast_.join (mcast_addr, reuse_addr, net_if) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("MCT_Event_Handler::join - %p\n"),
+ ACE_TEXT ("Could not join group")),
+ -1);
+
+ char buf[MAX_STRING_SIZE];
+ ACE_OS::sprintf (buf, "%s/%d",
+ mcast_addr.get_host_addr (),
+ mcast_addr.get_port_number ());
+ ACE_CString *str;
+ ACE_NEW_RETURN (str, ACE_CString (ACE::strnew (buf)), -1);
+ this->address_vec_.push_back (str);
+ return 0;
+}
+
+int
+MCT_Event_Handler::leave (const ACE_INET_Addr &mcast_addr,
+ const ACE_TCHAR *net_if)
+{
+ if (this->mcast_.leave (mcast_addr, net_if) == 0)
+ {
+ char buf[MAX_STRING_SIZE];
+ size_t size = this->address_vec_.size ();
+ for (size_t i = 0; i < size; ++i)
+ {
+ ACE_OS::sprintf (buf, "%s/%d",
+ mcast_addr.get_host_addr (),
+ mcast_addr.get_port_number ());
+ if (ACE_OS::strcasecmp (buf, this->address_vec_[i]->c_str ()) == 0)
+ {
+ this->address_vec_[i]->set ("");
+ break;
+ }
+ }
+ return 0;
+ }
+ return -1;
+}
+
+int
+MCT_Event_Handler::handle_input (ACE_HANDLE /*handle*/)
+{
+ char buf[MAX_STRING_SIZE];
+ ACE_OS::memset (buf, 0, sizeof buf);
+ ACE_INET_Addr addr;
+
+ if (this->mcast ()->recv (buf, sizeof buf, addr) == -1)
+ {
+ ++error;
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("MCT_Event_Handler::handle_input - ")
+ ACE_TEXT ("calling recv\n")), -1);
+ }
+
+ // Zero length buffer means we are done.
+ if (ACE_OS::strlen (buf) == 0)
+ return -1;
+ else if (this->find (buf) == -1)
+ {
+ ++error;
+ ACE_DEBUG ((LM_ERROR,
+ ACE_TEXT ("MCT_Event_Handler::handle_input - ")
+ ACE_TEXT ("Received dgram for a group we didn't join ")
+ ACE_TEXT ("(%s) \n"),
+ buf));
+ }
+ return 0;
+}
+
+int
+MCT_Event_Handler::handle_close (ACE_HANDLE /*fd*/,
+ ACE_Reactor_Mask /*close_mask*/)
+{
+ // If this is the last handler, use the finished flag to signal
+ // the task to exit.
+ if (--MCT_Event_Handler::active_handlers_ == 0)
+ finished = 1;
+
+ // The DONT_CALL flag keeps the reactor from calling handle_close ()
+ // again, since we commit suicide below.
+ this->reactor ()->remove_handler (this,
+ ACE_Event_Handler::ALL_EVENTS_MASK |
+ ACE_Event_Handler::DONT_CALL);
+ this->reactor (0);
+ delete this;
+ return 0;
+}
+
+ACE_HANDLE
+MCT_Event_Handler::get_handle (void) const
+{
+ return this->mcast_.get_handle ();
+}
+
+/******************************************************************************/
+
+/*
+ * Our MCT_Task object will be an Active Object if we are running the Consumer
+ * side of the test. open() calls active() which creates a thread and calls
+ * the svc() method that calls runs the reactor event loop.
+ */
+class MCT_Task : public ACE_Task<ACE_NULL_SYNCH>
+{
+public:
+ MCT_Task (const MCT_Config &config,
+ ACE_Reactor *reactor = ACE_Reactor::instance ());
+ ~MCT_Task (void);
+
+ // = Task hooks.
+ virtual int open (void *args = 0);
+ virtual int svc (void);
+
+private:
+ const MCT_Config &config_;
+ int iterations_;
+};
+
+MCT_Task::MCT_Task (const MCT_Config &config,
+ ACE_Reactor *reactor)
+ : config_ (config)
+{
+ this->reactor (reactor);
+}
+
+MCT_Task::~MCT_Task (void)
+{}
+
+int
+MCT_Task::open (void *)
+{
+ MCT_Event_Handler *handler;
+
+ ACE_INET_Addr addr = this->config_.group_start ();
+ int groups = this->config_.groups ();
+ for (int i = 0; i < groups; ++i)
+ {
+ ACE_NEW_RETURN (handler,
+ MCT_Event_Handler (this->config_.options ()), -1);
+ // We subscribe to all groups for the first one and one each for
+ // all the others.
+ if (i == 0)
+ {
+ // go ahead and hide the other one since we want our own.
+ ACE_INET_Addr addr = this->config_.group_start ();
+ for (int j = 0; j < groups; ++j)
+ {
+ // If OPT_BINDADDR_YES is set, this will fail after the first
+ // join, so just break and keep on going, otherwise it's a
+ // real error.
+ if (j > 0
+ && ACE_BIT_ENABLED (ACE_SOCK_Dgram_Mcast::OPT_BINDADDR_YES,
+ this->config_.options ()))
+ break;
+
+ if (handler->join (addr) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("MCT_Task::open - join error\n")),
+ -1);
+ advance_addr (addr);
+ }
+ }
+ else
+ {
+ if (handler->join (addr) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("MCT_Task::open - join error\n")),
+ -1);
+ }
+
+ advance_addr (addr);
+
+ if (this->reactor ()->register_handler (handler, READ_MASK) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("MCT_Task::open - cannot register ")
+ ACE_TEXT ("handler\n")),
+ -1);
+ }
+
+ if (this->activate (THR_NEW_LWP) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("MCT_TASK:open - activate failed")),
+ -1);
+ return 0;
+}
+
+int
+MCT_Task::svc (void)
+{
+ // make sure this thread owns the reactor or handle_events () won't do
+ // anything.
+ this->reactor ()->owner (ACE_Thread::self ());
+
+ // loop and call handle_events...
+ while (!finished)
+ this->reactor ()->handle_events ();
+
+ return 0;
+}
+
+/******************************************************************************/
+
+int send_dgram (ACE_SOCK_Dgram &socket, ACE_INET_Addr addr, int done = 0)
+{
+
+ // Send each message twice, once to the right port, and once to the "wrong"
+ // port. This helps generate noise and lets us see if port filtering is
+ // working properly.
+ const char *address = addr.get_host_addr ();
+ int port = addr.get_port_number ();
+
+ for (int i = 0; i < 2; ++i)
+ {
+ char buf[MAX_STRING_SIZE];
+ if (done)
+ buf[0] = 0;
+ else
+ ACE_OS::sprintf (buf, "%s/%d", address, port);
+ //ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("sending (%s)\n"), buf));
+ if (socket.send (buf, ACE_OS::strlen (buf),addr) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"),
+ ACE_TEXT ("send_dgram - error calling send on ")
+ ACE_TEXT ("ACE_SOCK_Dgram.")), -1);
+ addr.set_port_number (++port);
+ }
+ return 0;
+}
+
+int producer (MCT_Config &config)
+{
+ int retval = 0;
+
+ ACE_DEBUG ((LM_INFO, ACE_TEXT ("Starting producer...\n")));
+ ACE_SOCK_Dgram socket (ACE_sap_any_cast (ACE_INET_Addr &));
+
+ // set the TTL or hop count based on the config.ttl () value
+ if (config.ttl () > 1 && config.group_start().get_type() == AF_INET)
+ {
+ int ttl = config.ttl ();
+ if (socket.set_option (IPPROTO_IP,
+ IP_MULTICAST_TTL,
+ (void*) &ttl,
+ sizeof ttl) != 0)
+ ACE_DEBUG ((LM_ERROR,
+ ACE_TEXT ("could net set socket option IP_MULTICAST_TTL ")
+ ACE_TEXT ("= %d\n"),
+ ttl));
+ else
+ ACE_DEBUG ((LM_INFO, ACE_TEXT ("set IP_MULTICAST_TTL = %d\n"), ttl));
+ }
+#if defined (ACE_HAS_IPV6)
+ else
+ {
+ // for IPv6, a hop limit is used instead of TTL
+ int hops = config.ttl ();
+ if (socket.set_option (IPPROTO_IPV6,
+ IPV6_MULTICAST_HOPS,
+ (void*) &hops,
+ sizeof hops) != 0)
+ ACE_DEBUG ((LM_ERROR,
+ ACE_TEXT ("could net set socket option IPV6_MULTICAST_HOPS")
+ ACE_TEXT (" = %d\n"),
+ hops));
+ else
+ ACE_DEBUG ((LM_INFO, ACE_TEXT ("set IPV6_MULTICAST_HOPS = %d\n"),
+ hops));
+ }
+#endif /* ACE_HAS_IPV6 */
+
+
+ int iterations = config.iterations ();
+ // we add an extra 5 groups for noise.
+ int groups = config.groups () + 5;
+ for (int i = 0; (i < iterations || iterations == 0) && !finished; ++i)
+ {
+ ACE_INET_Addr addr = config.group_start ();
+ for (int j = 0; j < groups && !finished; ++j)
+ {
+ if ((retval += send_dgram (socket, addr,
+ ((i + 1) == iterations))) == -1)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("Calling send_dgram.\n")));
+ if ((retval += advance_addr (addr)) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Calling advance_addr.\n")));
+ }
+ // Give the task thread a chance to run.
+ ACE_Thread::yield ();
+ }
+ return retval;
+}
+
+/*
+ * Advance the address by 1, e.g., 239.255.0.1 => 239.255.0.2
+ * Note that the algorithm is somewhat simplistic, but sufficient for our
+ * purpose.
+ */
+int advance_addr (ACE_INET_Addr &addr)
+{
+ int a, b, c, d;
+ if (addr.get_type () == AF_INET)
+ {
+ ::sscanf (addr.get_host_addr (), "%d.%d.%d.%d", &a, &b, &c, &d);
+ if (d < 255)
+ ++d;
+ else if (c < 255)
+ {
+ d = 1;
+ ++c;
+ }
+ else if (b < 255)
+ {
+ d = 1;
+ c = 0;
+ ++b;
+ }
+ else if (a < 239)
+ {
+ d = 1;
+ c = 0;
+ b = 0;
+ ++a;
+ }
+ else
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("advance_addr - Cannot advance multicast ")
+ ACE_TEXT ("group address past %s\n"),
+ addr.get_host_addr ()),
+ -1);
+
+ ACE_TCHAR buf[MAX_STRING_SIZE];
+ ACE_OS::sprintf (buf, ACE_TEXT ("%d.%d.%d.%d:%d"),
+ a, b, c, d, addr.get_port_number ());
+ addr.set (buf);
+ return 0;
+ }
+#if defined (ACE_HAS_IPV6)
+ else // assume AF_INET6
+ {
+ sockaddr_in6 *saddr = reinterpret_cast<sockaddr_in6 *> (addr.get_addr ());
+ unsigned char *sin6_addr = reinterpret_cast<unsigned char *> (&saddr->sin6_addr);
+ int i = 15;
+
+ // i >= 2 is used here so that the flags and scope for the
+ // multicast address are not changed
+ while (i >= 2 && sin6_addr[i] == 0xff)
+ {
+ sin6_addr[i] = 0;
+ i--;
+ }
+
+ if (i >= 2)
+ {
+ sin6_addr[i]++;
+ }
+ else
+ {
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("advance_addr - Cannot advance ")
+ ACE_TEXT ("multicast group address past %s\n"),
+ addr.get_host_addr ()),
+ -1);
+
+ }
+
+ return 0;
+ }
+#endif /* ACE_HAS_IPV6 */
+
+ return 0;
+}
+
+int
+run_main (int argc, ACE_TCHAR *argv[])
+{
+ int retval = 0;
+ MCT_Config config;
+ retval = config.open (argc, argv);
+ if (retval != 0)
+ return 1;
+
+ const ACE_TCHAR *temp = ACE_TEXT ("Multicast_Test_IPV6");
+ ACE_TString test = temp;
+
+ u_long role = config.role ();
+ if (ACE_BIT_DISABLED (role, MCT_Config::PRODUCER)
+ || ACE_BIT_DISABLED (role, MCT_Config::CONSUMER))
+ {
+ if (ACE_BIT_ENABLED (role, MCT_Config::PRODUCER))
+ test += ACE_TEXT ("-PRODUCER");
+ else
+ test += ACE_TEXT ("-CONSUMER");
+ }
+
+ // Start test only if options are valid.
+ ACE_START_TEST (test.c_str ());
+
+#if defined (ACE_HAS_IPV6)
+
+# if !defined (ACE_LACKS_UNIX_SIGNALS)
+ // Register a signal handler to close down application gracefully.
+ ACE_Sig_Action sa ((ACE_SignalHandler) handler, SIGINT);
+# endif
+
+ // Dump the configuration info to the log if caller passed debug option.
+ if (config.debug ())
+ config.dump ();
+
+ ACE_Reactor *reactor = ACE_Reactor::instance ();
+
+ MCT_Task *task = new MCT_Task (config, reactor);
+
+ if (ACE_BIT_ENABLED (role, MCT_Config::CONSUMER))
+ {
+ ACE_DEBUG ((LM_INFO, ACE_TEXT ("Starting consumer...\n")));
+ // Open makes it an active object.
+ retval += task->open ();
+ }
+
+ // now produce the datagrams...
+ if (ACE_BIT_ENABLED (role, MCT_Config::PRODUCER))
+ retval += producer (config);
+
+ if (ACE_BIT_ENABLED (role, MCT_Config::CONSUMER))
+ {
+ // and wait for everything to finish
+ ACE_DEBUG ((LM_INFO,
+ ACE_TEXT ("start waiting for consumer to finish...\n")));
+ // Wait for the threads to exit.
+ // But, wait for a limited time since we could hang if the last udp
+ // message isn't received.
+ ACE_Time_Value max_wait ( config.wait ()/* seconds */);
+ ACE_Time_Value wait_time (ACE_OS::gettimeofday () + max_wait);
+ ACE_Time_Value *ptime = ACE_BIT_ENABLED (role, MCT_Config::PRODUCER)
+ ? &wait_time : 0;
+ if (ACE_Thread_Manager::instance ()->wait (ptime) == -1)
+ {
+ if (errno == ETIME)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("maximum wait time of %d msec exceeded\n"),
+ max_wait.msec ()));
+ else
+ ACE_OS::perror (ACE_TEXT ("wait"));
+
+ ++error;
+ }
+ }
+
+ delete task;
+#endif /* ACE_HAS_IPV6 */
+ ACE_END_TEST;
+ return (retval == 0 && error == 0) ? 0 : 1;
+}
+
+#else
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("Multicast_Test_IPV6"));
+
+ ACE_ERROR ((LM_INFO,
+ ACE_TEXT ("This test must be run on a platform ")
+ ACE_TEXT ("that support IP multicast and threads.\n")));
+
+ ACE_END_TEST;
+
+ return 0;
+}
+#endif /* ACE_HAS_IP_MULTICAST && ACE_HAS_THREADS */
diff --git a/ACE/tests/Multihomed_INET_Addr_Test.cpp b/ACE/tests/Multihomed_INET_Addr_Test.cpp
new file mode 100644
index 00000000000..8c89f1fe7db
--- /dev/null
+++ b/ACE/tests/Multihomed_INET_Addr_Test.cpp
@@ -0,0 +1,470 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Multihomed_INET_Addr_Test.cpp
+//
+// = DESCRIPTION
+// Performs several tests on the Multihomed_ACE_INET_Addr class.
+// It creates several IPv4 addresses and checks that the
+// address formed by the class is valid.
+//
+// = AUTHOR
+// Edward Mulholland (emulholl@atl.lmco.com)
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/OS_NS_string.h"
+#include "ace/Multihomed_INET_Addr.h"
+#include "ace/Log_Msg.h"
+#include "ace/OS_NS_arpa_inet.h"
+
+int run_main (int argc, ACE_TCHAR *argv[])
+{
+ ACE_UNUSED_ARG (argc);
+ ACE_UNUSED_ARG (argv);
+
+ ACE_START_TEST (ACE_TEXT ("Multihomed_INET_Addr_Test"));
+
+ int status = 0; // Innocent until proven guilty
+
+ // loop variables
+ size_t i, j;
+ sockaddr_in *pointer;
+
+ // The port will always be this
+ u_short port = 80;
+
+ // The primary address will always be this
+ const char *primary_dotted_decimal = "138.38.180.251";
+
+ // The secondary addresses will always be these...
+ const char *secondary_dotted_decimals[] = {
+ "64.219.54.121",
+ "127.0.0.1",
+ "21.242.14.51",
+ "53.141.124.24",
+ "42.12.44.9"
+ };
+
+ // ... and as you can see, there are 5 of them
+ const size_t num_secondaries = 5;
+
+ // We also need the primary address and the secondary addresses
+ // in ACE_UINT32 format in host byte order
+ ACE_UINT32 primary_addr32;
+ ACE_UINT32 secondary_addr32[5];
+
+ {
+ struct in_addr addrv4;
+ ACE_OS::inet_pton (AF_INET, primary_dotted_decimal, &addrv4);
+ ACE_OS::memcpy (&primary_addr32, &addrv4, sizeof (primary_addr32));
+ primary_addr32 = ACE_NTOHL(primary_addr32);
+ }
+
+ for (i = 0; i < num_secondaries; ++i) {
+ struct in_addr addrv4;
+ ACE_OS::inet_pton (AF_INET, secondary_dotted_decimals[i], &addrv4);
+ ACE_OS::memcpy (&secondary_addr32[i], &addrv4, sizeof (primary_addr32));
+ secondary_addr32[i] = ACE_NTOHL(secondary_addr32[i]);
+ }
+
+ // Test subject
+ ACE_Multihomed_INET_Addr addr;
+
+ // Array of ones (used to clear the secondary addresses of the test
+ // subject)
+ ACE_UINT32 array_of_threes[5] = { ACE_UINT32 (3),
+ ACE_UINT32 (3),
+ ACE_UINT32 (3),
+ ACE_UINT32 (3),
+ ACE_UINT32 (3) };
+
+ // Array of INET_Addrs that will repeatedly be passed into the
+ // get_secondary_addresses accessor of Multihomed_INET_Addr
+ ACE_INET_Addr in_out[5];
+
+ // Array of INET_Addrs against which the above array will be tested.
+ ACE_INET_Addr stay_out[5];
+
+ // Array of sockaddrs that will repeatedly be passed into the
+ // get_addresses accessor of Multihomed_INET_Addr
+ const size_t num_sockaddrs = 6;
+ sockaddr_in in_out_sockaddr[num_sockaddrs];
+
+ // Run the test with a varying number of secondary addresses
+ for (i = 0; i <= num_secondaries; ++i) {
+
+
+ /****** Clear the in_out array and test subject ******/
+
+
+ // Clear the in_out array by setting every port to 0 and every
+ // address to 1
+ for (j = 0; j < num_secondaries; ++j) {
+ in_out[j].set(0, ACE_UINT32 (1), 1);
+ }
+
+ // Clear the in_out_sockaddr array by setting every port to 0 and
+ // every address to 1
+ ACE_OS::memset(in_out_sockaddr, 0, num_sockaddrs * sizeof(sockaddr));
+
+ // Clear the test subject by setting the port to 2 and every
+ // address (both the primary and the secondaries) to 3
+ addr.set (2, ACE_UINT32 (3), 1, array_of_threes, num_secondaries);
+
+ // Check that the port is 2
+ if (addr.get_port_number() != 2) {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Failed get_port_number check\n")
+ ACE_TEXT ("%d != %d\n"),
+ addr.get_port_number(),
+ 2));
+ status = 1;
+ }
+
+ // Check that the primary address is 3
+ if (addr.get_ip_address() != ACE_UINT32 (3)) {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Failed get_ip_address check\n")
+ ACE_TEXT ("0x%x != 0x%x\n"),
+ addr.get_ip_address(),
+ ACE_UINT32 (3)));
+ status = 1;
+ }
+
+ // Check that the test subject reports the correct number of
+ // secondary addresses.
+ size_t returned_num_secondaries = addr.get_num_secondary_addresses();
+ if (returned_num_secondaries == num_secondaries) {
+
+ // Set a stay_out element to the state that we expect to see
+ // from every in_out element after the in_out array is passed to
+ // the accessor of the test subject.
+ stay_out[0].set(2, ACE_UINT32 (3), 1);
+
+ // Pass the in_out array to the accessor
+ addr.get_secondary_addresses(in_out, num_secondaries);
+
+ // Check that the in_out array matches stay_out element
+ for (j = 0; j < num_secondaries; ++j) {
+
+ if (in_out[j] != stay_out[0]) {
+
+ ACE_TCHAR in_out_string[100];
+ ACE_TCHAR stay_out_string[100];
+
+ in_out[j].addr_to_string(in_out_string, 100);
+ stay_out[0].addr_to_string(stay_out_string, 100);
+
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Failed get_secondary_addresses check\n")
+ ACE_TEXT ("%s != %s\n"),
+ in_out_string,
+ stay_out_string));
+
+ status = 1;
+ }
+ }
+
+ // Pass the in_out_sockaddr array to the accessor
+ addr.get_addresses(in_out_sockaddr, num_secondaries + 1);
+
+ // Check that the in_out_sockaddr array matches stay_out element
+ for (j = 0, pointer = in_out_sockaddr;
+ j < num_secondaries + 1;
+ ++j, ++pointer) {
+
+ if (ACE_OS::memcmp(pointer, stay_out[0].get_addr(), sizeof(sockaddr))) {
+
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Failed get_addresses check\n")));
+
+ status = 1;
+ }
+ }
+
+ } else {
+
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Failed get_num_secondary_addresses check\n")
+ ACE_TEXT ("%d != %d\n"),
+ returned_num_secondaries,
+ num_secondaries));
+ status = 1;
+
+ }
+
+
+ /**** Test set (u_short, const char[], int, int, const char *([]), size_t) ****/
+
+
+ addr.set(port,
+ primary_dotted_decimal,
+ 1,
+ AF_INET,
+ secondary_dotted_decimals,
+ i);
+
+ // Check the port number
+ if (addr.get_port_number() != port) {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Failed second get_port_number check\n")
+ ACE_TEXT ("%d != %d\n"),
+ addr.get_port_number(),
+ port));
+ status = 1;
+ }
+
+ // Check the primary address
+ if (0 != ACE_OS::strcmp (addr.get_host_addr(), primary_dotted_decimal))
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("%s failed get_host_addr() check\n")
+ ACE_TEXT ("%s != %s\n"),
+ primary_dotted_decimal,
+ addr.get_host_addr (),
+ primary_dotted_decimal));
+ status = 1;
+ }
+
+ // Check that the test subject reports the correct number of
+ // secondary addresses.
+ returned_num_secondaries = addr.get_num_secondary_addresses();
+ if (returned_num_secondaries == i) {
+
+ // Initialize the stay_out array with the secondary addresses
+ for (j = 0; j < i; ++j) {
+ stay_out[j].set(port, secondary_dotted_decimals[j]);
+ }
+
+ // Pass the in_out array to the accessor
+ addr.get_secondary_addresses(in_out, i);
+
+ // Check that the in_out array matches stay_out array
+ for (j = 0; j < i; ++j) {
+
+ if (in_out[j] != stay_out[j]) {
+
+ ACE_TCHAR in_out_string[100];
+ ACE_TCHAR stay_out_string[100];
+
+ in_out[j].addr_to_string(in_out_string, 100);
+ stay_out[j].addr_to_string(stay_out_string, 100);
+
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Failed second get_secondary_addresses check\n")
+ ACE_TEXT ("%s != %s\n"),
+ in_out_string,
+ stay_out_string));
+
+ status = 1;
+ }
+ }
+
+ // Pass the in_out_sockaddr array to the accessor
+ addr.get_addresses(in_out_sockaddr, i + 1);
+
+ // Check that the primary address in the in_out_sockaddr array
+ // matches the primary address reported by the superclass
+ if (ACE_OS::memcmp(in_out_sockaddr, addr.get_addr(), sizeof(sockaddr))) {
+
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Failed second get_addresses check ")
+ ACE_TEXT ("(for primary address)\n")));
+
+ status = 1;
+
+ }
+
+ // Check that the secondary addresses in the in_out_sockaddr
+ // array match the stay_out array
+ for (j = 1, pointer = &in_out_sockaddr[1];
+ j < i + 1;
+ ++j, ++pointer) {
+
+ if (ACE_OS::memcmp(pointer, stay_out[j-1].get_addr(), sizeof(sockaddr))) {
+
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Failed second get_addresses check ")
+ ACE_TEXT ("(for secondary addresses)\n")));
+
+ status = 1;
+ }
+ }
+
+ } else {
+
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Failed second get_num_secondary_addresses check\n")
+ ACE_TEXT ("%d != %d\n"),
+ returned_num_secondaries,
+ i));
+ status = 1;
+ }
+
+
+ /****** Clear the in_out array and test subject AGAIN ******/
+
+
+ // Clear the in_out array by setting every port to 0 and every
+ // address to 1
+ for (j = 0; j < num_secondaries; ++j) {
+ in_out[j].set(0, ACE_UINT32 (1), 1);
+ }
+
+ // Clear the test subject by setting the port to 2 and every
+ // address (both the primary and the secondaries) to 3
+ addr.set (2, ACE_UINT32 (3), 1, array_of_threes, num_secondaries);
+
+ // Check that the port is 2
+ if (addr.get_port_number() != 2) {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Failed third get_port_number check\n")
+ ACE_TEXT ("%d != %d\n"),
+ addr.get_port_number(),
+ 2));
+ status = 1;
+ }
+
+ // Check that the primary address is 3
+ if (addr.get_ip_address() != ACE_UINT32 (3)) {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Failed third get_ip_address check\n")
+ ACE_TEXT ("0x%x != 0x%x\n"),
+ addr.get_ip_address(),
+ ACE_UINT32 (3)));
+ status = 1;
+ }
+
+ // Check that the test subject reports the correct number of
+ // secondary addresses.
+ returned_num_secondaries = addr.get_num_secondary_addresses();
+ if (returned_num_secondaries == num_secondaries) {
+
+ // Set a stay_out element to the state that we expect to see
+ // from every in_out element after the in_out array is passed to
+ // the accessor of the test subject.
+ stay_out[0].set(2, ACE_UINT32 (3), 1);
+
+ // Pass the in_out array to the accessor
+ addr.get_secondary_addresses(in_out, num_secondaries);
+
+ // Check that the in_out array matches stay_out array
+ for (j = 0; j < num_secondaries; ++j) {
+
+ if (in_out[j] != stay_out[0]) {
+
+ ACE_TCHAR in_out_string[100];
+ ACE_TCHAR stay_out_string[100];
+
+ in_out[j].addr_to_string(in_out_string, 100);
+ stay_out[0].addr_to_string(stay_out_string, 100);
+
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Failed third get_secondary_addresses check\n")
+ ACE_TEXT ("%s != %s\n"),
+ in_out_string,
+ stay_out_string));
+
+ status = 1;
+ }
+ }
+
+ } else {
+
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Failed third get_num_secondary_addresses check\n")
+ ACE_TEXT ("%d != %d\n"),
+ returned_num_secondaries,
+ num_secondaries));
+ status = 1;
+
+ }
+
+
+ /**** Test set (u_short, ACE_UINT32, int, const ACE_UINT32 *, size_t) ****/
+
+ addr.set(port,
+ primary_addr32,
+ 1,
+ secondary_addr32,
+ i);
+
+ // Check the port number
+ if (addr.get_port_number() != port) {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Failed forth get_port_number check\n")
+ ACE_TEXT ("%d != %d\n"),
+ addr.get_port_number(),
+ port));
+ status = 1;
+ }
+
+ // Check the primary address
+ if (0 != ACE_OS::strcmp (addr.get_host_addr(), primary_dotted_decimal))
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("%s failed second get_ip_address() check\n")
+ ACE_TEXT ("%s != %s\n"),
+ primary_dotted_decimal,
+ addr.get_host_addr (),
+ primary_dotted_decimal));
+ status = 1;
+ }
+
+ // Check that the test subject reports the correct number of
+ // secondary addresses.
+ returned_num_secondaries = addr.get_num_secondary_addresses();
+ if (returned_num_secondaries == i) {
+
+ // Initialize the stay_out array with the secondary addresses
+ for (j = 0; j < i; ++j) {
+ stay_out[j].set(port, secondary_addr32[j]);
+ }
+
+ // Pass the in_out array to the accessor
+ addr.get_secondary_addresses(in_out, j);
+
+ // Check that the in_out array matches stay_out array
+ for (j = 0; j < i; ++j) {
+
+ if (in_out[j] != stay_out[j]) {
+
+ ACE_TCHAR in_out_string[100];
+ ACE_TCHAR stay_out_string[100];
+
+ in_out[j].addr_to_string(in_out_string, 100);
+ stay_out[j].addr_to_string(stay_out_string, 100);
+
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Failed forth get_secondary_addresses check\n")
+ ACE_TEXT ("%s != %s\n"),
+ in_out_string,
+ stay_out_string));
+
+ status = 1;
+ }
+ }
+
+ } else {
+
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Failed forth get_num_secondary_addresses check\n")
+ ACE_TEXT ("%d != %d\n"),
+ returned_num_secondaries,
+ i));
+ status = 1;
+ }
+
+ }
+
+ ACE_END_TEST;
+ return status;
+
+}
diff --git a/ACE/tests/Multihomed_INET_Addr_Test_IPV6.cpp b/ACE/tests/Multihomed_INET_Addr_Test_IPV6.cpp
new file mode 100644
index 00000000000..1607dd81fb2
--- /dev/null
+++ b/ACE/tests/Multihomed_INET_Addr_Test_IPV6.cpp
@@ -0,0 +1,191 @@
+// $Id$
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Multihomed_INET_Addr_Test.cpp
+//
+// = DESCRIPTION
+// Performs several tests on the Multihomed_ACE_INET_Addr class.
+// It creates several IPv6 addresses and checks that the
+// address formed by the class is valid.
+//
+// = AUTHOR
+// Edward Mulholland (emulholl@atl.lmco.com)
+// Brian Buesker (bbuesker@qualcomm.com) - Added testing of
+// ACE_Multihomed_INET_Addr class
+// using IPv6 addresses based on
+// Multihomed_INET_Addr_Test.
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/OS_NS_string.h"
+#include "ace/Multihomed_INET_Addr.h"
+#include "ace/Log_Msg.h"
+#include "ace/OS_NS_arpa_inet.h"
+
+int run_main (int argc, ACE_TCHAR *argv[])
+{
+ ACE_UNUSED_ARG (argc);
+ ACE_UNUSED_ARG (argv);
+
+ ACE_START_TEST (ACE_TEXT ("Multihomed_INET_Addr_Test_IPV6"));
+
+ int status = 0; // Innocent until proven guilty
+
+#if defined (ACE_HAS_IPV6)
+ // loop variables
+ size_t i, j;
+ sockaddr_in6 *pointer6;
+
+ const ACE_TCHAR *primary_ipv6 = ACE_TEXT("3ffe::123:4567:89ab:cdef");
+
+ const ACE_TCHAR *secondary_ipv6[] = {
+ ACE_IPV6_LOCALHOST,
+ ACE_TEXT("fe80::0123:4567:89ab:cdef"),
+ ACE_TEXT("fec0::0123:4567:89ab:cdef"),
+ ACE_TEXT("3ffe::1:0123:4567:89ab:cdef"),
+ ACE_TEXT("2002:3e02:5473::")
+ };
+
+ // The port will always be this
+ u_short port = 80;
+
+ // ... and as you can see, there are 5 of them
+ const size_t num_secondaries = 5;
+
+ // Test subject
+ ACE_Multihomed_INET_Addr addr;
+
+ // Array of INET_Addrs that will repeatedly be passed into the
+ // get_secondary_addresses accessor of Multihomed_INET_Addr
+ ACE_INET_Addr in_out[5];
+
+ // Array of INET_Addrs against which the above array will be tested.
+ ACE_INET_Addr stay_out[5];
+
+ // Array of sockaddrs that will repeatedly be passed into the
+ // get_addresses accessor of Multihomed_INET_Addr
+ const size_t num_sockaddrs = 6;
+ sockaddr_in6 in_out_sockaddr6[num_sockaddrs];
+
+ for (i = 0; i <= num_secondaries; ++i) {
+
+
+ /**** Test set (u_short, const char[], int, int, const char *([]), size_t) ****/
+
+
+ addr.set(port,
+ primary_ipv6,
+ 1,
+ AF_INET6,
+ secondary_ipv6,
+ i);
+
+ // Check the port number
+ if (addr.get_port_number() != port) {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Failed second get_port_number check\n")
+ ACE_TEXT ("%d != %d\n"),
+ addr.get_port_number(),
+ port));
+ status = 1;
+ }
+
+ // Check the primary address
+ if (0 != ACE_OS::strcmp (ACE_TEXT_CHAR_TO_TCHAR(addr.get_host_addr()), primary_ipv6))
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("%s failed get_host_addr() check\n")
+ ACE_TEXT ("%s != %s\n"),
+ primary_ipv6,
+ addr.get_host_addr (),
+ primary_ipv6));
+ status = 1;
+ }
+
+ // Check that the test subject reports the correct number of
+ // secondary addresses.
+ size_t returned_num_secondaries = addr.get_num_secondary_addresses();
+ if (returned_num_secondaries == i) {
+
+ // Initialize the stay_out array with the secondary addresses
+ for (j = 0; j < i; ++j) {
+ stay_out[j].set(port, secondary_ipv6[j]);
+ }
+
+ // Pass the in_out array to the accessor
+ addr.get_secondary_addresses(in_out, i);
+
+ // Check that the in_out array matches stay_out array
+ for (j = 0; j < i; ++j) {
+
+ if (in_out[j] != stay_out[j]) {
+
+ ACE_TCHAR in_out_string[100];
+ ACE_TCHAR stay_out_string[100];
+
+ in_out[j].addr_to_string(in_out_string, 100);
+ stay_out[j].addr_to_string(stay_out_string, 100);
+
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Failed get_secondary_addresses check\n")
+ ACE_TEXT ("%s != %s\n"),
+ in_out_string,
+ stay_out_string));
+
+ status = 1;
+ }
+ }
+
+ // Pass the in_out_sockaddr array to the accessor
+ addr.get_addresses(in_out_sockaddr6, i + 1);
+
+ // Check that the primary address in the in_out_sockaddr array
+ // matches the primary address reported by the superclass
+ if (ACE_OS::memcmp(in_out_sockaddr6, addr.get_addr(),
+ sizeof(sockaddr_in6))) {
+
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Failed second get_addresses check ")
+ ACE_TEXT ("(for primary address)\n")));
+
+ status = 1;
+
+ }
+
+ // Check that the secondary addresses in the in_out_sockaddr
+ // array match the stay_out array
+ for (j = 1, pointer6 = &in_out_sockaddr6[1];
+ j < i + 1;
+ ++j, ++pointer6) {
+
+ if (ACE_OS::memcmp(pointer6, stay_out[j-1].get_addr(),
+ sizeof(sockaddr_in6))) {
+
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Failed get_addresses check ")
+ ACE_TEXT ("(for secondary addresses)\n")));
+
+ status = 1;
+ }
+ }
+ } else {
+
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Failed get_num_secondary_addresses check\n")
+ ACE_TEXT ("%d != %d\n"),
+ returned_num_secondaries,
+ i));
+ status = 1;
+ }
+ }
+#endif /* ACE_HAS_IPV6 */
+
+ ACE_END_TEST;
+ return status;
+
+}
diff --git a/ACE/tests/Naming_Test.cpp b/ACE/tests/Naming_Test.cpp
new file mode 100644
index 00000000000..571f2fc5ea0
--- /dev/null
+++ b/ACE/tests/Naming_Test.cpp
@@ -0,0 +1,288 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Naming_Test.cpp
+//
+// = DESCRIPTION
+// This is a test to illustrate the Naming Services. The test
+// does binds, rebinds, finds, and unbinds on name bindings using
+// the local naming context.
+//
+// = AUTHOR
+// Prashant Jain <pjain@cs.wustl.edu> and Irfan Pyarali <irfan@cs.wustl.edu>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/ACE.h"
+#include "ace/SString.h"
+#include "ace/Naming_Context.h"
+#include "ace/Profile_Timer.h"
+#include "ace/OS_NS_stdio.h"
+#include "ace/OS_NS_string.h"
+#include "ace/OS_NS_unistd.h"
+
+ACE_RCSID(tests, Naming_Test, "$Id$")
+
+static char name[BUFSIZ];
+static char value[BUFSIZ];
+static char type[BUFSIZ];
+
+static void
+print_time (ACE_Profile_Timer &timer,
+ const char *test)
+{
+ ACE_Profile_Timer::ACE_Elapsed_Time et;
+ timer.stop ();
+ timer.elapsed_time (et);
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT (" ***** %s ***** \n"), test));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("real time = %f secs, user time = %f secs, system time = %f secs\n"),
+ et.real_time, et.user_time, et.system_time));
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("time per call = %f usecs\n"),
+ (et.real_time / double (ACE_NS_MAX_ENTRIES)) * 1000000));
+}
+
+static void
+test_bind (ACE_Naming_Context &ns_context)
+{
+ int array [ACE_NS_MAX_ENTRIES];
+ randomize (array, sizeof array / sizeof (int));
+
+ // do the binds
+ for (size_t i = 0; i < ACE_NS_MAX_ENTRIES; i++)
+ {
+ ACE_OS::sprintf (name, "%s%d", "name", array[i]);
+ ACE_NS_WString w_name (name);
+
+ ACE_OS::sprintf (value, "%s%d", "value", array[i]);
+ ACE_NS_WString w_value (value);
+
+ ACE_OS::sprintf (type, "%s%d", "type", array [i]);
+ int bind_result = ns_context.bind (w_name, w_value, type);
+ ACE_ASSERT (bind_result != -1);
+ }
+}
+
+static void
+test_find_failure (ACE_Naming_Context &ns_context)
+{
+ ACE_OS::sprintf (name, "%s", "foo-bar");
+ ACE_NS_WString w_name (name);
+ ACE_NS_WString w_value;
+ char *l_type = 0;
+
+ // Do the finds.
+ for (size_t i = 0; i < ACE_NS_MAX_ENTRIES; i++)
+ {
+ int resolve = ns_context.resolve (w_name, w_value, l_type);
+ ACE_ASSERT (resolve == -1);
+ }
+}
+
+static void
+test_rebind (ACE_Naming_Context &ns_context)
+{
+ int array [ACE_NS_MAX_ENTRIES];
+ randomize (array, sizeof array / sizeof (int));
+
+ // do the rebinds
+ for (size_t i = 0; i < ACE_NS_MAX_ENTRIES; i++)
+ {
+ ACE_OS::sprintf (name, "%s%d", "name", array[i]);
+ ACE_NS_WString w_name (name);
+
+ ACE_OS::sprintf (value, "%s%d", "value", -array[i]);
+ ACE_NS_WString w_value (value);
+
+ ACE_OS::sprintf (type, "%s%d", "type", -array[i]);
+ int rebind = ns_context.rebind (w_name, w_value, type);
+ ACE_ASSERT (rebind != -1);
+ }
+}
+
+static void
+test_unbind (ACE_Naming_Context &ns_context)
+{
+ int array [ACE_NS_MAX_ENTRIES];
+ randomize (array, sizeof array / sizeof (int));
+
+ // do the unbinds
+ for (size_t i = 0; i < ACE_NS_MAX_ENTRIES; i++)
+ {
+ ACE_OS::sprintf (name, "%s%d", "name", array[i]);
+ ACE_NS_WString w_name (name);
+ int unbind = ns_context.unbind (w_name);
+ ACE_ASSERT (unbind != -1);
+ }
+}
+
+static void
+test_find (ACE_Naming_Context &ns_context, int sign, int result)
+{
+ char temp_val[BUFSIZ];
+ char temp_type[BUFSIZ];
+
+ int array [ACE_NS_MAX_ENTRIES];
+ randomize (array, sizeof array / sizeof (int));
+
+ // do the finds
+ for (size_t i = 0; i < ACE_NS_MAX_ENTRIES; i++)
+ {
+ if (sign == 1)
+ {
+ ACE_OS::sprintf (temp_val, "%s%d", "value", array[i]);
+ ACE_OS::sprintf (temp_type, "%s%d", "type", array[i]);
+ }
+ else
+ {
+ ACE_OS::sprintf (temp_val, "%s%d", "value", -array[i]);
+ ACE_OS::sprintf (temp_type, "%s%d", "type", -array[i]);
+ }
+
+ ACE_OS::sprintf (name, "%s%d", "name", array[i]);
+
+ ACE_NS_WString w_name (name);
+ ACE_NS_WString w_value;
+ char *type_out = 0;
+ ACE_NS_WString val (temp_val);
+
+ int const resolve_result = ns_context.resolve (w_name, w_value, type_out);
+ if (resolve_result != result)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Error, resolve result not equal to resutlt (%d != %d)\n"),
+ resolve_result, result));
+
+ char *l_value = w_value.char_rep ();
+
+ if (l_value)
+ {
+ ACE_ASSERT (w_value == val);
+ if (ns_context.name_options ()->debug ())
+ {
+ if (type_out)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Name: %s\tValue: %s\tType: %s\n"),
+ name, l_value, type_out));
+ else
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Name: %s\tValue: %s\n"),
+ name, l_value));
+ }
+
+ if (type_out)
+ {
+ ACE_ASSERT (ACE_OS::strcmp (type_out, temp_type) == 0);
+ delete[] type_out;
+ }
+ }
+
+ delete[] l_value;
+ }
+}
+
+
+int
+run_main (int argc, ACE_TCHAR *argv[])
+{
+ ACE_START_TEST (ACE_TEXT ("Naming_Test"));
+ ACE_TCHAR temp_file [BUFSIZ];
+ ACE_Naming_Context *ns_context = 0;
+ ACE_NEW_RETURN (ns_context, ACE_Naming_Context, -1);
+
+ ACE_Name_Options *name_options = ns_context->name_options ();
+
+ name_options->parse_args (argc, argv);
+
+ int unicode = 0;
+#if (defined (ACE_WIN32) && defined (ACE_USES_WCHAR))
+ unicode = 1;
+#endif /* ACE_WIN32 && ACE_USES_WCHAR */
+ if (unicode && name_options->use_registry () == 1)
+ {
+ name_options->namespace_dir (ACE_TEXT ("Software\\ACE\\Name Service"));
+ name_options->database (ACE_TEXT ("Version 1"));
+ }
+ else
+ {
+ // Allow the user to determine where the context file will be
+ // located just in case the current directory is not suitable for
+ // locking. We don't just set namespace_dir () on name_options
+ // because that is not sufficient to work around locking problems
+ // for Tru64 when the current directory is NFS mounted from a
+ // system that does not properly support locking.
+ const char* temp_envs[] = { "TMPDIR", "TEMP", "TMP", 0 };
+ for(const char** temp_env = temp_envs; *temp_env != 0; ++temp_env)
+ {
+ char* temp_dir = ACE_OS::getenv(*temp_env);
+ if (temp_dir != 0)
+ {
+ ACE_OS::chdir (temp_dir);
+ break;
+ }
+ }
+ ACE_OS::strcpy (temp_file, ACE::basename (name_options->process_name (),
+ ACE_DIRECTORY_SEPARATOR_CHAR));
+ ACE_OS::strcat (temp_file, ACE_TEXT ("XXXXXX"));
+
+ // Set the database name using mktemp to generate a unique file name
+ name_options->database (ACE_OS::mktemp (temp_file));
+ }
+
+ ACE_ASSERT (ns_context->open (ACE_Naming_Context::PROC_LOCAL, 1) != -1);
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("time to test %d iterations using %s\n"),
+ ACE_NS_MAX_ENTRIES, name_options->use_registry () ?
+ ACE_TEXT ("Registry") : ACE_TEXT ("ACE")));
+
+ ACE_Profile_Timer timer;
+
+ timer.start ();
+ // Add some bindings to the database
+ test_bind (*ns_context);
+ print_time (timer, "Binds");
+
+ timer.start ();
+ // Should find the entries
+ test_find (*ns_context, 1, 0);
+ print_time (timer, "Successful Finds");
+
+ timer.start ();
+ // Rebind with negative values
+ test_rebind (*ns_context);
+ print_time (timer, "Rebinds");
+
+ timer.start ();
+ // Should find the entries
+ test_find (*ns_context, -1, 0);
+ print_time (timer, "Successful Finds");
+
+ timer.start ();
+ // Should not find the entries
+ test_find_failure (*ns_context);
+ print_time (timer, "UnSuccessful Finds");
+
+ timer.start ();
+ // Remove all bindings from database
+ test_unbind (*ns_context);
+ print_time (timer, "Unbinds");
+
+ ACE_OS::sprintf (temp_file, ACE_TEXT ("%s%s%s"),
+ name_options->namespace_dir (),
+ ACE_DIRECTORY_SEPARATOR_STR,
+ name_options->database ());
+
+ delete ns_context;
+
+ // Remove any existing files. No need to check return value here
+ // since we don't care if the file doesn't exist.
+ ACE_OS::unlink (temp_file);
+
+ ACE_END_TEST;
+ return 0;
+}
diff --git a/ACE/tests/Network_Adapters_Test.cpp b/ACE/tests/Network_Adapters_Test.cpp
new file mode 100644
index 00000000000..882ac59118c
--- /dev/null
+++ b/ACE/tests/Network_Adapters_Test.cpp
@@ -0,0 +1,1174 @@
+// $Id$
+//
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Network_Adapters_Test.cpp
+//
+// = DESCRIPTION
+// Tests the ICMP-echo support in ACE.
+//
+// = AUTHOR
+// Robert S. Iakobashvili <coroberti@gmail.com> <coroberti@walla.co.il>
+// Gonzalo A. Diethelm <gonzalo.diethelm@aditiva.com>
+//
+// ============================================================================
+
+// We need this to be able to check for ACE_HAS_ICMP_SUPPORT
+#include "ace/config-all.h"
+#include "test_config.h"
+
+#if defined (ACE_HAS_ICMP_SUPPORT) && (ACE_HAS_ICMP_SUPPORT == 1)
+
+#include "ace/ACE.h"
+#include "ace/Get_Opt.h"
+#include "ace/Signal.h"
+#include "ace/High_Res_Timer.h"
+#include "ace/Atomic_Op.h"
+#include "ace/Sched_Params.h"
+#include "ace/Reactor.h"
+#include "ace/Timer_Queue.h"
+#include "ace/OS_NS_string.h"
+
+#include "Network_Adapters_Test.h"
+
+
+ACE_RCSID (tests,
+ Network_Adapters_Test,
+ "$Id$")
+
+
+/**
+ * There are two major uses of the functionality:
+ *
+ * 1. to check a local network adapter;
+ * 2. to check which of the remote CEs (computer elements) are alive.
+ *
+ * For the first purpose we are creating a raw socket, binding it to
+ * the IP-address in question (adapter to be monitored), and are
+ * sending via the adapter ICMP echo-checks to a list of 3rd party
+ * ping-points. If at least a single 3rd party replies us within a
+ * configurable timeout by an ICMP-reply, our adapter is OK. If not, we
+ * may wish to repeat ICMP-probing once or twice more. We may also
+ * wish to make such tests regular with a configurable interval in seconds.
+ *
+ * For the second purpose we are creating a raw socket, and without
+ * binding it are sending via any our CE's adapter ICMP echo-checks to
+ * a list of CEs to be monitored. An array of chars (named ping_status
+ * in main ()), corresponding to the array of addresses
+ * (ping_points_addrs in main ()), contains status of each monitored
+ * CE. When we get ICMP-reply from a ping_points_addrs[I] IP-address,
+ * we are placing 0 to the ping_status[I]. The ICMP-probing may be
+ * configured to test 2-3 times each pinged CE. We may also wish to
+ * make such tests regular with a configurable interval in seconds.
+ *
+ * Command line options:
+ *
+ * -b IPv4 of the interface to bind to the socket (only for the
+ * purpose 1), e.g. -b 192.168.5.5;
+ *
+ * -p IPv4 addresses of the remote CEs, which we are going to check
+ * (purpose 2), or they are 3rd points for the purpose 1,
+ * e.g. “-p 192.168.5.120: 192.168.5.122: 192.168.5.125
+ *
+ * -w milliseconds to wait for echo-reply, on lan 100-200 msec, on
+ * WAN may be 2000-5000 msec, for GPRS may reach 10000 - 20000
+ * mseconds;
+ *
+ * -t as we are doing such checks regularly time in seconds between
+ * checks.
+ *
+ * In main we are activating by open () an instance of Echo_Handler
+ * with parameters.
+ *
+ * Repeats_Handler serves to repeat the checks each
+ * repeats_seconds_timer seconds.
+ *
+ * Stop_Handler contains a list of handlers to be stopped and is
+ * supposed to close this business.
+
+ * Attention: Running the test without parameters (just using defaults)
+ * makes pinging to the loopback address. Therefore, the raw socket
+ * sees both ICMP_ECHO and ICMP_ECHOREPLY with the first output in log
+ * as not a ICMP_ECHOREPLY message and further ICMP_ECHOREPLY
+ * received. Don't worry, be happy - it's ok.
+ */
+
+
+Echo_Handler::Echo_Handler (void)
+ : ping_socket_ (),
+ reply_wait_ (),
+ remote_addrs_ (0),
+ number_remotes_ (0),
+ success_status_ (0),
+ delete_success_status_ (0),
+ max_attempts_num_ (0),
+ current_attempt_ (0),
+ connect_to_remote_ (0)
+{
+}
+
+Echo_Handler::~Echo_Handler (void)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Echo_Handler::~Echo_Handler - entered.\n")));
+
+ this->ping_socket ().close ();
+ if (this->remote_addrs_)
+ {
+ delete [] this->remote_addrs_;
+ this->remote_addrs_ = 0;
+ }
+ if (this->success_status_ && this->delete_success_status_)
+ {
+ delete this->success_status_;
+ }
+ this->success_status_ = 0;
+
+ ACE_DEBUG
+ ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Echo_Handler::~Echo_Handler - completed.\n")));
+}
+
+int
+Echo_Handler::open (ACE_Reactor * const reactor,
+ ACE_Time_Value const & reply_wait,
+ ACE_INET_Addr const & remote_addr,
+ ACE_TCHAR * success_status,
+ size_t max_attempts_num,
+ ACE_Addr const & local_addr,
+ int connect_to_remote)
+{
+ if (this->reactor ())
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Echo_Handler::open - failed: ")
+ ACE_TEXT ("reactor is already set. \n")),
+ -1);
+ if (!reactor)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Echo_Handler::open - failed : ")
+ ACE_TEXT ("NULL pointer to reactor provided. \n")),
+ -1);
+
+ this->reactor (reactor);
+ this->reply_wait_ = reply_wait;
+
+ if (this->remote_addrs_)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Echo_Handler::open - failed: ")
+ ACE_TEXT ("remote_addrs_ already initialized.\n")),
+ -1);
+
+ ACE_NEW_RETURN (this->remote_addrs_, ACE_INET_Addr, -1);
+
+ // now copy to keep it locally
+ this->remote_addrs_[0] = remote_addr;
+ this->number_remotes_ = 1;
+ if (this->success_status_)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Echo_Handler::open - failed: ")
+ ACE_TEXT ("success_status_ already initialized.\n")),
+ -1);
+
+ if (! success_status)
+ {
+ ACE_NEW_RETURN (this->success_status_, ACE_TCHAR, -1);
+ this->delete_success_status_ = 1;
+ }
+ else
+ {
+ this->success_status_ = success_status;
+ }
+
+ // place 'failed' to the array.
+ this->success_status_[0] = 1;
+
+ this->max_attempts_num_ = max_attempts_num;
+ this->current_attempt_ = this->max_attempts_num_;
+
+ if (this->ping_socket ().open (local_addr) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Echo_Handler::open: %p\n"),
+ ACE_TEXT ("ping_socket_")),
+ -1);
+
+ this->connect_to_remote_ = connect_to_remote;
+
+ // Register with the reactor for input.
+ if (this->reactor ()->register_handler (this,
+ ACE_Event_Handler::READ_MASK) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Echo_Handler::open: %p\n"),
+ ACE_TEXT ("register_handler for input")),
+ -1);
+ return 0;
+}
+
+int
+Echo_Handler::open (ACE_Reactor * const reactor,
+ ACE_Time_Value const & reply_wait,
+ ACE_INET_Addr const remote_addrs[],
+ size_t number_remotes,
+ ACE_TCHAR *success_status,
+ size_t max_attempts_num,
+ ACE_Addr const & local_addr)
+{
+ if (this->reactor ())
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Echo_Handler::open - failed: ")
+ ACE_TEXT ("reactor is already set.\n")),
+ -1);
+
+ if (!reactor)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Echo_Handler::open - failed: NULL ")
+ ACE_TEXT ("pointer to reactor provided.\n")),
+ -1);
+
+ this->reactor (reactor);
+ this->reply_wait_ = reply_wait;
+
+ if (!remote_addrs)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Echo_Handler::open - failed: ")
+ ACE_TEXT ("NULL remote_addr pointer provided.\n")),
+ -1);
+
+ if (!number_remotes)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Echo_Handler::open - failed: ")
+ ACE_TEXT ("size of remote_addrs array is 0.\n")),
+ -1);
+
+ this->number_remotes_ = number_remotes;
+
+ if (this->remote_addrs_)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Echo_Handler::open - failed: ")
+ ACE_TEXT ("remote_addrs_ already initialized.\n")),
+ -1);
+
+ ACE_NEW_RETURN (this->remote_addrs_,
+ ACE_INET_Addr[this->number_remotes_],
+ -1);
+
+ // now copy to keep them locally
+ for (size_t i = 0; i < this->number_remotes_; ++i)
+ {
+ this->remote_addrs_[i] = remote_addrs[i];
+ }
+
+ if (this->success_status_)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Echo_Handler::open - failed: ")
+ ACE_TEXT ("success_status_ already initialized.\n")),
+ -1);
+
+ if (! success_status)
+ {
+ ACE_NEW_RETURN (this->success_status_,
+ ACE_TCHAR[this->number_remotes_],
+ -1);
+ this->delete_success_status_ = 1;
+ }
+ else
+ {
+ this->success_status_ = success_status;
+ }
+
+ // place 'failed' to the this->success_status_ array.
+ for (size_t j = 0; j < this->number_remotes_; ++j)
+ {
+ this->success_status_[j] = 1;
+ }
+
+ this->max_attempts_num_ = max_attempts_num;
+ this->current_attempt_ = this->max_attempts_num_;
+
+ if (this->ping_socket ().open (local_addr) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Echo_Handler::open: %p\n"),
+ ACE_TEXT ("ping_socket_")),
+ -1);
+
+ // register with the reactor for input
+ if (this->reactor ()->register_handler (this,
+ ACE_Event_Handler::READ_MASK) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Echo_Handler::open: %p\n"),
+ ACE_TEXT ("register_handler for input")),
+ -1);
+ return 0;
+}
+
+ACE_Ping_Socket &
+Echo_Handler::ping_socket (void)
+{
+ return this->ping_socket_;
+}
+
+int
+Echo_Handler::dispatch_echo_checks (int first_call)
+{
+ // Set ones , if this is the first call (not from handle_timeout)
+ if (first_call)
+ {
+ for (size_t j = 0; j < this->number_remotes_; ++j)
+ {
+ this->success_status_[j] = 1;
+ }
+ this->current_attempt_ = this->max_attempts_num_;
+ }
+
+ // Send echo-checks.
+ for (size_t i = 0; i < this->number_remotes_; ++i)
+ {
+ if (this->success_status_[i] != 0)
+ {
+ if (this->ping_socket ().send_echo_check (
+ this->remote_addrs_[i],
+ this->connect_to_remote_) == -1)
+ ACE_ERROR
+ ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Echo_Handler::dispatch_echo_checks - ")
+ ACE_TEXT ("failed for this->remote_addrs_[%d].\n"),
+ i));
+ }
+ }
+
+ int rval_sched = -1;
+ if ((rval_sched =
+ this->reactor ()->schedule_timer (this,
+ 0,
+ ACE_Time_Value (1),
+ this->reply_wait_)) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Echo_Handler::dispatch_echo_checks:")
+ ACE_TEXT (" %p\n"),
+ ACE_TEXT ("schedule_timer")),
+ -1);
+ return 0;
+}
+
+int
+Echo_Handler::handle_close (ACE_HANDLE, ACE_Reactor_Mask)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Echo_Handler::handle_close - started.\n")));
+
+#if 0
+ this->ping_socket ().close ();
+#endif
+
+ this->reactor ()->cancel_timer (this);
+
+#if 0
+ this->reactor ()->remove_handler (this,
+ ACE_Event_Handler::ALL_EVENTS_MASK |
+ ACE_Event_Handler::DONT_CALL);
+#endif
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Echo_Handler::handle_close - completed.\n")));
+ return 0;
+}
+
+ACE_HANDLE
+Echo_Handler::get_handle (void) const
+{
+ return ((ACE_ICMP_Socket &) this->ping_socket_).get_handle ();
+}
+
+int
+Echo_Handler::handle_input (ACE_HANDLE)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Echo_Handler::handle_input - ")
+ ACE_TEXT ("activity occurred on handle %d!\n"),
+ this->ping_socket ().get_handle ()));
+
+ ACE_TCHAR buf[BUFSIZ];
+ ACE_OS::memset (buf, 0, sizeof buf);
+
+ ACE_INET_Addr addr;
+ int rval_recv = -1;
+
+ // Receive an <n> byte <buf> from the datagram socket
+ // (uses<recvfrom(3)>).
+ rval_recv =
+ this->ping_socket ().recv (this->ping_socket ().icmp_recv_buff (),
+ ACE_Ping_Socket::PING_BUFFER_SIZE,
+ addr);
+ switch (rval_recv)
+ {
+ case -1:
+ // Complain and leave, but keep registered, returning 0.
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Echo_Handler::handle_input - ")
+ ACE_TEXT ("%p: bad read\n"),
+ ACE_TEXT ("client")),
+ 0);
+ // NOTREACHED
+
+ case 0:
+ // Complain and leave
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Echo_Handler::handle_input - ")
+ ACE_TEXT ("closing daemon (fd = %d)\n"),
+ this->get_handle ()),
+ 0);
+ // NOTREACHED
+
+ default:
+ ACE_DEBUG ((LM_INFO,
+ ACE_TEXT ("(%P|%t) Echo_Handler::handle_input - ")
+ ACE_TEXT ("message from %d bytes received.\n"),
+ rval_recv));
+
+ if (! this->ping_socket ().process_incoming_dgram (
+ this->ping_socket ().icmp_recv_buff (),
+ rval_recv))
+ {
+ for (size_t k = 0; k <this->number_remotes_; ++k)
+ {
+ if (addr.get_ip_address () ==
+ this->remote_addrs_[k].get_ip_address ())
+ {
+ if (addr.addr_to_string (buf, sizeof buf) == -1)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("can't obtain peer's address")));
+ }
+ else
+ {
+ ACE_DEBUG
+ ((LM_INFO,
+ ACE_TEXT ("(%P|%t) Echo_Handler::handle_input - ")
+ ACE_TEXT ("ECHO_REPLY received ")
+ ACE_TEXT ("from %s; marking this peer alive\n"),
+ buf));
+ }
+ // mark as successful
+ this->success_status_[k] = 0;
+ break;
+ }
+ }
+ }
+ break;
+ }
+
+ return 0;
+}
+
+int
+Echo_Handler::handle_timeout (ACE_Time_Value const &,
+ void const *)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Echo_Handler::handle_timeout - ")
+ ACE_TEXT ("timer for ping_socket_ with handle %d.\n"),
+ this->ping_socket ().get_handle ()));
+
+ int need_to_proceed = 0;
+
+ for (size_t i = 0; i < this->number_remotes_; ++i)
+ {
+ if (this->success_status_[i])
+ {
+ need_to_proceed = 1;
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Echo_Handler::handle_timeout - ")
+ ACE_TEXT ("this->success_status_[%d] is not zero. ")
+ ACE_TEXT ("Need to proceed echo-checks.\n"), i));
+ break;
+ }
+ }
+
+ if (!need_to_proceed)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Echo_Handler::handle_timeout - ")
+ ACE_TEXT ("need_to_proceed == 0. ")
+ ACE_TEXT ("Completed echo-checks.\n")));
+ }
+
+ if (!this->current_attempt_ || !need_to_proceed)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Echo_Handler::handle_timeout - ")
+ ACE_TEXT ("completed ECHO-checks for handle (%d).\n"),
+ this->ping_socket ().get_handle ()));
+ return -1; // to de-register from Reactor and make clean-up
+ // in handle-close
+ }
+
+ if (this->current_attempt_)
+ {
+ --this->current_attempt_;
+ }
+
+ ACE_DEBUG
+ ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Echo_Handler::handle_timeout - attempt %d.\n"),
+ this->current_attempt_));
+
+ this->dispatch_echo_checks ();
+ return 0;
+}
+
+int
+Echo_Handler::does_echo_test_successful (void)
+{
+ for (size_t i = 0; i < this->number_remotes_; ++i)
+ {
+ if (!this->success_status_[i])
+ {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
+Stop_Handler::Stop_Handler (ACE_Reactor * const reactor)
+ : counter_ ((counter_sig) 1)
+{
+ this->reactor (reactor);
+ ACE_OS::memset (this->handlers_to_stop_,
+ 0,
+ sizeof this->handlers_to_stop_);
+}
+
+Stop_Handler::~Stop_Handler (void)
+{
+ ACE_DEBUG ((LM_INFO, ACE_TEXT ("(%P|%t) Stop_Handler::~Stop_Handler.\n")));
+}
+
+int
+Stop_Handler::open (void)
+{
+ // Register the signal handler object to catch the signals.
+ if (this->reactor ()->register_handler (SIGINT, this) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Stop_Handler::open: %p\n"),
+ ACE_TEXT ("register_handler for SIGINT")),
+ -1);
+
+ if (this->reactor ()->register_handler (SIGTERM, this) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Stop_Handler::open: %p\n"),
+ ACE_TEXT ("register_handler for SIGTERM")),
+ -1);
+
+#if ! defined (ACE_WIN32)
+ if (this->reactor ()->register_handler (SIGQUIT, this) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Stop_Handler::open: %p\n"),
+ ACE_TEXT ("register_handler for SIGQUIT")),
+ -1);
+#endif /* #if ! defined (ACE_WIN32) */
+ return 0;
+}
+
+int
+Stop_Handler::handle_signal (int signum,
+ siginfo_t * ,
+ ucontext_t *)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Stop_Handler::handle_signal - started.\n")));
+ if (! --this->counter_)
+ {
+ ACE_DEBUG ((LM_INFO, ACE_TEXT ("\n-- Stop_Handler::handle_signal --- ")
+ ACE_TEXT ("SIGNAL %d RECEIVED -----------.\n"),
+ signum));
+ return reactor ()->notify (this, ACE_Event_Handler::READ_MASK);
+ }
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) Stop_Handler::handle_signal - ")
+ ACE_TEXT ("finished.\n")));
+ return 0;
+}
+
+int
+Stop_Handler::handle_input (ACE_HANDLE handle)
+{
+ ACE_UNUSED_ARG (handle);
+
+ ACE_DEBUG ((LM_INFO,
+ ACE_TEXT ("(%P|%t) Stop_Handler::handle_input - entered\n")));
+
+ for (size_t i = 0; i < HANDLERS_TO_STOP_TABLE_SIZE; ++i)
+ {
+ // remove from the reactor's tables all non-null entries
+ if (this->handlers_to_stop_[i])
+ {
+#if defined ACE_HAS_EXCEPTIONS
+
+ // protect from deleted pointer
+ try
+ {
+#endif // ACE_HAS_EXCEPTIONS
+
+ this->reactor ()->cancel_timer (this->handlers_to_stop_[i]);
+ this->reactor ()->remove_handler
+ (this->handlers_to_stop_[i],
+ ACE_Event_Handler::ALL_EVENTS_MASK
+ | ACE_Event_Handler::DONT_CALL);
+#if defined ACE_HAS_EXCEPTIONS
+ }
+ catch (...)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Stop_Handler::handle_input - ")
+ ACE_TEXT ("EXCEPTION CATCHED. Most probably ")
+ ACE_TEXT ("handler's pointer has been deleted.\n")));
+ }
+#endif // ACE_HAS_EXCEPTIONS
+ this->handlers_to_stop_[i] = 0;
+ }
+ }
+
+ this->reactor ()->remove_handler (this,
+ ACE_Event_Handler::SIGNAL_MASK |
+ ACE_Event_Handler::DONT_CALL);
+
+ if (reactor ()->end_reactor_event_loop () == -1)
+ {
+ ACE_ERROR_RETURN ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Stop_Handler::handle_signal:%p\n"),
+ ACE_TEXT ("end_reactor_event_loop")),
+ -1);
+ }
+
+ ACE_DEBUG ((LM_INFO,
+ ACE_TEXT ("(%P|%t) Stop_Handler::handle_input - completed.\n")));
+ return 0;
+}
+
+int
+Stop_Handler::handle_close (ACE_HANDLE, ACE_Reactor_Mask)
+{
+ ACE_DEBUG ((LM_INFO,
+ ACE_TEXT ("(%P|%t) Stop_Handler::handle_close - entered.\n")));
+ this->reactor ()->remove_handler (this,
+ ACE_Event_Handler::SIGNAL_MASK |
+ ACE_Event_Handler::DONT_CALL);
+
+ if (reactor ()->end_reactor_event_loop () == -1)
+ ACE_ERROR_RETURN ((LM_DEBUG,
+ ACE_TEXT ("Stop_Handler::handle_close: %p\n"),
+ ACE_TEXT ("end_reactor_event_loop")),
+ -1);
+ return 0;
+}
+
+int
+Stop_Handler::handle_timeout (ACE_Time_Value const &,
+ void const *)
+{
+ return 0;
+}
+
+// Register handler with us for stopping.
+int
+Stop_Handler::register_handler (ACE_Event_Handler *handler)
+{
+ if (!handler)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Stop_Handler::register_handler - ")
+ ACE_TEXT ("error, handler is a null pointer.\n")),
+ -1);
+
+ size_t index = 0;
+
+ for (index = 0;
+ (index < HANDLERS_TO_STOP_TABLE_SIZE &&
+ this->handlers_to_stop_[index]);
+ ++index)
+ ;
+
+ if (index == HANDLERS_TO_STOP_TABLE_SIZE)
+ {
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Stop_Handler::register_handler ")
+ ACE_TEXT ("- error, no space in ")
+ ACE_TEXT ("handlers_to_stop_table.\nIncrease ")
+ ACE_TEXT ("HANDLERS_TO_STOP_TABLE_SIZE.\n")),
+ -1);
+ }
+
+ this->handlers_to_stop_[index] = handler;
+ return 0;
+}
+
+// Unregister handler, registered before with us for stopping.
+int
+Stop_Handler::unregister_handler (ACE_Event_Handler *handler)
+{
+ if (!handler)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Stop_Handler::unregister_handler - ")
+ ACE_TEXT ("error, handler is a null pointer.\n")),
+ -1);
+
+ size_t index = 0;
+
+ for (index = 0;
+ (index < HANDLERS_TO_STOP_TABLE_SIZE &&
+ handler != this->handlers_to_stop_[index]);
+ ++index)
+ ;
+
+ size_t entrance = 0;
+ if (index == HANDLERS_TO_STOP_TABLE_SIZE)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Stop_Handler::unregister_")
+ ACE_TEXT ("handler - error, the handler was not ")
+ ACE_TEXT ("found among registered handlers.\n")),
+ -1);
+
+ entrance = index;
+ // null the entrance. Nulled entrances cannot be destroyed
+ this->handlers_to_stop_[entrance] = 0;
+
+ return 0;
+}
+
+
+Repeats_Handler::Repeats_Handler (void)
+ : check_handler_ (0),
+ seconds_timer_ (60),
+ counter_ (0)
+{
+}
+
+Repeats_Handler::~Repeats_Handler (void)
+{
+ ACE_DEBUG ((LM_INFO,
+ ACE_TEXT ("(%P|%t) Repeats_Handler::~Repeats_Handler.\n")));
+}
+
+int
+Repeats_Handler::open (Echo_Handler * check_handler,
+ ACE_Reactor * const reactor,
+ unsigned int seconds_timer)
+{
+ if (!check_handler)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Repeats_Handler::open - error: ")
+ ACE_TEXT ("NULL check_handler.\n")),
+ -1);
+
+ this->check_handler_ = check_handler;
+
+ if (!reactor)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Stop_Handler::open - error: ")
+ ACE_TEXT ("NULL reactor.\n")),
+ -1);
+
+ this->reactor (reactor);
+ this->seconds_timer_ = seconds_timer;
+
+ if (this->reactor ()->schedule_timer (
+ this,
+ 0,
+ ACE_Time_Value (1),
+ ACE_Time_Value (this->seconds_timer_)) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Repeats_Handler::open: %p\n"),
+ ACE_TEXT ("schedule_timer")),
+ -1);
+ return 0;
+}
+
+int
+Repeats_Handler::handle_close (ACE_HANDLE, ACE_Reactor_Mask)
+{
+ ACE_DEBUG
+ ((LM_INFO,
+ ACE_TEXT ("(%P|%t) Repeats_Handler::handle_close - entered.\n")));
+
+ this->reactor ()->remove_handler (this,
+ ACE_Event_Handler::ALL_EVENTS_MASK |
+ ACE_Event_Handler::DONT_CALL);
+ return 0;
+}
+
+static int one_button_test = 0;
+
+int
+Repeats_Handler::handle_timeout (ACE_Time_Value const &,
+ void const *)
+{
+ this->counter_++ ;
+ if (one_button_test && this->counter_ > 3)
+ {
+ ::raise (SIGINT);
+ }
+ if (this->check_handler_)
+ {
+ return this->check_handler_->dispatch_echo_checks (true);
+ }
+
+ return -1;
+}
+
+// to create core on some UNIX platforms
+#if defined (ACE_HAS_SIG_C_FUNC)
+extern "C"
+{
+#endif /* #if defined (ACE_HAS_SIG_C_FUNC) */
+
+#if ! defined (ACE_WIN32)
+ static void sigsegv_handler (int)
+ {
+ ACE_OS::abort ();
+ }
+#endif /* #if ! defined (ACE_WIN32) */
+
+#if defined (ACE_HAS_SIG_C_FUNC)
+}
+#endif /* #if defined (ACE_HAS_SIG_C_FUNC) */
+
+#if defined (ACE_WIN32)
+BOOL CtrlHandler(DWORD fdwCtrlType)
+{
+ switch (fdwCtrlType)
+ {
+ case CTRL_C_EVENT:
+ case CTRL_BREAK_EVENT:
+ case CTRL_SHUTDOWN_EVENT:
+ case CTRL_CLOSE_EVENT:
+ case CTRL_LOGOFF_EVENT:
+ ::raise (SIGINT);
+ return TRUE;
+
+ // Pass other signals to the next handler.
+ default:
+ return FALSE;
+ }
+}
+#endif /* #if defined (ACE_WIN32) */
+
+
+Fini_Guard::Fini_Guard (void)
+{
+}
+
+Fini_Guard::~Fini_Guard (void)
+{
+ ACE::fini ();
+}
+
+
+#define MAX_NUMBER_OF_PING_POINTS 16
+
+static int number_of_ping_points = 0;
+static char ping_points_ips [MAX_NUMBER_OF_PING_POINTS][16];
+static ACE_INET_Addr ping_points_addrs [MAX_NUMBER_OF_PING_POINTS];
+static ACE_TCHAR local_ip_to_bind [16];
+
+static int wait_echo_reply_timer = 500; // 500 ms to wait is the default
+static int repeats_seconds_timer = 60; // 60 seconds between repeats
+
+static int
+is_ip_address_local (char const * const ip_to_bind)
+{
+ ACE_INET_Addr *the_addr_array;
+ size_t how_many = 0;
+ int rc = ACE::get_ip_interfaces (how_many, the_addr_array);
+
+ if (rc != 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("is_ip_address_local: %p\n"),
+ ACE_TEXT ("ACE::get_ip_interfaces")),
+ -1);
+
+ if (how_many == 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("is_ip_address_local: "),
+ ACE_TEXT ("No interfaces presently configured ")
+ ACE_TEXT ("in the kernel\n")),
+ -1);
+
+ // debugging messages
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("is_ip_address_local () - there are %d interfaces\n"),
+ how_many));
+
+ for (size_t i = 0; i < how_many; ++i)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\t%s\n"),
+ the_addr_array[i].get_host_addr ()));
+ }
+
+ for (size_t j = 0; j < how_many; ++j)
+ {
+ if (!ACE_OS::strcmp (the_addr_array[j].get_host_addr (), ip_to_bind))
+ {
+ return 0;
+ }
+ }
+ return -1;
+}
+
+static int
+parse_args (int argc, ACE_TCHAR *argv[])
+{
+ ACE_OS::memset (ping_points_ips, 0, sizeof ping_points_ips);
+ ACE_OS::memset (local_ip_to_bind, 0, sizeof local_ip_to_bind);
+
+ if (argc == 1) // one button test
+ {
+ one_button_test = 1;
+ repeats_seconds_timer = 2;
+ number_of_ping_points = 1;
+
+ ACE_OS::strncpy (ping_points_ips [0],
+ "127.0.0.1",
+ sizeof ping_points_ips [0]);
+
+ ping_points_addrs[0].set ((u_short) 0, ping_points_ips[0]);
+ return 0;
+ }
+
+ ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("b:p:t:w:"));
+ int c, counter = 0;
+ ACE_INET_Addr b_temp_addr;
+ ACE_TCHAR *token = 0;
+ while ((c = get_opt ()) != EOF)
+ {
+ switch (c)
+ {
+ case 'b': // ip-address of the interface to bind to
+ ACE_OS::strncpy (local_ip_to_bind,
+ get_opt.optarg,
+ sizeof local_ip_to_bind);
+
+ if (!ACE_OS::strlen (local_ip_to_bind) ||
+ b_temp_addr.set ((u_short)0, local_ip_to_bind) != 0)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("-b should be followed by a valid ")
+ ACE_TEXT ("IPv4 address.\n")));
+ // print_usage ();
+ return -1;
+ }
+ if (is_ip_address_local (local_ip_to_bind) == -1)
+ {
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("the -b address (%s) ")
+ ACE_TEXT ("is not a local ")
+ ACE_TEXT ("address of your computer.\n")
+ ACE_TEXT ("\tPlease correct it.\n"),
+ local_ip_to_bind),
+ -1);
+ }
+ break;
+
+ case 'p': // ping-point (target) ip-addresses, separated by ":'"
+
+ // tokenizing the string
+ for (token = ACE_OS::strtok (get_opt.optarg, ACE_TEXT (":"));
+ token != 0 && counter < MAX_NUMBER_OF_PING_POINTS;
+ token = ACE_OS::strtok (0, ACE_TEXT (":")))
+ {
+ if (ping_points_addrs[counter].set ((u_short)0, token) != 0)
+ ACE_ERROR_RETURN
+ ((LM_ERROR,
+ ACE_TEXT ("Error: the address \"%s\" is not ")
+ ACE_TEXT ("a valid IPv4 address.\n"),
+ token),
+ -1);
+ ++number_of_ping_points;
+ ++counter;
+ }
+ break;
+
+ case 't':
+ repeats_seconds_timer = ACE_OS::atoi (get_opt.optarg);
+ break;
+
+ case 'w':
+ wait_echo_reply_timer = ACE_OS::atoi (get_opt.optarg);
+ break;
+
+ default:
+ // return print_usage (argc,argv);
+ break;
+
+ }
+ }
+
+ if (!number_of_ping_points)
+ {
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("Error: no valid IPv4 addresses ")
+ ACE_TEXT ("were provided, using -p option.\n")),
+ -1);
+ }
+
+ return 0;
+}
+
+int
+run_main (int argc, ACE_TCHAR *argv[])
+{
+ ACE_START_TEST (ACE_TEXT ("Network_Adapters_Test"));
+
+ ACE::init ();
+
+ // to call for ACE::fini () in its destructor
+ Fini_Guard fg;
+
+#if defined (ACE_WIN32)
+ SetConsoleCtrlHandler((PHANDLER_ROUTINE) CtrlHandler, TRUE);
+#else /* #if defined (ACE_WIN32) */
+ // Set a handler for SIGSEGV signal to call for abort.
+ ACE_Sig_Action sa1 ((ACE_SignalHandler) sigsegv_handler, SIGSEGV);
+#endif /* #if defined (ACE_WIN32) */
+ if (::parse_args (argc, argv) == -1)
+ {
+ return -1;
+ }
+
+ ACE_Reactor * main_reactor = 0;
+ ACE_NEW_RETURN (main_reactor, ACE_Reactor, -1);
+
+ (void) ACE_High_Res_Timer::global_scale_factor ();
+ main_reactor->timer_queue ()->gettimeofday
+ (&ACE_High_Res_Timer::gettimeofday_hr);
+
+ /**
+ * Stop_Handler's is supposed to stop the activity of all
+ * handlers by a SIGINT signal. We create and activate here an object of
+ * Stop_Handler and pass an instance of reactor (main_reactor),
+ * running demultiplexing event loop in the "main thread".
+ */
+ Stop_Handler* stop_handler = 0;
+ ACE_NEW_RETURN (stop_handler, Stop_Handler (main_reactor), -1);
+ if (stop_handler->open () == -1)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n"),
+ ACE_TEXT ("main() - stop_handler->open")));
+ ACE_OS::exit(-2);
+ }
+
+ ACE_TCHAR *ping_status = 0;
+ ACE_NEW_RETURN (ping_status, ACE_TCHAR[number_of_ping_points], -1);
+
+ // wait_echo_reply_timer is in msec
+ int seconds = 0;
+ int milliseconds = 0;
+ seconds = wait_echo_reply_timer / 1000;
+ milliseconds = wait_echo_reply_timer % 1000;
+ ACE_Time_Value const wait_timer (seconds, milliseconds);
+
+ Echo_Handler *ping_handler;
+ ACE_NEW_RETURN (ping_handler, Echo_Handler, -1);
+
+ if (ACE_OS::strlen (local_ip_to_bind))
+ {
+ // We are willing to bind the raw-socket to a certain adapter,
+ // probably because we are willing to check connectivity/etc
+ // of the local adapter.
+ ACE_INET_Addr local_adapter;
+ local_adapter.set ((u_short) 0, local_ip_to_bind);
+ if (ping_handler->open (main_reactor,
+ wait_timer,
+ ping_points_addrs,
+ number_of_ping_points,
+ ping_status,
+ 2, // max_attempts_number
+ local_adapter) == -1)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n"),
+ ACE_TEXT ("main() - ping_handler->open")));
+ ACE_OS::exit (-4);
+ }
+ }
+ else
+ {
+ // Binding to a local adapter is not of our interest. We just
+ // are willing to check all these remote IPs, to monitor, that
+ // they are alive.
+ if (ping_handler->open (main_reactor,
+ wait_timer,
+ ping_points_addrs,
+ number_of_ping_points,
+ ping_status,
+ 2) == -1) // max_attempts_number
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n"),
+ ACE_TEXT ("main() - ping_handler->open ()")));
+ ACE_OS::exit (-4);
+ }
+ }
+
+ Repeats_Handler *repeats_handler;
+ ACE_NEW_RETURN (repeats_handler, Repeats_Handler, -1);
+ if (repeats_handler->open (ping_handler,
+ main_reactor,
+ repeats_seconds_timer) == -1)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n"),
+ ACE_TEXT ("main() - repeats_handler->open")));
+ ACE_OS::exit (-4);
+ }
+
+ stop_handler->register_handler (repeats_handler);
+ stop_handler->register_handler (ping_handler);
+
+ // Demultiplexing event loop of the main_reactor.
+ while (main_reactor->reactor_event_loop_done () == 0)
+ {
+ main_reactor->run_reactor_event_loop ();
+ }
+
+ ACE_DEBUG ((LM_INFO,
+ ACE_TEXT ("(%P|%t|%T) \"Network_Adapters_Test\" main() - ")
+ ACE_TEXT ("out of reactor's loop.\n")));
+
+ delete repeats_handler;
+ delete ping_handler;
+ delete [] ping_status;
+ delete stop_handler;
+ delete main_reactor;
+
+ ACE_END_TEST;
+ return 0;
+}
+
+#else
+
+int
+run_main (int argc, ACE_TCHAR *argv[])
+{
+ ACE_UNUSED_ARG (argc);
+ ACE_UNUSED_ARG (argv);
+
+ ACE_START_TEST (ACE_TEXT ("Network_Adapters_Test"));
+
+ ACE_DEBUG ((LM_INFO,
+ ACE_TEXT ("(%P|%t|%T) \"Network_Adapters_Test\" main() - ")
+ ACE_TEXT ("ICMP support not configured.\n")
+ ACE_TEXT ("Define ACE_HAS_ICMP_SUPPORT = 1 in your config.h ")
+ ACE_TEXT ("file to enable.\n")));
+
+ ACE_END_TEST;
+
+ return 0;
+}
+
+#endif /* ACE_HAS_ICMP_SUPPORT == 1 */
diff --git a/ACE/tests/Network_Adapters_Test.h b/ACE/tests/Network_Adapters_Test.h
new file mode 100644
index 00000000000..c49cb40f03d
--- /dev/null
+++ b/ACE/tests/Network_Adapters_Test.h
@@ -0,0 +1,272 @@
+// -*- C++ -*-
+
+// $Id$
+//
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Network_Adapters_Test.h
+//
+// = DESCRIPTION
+// Definitions for Network_Adapters_Test.cpp.
+//
+// = AUTHOR
+// Robert S. Iakobashvili <roberti@go-WLAN.com> <coroberti@walla.co.il>
+// Gonzalo A. Diethelm <gonzalo.diethelm@aditiva.com> made aceing
+//
+// ============================================================================
+
+#ifndef ACE_NETWORK_ADAPTERS_TEST_H
+#define ACE_NETWORK_ADAPTERS_TEST_H
+
+#include "ace/Ping_Socket.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#if defined (ACE_HAS_ICMP_SUPPORT) && (ACE_HAS_ICMP_SUPPORT == 1)
+
+#include "ace/Reactor.h"
+#include "ace/INET_Addr.h"
+#include "ace/Event_Handler.h"
+#include "ace/Mutex.h"
+
+/*
+ * Echo_Handler performs echo-checks against a single ICMP echo-point.
+ */
+class Echo_Handler : public ACE_Event_Handler
+{
+public:
+ // = Initialization and termination methods.
+
+ /// Default constructor
+ Echo_Handler (void);
+
+ /// Destructor
+ virtual ~Echo_Handler (void);
+
+ /**
+ * Initialization of a handler, performing echo-checks against a
+ * SINGLE echo-point (supposed to be a really reliable, like hub,
+ * router).
+ *
+ * <reactor> - to be used for demultiplexing of any input and
+ * timeout
+ * <reply_wait> - time to wait for reply
+ * <remote_addr> - pointer to the remote address to sent to ICMP
+ * ECHO_CHECK datagram
+ * <success_status> - a pointer to char to be set as a 0 - on
+ * success, and 1 - when failed
+ * <max_attempts_num> - maximum number of attempts to perform
+ * <local_addr> - the local address to bind the underlaying
+ * ACE::Ping_Socket; useful for checks of local network adapters
+ * <connect_to_remote> - whether to connect the underlaying
+ * ACE::Ping_Socket to the remote address (1), or not (0)
+ */
+ int open (ACE_Reactor * const reactor,
+ const ACE_Time_Value & reply_wait,
+ const ACE_INET_Addr & remote_addr,
+ ACE_TCHAR * success_status = 0,
+ size_t max_attempts_num = 1,
+ const ACE_Addr & local_addr = ACE_Addr::sap_any,
+ int connect_to_remote = 0);
+
+ /**
+ * Initialization of a handler, performing echo-checks against
+ * MULTIPLE echo-points.
+ *
+ * <reactor> - to be used for demultiplexing of any input and
+ * timeout;
+ * <reply_wait> - time to wait for reply;
+ * <remote_addrs> - an array of remote addresses to sent to ICMP
+ * ECHO_CHECK datagram;
+ * <success_status> - an array of chars, each of them representing
+ * a respective remote address to be set as a 0 - on success, and
+ * 1 - when failed;
+ * <max_attempts_num> - maximum number of attempts to perform;
+ * <local_addr> - the local address to bind the underlaying
+ * ACE::Ping_Socket; useful for checks of the local network adapters
+ * connectivity;
+ */
+ int open (ACE_Reactor * const reactor,
+ ACE_Time_Value const & reply_wait,
+ ACE_INET_Addr const remote_addrs[],
+ size_t number_remotes,
+ ACE_TCHAR * success_status = 0,
+ size_t max_attempts_num = 1,
+ ACE_Addr const & local_addr = ACE_Addr::sap_any);
+
+ /// Returns reference to the ACE::Ping_Socket. Necessary for ACE_Reactor.
+ virtual ACE_HANDLE get_handle (void) const;
+
+ /**
+ * Takes care of the input. Reads the incoming ICMP datagrams and
+ * calls for process_incoming () of the ping_socket for processing.
+ */
+ virtual int handle_input (ACE_HANDLE handle);
+
+ /*
+ * Decides, if we need to continue checks (when at least a single
+ * address not returned ICMP_ECHO_REPLY and number of attempts,
+ * set in open () not expired). If yes, calls for dispatch_echo_checks (),
+ * if not returns -1 to initiate clean-up.
+ */
+ virtual int handle_timeout (ACE_Time_Value const & tv,
+ void const * arg = 0);
+
+ /// Makes clean-up
+ virtual int handle_close (ACE_HANDLE handle,
+ ACE_Reactor_Mask close_mask);
+
+ /// Calls send_echo_check() for all remote_addrs_
+ int dispatch_echo_checks (int first_call = 0);
+
+ /// Access to ping_socket.
+ ACE_Ping_Socket& ping_socket (void);
+
+ /// Returns 1 if a single char of success_status_ is 0
+ /// (connected).
+ int does_echo_test_successful (void);
+
+private:
+
+ /// Wrapper for sending/receiving ICMPs.
+ ACE_Ping_Socket ping_socket_;
+
+ /// Time to wait for reply.
+ ACE_Time_Value reply_wait_;
+
+ /// Remote address to ping on it
+ ACE_INET_Addr *remote_addrs_;
+
+ /// Number of remote echo points
+ size_t number_remotes_;
+
+ /// When 0 - success, 1 - failed.
+ ACE_TCHAR *success_status_;
+
+ /// If 1 - we 'own'
+ int delete_success_status_;
+
+ /// Maximum number of attempts.
+ size_t max_attempts_num_;
+
+ /// The number of the current attempt.
+ size_t current_attempt_;
+
+ /// Whether to make connect to the remote address or not. May be
+ /// buggy on some platforms.
+ int connect_to_remote_;
+};
+
+
+/*
+ * Class Stop_Handler - the most important class of the process.
+ * Knows how to stop all this business.
+ */
+class Stop_Handler : public ACE_Event_Handler
+{
+public:
+ typedef ACE_Atomic_Op<ACE_Mutex, long> counter_sig;
+
+ // Constructor.
+ Stop_Handler (ACE_Reactor * const reactor = ACE_Reactor::instance ());
+
+ // Destructor.
+ virtual ~Stop_Handler (void);
+
+ // Initialization. Registers this for SIGINT, SIGTERM and SIGQUIT.
+ virtual int open (void);
+
+ // De-registers this from the reactor and stops reactors event_loop.
+ virtual int handle_close (ACE_HANDLE handle,
+ ACE_Reactor_Mask close_mask);
+
+ // Called by reactor from the notification queue.
+ virtual int handle_input (ACE_HANDLE);
+
+ // Dispatches handle_input () notification.
+ virtual int handle_signal (int signum,
+ siginfo_t * = 0,
+ ucontext_t * = 0);
+
+ virtual int handle_timeout (ACE_Time_Value const & current_time,
+ void const * act = 0);
+
+ // Register handler with us for stopping.
+ virtual int register_handler (ACE_Event_Handler * handler);
+
+ // Unregister handler, registered before with us for stopping.
+ virtual int unregister_handler (ACE_Event_Handler * handler);
+
+private:
+
+ enum
+ {
+ HANDLERS_TO_STOP_TABLE_SIZE = 10
+ };
+
+ // Flag to prevent multiple dispatching of handle_input ().
+ counter_sig counter_;
+
+ // Table to place here pointers to all tasks in the process.
+ ACE_Event_Handler * handlers_to_stop_[HANDLERS_TO_STOP_TABLE_SIZE];
+};
+
+
+/*
+ * TODO comment
+ */
+class Repeats_Handler : public ACE_Event_Handler
+{
+public:
+ // Constructor.
+ Repeats_Handler (void);
+
+ // Destructor.
+ virtual ~Repeats_Handler (void);
+
+ // Initialization.
+ virtual int open (Echo_Handler *check_handler,
+ ACE_Reactor * const reactor = ACE_Reactor::instance (),
+ unsigned int seconds_timer = 60);
+
+ virtual int handle_close (ACE_HANDLE handle,
+ ACE_Reactor_Mask close_mask);
+
+ // dispatches a new echo-checks series
+ virtual int handle_timeout (ACE_Time_Value const & current_time,
+ void const * act = 0);
+
+private:
+ // an instance of a handler
+ Echo_Handler * check_handler_;
+
+ // timer in seconds to repeat the checks
+ unsigned int seconds_timer_;
+
+ // counts repeats
+ unsigned long counter_;
+};
+
+
+/*
+ * TODO comment
+ */
+class Fini_Guard
+{
+public:
+ // Constructor
+ Fini_Guard (void);
+
+ // Destructor - calls for fini
+ ~Fini_Guard (void);
+};
+
+#endif /* ACE_HAS_ICMP_SUPPORT == 1 */
+
+#endif /* ACE_NETWORK_ADAPTERS_TEST_H */
diff --git a/ACE/tests/New_Fail_Test.cpp b/ACE/tests/New_Fail_Test.cpp
new file mode 100644
index 00000000000..4a25d63933c
--- /dev/null
+++ b/ACE/tests/New_Fail_Test.cpp
@@ -0,0 +1,197 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// New_Fail_Test.cpp
+//
+// = DESCRIPTION
+// Checks to be sure that a failed ACE_NEW[_RETURN | _NORETURN] doesn't end
+// up throwing an exception up to the caller.
+//
+// Note that this test doesn't get a real attempt on platforms which:
+// 1. Are known to throw exceptions when 'new' runs out of resources,
+// 2. Are built with exceptions disabled.
+// In these cases, the test puts a message in the log noting that a failed
+// new will throw an exception, and trust that the user accepts that risk.
+//
+// = AUTHOR
+// Steve Huston <shuston@riverace.com>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/Log_Msg.h"
+#include "ace/OS_Memory.h"
+#include "ace/CORBA_macros.h"
+
+ACE_RCSID(tests, New_Fail_Test, "$Id$")
+
+#if (!defined (__SUNPRO_CC) && !defined (__GNUG__)) || \
+ defined (ACE_HAS_EXCEPTIONS)
+// This test allocates all of the heap memory, forcing 'new' to fail
+// because of a lack of memory. The ACE_NEW macros should prevent an
+// exception from being thrown past the ACE_NEW. If this test doesn't
+// wipe out on an alloc exception, it passes.
+//
+// If it doesn't ever fail an allocation, there's a warning that something is
+// wrong. The allocated memory is always freed to avoid masking a leak
+// somewhere else in the test.
+
+// 1MB
+static const int BIG_BLOCK = 1024*1024;
+
+// about 4GB max in the test
+static const int MAX_ALLOCS_IN_TEST = 4096;
+
+static void
+try_ace_new (char **p)
+{
+ ACE_NEW (*p, char[BIG_BLOCK]);
+ return;
+}
+
+static char *
+try_ace_new_return (void)
+{
+ char *p = 0;
+ ACE_NEW_RETURN (p, char[BIG_BLOCK], 0);
+ return p;
+}
+
+static char *
+try_ace_new_noreturn (void)
+{
+ char *p = 0;
+ ACE_NEW_NORETURN (p, char[BIG_BLOCK]);
+ return p;
+}
+#endif /* (!__SUNPRO_CC && !__GNUG__) || ACE_HAS_EXCEPTIONS */
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("New_Fail_Test"));
+ int status = 0;
+
+ // Some platforms are known to throw an exception on a failed 'new',
+ // but are customarily built without exception support to improve
+ // performance. These platforms are noted, and the test passes.
+ // For new ports, it is wise to let this test run. Depending on
+ // intended conditions, exceptions can be disabled when the port is
+ // complete.
+#if (defined (__SUNPRO_CC) || defined (__GNUG__)) && \
+ !defined (ACE_HAS_EXCEPTIONS)
+ ACE_DEBUG ((LM_NOTICE, ACE_TEXT ("Out-of-memory will throw an unhandled exception\n")));
+ ACE_DEBUG ((LM_NOTICE, ACE_TEXT ("Rebuild with exceptions=1 to prevent this, but it may impair performance.\n")));
+
+#else
+
+ char *blocks[MAX_ALLOCS_IN_TEST];
+ int i;
+
+# if defined (ACE_HAS_EXCEPTIONS)
+ try
+ {
+# endif /* ACE_HAS_EXCEPTIONS */
+ // First part: test ACE_NEW
+ for (i = 0; i < MAX_ALLOCS_IN_TEST; i++)
+ {
+ try_ace_new (&blocks[i]);
+ if (blocks[i] == 0)
+ break;
+ }
+ if (i == MAX_ALLOCS_IN_TEST)
+ {
+ ACE_ERROR((LM_WARNING,
+ ACE_TEXT ("Test didn't exhaust all available memory\n")));
+ // Back up to valid pointer for deleting.
+ --i;
+ }
+ else
+ {
+ ACE_ASSERT (blocks[i] == 0);
+ ACE_ASSERT (errno == ENOMEM);
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("ACE_NEW failed properly at block %d\n"),
+ i));
+ }
+
+ // Free the memory to try ACE_NEW_RETURN
+ while (i >= 0)
+ delete [] blocks[i--];
+
+ // Second part: test ACE_NEW_RETURN
+ for (i = 0; i < MAX_ALLOCS_IN_TEST; i++)
+ {
+ blocks[i] = try_ace_new_return ();
+ if (blocks[i] == 0)
+ break;
+ }
+
+ if (i == MAX_ALLOCS_IN_TEST)
+ {
+ ACE_ERROR ((LM_WARNING,
+ ACE_TEXT ("Test didn't exhaust all available memory\n")));
+ // Back up to valid pointer.
+ --i;
+ }
+ else
+ {
+ ACE_ASSERT (blocks[i] == 0);
+ ACE_ASSERT (errno == ENOMEM);
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("ACE_NEW_RETURN failed properly at block %d\n"),
+ i));
+ }
+ while (i >= 0)
+ delete [] blocks[i--];
+
+ // Third part: test ACE_NEW_NORETURN
+ for (i = 0; i < MAX_ALLOCS_IN_TEST; i++)
+ {
+ blocks[i] = try_ace_new_noreturn ();
+ if (blocks[i] == 0)
+ break;
+ }
+
+ if (i == MAX_ALLOCS_IN_TEST)
+ {
+ ACE_ERROR ((LM_WARNING,
+ ACE_TEXT ("Test didn't exhaust all available memory\n")));
+ // Back up to valid pointer.
+ --i;
+ }
+ else
+ {
+ ACE_ASSERT (blocks[i] == 0);
+ ACE_ASSERT (errno == ENOMEM);
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("ACE_NEW_NORETURN failed properly at block %d\n"),
+ i));
+ }
+ while (i >= 0)
+ delete [] blocks[i--];
+
+# if defined (ACE_HAS_EXCEPTIONS)
+ }
+
+ catch (...)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Caught exception during test; ")
+ ACE_TEXT ("ACE_bad_alloc not defined correctly, or\n")));
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("ACE_NEW_THROWS_EXCEPTIONS is not #defined (and should be).\n")));
+ // Mark test failure
+ status = 1;
+ }
+# endif /* ACE_HAS_EXCEPTIONS */
+#endif /* __SUNPRO_CC && !ACE_HAS_EXCEPTIONS */
+
+ ACE_END_TEST;
+ return status;
+}
diff --git a/ACE/tests/NonBlocking_Conn_Test.cpp b/ACE/tests/NonBlocking_Conn_Test.cpp
new file mode 100644
index 00000000000..1b4dfa8a884
--- /dev/null
+++ b/ACE/tests/NonBlocking_Conn_Test.cpp
@@ -0,0 +1,319 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// NonBlocking_Conn_Test.cpp
+//
+// = DESCRIPTION
+// This test checks for the proper working of the following:
+// - blocking connections
+// - blocking connections with timeouts
+// - non-blocking connections
+// - non-blocking connections without waiting for completions
+// - non-blocking connections with timeouts
+//
+// = AUTHOR
+// Irfan Pyarali <irfan@oomworks.com>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "NonBlocking_Conn_Test.h"
+#include "ace/Connector.h"
+#include "ace/SOCK_Connector.h"
+#include "ace/Select_Reactor.h"
+#include "ace/TP_Reactor.h"
+#include "ace/WFMO_Reactor.h"
+#include "ace/Get_Opt.h"
+
+static int test_select_reactor = 1;
+static int test_tp_reactor = 1;
+static int test_wfmo_reactor = 1;
+
+Svc_Handler::Svc_Handler (void)
+ : status_ (0),
+ completion_counter_ (0)
+{
+}
+
+void
+Svc_Handler::connection_status (Connection_Status &status,
+ int &completion_counter)
+{
+ this->status_ = &status;
+ this->completion_counter_ = &completion_counter;
+}
+
+int
+Svc_Handler::open (void *)
+{
+ *this->status_ = SUCCEEDED;
+ (*this->completion_counter_)++;
+
+ return 0;
+}
+
+int
+Svc_Handler::handle_close (ACE_HANDLE handle,
+ ACE_Reactor_Mask mask)
+{
+ *this->status_ = FAILED;
+ (*this->completion_counter_)++;
+
+ return ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH>::handle_close (handle,
+ mask);
+}
+
+typedef ACE_Connector<Svc_Handler,
+ ACE_SOCK_CONNECTOR>
+ CONNECTOR;
+
+static const char* hosts[] = {
+ "www.russiantvguide.com:80",
+ "www.pakarmy.gov.pk:80",
+ "www.cnn.com:80",
+ "www.waca.com.au:80",
+ "www.uganda.co.ug:80",
+ "www.cs.wustl.edu:80",
+ "www.dre.vanderbilt.edu:80",
+ "www.dhm.gov.np:80",
+ "www.msn.com:80",
+ "www.presidencymaldives.gov.mv:80" };
+
+static int number_of_connections = 0;
+
+void
+test_connect (ACE_Reactor &reactor,
+ ACE_INET_Addr *addresses,
+ ACE_Synch_Options &synch_options,
+ int complete_nonblocking_connections)
+{
+ CONNECTOR connector (&reactor);
+
+ int i = 0;
+
+ int completion_counter = 0;
+ Svc_Handler::Connection_Status *connection_status =
+ new Svc_Handler::Connection_Status[number_of_connections];
+
+ Svc_Handler **svc_handlers =
+ new Svc_Handler *[number_of_connections];
+
+ for (i = 0; i < number_of_connections; ++i)
+ {
+ svc_handlers[i] =
+ new Svc_Handler;
+
+ svc_handlers[i]->connection_status (connection_status[i],
+ completion_counter);
+ }
+
+ connector.connect_n (number_of_connections,
+ svc_handlers,
+ addresses,
+ 0,
+ synch_options);
+
+ if (!synch_options[ACE_Synch_Options::USE_REACTOR])
+ ACE_ASSERT (completion_counter == number_of_connections);
+
+ if (complete_nonblocking_connections)
+ {
+ while (completion_counter != number_of_connections)
+ {
+ connector.reactor ()->handle_events ();
+ }
+ }
+
+ connector.close ();
+
+ for (i = 0; i < number_of_connections; ++i)
+ {
+ ACE_TCHAR buffer[1024];
+ addresses[i].addr_to_string (buffer,
+ sizeof buffer,
+ 1);
+
+ ACE_DEBUG ((LM_DEBUG,
+ "Connection to %s %s\n",
+ buffer,
+ connection_status[i] == Svc_Handler::SUCCEEDED ?
+ "succeeded" : "failed"));
+
+ if (connection_status[i] == Svc_Handler::SUCCEEDED)
+ {
+ svc_handlers[i]->close ();
+ }
+ }
+
+ delete[] svc_handlers;
+ delete[] connection_status;
+}
+
+void
+test (ACE_Reactor_Impl *impl)
+{
+ size_t nr_names = sizeof hosts / sizeof (char *);
+ ACE_INET_Addr *addresses =
+ new ACE_INET_Addr[nr_names];
+
+ for (size_t i = 0, number_of_connections = 0; i < nr_names; ++i)
+ {
+ if (addresses[number_of_connections].set (hosts[i]) == 0)
+ ++number_of_connections;
+ else
+ ACE_DEBUG ((LM_INFO,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT_CHAR_TO_TCHAR (hosts[i])));
+ }
+
+ ACE_Reactor reactor (impl,
+ 1);
+
+ int complete_nonblocking_connections = 1;
+ int dont_wait_for_nonblocking_connections = 0;
+ int ignored = 99;
+
+ ACE_Synch_Options blocking_connect =
+ ACE_Synch_Options::defaults;
+
+ ACE_DEBUG ((LM_DEBUG,
+ "\nBlocking connections...\n\n"));
+
+ test_connect (reactor,
+ addresses,
+ blocking_connect,
+ ignored);
+
+ blocking_connect.set (ACE_Synch_Options::USE_TIMEOUT,
+ ACE_Time_Value (0, 50 * 1000));
+
+ ACE_DEBUG ((LM_DEBUG,
+ "\nBlocking connections (with timeouts)...\n\n"));
+
+ test_connect (reactor,
+ addresses,
+ blocking_connect,
+ ignored);
+
+ ACE_Synch_Options nonblocking_connect
+ (ACE_Synch_Options::USE_REACTOR);
+
+ ACE_DEBUG ((LM_DEBUG,
+ "\nNon-blocking connections...\n\n"));
+
+ test_connect (reactor,
+ addresses,
+ nonblocking_connect,
+ complete_nonblocking_connections);
+
+ ACE_DEBUG ((LM_DEBUG,
+ "\nNon-blocking connections (without waiting for completions)...\n\n"));
+
+ test_connect (reactor,
+ addresses,
+ nonblocking_connect,
+ dont_wait_for_nonblocking_connections);
+
+ nonblocking_connect.set (ACE_Synch_Options::USE_REACTOR |
+ ACE_Synch_Options::USE_TIMEOUT,
+ ACE_Time_Value (0, 500 * 1000));
+
+ ACE_DEBUG ((LM_DEBUG,
+ "\nNon-blocking connections (with timeouts)...\n\n"));
+
+ test_connect (reactor,
+ addresses,
+ nonblocking_connect,
+ complete_nonblocking_connections);
+
+ delete[] addresses;
+}
+
+static int
+parse_args (int argc, ACE_TCHAR *argv[])
+{
+ ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("a:b:c:"));
+
+ int cc;
+ while ((cc = get_opt ()) != -1)
+ {
+ switch (cc)
+ {
+ case 'a':
+ test_select_reactor = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'b':
+ test_tp_reactor = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'c':
+ test_wfmo_reactor = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case '?':
+ case 'u':
+ default:
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("\nusage: %s \n\n")
+ ACE_TEXT ("\t[-a test Select Reactor] (defaults to %d)\n")
+ ACE_TEXT ("\t[-b test TP Reactor] (defaults to %d)\n")
+ ACE_TEXT ("\t[-c test WFMO Reactor] (defaults to %d)\n")
+ ACE_TEXT ("\n"),
+ argv[0],
+ test_select_reactor,
+ test_tp_reactor,
+ test_wfmo_reactor));
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+int
+run_main (int argc, ACE_TCHAR *argv[])
+{
+ ACE_START_TEST (ACE_TEXT ("NonBlocking_Conn_Test"));
+
+ // Validate options.
+ int result =
+ parse_args (argc, argv);
+ if (result != 0)
+ return result;
+
+ if (test_select_reactor)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ "\n\nTesting Select Reactor....\n\n"));
+
+ test (new ACE_Select_Reactor);
+ }
+
+ if (test_tp_reactor)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ "\n\nTesting TP Reactor....\n\n"));
+
+ test (new ACE_TP_Reactor);
+ }
+
+#if defined (ACE_WIN32)
+
+ if (test_wfmo_reactor)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ "\n\nTesting WFMO Reactor....\n\n"));
+
+ test (new ACE_WFMO_Reactor);
+ }
+
+#endif /* ACE_WIN32 */
+
+ ACE_END_TEST;
+
+ return 0;
+}
+
diff --git a/ACE/tests/NonBlocking_Conn_Test.h b/ACE/tests/NonBlocking_Conn_Test.h
new file mode 100644
index 00000000000..77746238226
--- /dev/null
+++ b/ACE/tests/NonBlocking_Conn_Test.h
@@ -0,0 +1,54 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// NonBlocking_Conn_Test.cpp
+//
+// = DESCRIPTION
+// This test checks for the proper working of the following:
+// - blocking connections
+// - blocking connections with timeouts
+// - non-blocking connections
+// - non-blocking connections without waiting for completions
+// - non-blocking connections with timeouts
+//
+// = AUTHOR
+// Irfan Pyarali <irfan@oomworks.com>
+//
+// ============================================================================
+
+#ifndef NONBLOCKING_CONN_TEST_H
+#define NONBLOCKING_CONN_TEST_H
+
+#include "ace/Svc_Handler.h"
+#include "ace/SOCK_Stream.h"
+
+class Svc_Handler : public ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH>
+{
+public:
+
+ enum Connection_Status
+ {
+ SUCCEEDED,
+ FAILED
+ };
+
+ Svc_Handler (void);
+
+ void connection_status (Connection_Status &status,
+ int &completion_counter);
+
+ int open (void *);
+
+ int handle_close (ACE_HANDLE handle,
+ ACE_Reactor_Mask mask);
+
+ Connection_Status *status_;
+ int *completion_counter_;
+};
+
+#endif /* NONBLOCKING_CONN_TEST_H */
diff --git a/ACE/tests/Notify_Performance_Test.cpp b/ACE/tests/Notify_Performance_Test.cpp
new file mode 100644
index 00000000000..b812630a065
--- /dev/null
+++ b/ACE/tests/Notify_Performance_Test.cpp
@@ -0,0 +1,257 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Notify_Performance_Test.cpp
+//
+// = DESCRIPTION
+// This test is used to time the notification mechanisms of the
+// ACE_Reactors. Both the WFMO_Reactor and Select_Reactor can be
+// tested. The notify() mechanism can also be tested with or
+// without data.
+//
+// = AUTHOR
+// Irfan Pyarali <irfan@cs.wustl.edu>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/Profile_Timer.h"
+#include "ace/Get_Opt.h"
+#include "ace/Thread_Manager.h"
+#include "ace/Reactor.h"
+#include "ace/WFMO_Reactor.h"
+#include "ace/Select_Reactor.h"
+#include "ace/Dev_Poll_Reactor.h"
+#include "ace/Auto_Ptr.h"
+#include "ace/Atomic_Op.h"
+
+ACE_RCSID(tests, Notify_Performance_Test, "$Id$")
+
+#if defined (ACE_HAS_THREADS)
+
+// Number of client (user) threads
+static long opt_nthreads = 1;
+
+// Number of notify calls
+static int opt_nloops = 20000;
+
+// Use the WFMO_Reactor
+static int opt_wfmo_reactor = 0;
+
+// Use the Select_Reactor
+static int opt_select_reactor = 0;
+
+// Use the Dev_Poll_Reactor
+static int opt_dev_poll_reactor = 0;
+
+// Pass data through the notify call
+static int opt_pass_notify_data = 0;
+
+// Simple no-op handler
+class Handler : public ACE_Event_Handler
+{
+public:
+ virtual int handle_exception (ACE_HANDLE fd = ACE_INVALID_HANDLE);
+ // The Handler callbacks.
+};
+
+int
+Handler::handle_exception (ACE_HANDLE handle)
+{
+ ACE_UNUSED_ARG (handle);
+
+ return 0;
+}
+
+// Execute the client tests.
+
+static void *
+client (void *arg)
+{
+ // Number of client (user) threads
+ static ACE_Atomic_Op<ACE_Thread_Mutex, long> thread_counter;
+ thread_counter = opt_nthreads;
+
+ // To pass or not to pass is the question
+ Handler *handler = 0;
+ if (!opt_pass_notify_data)
+ handler = 0;
+ else
+ handler = (Handler *) arg;
+
+ for (int i = 0; i < opt_nloops; i++)
+ ACE_Reactor::instance ()->notify (handler);
+
+ if (--thread_counter == 0)
+ ACE_Reactor::instance()->end_reactor_event_loop ();
+
+ return 0;
+}
+
+// Sets up the correct reactor (based on platform and options)
+
+static void
+create_reactor (void)
+{
+ ACE_Reactor_Impl *impl = 0;
+
+ if (opt_wfmo_reactor)
+ {
+#if defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)
+ ACE_NEW (impl, ACE_WFMO_Reactor);
+#endif /* ACE_WIN32 */
+ }
+ else if (opt_select_reactor)
+ {
+ ACE_NEW (impl, ACE_Select_Reactor);
+ }
+ else if (opt_dev_poll_reactor)
+ {
+#if defined (ACE_HAS_EVENT_POLL) || defined (ACE_HAS_DEV_POLL)
+ ACE_NEW (impl, ACE_Dev_Poll_Reactor);
+#endif /* ACE_HAS_EVENT_POLL || ACE_HAS_DEV_POLL */
+ }
+ ACE_Reactor *reactor = 0;
+ ACE_NEW (reactor, ACE_Reactor (impl));
+ ACE_Reactor::instance (reactor);
+}
+
+static void
+print_results (ACE_Profile_Timer::ACE_Elapsed_Time &et)
+{
+ const ACE_TCHAR *reactor_type = 0;
+ if (opt_wfmo_reactor)
+ reactor_type = ACE_TEXT ("WFMO_Reactor");
+ else if (opt_select_reactor)
+ reactor_type = ACE_TEXT ("Select_Reactor");
+ else if (opt_dev_poll_reactor)
+ reactor_type = ACE_TEXT ("Dev_Poll_Reactor");
+ else
+ reactor_type = ACE_TEXT ("Platform's default Reactor");
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\nNotify_Performance Test statistics:\n\n")));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\tReactor Type: %s\n"),
+ reactor_type));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\tWorker threads (calling notify()): %d\n"),
+ opt_nthreads));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\tIteration per thread: %d\n"),
+ opt_nloops));
+ if (opt_pass_notify_data)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\tData was passed in the notify() call\n")));
+ else
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\tNo data was passed in the notify() call\n")));
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\n\tTiming results notify() call:\n")));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\t\treal time = %f secs \n\t\tuser time = %f secs \n\t\tsystem time = %f secs\n\n"),
+ et.real_time,
+ et.user_time,
+ et.system_time));
+}
+
+int
+run_main (int argc, ACE_TCHAR *argv[])
+{
+ ACE_START_TEST (ACE_TEXT ("Notify_Performance_Test"));
+
+ ACE_Get_Opt getopt (argc, argv, ACE_TEXT ("pswdc:l:"));
+
+ for (int c; (c = getopt ()) != -1; )
+ switch (c)
+ {
+ case 'p':
+ opt_dev_poll_reactor = 1;
+ break;
+ case 's':
+ opt_select_reactor = 1;
+ break;
+ case 'w':
+ opt_wfmo_reactor = 1;
+ break;
+ case 'c':
+ opt_nthreads = ACE_OS::atoi (getopt.opt_arg ());
+ break;
+ case 'l':
+ opt_nloops = ACE_OS::atoi (getopt.opt_arg ());
+ break;
+ case 'd':
+ opt_pass_notify_data = 1;
+ break;
+ }
+
+ // Sets up the correct reactor (based on platform and options)
+ create_reactor ();
+
+ // Manage memory automagically.
+ auto_ptr<ACE_Reactor> reactor (ACE_Reactor::instance ());
+ auto_ptr<ACE_Reactor_Impl> impl;
+
+ // If we are using other that the default implementation, we must
+ // clean up.
+ if (opt_select_reactor || opt_wfmo_reactor || opt_dev_poll_reactor)
+ {
+ auto_ptr<ACE_Reactor_Impl> auto_impl (ACE_Reactor::instance ()->implementation ());
+ impl = auto_impl;
+ }
+
+ // Callback object
+ Handler handler;
+
+ // Spawn worker threads
+ if (ACE_Thread_Manager::instance ()->spawn_n
+ (opt_nthreads,
+ ACE_THR_FUNC (client),
+ (void *) &handler,
+ THR_NEW_LWP | THR_DETACHED) == -1)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%P|%t) %p\n%a"), ACE_TEXT ("thread create failed")));
+
+ // Timer business
+ ACE_Profile_Timer timer;
+ timer.start ();
+
+ // Run event loop
+ ACE_Reactor::instance()->run_reactor_event_loop ();
+
+ timer.stop ();
+
+ ACE_Profile_Timer::ACE_Elapsed_Time et;
+ timer.elapsed_time (et);
+
+ // Print results
+ print_results (et);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) waiting for the worker threads...\n")));
+
+ // Wait for all worker to get done.
+ ACE_Thread_Manager::instance ()->wait ();
+
+ ACE_END_TEST;
+ return 0;
+}
+
+#else
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("Notify_Performance_Test"));
+
+ ACE_ERROR ((LM_INFO,
+ ACE_TEXT ("threads not supported on this platform\n")));
+
+ ACE_END_TEST;
+ return 0;
+}
+#endif /* ACE_HAS_THREADS */
diff --git a/ACE/tests/OS_Test.cpp b/ACE/tests/OS_Test.cpp
new file mode 100644
index 00000000000..fa7b058e4e4
--- /dev/null
+++ b/ACE/tests/OS_Test.cpp
@@ -0,0 +1,853 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = DESCRIPTION
+// This simple test exercises and illustrates use of OS wrapper functions.
+//
+// = AUTHOR
+// Steve Huston <shuston@riverace.com>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/OS_NS_string.h"
+#include "ace/OS_NS_strings.h"
+#include "ace/OS_NS_stdlib.h"
+#include "ace/OS_NS_sys_time.h"
+#include "ace/OS_NS_time.h"
+#include "ace/OS_NS_stdio.h"
+#include "ace/OS_NS_sys_stat.h"
+#include "ace/OS_NS_unistd.h"
+#include "ace/OS_NS_errno.h"
+
+ACE_RCSID(tests, OS_Test, "$Id$")
+
+// Test ACE_OS::access() to be sure a file's existence is correctly noted.
+int
+access_test (void)
+{
+ int test_status = 0;
+
+ int status = ACE_OS::access (ACE_TEXT ("missing_file.txt"), F_OK);
+ if (status == -1)
+ {
+ if (errno == ENOTSUP)
+ ACE_ERROR_RETURN ((LM_INFO,
+ ACE_TEXT ("ACE_OS::access() not supported\n")),
+ 0);
+ }
+ else
+ {
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("Missing file noted as present.\n")));
+ test_status = -1;
+ }
+
+ return test_status;
+}
+
+// Test ACE_OS::rename to be sure the files come and go as expected.
+int
+rename_test (void)
+{
+#if defined (ACE_LACKS_RENAME) || defined (ACE_VXWORKS)
+ // On VxWorks only some filesystem drivers support rename
+ // and as we do not know which is used, skip the test here
+ ACE_ERROR_RETURN ((LM_INFO,
+ ACE_TEXT ("rename not supported on this platform\n")),
+ 0);
+#else
+ ACE_TCHAR old_file[MAXPATHLEN];
+ ACE_TCHAR new_file[MAXPATHLEN];
+ ACE_OS::strcpy (old_file, ACE_TEXT ("rename_test_old"));
+ ACE_OS::strcpy (new_file, ACE_TEXT ("rename_test_new"));
+
+ // Test 1. Rename old to new when new already exists.
+ // To set up, create two files, old and new. Both get opened and truncated
+ // in case they're left over from a previous run. The first one (old) gets
+ // something written in it so it's non-zero length - this is how the rename
+ // is verified.
+ FILE *f = ACE_OS::fopen (old_file, ACE_TEXT ("w+"));
+ if (f == 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%s: %p\n"),
+ old_file,
+ ACE_TEXT ("fopen")),
+ -1);
+ // Write something in the old_file so it has non-zero length
+ ACE_OS::fputs (ACE_TEXT ("this is a test\n"), f);
+ ACE_OS::fclose (f);
+ f = ACE_OS::fopen (new_file, ACE_TEXT ("w+"));
+ if (f == 0)
+ {
+ ACE_OS::unlink (old_file);
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%s: %p\n"),
+ new_file,
+ ACE_TEXT ("fopen")),
+ -1);
+ }
+ ACE_OS::fclose (f);
+
+#if defined (ACE_WIN32) && defined (ACE_HAS_WINNT4) && ACE_HAS_WINNT4 == 0
+ // Can't rename if new_file exists already.
+ ACE_OS::unlink (new_file);
+#endif
+
+ if (ACE_OS::rename (old_file, new_file) != 0)
+ {
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("rename test 1")));
+ ACE_OS::unlink (old_file);
+ ACE_OS::unlink (new_file);
+ return -1;
+ }
+ // Verify that the old file was really renamed.
+ ACE_stat checking;
+ int result = 0;
+ if (ACE_OS::stat (new_file, &checking) == -1 || checking.st_size == 0)
+ {
+ result = -1;
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Rename test 1: new_file not correct\n")));
+ }
+ if (ACE_OS::stat (old_file, &checking) == 0)
+ {
+ result = -1;
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Rename test 1: old_file still there\n")));
+ }
+ if (result == 0)
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Rename when dest. exists: success\n")));
+
+ // Now test 2 - rename when the new file does not exist. If test 1 worked,
+ // the old_file is now new_file and there is no old_file.
+ if (ACE_OS::rename (new_file, old_file) != 0)
+ {
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("rename test 2")));
+ ACE_OS::unlink (old_file);
+ ACE_OS::unlink (new_file);
+ return -1;
+ }
+ if (ACE_OS::stat (old_file, &checking) == -1 || checking.st_size == 0)
+ {
+ result = -1;
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Rename test 2: new_file not correct\n")));
+ }
+ else if (ACE_OS::stat (new_file, &checking) == 0)
+ {
+ result = -1;
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Rename test 2: old_file still there\n")));
+ }
+ else
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Rename when dest. gone: success\n")));
+
+ ACE_OS::unlink (new_file);
+ ACE_OS::unlink (old_file);
+
+ // Test 3: It should fail... there are no files.
+ if (ACE_OS::rename (old_file, new_file) == -1)
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Rename test 3 should bomb, and did.\n")));
+ else
+ {
+ result = -1;
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Rename expected fail, but succeeded\n")));
+ }
+
+ return result;
+#endif /* ACE_LACKS_RENAME */
+}
+
+//
+int
+string_emulation_test (void)
+{
+ {
+ // ========================================================================
+ // Test memchr
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Testing memchr\n")));
+
+ const char *memchr1 = "abcdefghijklmnopqrstuvwxyz";
+
+ ACE_ASSERT (ACE_OS::memchr (static_cast<const void *> (NULL),
+ 'a',
+ 0) == NULL);
+ ACE_ASSERT (ACE_OS::memchr (memchr1, 'a', sizeof (memchr1)) != NULL);
+ ACE_ASSERT (ACE_OS::memchr (memchr1, '1', sizeof (memchr1)) == NULL);
+
+ // ========================================================================
+ // Test strchr
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Testing strchr\n")));
+
+ const char *strchr1 = "abcdefghijkabcdefghijk";
+
+ ACE_ASSERT (*ACE_OS::strchr (strchr1, 'h') == 'h');
+ ACE_ASSERT (ACE_OS::strchr (strchr1, 'h') == strchr1 + 7);
+ ACE_ASSERT (ACE_OS::strchr (strchr1, '1') == NULL);
+
+ // ========================================================================
+ // Test strrchr
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Testing strrchr\n")));
+
+ const char *strrchr1 = "abcdefghijkabcdefghijk";
+
+ ACE_ASSERT (*ACE_OS::strrchr (strrchr1, 'h') == 'h');
+ ACE_ASSERT (ACE_OS::strrchr (strrchr1, 'h') == strrchr1 + 18);
+ ACE_ASSERT (ACE_OS::strrchr (strrchr1, '1') == NULL);
+
+ // ========================================================================
+ // Test strcspn
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Testing strcspn\n")));
+
+ const char *strcspn1 = "abcdefghijkabcdefghijk";
+
+ ACE_ASSERT (ACE_OS::strcspn (strcspn1, "d") == 3);
+ ACE_ASSERT (ACE_OS::strcspn (strcspn1, "abcdefghijk") == 0);
+
+ // ========================================================================
+ // Test strcasecmp
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Testing strcasecmp\n")));
+
+ const char *strcasecmp1 = "stringf";
+ const char *strcasecmp2 = "stringfe"; // An extra character
+ const char *strcasecmp3 = "stringg"; // The last letter is higher
+ const char *strcasecmp4 = "STRINGF"; // Different case
+ const char *strcasecmp5 = "stringe"; // The last letter is lower
+
+ ACE_ASSERT (ACE_OS::strcasecmp (strcasecmp1, strcasecmp1) == 0);
+ ACE_ASSERT (ACE_OS::strcasecmp (strcasecmp1, strcasecmp2) < 0);
+ ACE_ASSERT (ACE_OS::strcasecmp (strcasecmp1, strcasecmp3) < 0);
+ ACE_ASSERT (ACE_OS::strcasecmp (strcasecmp1, strcasecmp4) == 0);
+ ACE_ASSERT (ACE_OS::strcasecmp (strcasecmp1, strcasecmp5) > 0);
+
+ // ========================================================================
+ // Test strtok_r
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Testing strtok_r\n")));
+
+ char strtok_r1[] = "A string of tokens";
+ char *strtok_r2;
+
+ ACE_ASSERT (ACE_OS::strcmp (ACE_OS::strtok_r (strtok_r1,
+ " ",
+ &strtok_r2),
+ "A") == 0);
+ ACE_ASSERT (ACE_OS::strcmp (ACE_OS::strtok_r (0,
+ " ",
+ &strtok_r2),
+ "string") == 0);
+ ACE_ASSERT (ACE_OS::strcmp (ACE_OS::strtok_r (0,
+ " ",
+ &strtok_r2),
+ "of") == 0);
+ ACE_ASSERT (ACE_OS::strcmp (ACE_OS::strtok_r (0,
+ " ",
+ &strtok_r2),
+ "tokens") == 0);
+ ACE_ASSERT (ACE_OS::strtok_r (0, " ", &strtok_r2) == 0);
+
+ // ========================================================================
+ // Test itoa
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Testing itoa\n")));
+
+ char itoa1[33];
+
+ ACE_ASSERT (ACE_OS::strcmp (ACE_OS::itoa (42, itoa1, 2),
+ "101010") == 0);
+
+ ACE_ASSERT (ACE_OS::strcmp (ACE_OS::itoa (42, itoa1, 3),
+ "1120") == 0);
+
+ ACE_ASSERT (ACE_OS::strcmp (ACE_OS::itoa (42, itoa1, 16),
+ "2a") == 0);
+
+ ACE_ASSERT (ACE_OS::strcmp (ACE_OS::itoa (8, itoa1, 10),
+ "8") == 0);
+
+ ACE_ASSERT (ACE_OS::strcmp (ACE_OS::itoa (-8, itoa1, 10),
+ "-8") == 0);
+
+ ACE_ASSERT (ACE_OS::strcmp (ACE_OS::itoa (20345, itoa1, 10),
+ "20345") == 0);
+
+ ACE_ASSERT (ACE_OS::strcmp (ACE_OS::itoa (-20345, itoa1, 10),
+ "-20345") == 0);
+
+ ACE_ASSERT (ACE_OS::strcmp (ACE_OS::itoa (4566733, itoa1, 10),
+ "4566733") == 0);
+
+ ACE_ASSERT (ACE_OS::strcmp (ACE_OS::itoa (-4566733, itoa1, 10),
+ "-4566733") == 0);
+ }
+
+#if defined (ACE_HAS_WCHAR)
+ {
+ // ========================================================================
+ // Test itoa (wchar_t version)
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Testing itoa (wchar_t version)\n")));
+
+ wchar_t itow1[33];
+
+ ACE_ASSERT (ACE_OS::strcmp (ACE_OS::itoa (42, itow1, 2),
+ ACE_TEXT_WIDE ("101010")) == 0);
+
+ ACE_ASSERT (ACE_OS::strcmp (ACE_OS::itoa (42, itow1, 3),
+ ACE_TEXT_WIDE ("1120")) == 0);
+
+ ACE_ASSERT (ACE_OS::strcmp (ACE_OS::itoa (42, itow1, 16),
+ ACE_TEXT_WIDE ("2a")) == 0);
+
+
+ // ========================================================================
+ // Test strcmp (wchar_t version)
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Testing strcmp (wchar_t version)\n")));
+
+ const wchar_t *strcmp1 = ACE_TEXT_WIDE ("stringf");
+ const wchar_t *strcmp2 = ACE_TEXT_WIDE ("stringfe");
+ const wchar_t *strcmp3 = ACE_TEXT_WIDE ("stringg");
+ const wchar_t *strcmp4 = ACE_TEXT_WIDE ("STRINGF");
+ const wchar_t *strcmp5 = ACE_TEXT_WIDE ("stringe");
+
+ ACE_ASSERT (ACE_OS::strcmp (strcmp1, strcmp1) == 0);
+ ACE_ASSERT (ACE_OS::strcmp (strcmp1, strcmp2) < 0);
+ ACE_ASSERT (ACE_OS::strcmp (strcmp1, strcmp3) < 0);
+ ACE_ASSERT (ACE_OS::strcmp (strcmp1, strcmp4) != 0);
+ ACE_ASSERT (ACE_OS::strcmp (strcmp1, strcmp5) > 0);
+
+ // ========================================================================
+ // Test strcpy (wchar_t version)
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Testing strcpy (wchar_t version)\n")));
+
+ const wchar_t *strcpy1 = ACE_TEXT_WIDE ("abcdefghijklmnopqrstuvwxyz");
+ wchar_t strcpy2[27];
+
+ ACE_ASSERT
+ (ACE_OS::strcmp (ACE_OS::strcpy (strcpy2, strcpy1),
+ strcpy1) == 0);
+ ACE_ASSERT (ACE_OS::strcmp (strcpy2, strcpy1) == 0);
+
+ // ========================================================================
+ // Test strcat (wchar_t version)
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Testing strcat (wchar_t version)\n")));
+
+ const wchar_t *strcat1 = ACE_TEXT_WIDE ("abcdefghijklmnopqrstuvwxyz");
+ wchar_t strcat2[27] = ACE_TEXT_WIDE ("abcdefghijkl");
+ const wchar_t *strcat3 = ACE_TEXT_WIDE ("mnopqrstuvwxyz");
+
+ ACE_ASSERT
+ (ACE_OS::strcmp (ACE_OS::strcat (strcat2, strcat3),
+ strcat1) == 0);
+ ACE_ASSERT (ACE_OS::strcmp (strcat2, strcat1) == 0);
+
+ // ========================================================================
+ // Test strncat (wchar_t version)
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Testing strncat (wchar_t version)\n")));
+
+ const wchar_t *strncat1 = ACE_TEXT_WIDE ("abcdefghijklmnopqrstuvwxyz");
+ wchar_t strncat2[27] = ACE_TEXT_WIDE ("abcdefghijkl");
+ const wchar_t *strncat3 = ACE_TEXT_WIDE ("mnopqrstuvwxyzabc");
+
+ ACE_ASSERT
+ (ACE_OS::strcmp (ACE_OS::strncat (strncat2, strncat3, 14),
+ strncat1) == 0);
+ ACE_ASSERT (ACE_OS::strcmp (strncat2, strncat1) == 0);
+
+ // ========================================================================
+ // Test strspn (wchar_t version)
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Testing strspn (wchar_t version)\n")));
+
+ const wchar_t *strspn1 = ACE_TEXT_WIDE ("abcdefghijkabcdefghijk");
+
+ ACE_ASSERT (ACE_OS::strspn (strspn1,
+ ACE_TEXT_WIDE ("abcdf")) == 4);
+ ACE_ASSERT (ACE_OS::strspn (strspn1,
+ ACE_TEXT_WIDE ("mno")) == 0);
+
+ // ========================================================================
+ // Test strchr (wchar_t version)
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Testing strchr (wchar_t version)\n")));
+
+ const wchar_t *strchr1 = ACE_TEXT_WIDE ("abcdefghijkabcdefghijk");
+
+ ACE_ASSERT (*ACE_OS::strchr (strchr1, ACE_TEXT_WIDE ('h'))
+ == ACE_TEXT_WIDE ('h'));
+ ACE_ASSERT (ACE_OS::strchr (strchr1, ACE_TEXT_WIDE ('h'))
+ == strchr1 + 7);
+ ACE_ASSERT (ACE_OS::strchr (strchr1, ACE_TEXT_WIDE ('1')) == NULL);
+
+ // ========================================================================
+ // Test strstr (wchar_t version)
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Testing strstr (wchar_t version)\n")));
+
+ const wchar_t *strstr1 = ACE_TEXT_WIDE ("abcdefghijkabcdefghijk");
+
+ ACE_ASSERT (ACE_OS::strncmp (
+ ACE_OS::strstr (strstr1, ACE_TEXT_WIDE ("def")),
+ ACE_TEXT_WIDE ("def"),
+ 3)
+ == 0);
+ ACE_ASSERT (ACE_OS::strstr (strstr1,
+ ACE_TEXT_WIDE ("mno")) == 0);
+
+ // ========================================================================
+ // Test strlen (wchar_t version)
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Testing strlen (wchar_t version)\n")));
+
+ const wchar_t *strlen1 = ACE_TEXT_WIDE ("");
+ const wchar_t *strlen2 = ACE_TEXT_WIDE ("12345");
+
+ ACE_ASSERT (ACE_OS::strlen (strlen1) == 0);
+ ACE_ASSERT (ACE_OS::strlen (strlen2) == 5);
+
+ // ========================================================================
+ // Test strpbrk (wchar_t version)
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Testing strpbrk (wchar_t version)\n")));
+
+ const wchar_t *strpbrk1 = ACE_TEXT_WIDE ("abcdefghijkabcdefghijk");
+
+ ACE_ASSERT (ACE_OS::strpbrk (strpbrk1, ACE_TEXT_WIDE ("ijkb"))
+ == strpbrk1 + 1);
+ ACE_ASSERT (ACE_OS::strpbrk (strpbrk1,
+ ACE_TEXT_WIDE ("mno")) == 0);
+
+ // ========================================================================
+ // Test strrchr (wchar_t version)
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Testing strrchr (wchar_t version)\n")));
+
+ const wchar_t *strrchr1 = ACE_TEXT_WIDE ("abcdefghijkabcdefghijk");
+
+ ACE_ASSERT (*ACE_OS::strrchr (strrchr1, ACE_TEXT_WIDE ('h'))
+ == ACE_TEXT_WIDE ('h'));
+ ACE_ASSERT (ACE_OS::strrchr (strrchr1, ACE_TEXT_WIDE ('h'))
+ == strrchr1 + 18);
+ ACE_ASSERT (ACE_OS::strrchr (strrchr1, ACE_TEXT_WIDE ('1'))
+ == NULL);
+
+ // ========================================================================
+ // Test strcasecmp (wchar_t version)
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Testing strcasecmp (wchar_t version)\n")));
+
+ const wchar_t *strcasecmp1 = ACE_TEXT_WIDE ("stringf");
+ const wchar_t *strcasecmp2 = ACE_TEXT_WIDE ("stringfe");
+ const wchar_t *strcasecmp3 = ACE_TEXT_WIDE ("stringg");
+ const wchar_t *strcasecmp4 = ACE_TEXT_WIDE ("STRINGF");
+ const wchar_t *strcasecmp5 = ACE_TEXT_WIDE ("stringe");
+
+ ACE_ASSERT (ACE_OS::strcasecmp (strcasecmp1, strcasecmp1) == 0);
+ ACE_ASSERT (ACE_OS::strcasecmp (strcasecmp1, strcasecmp2) < 0);
+ ACE_ASSERT (ACE_OS::strcasecmp (strcasecmp1, strcasecmp3) < 0);
+ ACE_ASSERT (ACE_OS::strcasecmp (strcasecmp1, strcasecmp4) == 0);
+ ACE_ASSERT (ACE_OS::strcasecmp (strcasecmp1, strcasecmp5) > 0);
+
+ // ========================================================================
+ // Test strncasecmp (wchar_t version)
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Testing strncasecmp (wchar_t version)\n")));
+
+ const wchar_t *strncasecmp1 = ACE_TEXT_WIDE ("stringf");
+ const wchar_t *strncasecmp2 = ACE_TEXT_WIDE ("stringfe");
+ const wchar_t *strncasecmp3 = ACE_TEXT_WIDE ("stringg");
+ const wchar_t *strncasecmp4 = ACE_TEXT_WIDE ("STRINGF");
+ const wchar_t *strncasecmp5 = ACE_TEXT_WIDE ("stringe");
+
+ ACE_ASSERT
+ (ACE_OS::strncasecmp (strncasecmp1, strncasecmp2, 7) == 0);
+ ACE_ASSERT
+ (ACE_OS::strncasecmp (strncasecmp1, strncasecmp2, 8) < 0);
+ ACE_ASSERT
+ (ACE_OS::strncasecmp (strncasecmp1, strncasecmp3, 7) < 0);
+ ACE_ASSERT
+ (ACE_OS::strncasecmp (strncasecmp1, strncasecmp4, 7) == 0);
+ ACE_ASSERT
+ (ACE_OS::strncasecmp (strncasecmp1, strncasecmp5, 7) > 0);
+
+ // ========================================================================
+ // Test strncmp (wchar_t version)
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Testing strncmp (wchar_t version)\n")));
+
+ const wchar_t *strncmp1 = ACE_TEXT_WIDE ("stringf");
+ const wchar_t *strncmp2 = ACE_TEXT_WIDE ("stringfe");
+ const wchar_t *strncmp3 = ACE_TEXT_WIDE ("stringg");
+ const wchar_t *strncmp4 = ACE_TEXT_WIDE ("STRINGF");
+ const wchar_t *strncmp5 = ACE_TEXT_WIDE ("stringe");
+
+ ACE_ASSERT (ACE_OS::strncmp (strncmp1, strncmp2, 7) == 0);
+ ACE_ASSERT (ACE_OS::strncmp (strncmp1, strncmp2, 8) < 0);
+ ACE_ASSERT (ACE_OS::strncmp (strncmp1, strncmp3, 7) < 0);
+ ACE_ASSERT (ACE_OS::strncmp (strncmp1, strncmp4, 7) != 0);
+ ACE_ASSERT (ACE_OS::strncmp (strncmp1, strncmp5, 7) > 0);
+
+ // ========================================================================
+ // Test strncpy (wchar_t version)
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Testing strncpy (wchar_t version)\n")));
+
+ wchar_t strncpy1[] = ACE_TEXT_WIDE ("abcdefghijklmnopqrstuvwxyzabc");
+ wchar_t strncpy2[27];
+
+ ACE_ASSERT
+ (ACE_OS::strncmp (ACE_OS::strncpy (strncpy2,
+ strncpy1,
+ 26),
+ strncpy1,
+ 26) == 0);
+
+ strncpy1[26] = 0;
+ strncpy2[26] = 0;
+ ACE_ASSERT (ACE_OS::strcmp (strncpy2, strncpy1) == 0);
+
+ // ========================================================================
+ // Test strtok (wchar_t version)
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Testing strtok (wchar_t version)\n")));
+ wchar_t strtok_r1[] = ACE_TEXT_WIDE ("A string of tokens");
+
+ ACE_ASSERT (ACE_OS::strcmp (ACE_OS::strtok (strtok_r1,
+ ACE_TEXT_WIDE (" ")),
+ ACE_TEXT_WIDE ("A")) == 0);
+ ACE_ASSERT (ACE_OS::strcmp (ACE_OS::strtok (0,
+ ACE_TEXT_WIDE (" ")),
+ ACE_TEXT_WIDE ("string") ) == 0);
+ ACE_ASSERT (ACE_OS::strcmp (ACE_OS::strtok (0,
+ ACE_TEXT_WIDE (" ")),
+ ACE_TEXT_WIDE ("of") ) == 0);
+ ACE_ASSERT (ACE_OS::strcmp (ACE_OS::strtok (0,
+ ACE_TEXT_WIDE (" ")),
+ ACE_TEXT_WIDE ("tokens") ) == 0);
+ ACE_ASSERT (ACE_OS::strtok (0, ACE_TEXT_WIDE (" ")) == 0);
+
+
+ }
+#endif /* ACE_HAS_WCHAR */
+
+ return 0;
+}
+
+
+static int
+ctime_r_test (void)
+{
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Testing ctime_r\n")));
+
+ int result = 0;
+
+ // test 'normal' buffer
+ ACE_TCHAR buf[27];
+ buf[26] = 'Z';
+
+ ACE_Time_Value cur_time =
+ ACE_OS::gettimeofday ();
+
+ time_t secs = cur_time.sec ();
+ if (ACE_OS::ctime_r (&secs, buf, 26) == 0)
+ {
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"),
+ ACE_TEXT ("ctime_r with 26 bytes")));
+ result = -1;
+ }
+ else if (buf[0] == '\0')
+ {
+ result = -1;
+
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("Truncated input buffer\n")));
+ }
+ else if (buf[26] != 'Z')
+ {
+ result = -1;
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("Wrote past end of input buffer\n")));
+ }
+
+ // test small buffer - should not do anything unless 3rd arg is at least 26.
+ if (result == 0)
+ {
+ ACE_TCHAR bufcheck[27];
+ ACE_OS::strcpy (bufcheck, buf);
+ if (ACE_OS::ctime_r (&secs, buf, 10) != 0)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("ctime_r with short len returned %s\n"),
+ buf));
+ result = -1;
+ }
+ else if (errno != ERANGE)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("ctime_r short; wrong error")));
+ result = -1;
+ }
+ // Make sure it didn't scribble
+ else if (ACE_OS::strcmp (buf, bufcheck) != 0)
+ {
+ result = -1;
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("ctime_r short; got %s, expected %s\n"),
+ buf, bufcheck));
+ }
+ }
+
+ return result;
+}
+
+
+int
+string_strsncpy_test (void)
+{
+ {
+ // Test strsncpy (char version)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Testing strsncpy (char version)\n")));
+
+ char strsncpy1[] = "abcdefghijklmnopqrstuvwxyzabc";
+ char strsncpy2[36];
+
+ // strsncpy() where the max. length doesn't matter
+ ACE_ASSERT
+ (ACE_OS::strcmp (ACE_OS::strsncpy (strsncpy2,
+ strsncpy1,
+ 36),
+ strsncpy1) == 0);
+
+ // strsncpy() where the max length does matter
+ ACE_ASSERT
+ (ACE_OS::strncmp (ACE_OS::strsncpy (strsncpy2,
+ strsncpy1,
+ 26),
+ strsncpy1,
+ 25) == 0);
+
+ // strsncpy1 and strsncpy2 are different size --> not equal
+ ACE_ASSERT (ACE_OS::strcmp (strsncpy2, strsncpy1) != 0);
+
+ // max. length == 2 --> 1 char available
+ ACE_ASSERT
+ (ACE_OS::strncmp (ACE_OS::strsncpy (strsncpy2,
+ strsncpy1,
+ 2),
+ strsncpy1,
+ 1) == 0);
+
+ // max length == 1 --> empty string
+ ACE_ASSERT
+ (ACE_OS::strlen (ACE_OS::strsncpy (strsncpy2,
+ strsncpy1,
+ 1)) == 0);
+
+ // just preparation for the next assert
+ ACE_ASSERT
+ (ACE_OS::strcmp (ACE_OS::strsncpy (strsncpy2,
+ strsncpy1,
+ 36),
+ strsncpy1) == 0);
+
+ // A tricky one, if the max. length == 0 --> do nothing
+ // so the strsncpy2 shouldn't change
+ ACE_ASSERT
+ (ACE_OS::strcmp (ACE_OS::strsncpy (strsncpy2,
+ "test",
+ 0),
+ strsncpy1) == 0);
+
+ // If src == dst --> truncate dst if needed!
+ ACE_ASSERT
+ (ACE_OS::strncmp (ACE_OS::strsncpy (strsncpy2,
+ strsncpy2,
+ 10),
+ strsncpy1,
+ 9) == 0);
+ // size should be 9 (+ '\0' char)
+ ACE_ASSERT(ACE_OS::strlen(strsncpy2) == 9);
+
+ }
+
+#if defined (ACE_HAS_WCHAR)
+ {
+ // Test strsncpy (wchar_t version)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Testing strsncpy (wchar_t version)\n")));
+
+ wchar_t strsncpy1[] = ACE_TEXT_WIDE ("abcdefghijklmnopqrstuvwxyzabc");
+ wchar_t strsncpy2[36];
+
+ // strsncpy() where the max. length doesn't matter
+ ACE_ASSERT
+ (ACE_OS::strcmp (ACE_OS::strsncpy (strsncpy2,
+ strsncpy1,
+ 36),
+ strsncpy1) == 0);
+
+ // strsncpy() where the max length does matter
+ ACE_ASSERT
+ (ACE_OS::strncmp (ACE_OS::strsncpy (strsncpy2,
+ strsncpy1,
+ 26),
+ strsncpy1,
+ 25) == 0);
+
+ // strsncpy1 and strsncpy2 are different size --> not equal
+ ACE_ASSERT (ACE_OS::strcmp (strsncpy2, strsncpy1) != 0);
+
+ // max. length == 2 --> 1 char available
+ ACE_ASSERT
+ (ACE_OS::strncmp (ACE_OS::strsncpy (strsncpy2,
+ strsncpy1,
+ 2),
+ strsncpy1,
+ 1) == 0);
+
+ // max length == 1 --> empty string
+ ACE_ASSERT
+ (ACE_OS::strlen (ACE_OS::strsncpy (strsncpy2,
+ strsncpy1,
+ 1)) == 0);
+
+ // just preparation for the next assert
+ ACE_ASSERT
+ (ACE_OS::strcmp (ACE_OS::strsncpy (strsncpy2,
+ strsncpy1,
+ 36),
+ strsncpy1) == 0);
+
+ // A tricky one, if the max. length == 0 --> do nothing
+ // so the strsncpy2 shouldn't change
+ ACE_ASSERT
+ (ACE_OS::strcmp (ACE_OS::strsncpy (strsncpy2,
+ ACE_TEXT_WIDE
+ ("test"),
+ 0),
+ strsncpy1) == 0);
+
+ // If src == dst --> truncate dst if needed!
+ ACE_ASSERT
+ (ACE_OS::strncmp (ACE_OS::strsncpy (strsncpy2,
+ strsncpy2,
+ 10),
+ strsncpy1,
+ 9) == 0);
+ // size should be 9 (+ '\0' char)
+ ACE_ASSERT(ACE_OS::strlen(strsncpy2) == 9);
+ }
+#endif /* ACE_HAS_WCHAR */
+
+ return 0;
+}
+
+
+// Test conversion between narrow and wide chars.
+int
+string_convert_test (void)
+{
+#if defined (ACE_HAS_WCHAR)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Testing narrow/wide string conversion\n")));
+
+ int result = 0;
+ const char *test1_n = "abcdefg";
+ const wchar_t *test1_w = ACE_TEXT_WIDE ("abcdefg");
+ const char *test2_n = "\xe9\xe8\xe0\xf9\xea";
+ const wchar_t *test2_w = ACE_TEXT_WIDE ("\xe9\xe8\xe0\xf9\xea");
+ wchar_t str_w[10];
+ char str_n[10];
+ ACE_OS::strcpy (str_w, ACE_Ascii_To_Wide (test1_n).wchar_rep ());
+ if (0 != ACE_OS::strcmp (test1_w, str_w))
+ {
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("Simple narrow->wide failed: ")
+ ACE_TEXT ("Expected \"%W\"; Got \"%W\"\n"), test1_w, str_w));
+ result = 1;
+ }
+ ACE_OS::strcpy (str_n, ACE_Wide_To_Ascii (test1_w).char_rep ());
+ if (0 != ACE_OS::strcmp (test1_n, str_n))
+ {
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("Simple wide->narrow failed: ")
+ ACE_TEXT ("Expected \"%C\"; Got \"%C\"\n"), test1_n, str_n));
+ result = 1;
+ }
+ ACE_OS::strcpy (str_w, ACE_Ascii_To_Wide (test2_n).wchar_rep ());
+ if (0 != ACE_OS::strcmp (test2_w, str_w))
+ {
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("Complex narrow->wide failed: ")
+ ACE_TEXT ("Expected \"%W\"; Got \"%W\"\n"), test2_w, str_w));
+ result = 1;
+ }
+ ACE_OS::strcpy (str_n, ACE_Wide_To_Ascii (test2_w).char_rep ());
+ if (0 != ACE_OS::strcmp (test2_n, str_n))
+ {
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("Complex wide->narrow failed: ")
+ ACE_TEXT ("Expected \"%C\"; Got \"%C\"\n"), test2_n, str_n));
+ result = 1;
+ }
+ return result;
+#else
+ return 0;
+#endif /* ACE_HAS_WCHAR */
+}
+
+// Test the methods for getting cpu info
+int
+cpu_info_test (void)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Testing cpu info methods\n")));
+
+ long number_processors = ACE_OS::num_processors();
+ long number_processors_online = ACE_OS::num_processors_online();
+
+ if (number_processors == -1)
+ {
+ ACE_ERROR ((LM_INFO,
+ ACE_TEXT ("number of processors not supported on ")
+ ACE_TEXT ("this platform\n")));
+ }
+ else
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("This system has %d processors\n"),
+ number_processors));
+ }
+
+ if (number_processors_online == -1)
+ {
+ ACE_ERROR ((LM_INFO,
+ ACE_TEXT ("number of processors online not supported on ")
+ ACE_TEXT ("this platform\n")));
+ }
+ else
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("This system has %d processors online\n"),
+ number_processors_online));
+ }
+
+ return 0;
+}
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("OS_Test"));
+
+ int status = 0;
+ int result;
+
+ if ((result = access_test ()) != 0)
+ status = result;
+
+ if ((result = rename_test ()) != 0)
+ status = result;
+
+ if ((result = string_emulation_test ()) != 0)
+ status = result;
+
+ if ((result = ctime_r_test ()) != 0)
+ status = result;
+
+ if ((result = string_strsncpy_test ()) != 0)
+ status = result;
+
+ if ((result = cpu_info_test ()) != 0)
+ status = result;
+
+ ACE_END_TEST;
+ return status;
+}
diff --git a/ACE/tests/Object_Manager_Test.cpp b/ACE/tests/Object_Manager_Test.cpp
new file mode 100644
index 00000000000..79cd94c8ccd
--- /dev/null
+++ b/ACE/tests/Object_Manager_Test.cpp
@@ -0,0 +1,119 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Object_Manager_Test.cpp
+//
+// = DESCRIPTION
+// Tests the basic functions of the ACE_Object_Manager.
+//
+// = AUTHOR
+// David L. Levine <levine@cs.wustl.edu>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/Object_Manager.h"
+#include "ace/OS_Memory.h"
+#include "ace/ACE.h"
+
+ACE_RCSID(tests, Object_Manager_Test, "$Id$")
+
+static u_int *ip;
+
+extern "C"
+void
+hook1 (void)
+{
+ delete ip;
+ ip = 0;
+}
+
+extern "C"
+void
+hook2 (void * /* object */, void *param)
+{
+ u_int *paramp = reinterpret_cast<u_int *> (param);
+
+ // We can use ACE_Log_Msg in an ACE_Object_Manager cleanup hook.
+ // But NOT in an ACE_OS::atexit () hook! However, the ACE_END_TEST
+ // invocation in main () will prevent this from being output to the
+ // log stream.
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("hook2: %d\n"),
+ *paramp));
+ delete paramp;
+}
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE::init ();
+
+ ACE_START_TEST (ACE_TEXT ("Object_Manager_Test"));
+
+ u_int errors = 0;
+
+ // If hook1 never gets called, this will show up as a memory leak.
+ ACE_NEW_RETURN (ip,
+ u_int,
+ -1);
+
+ const int starting_up =
+ ACE_Object_Manager::instance ()->starting_up ();
+ const int shutting_down =
+ ACE_Object_Manager::instance ()->shutting_down ();
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("starting_up: %d, shutting_down: %d\n"),
+ starting_up,
+ shutting_down));
+
+ if (starting_up || shutting_down)
+ {
+ ++errors;
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("starting_up and shutting_down are supposed to ")
+ ACE_TEXT (" be 0!!!!")));
+ }
+
+ if (ACE_OS::atexit (hook1) != 0)
+ {
+ ++errors;
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("ACE_OS::atexit () returned non-zero!!!!")));
+ }
+
+ for (u_int i = 0; i < 10; ++i)
+ {
+ u_int *paramp;
+ ACE_NEW_RETURN (paramp,
+ u_int,
+ -1);
+ *paramp = i;
+
+ // The first paramp argument is only used to distinguish the
+ // at_exit entries. The ACE_Object_Manager only allows one
+ // at_exit per object. It's not used in the hook.
+ if (ACE_Object_Manager::instance ()->at_exit (paramp,
+ hook2,
+ paramp))
+ {
+ ++errors;
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("ACE_Object_Manager::at_exit () ")
+ ACE_TEXT ("returned non-zero!!!!")));
+ }
+ }
+
+ ACE_END_TEST;
+ ACE::fini ();
+ return errors == 0 ? 0 : 1;
+}
diff --git a/ACE/tests/Obstack_Test.cpp b/ACE/tests/Obstack_Test.cpp
new file mode 100644
index 00000000000..e6539f32b3f
--- /dev/null
+++ b/ACE/tests/Obstack_Test.cpp
@@ -0,0 +1,116 @@
+// $Id$
+//
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Obtack_Test.cpp
+//
+// = DESCRIPTION
+// Checks the functionality of ACE_Obstack<T>
+//
+// = AUTHOR
+// Steve Huston <shuston@riverace.com>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/OS_NS_string.h"
+#include "ace/Obstack.h"
+#include "ace/Log_Msg.h"
+
+ACE_RCSID(tests, Obstack_Test, "$Id$")
+
+
+int run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("Obstack_Test"));
+
+ int errors = 0;
+ // For this test, the length of the ACE_Obstack must be larger than
+ // both of these strings, but less than their sum.
+ const ACE_TCHAR str1[] = ACE_TEXT ("Mary had a little lamb.");
+ const ACE_TCHAR str2[] = ACE_TEXT ("It's fleece was white as snow; but....");
+ ACE_Obstack_T<ACE_TCHAR> stack (sizeof (str1) + 1);
+
+ for (size_t i = 0; i < ACE_OS::strlen (str1); i++)
+ stack.grow_fast (str1[i]);
+
+ ACE_TCHAR *str = stack.freeze ();
+
+ if (str == 0)
+ {
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("freeze failed!\n")));
+ ++errors;
+ }
+ else if (ACE_OS::strcmp (str, str1) != 0)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT("Lost first string; expected: %s, have: %s\n"),
+ str1, str));
+ ++errors;
+ }
+
+ for (size_t j = 0; j < ACE_OS::strlen (str2); ++j)
+ stack.grow (str2[j]);
+
+ ACE_TCHAR* temp = stack.freeze();
+
+ if (temp == 0)
+ {
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("freeze failed!\n")));
+ ++errors;
+ }
+ else if (ACE_OS::strcmp (temp, str2) != 0)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT("Lost second string; expected: %s, have: %s\n"),
+ str2, temp));
+ ++errors;
+ }
+
+ for (size_t k = 0; k < ACE_OS::strlen (str1); ++k)
+ stack.grow (str1[k]);
+
+ ACE_TCHAR* tmp = stack.freeze ();
+ if (tmp == 0)
+ {
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("freeze failed!\n")));
+ ++errors;
+ }
+ else if (ACE_OS::strcmp (tmp, str1) != 0)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Lost third string; expected: %s, have: %s\n"),
+ str1, tmp));
+ ++errors;
+ }
+
+ stack.unwind (temp);
+
+ for (size_t l = 0; l < ACE_OS::strlen (str2); ++l)
+ stack.grow (str2[l]);
+
+ temp = stack.freeze();
+
+ if (temp == 0)
+ {
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("freeze failed!\n")));
+ ++errors;
+ }
+ else if (ACE_OS::strcmp (temp, str2) != 0)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Lost fourth string; expected: %s, have: %s\n"),
+ str2, temp));
+ ++errors;
+ }
+
+ if (!errors)
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Test ok\n")));
+
+ ACE_END_TEST;
+ return errors == 0 ? 0 : 1;
+}
diff --git a/ACE/tests/OrdMultiSet_Test.cpp b/ACE/tests/OrdMultiSet_Test.cpp
new file mode 100644
index 00000000000..689cbd7d13c
--- /dev/null
+++ b/ACE/tests/OrdMultiSet_Test.cpp
@@ -0,0 +1,220 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// OrdMultiSet_Test.cpp
+//
+// = DESCRIPTION
+// This is a simple test of the <ACE_Ordered_MultiSet> and
+// <ACE_Ordered_MultiSet_Iterator> class templates, instantiating
+// them with type int. No command line arguments are needed to run
+// the test.
+//
+// = AUTHOR
+// Chris Gill <cdgill@cs.wustl.edu>
+//
+// ============================================================================
+
+// Note, for this test the config.h file *must* come first!
+#include "ace/config-all.h"
+
+#include "test_config.h"
+#include "ace/Containers.h"
+
+ACE_RCSID(tests, OrdMultiSet_Test, "$Id$")
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ int ret = 0;
+ int *ptr = 0;
+
+ ACE_START_TEST (ACE_TEXT ("OrdMultiSet_Test"));
+
+ // make an empty set of int and an iterator
+ ACE_Ordered_MultiSet<int> set;
+ ACE_Ordered_MultiSet_Iterator<int> iter(set);
+
+ // Put in a range of odd ints, without an iterator.
+ int i;
+ for (i = -10; i < 10; ++i)
+ set.insert (2 * i + 1);
+
+ // Put in an interleaved range of even ints, using an iterator.
+ for (i = -10; i <= 10; ++i)
+ set.insert (2 * i, iter);
+
+ // Remove the first and last elements of range.
+ while (set.remove (-20) == 0);
+ while (set.remove (20) == 0);
+
+ // Should still have 39 elements in the set.
+ ACE_ASSERT (set.is_empty () == 0);
+ ACE_ASSERT (set.size () == 39);
+
+ // Iterate forward through the range we created: should be one of
+ // each.
+ iter.first ();
+ for (i = -19; i <= 19; ++i)
+ {
+ // we should still be in the set
+ ACE_ASSERT (iter.done () == 0);
+
+ // make sure the current element is what we expect
+ iter.next (ptr);
+ ACE_ASSERT (ptr != 0);
+ ACE_ASSERT (*ptr == i);
+
+ // move to the next element in the set
+ iter.advance ();
+ }
+
+ // We should have iterated through the entire set.
+ ACE_ASSERT (iter.done () != 0);
+
+ // Iterate backward through the range we created: should be one of
+ // each.
+ iter.last ();
+ for (i = 19; i >= -19; --i)
+ {
+ // We should still be in the set.
+ ACE_ASSERT (iter.done () == 0);
+
+ // Make sure the current element is what we expect.
+ int *ptr = 0;
+ iter.next (ptr);
+ ACE_ASSERT (ptr != 0);
+ ACE_ASSERT (*ptr == i);
+
+ // Move to the previous element in the set.
+ iter.retreat ();
+ }
+
+ // We should have iterated through the entire set.
+ ACE_ASSERT (iter.done () != 0);
+
+ // Iterate through the set and use the operator* to get the element
+ iter.first ();
+ for (i = -19; i <= 19; ++i)
+ {
+ // we should still be in the set
+ ACE_ASSERT (iter.done () == 0);
+
+ // make sure the current element is what we expect
+ int& l = *iter;
+ ACE_ASSERT (l == i);
+
+ // move to the next element in the set
+ iter.advance ();
+ }
+
+ // We should have iterated through the entire set.
+ ACE_ASSERT (iter.done () != 0);
+
+ // Clear the set, restart the iterator, and make sure the iterator
+ // is out of range at both ends, the set is empty, and a subsequent
+ // advance or retreat on an out of range iterator does not cause
+ // problems
+ set.reset ();
+ ACE_ASSERT (set.is_empty () != 0);
+ iter.first ();
+ ACE_ASSERT (iter.done () != 0);
+ iter.retreat ();
+ iter.last ();
+ ACE_ASSERT (iter.done () != 0);
+ iter.advance ();
+
+ // Put in a bunch of ints in various relative positions, using an
+ // iterator for the odds and no iterator for the evens.
+ set.insert (203, iter);
+ set.insert (202);
+ set.insert (204);
+ set.insert (201, iter);
+ set.insert (205, iter);
+
+ set.insert (203, iter);
+ set.insert (203, iter);
+
+ set.insert (204);
+ set.insert (204);
+ set.insert (204);
+ set.insert (205, iter);
+ set.insert (205, iter);
+ set.insert (205, iter);
+ set.insert (205, iter);
+ set.insert (202);
+
+ // remove the middle elements
+ while (set.remove (204) == 0);
+ while (set.remove (202) == 0);
+ while (set.remove (203) == 0);
+
+ // Put the iterator out of range and make sure it stays
+ // that way for finds on the missing elements.
+ iter.last ();
+ iter.advance ();
+ set.find (203, iter);
+ ACE_ASSERT (iter.done () != 0);
+ set.find (202, iter);
+ ACE_ASSERT (iter.done () != 0);
+ set.find (204, iter);
+ ACE_ASSERT (iter.done () != 0);
+
+ // Make sure the other elements can be found.
+ set.find (205, iter);
+ ACE_ASSERT (iter.done () == 0);
+ iter.next (ptr);
+ ACE_ASSERT (ptr != 0);
+ ACE_ASSERT (*ptr == 205);
+ set.find (201, iter);
+ ACE_ASSERT (iter.done () == 0);
+ iter.next (ptr);
+ ACE_ASSERT (ptr != 0);
+ ACE_ASSERT (*ptr == 201);
+
+ // Finally, iterate through the set and make sure its contents are
+ // correct (one 201 and five 205s).
+ iter.first ();
+ ACE_ASSERT (iter.done () == 0);
+ iter.next (ptr);
+ ACE_ASSERT (ptr != 0);
+ ACE_ASSERT (*ptr == 201);
+ iter.advance ();
+
+ for (i = 1; i <= 5; ++i)
+ {
+ // Should be in the set, able to access the element, value
+ // should be 205
+ ACE_ASSERT (iter.done () == 0);
+ iter.next (ptr);
+ ACE_ASSERT (ptr != 0);
+ ACE_ASSERT (*ptr == 205);
+
+ // Move to the next element in the set.
+ iter.advance ();
+ }
+
+ // Should not be anything else in the set.
+ ACE_ASSERT (iter.done () != 0);
+
+ // remove the rest
+ while (set.remove (205) == 0);
+ while (set.remove (201) == 0);
+
+ // Should have no more elements in the set.
+ ACE_ASSERT (set.is_empty () != 0);
+ ACE_ASSERT (set.size () == 0);
+ iter.first ();
+ ACE_ASSERT (iter.done () != 0);
+ iter.last ();
+ ACE_ASSERT (iter.done () != 0);
+
+ ACE_END_TEST;
+
+ return ret;
+}
+
diff --git a/ACE/tests/Pipe_Test.cpp b/ACE/tests/Pipe_Test.cpp
new file mode 100644
index 00000000000..bf722c921b9
--- /dev/null
+++ b/ACE/tests/Pipe_Test.cpp
@@ -0,0 +1,172 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Pipe_Test.cpp
+//
+// = DESCRIPTION
+// Tests the construction of multiple pipes in a process.
+//
+// = AUTHOR
+// Irfan Pyarali <irfan@cs.wustl.edu>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/Pipe.h"
+#include "ace/Process.h"
+#include "ace/Get_Opt.h"
+#include "ace/ACE.h"
+#include "ace/OS_NS_stdio.h"
+#include "ace/OS_NS_stdlib.h"
+#include "ace/OS_NS_unistd.h"
+
+ACE_RCSID(tests, Pipe_Test, "$Id$")
+
+// Indicates whether we should close the pipe or not.
+static int close_pipe = 1;
+
+// Indicates whether we're running as the child or the parent.
+static int child_process = 0;
+
+// Number of iterations to run the test.
+static int iterations = ACE_MAX_ITERATIONS;
+
+// Explain usage and exit.
+static void
+print_usage_and_die (void)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("usage: %n [-d (don't close pipes)] ")
+ ACE_TEXT ("[-c (child process)] [-i (iterations)] \n")));
+ ACE_OS::exit (1);
+}
+
+// Parse the command-line arguments and set options.
+
+static void
+parse_args (int argc, ACE_TCHAR *argv[])
+{
+ ACE_Get_Opt get_opt (argc, argv, ACE_TEXT("dci:"));
+
+ int c;
+
+ while ((c = get_opt ()) != -1)
+ switch (c)
+ {
+ case 'd':
+ close_pipe = 0;
+ break;
+ case 'c':
+ child_process = 1;
+ break;
+ case 'i':
+ iterations = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ default:
+ print_usage_and_die ();
+ break;
+ }
+}
+
+// Consolidate the ACE_Pipe initializations.
+
+static void
+open (ACE_Pipe &pipe,
+ const char *name)
+{
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("opening %C\n"), name));
+ int result = pipe.open ();
+
+ ACE_ASSERT (result != -1);
+ result = pipe.read_handle () != ACE_INVALID_HANDLE
+ && pipe.write_handle () != ACE_INVALID_HANDLE;
+ ACE_ASSERT (result == 1);
+
+ if (close_pipe)
+ pipe.close ();
+}
+
+int
+run_main (int argc, ACE_TCHAR *argv[])
+{
+ parse_args (argc, argv);
+
+ if (child_process)
+ {
+ ACE_APPEND_LOG (ACE_TEXT("Pipe_Test-children"));
+ ACE_Pipe a, b, c, d, e;
+
+ open (a, "a");
+ open (b, "b");
+ open (c, "c");
+ open (d, "d");
+ open (e, "e");
+
+ ACE_END_LOG;
+ }
+ else
+ {
+ ACE_START_TEST (ACE_TEXT("Pipe_Test"));
+ ACE_INIT_LOG (ACE_TEXT("Pipe_Test-children"));
+
+# if defined (ACE_WIN32) || !defined (ACE_USES_WCHAR)
+ const ACE_TCHAR *cmdline_fmt = ACE_TEXT ("%s -c%s");
+# else
+ const ACE_TCHAR *cmdline_fmt = ACE_TEXT ("%ls -c%ls");
+# endif /* ACE_WIN32 || !ACE_USES_WCHAR */
+ ACE_Process_Options options;
+ options.command_line (cmdline_fmt,
+ argv[0],
+ close_pipe == 0 ? ACE_TEXT (" -d") : ACE_TEXT (""));
+
+ ACE_exitcode status = 0;
+
+ for (int i = 0; i < ::iterations; i++)
+ {
+ ACE_Process server;
+
+ if (server.spawn (options) == -1)
+ {
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("spawn failed")),
+ -1);
+ }
+ else
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Server forked with pid = %d.\n"),
+ server.getpid ()));
+ }
+
+ // Wait for the process we just created to exit.
+ server.wait (&status);
+
+ // Check if child exited without error.
+ if (WIFEXITED (status) != 0
+ && WEXITSTATUS (status) != 0)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Child of server %d finished with error ")
+ ACE_TEXT ("exit status %d\n"),
+ server.getpid (),
+ WEXITSTATUS (status)));
+
+ ACE_END_TEST;
+
+ exit (WEXITSTATUS (status));
+ }
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Server %d finished\n"),
+ server.getpid ()));
+ }
+ ACE_END_TEST;
+ }
+
+ return 0;
+}
diff --git a/ACE/tests/Priority_Buffer_Test.cpp b/ACE/tests/Priority_Buffer_Test.cpp
new file mode 100644
index 00000000000..dbb9b27046c
--- /dev/null
+++ b/ACE/tests/Priority_Buffer_Test.cpp
@@ -0,0 +1,182 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Priority_Buffer_Test.cpp
+//
+// = DESCRIPTION
+// This is a simple test to illustrate the priority mechanism of
+// <ACE_Message_Queue>s. The producer uses an <ACE_Message_Queue>
+// to enqueue a bunch of messages with different priorities which
+// are then dequeued by the consumer.
+//
+// = AUTHOR
+// Prashant Jain <pjain@cs.wustl.edu> and
+// Douglas C. Schmidt <schmidt@cs.wustl.edu>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/Message_Queue.h"
+#include "ace/Thread_Manager.h"
+
+ACE_RCSID(tests, Priority_Buffer_Test, "$Id$")
+
+#if defined (ACE_HAS_THREADS)
+
+static const char ACE_ALPHABET[] = "abcdefghijklmnopqrstuvwxyz";
+
+// Global message count.
+static int count = 0;
+
+// Make the queue be capable of being *very* large.
+static const long max_queue = LONG_MAX;
+
+// The consumer dequeues a message from the ACE_Message_Queue, writes
+// the message to the stderr stream, and deletes the message. The
+// producer sends a 0-sized message to inform the consumer to stop
+// reading and exit.
+
+static void *
+consumer (void *args)
+{
+ ACE_Message_Queue<ACE_MT_SYNCH> *msg_queue =
+ reinterpret_cast<ACE_Message_Queue<ACE_MT_SYNCH> *> (args);
+
+ u_long cur_priority = 27;
+ ACE_UNUSED_ARG (cur_priority);
+ // To suppress ghs warning about unused local variable
+ // "cur_priority".
+
+ int local_count = 0;
+
+ // Keep looping, reading a message out of the queue, until we get a
+ // message with a length == 0, which signals us to quit.
+ for (char c = 'z'; ; c--)
+ {
+ ACE_Message_Block *mb = 0;
+
+ int result = msg_queue->dequeue_head (mb);
+
+ if (result == -1)
+ break;
+
+ local_count++;
+
+ size_t length = mb->length ();
+
+ if (length > 0)
+ {
+ // This isn't a "shutdown" message, so process it
+ // "normally."
+ ACE_ASSERT (c == *mb->rd_ptr ());
+ ACE_ASSERT (mb->msg_priority () < cur_priority);
+ cur_priority = mb->msg_priority ();
+ }
+
+ // Free up the buffer memory and the Message_Block. Note that
+ // the destructor of Message Block will delete the the actual
+ // buffer.
+ mb->release ();
+
+ if (length == 0)
+ // This was a "shutdown" message, so break out of the loop.
+ break;
+ }
+
+ ACE_ASSERT (local_count == count);
+ return 0;
+}
+
+// The producer reads data from the stdin stream, creates a message,
+// and then queues the message in the message list, where it is
+// removed by the consumer thread. A 0-sized message is enqueued when
+// there is no more data to read. The consumer uses this as a flag to
+// know when to exit.
+
+static void *
+producer (void *args)
+{
+ ACE_Message_Queue<ACE_MT_SYNCH> *msg_queue =
+ reinterpret_cast<ACE_Message_Queue<ACE_MT_SYNCH> *> (args);
+
+ ACE_Message_Block *mb;
+
+ for (const char *c = ACE_ALPHABET; *c != '\0'; c++)
+ {
+ count++;
+
+ // Allocate a new message
+
+ ACE_NEW_RETURN (mb,
+ ACE_Message_Block (1),
+ 0);
+ *mb->wr_ptr () = *c;
+
+ // Set the priority.
+ mb->msg_priority (count);
+ mb->wr_ptr (1);
+
+ // Enqueue in priority order.
+ if (msg_queue->enqueue_prio (mb) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%t) %p\n"),
+ ACE_TEXT ("put_next")),
+ 0);
+ }
+
+ // Now send a 0-sized shutdown message to the other thread
+ ACE_NEW_RETURN (mb,
+ ACE_Message_Block ((size_t) 0),
+ 0);
+
+ if (msg_queue->enqueue_tail (mb) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%t) %p\n"),
+ ACE_TEXT ("put_next")));
+
+ count++;
+
+ // Now read all the items out in priority order (i.e., ordered by
+ // the size of the lines!).
+ consumer (msg_queue);
+
+ return 0;
+}
+
+#endif /* ACE_HAS_THREADS */
+
+// Spawn off one thread that copies stdin to stdout in order of the
+// size of each line.
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("Priority_Buffer_Test"));
+
+#if defined (ACE_HAS_THREADS)
+ // Message queue.
+ ACE_Message_Queue<ACE_MT_SYNCH> msg_queue (max_queue);
+
+ if (ACE_Thread_Manager::instance ()->spawn
+ (ACE_THR_FUNC (producer),
+ (void *) &msg_queue,
+ THR_NEW_LWP | THR_DETACHED) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("spawn")),
+ 1);
+
+ // Wait for producer and consumer threads to exit.
+ ACE_Thread_Manager::instance ()->wait ();
+#else
+ ACE_ERROR ((LM_INFO,
+ ACE_TEXT ("threads not supported on this platform\n")));
+#endif /* ACE_HAS_THREADS */
+ ACE_END_TEST;
+ return 0;
+}
diff --git a/ACE/tests/Priority_Reactor_Test.cpp b/ACE/tests/Priority_Reactor_Test.cpp
new file mode 100644
index 00000000000..b790b78b21c
--- /dev/null
+++ b/ACE/tests/Priority_Reactor_Test.cpp
@@ -0,0 +1,397 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Priority_Reactor_Test.cpp
+//
+// = DESCRIPTION
+// This is a test of the <ACE_Priority_Reactor>. The test forks
+// two processes (for a total of three processes) which connect to
+// the main process and The clients send data to a connector,
+// interestingly enough the acceptor will give more priority to
+// the second connection, which should run always before the first
+// one.
+//
+// The test itself is interesting, it shows how to write very
+// simple <ACE_Svc_Handler>, <ACE_Connectors> and <ACE_Acceptors>.
+//
+// = AUTHOR
+// Carlos O'Ryan <coryan@cs.wustl.edu>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/Get_Opt.h"
+#include "ace/SOCK_Connector.h"
+#include "ace/SOCK_Acceptor.h"
+#include "ace/Acceptor.h"
+#include "ace/Handle_Set.h"
+#include "ace/Connector.h"
+#include "ace/Auto_Ptr.h"
+#include "ace/Priority_Reactor.h"
+#include "Priority_Reactor_Test.h"
+#include "ace/OS_NS_sys_wait.h"
+#include "ace/OS_NS_unistd.h"
+
+ACE_RCSID(tests, Priority_Reactor_Test, "$Id$")
+
+static const char ACE_ALPHABET[] = "abcdefghijklmnopqrstuvwxyz";
+
+// The number of children to run, it can be changed using the -c
+// option.
+static int opt_nchildren = 10;
+
+// The number of loops per children, it can be changed using the -l
+// option.
+static int opt_nloops = 200;
+
+// If not set use the normal reactor, it can be changed using the -d
+// option.
+static int opt_priority_reactor = 1;
+
+// Maximum time to wait for the test termination (-t)
+static int opt_max_duration = 60;
+
+// Maximum number of retries to connect, it can be changed using the
+// -m option.
+static int max_retries = 5;
+
+typedef ACE_Connector<Write_Handler, ACE_SOCK_CONNECTOR>
+ CONNECTOR;
+typedef ACE_Acceptor<Read_Handler, ACE_SOCK_ACCEPTOR>
+ ACCEPTOR;
+
+int Read_Handler::waiting_ = 0;
+int Read_Handler::started_ = 0;
+
+void
+Read_Handler::set_countdown (int nchildren)
+{
+ Read_Handler::waiting_ = nchildren;
+}
+
+int
+Read_Handler::get_countdown (void)
+{
+ return Read_Handler::waiting_;
+}
+
+int
+Read_Handler::open (void *)
+{
+ if (this->peer ().enable (ACE_NONBLOCK) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Read_Handler::open, ")
+ ACE_TEXT ("cannot set non blocking mode")),
+ -1);
+
+ if (reactor ()->register_handler (this, READ_MASK) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Read_Handler::open, ")
+ ACE_TEXT ("cannot register handler")),
+ -1);
+
+ // A number larger than the actual number of priorities, so some
+ // clients are misbehaved, hence pusnished.
+ const int max_priority = 15;
+
+ this->priority (ACE_Event_Handler::LO_PRIORITY + started_ % max_priority);
+ started_++;
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) created svc_handler for handle %d ")
+ ACE_TEXT ("with priority %d\n"),
+ get_handle (),
+ priority ()));
+ return 0;
+}
+
+int
+Read_Handler::handle_input (ACE_HANDLE h)
+{
+ // ACE_DEBUG((LM_DEBUG,
+ // "(%P|%t) Read_Handler::handle_input (%d)\n", h));
+ ACE_UNUSED_ARG (h);
+
+ char buf[BUFSIZ];
+
+ ssize_t result = this->peer ().recv (buf, sizeof (buf));
+
+ if (result <= 0)
+ {
+ if (result < 0 && errno == EWOULDBLOCK)
+ return 0;
+
+ if (result != 0)
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) %p\n"),
+ ACE_TEXT ("Read_Handler::handle_input")));
+ waiting_--;
+
+ if (waiting_ == 0)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Last svc_handler closed, shutting down\n")));
+ ACE_Reactor::instance()->end_reactor_event_loop();
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Read_Handler::handle_input closing down\n")));
+ return -1;
+ }
+
+ // ACE_DEBUG((LM_DEBUG,
+ // "(%P|%t) read %d bytes from handle %d, priority %d\n",
+ // result, h, priority ()));
+ return 0;
+}
+
+int
+Write_Handler::open (void *)
+{
+ return 0;
+}
+
+int
+Write_Handler::svc (void)
+{
+ // Send several short messages, doing pauses between each message.
+ // The number of messages can be controlled from the command line.
+ ACE_Time_Value pause (0, 1000);
+
+ for (int i = 0; i < opt_nloops; ++i)
+ {
+ if (this->peer ().send_n (ACE_ALPHABET,
+ sizeof (ACE_ALPHABET) - 1) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n"),
+ ACE_TEXT ("send_n")));
+ ACE_OS::sleep (pause);
+ }
+
+ return 0;
+}
+
+#if !defined (ACE_LACKS_FORK) || defined (ACE_HAS_THREADS)
+
+// Execute the client tests.
+static void *
+client (void *arg)
+{
+ ACE_INET_Addr *connection_addr =
+ reinterpret_cast<ACE_INET_Addr *> (arg);
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) running client\n")));
+ CONNECTOR connector;
+
+ Write_Handler *writer = 0;
+
+ // Do exponential backoff connections
+ ACE_Synch_Options options = ACE_Synch_Options::synch;
+
+ // Start with one msec timeouts.
+ ACE_Time_Value msec (0, 1000);
+ options.timeout (msec);
+
+ // Try up to <max_retries> to connect to the server.
+ for (int i = 0; i < max_retries; i++)
+ {
+ if (connector.connect (writer,
+ *connection_addr,
+ options) == -1)
+ {
+ // Double the timeout...
+ ACE_Time_Value tmp = options.timeout ();
+ tmp += options.timeout ();
+ options.timeout (tmp);
+ writer = 0;
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) still trying to connect\n")));
+ }
+ else
+ {
+ // Let the new Svc_Handler to its job...
+ writer->svc ();
+
+ // then close the connection and release the Svc_Handler.
+ writer->destroy ();
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) finishing client\n")));
+ return 0;
+ }
+ }
+
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) failed to connect after %d retries\n"),
+ max_retries));
+ return 0;
+}
+
+#endif
+
+int
+run_main (int argc, ACE_TCHAR *argv[])
+{
+ ACE_START_TEST (ACE_TEXT ("Priority_Reactor_Test"));
+
+ ACE_Get_Opt getopt (argc, argv, ACE_TEXT ("dc:l:m:t:"));
+
+ for (int c; (c = getopt ()) != -1; )
+ switch (c)
+ {
+ case 'd':
+ opt_priority_reactor = 0;
+ break;
+ case 'c':
+ opt_nchildren = ACE_OS::atoi (getopt.opt_arg ());
+ break;
+ case 'l':
+ opt_nloops = ACE_OS::atoi (getopt.opt_arg ());
+ break;
+ case 'm':
+ max_retries = ACE_OS::atoi (getopt.opt_arg ());
+ break;
+ case 't':
+ opt_max_duration = ACE_OS::atoi (getopt.opt_arg ());
+ break;
+ case '?':
+ default:
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("Usage: Priority_Reactor_Test ")
+ ACE_TEXT (" [-d] (disable priority reactor)\n")
+ ACE_TEXT (" [-c nchildren] (number of threads/processes)\n")
+ ACE_TEXT (" [-l loops] (number of loops per child)\n")
+ ACE_TEXT (" [-m maxretries] (attempts to connect)\n")
+ ACE_TEXT (" [-t max_time] (limits test duration)\n")),
+ -1);
+ ACE_NOTREACHED (break);
+ }
+
+ // Manage Reactor memory automagically.
+ // Note: If opt_priority_reactor is false, the default ACE_Reactor is used
+ // and we don't need to set one up.
+ ACE_Reactor *orig_reactor = 0;
+ auto_ptr<ACE_Reactor> reactor;
+
+ if (opt_priority_reactor)
+ {
+ ACE_Select_Reactor *impl_ptr;
+ ACE_NEW_RETURN (impl_ptr, ACE_Priority_Reactor, -1);
+ auto_ptr<ACE_Select_Reactor> auto_impl (impl_ptr);
+
+ ACE_Reactor *reactor_ptr;
+ ACE_NEW_RETURN (reactor_ptr, ACE_Reactor (impl_ptr, 1), -1);
+ auto_impl.release (); // ACE_Reactor dtor will take it from here
+ auto_ptr<ACE_Reactor> auto_reactor (reactor_ptr);
+ reactor = auto_reactor;
+ orig_reactor = ACE_Reactor::instance (reactor_ptr);
+ }
+
+ Read_Handler::set_countdown (opt_nchildren);
+
+ // Acceptor
+ ACCEPTOR acceptor;
+
+ acceptor.priority (ACE_Event_Handler::HI_PRIORITY);
+ ACE_INET_Addr server_addr;
+
+ // Bind acceptor to any port and then find out what the port was.
+ if (acceptor.open (ACE_sap_any_cast (const ACE_INET_Addr &)) == -1
+ || acceptor.acceptor ().get_local_addr (server_addr) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n"),
+ ACE_TEXT ("open")),
+ -1);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) starting server at port %d\n"),
+ server_addr.get_port_number ()));
+
+ ACE_INET_Addr connection_addr (server_addr.get_port_number (),
+ ACE_DEFAULT_SERVER_HOST);
+
+ int i;
+
+#if defined (ACE_HAS_THREADS)
+ for (i = 0; i < opt_nchildren; ++i)
+ {
+ if (ACE_Thread_Manager::instance ()->spawn
+ (ACE_THR_FUNC (client),
+ (void *) &connection_addr,
+ THR_NEW_LWP | THR_DETACHED) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n%a"),
+ ACE_TEXT ("thread create failed"),
+ 1));
+ }
+#elif !defined (ACE_LACKS_FORK)
+ for (i = 0; i < opt_nchildren; ++i)
+ {
+ switch (ACE_OS::fork ("child"))
+ {
+ case -1:
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n%a"),
+ ACE_TEXT ("fork failed"),
+ 1));
+ exit (-1);
+ /* NOTREACHED */
+ case 0:
+ client (&connection_addr);
+ exit (0);
+ break;
+ /* NOTREACHED */
+ default:
+ break;
+ /* NOTREACHED */
+ }
+ }
+#else
+ ACE_ERROR ((LM_INFO,
+ ACE_TEXT ("(%P|%t) ")
+ ACE_TEXT ("only one thread may be run ")
+ ACE_TEXT ("in a process on this platform\n")));
+#endif /* ACE_HAS_THREADS */
+
+ ACE_Time_Value tv (opt_max_duration);
+
+ ACE_Reactor::instance()->register_handler
+ (&acceptor, ACE_Event_Handler::READ_MASK);
+ ACE_Reactor::instance()->run_reactor_event_loop (tv);
+
+ if (Read_Handler::get_countdown () != 0)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) running out of time, ")
+ ACE_TEXT ("probably due to failed connections.\n")));
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) waiting for the children...\n")));
+
+#if defined (ACE_HAS_THREADS)
+ ACE_Thread_Manager::instance ()->wait ();
+#elif !defined (ACE_WIN32) && !defined (VXWORKS) && !defined (ACE_PSOS)
+ for (i = 0; i < opt_nchildren; ++i)
+ {
+ pid_t pid = ACE_OS::wait();
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) child %d terminated\n"),
+ pid));
+ }
+#else
+ /* NOTREACHED */
+ // We aborted on the previous #ifdef
+#endif /* ACE_HAS_THREADS */
+
+ if (orig_reactor != 0)
+ ACE_Reactor::instance (orig_reactor);
+
+ ACE_END_TEST;
+ return 0;
+}
+
diff --git a/ACE/tests/Priority_Reactor_Test.h b/ACE/tests/Priority_Reactor_Test.h
new file mode 100644
index 00000000000..fdf17865448
--- /dev/null
+++ b/ACE/tests/Priority_Reactor_Test.h
@@ -0,0 +1,76 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Priority_Reactor_Test.h
+//
+// = DESCRIPTION
+// This class gets its own header file to work around AIX C++
+// compiler "features" related to template instantiation... It is
+// only used by Priority_Reactor_Test.cpp.
+//
+// = AUTHOR
+// Carlos O'Ryan <coryan@cs.wustl.edu>
+//
+// ============================================================================
+
+#ifndef ACE_TESTS_PRIORITY_REACTOR_TEST_H
+#define ACE_TESTS_PRIORITY_REACTOR_TEST_H
+
+#include "ace/Service_Config.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "ace/SOCK_Stream.h"
+#include "ace/Svc_Handler.h"
+
+class Read_Handler : public ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_SYNCH>
+ // = TITLE
+ // A Svc_Handler with a priority twist.
+ //
+ // = DESCRIPTION
+ // This Svc_Handler receives the data sent by the childs or writer
+ // threads; each one sets it own priority to a new level, in a
+ // cyclic manner. The main point is test and exercise the
+ // priority dispatching features of ACE_Priority_Reactor.
+{
+public:
+ static void set_countdown (int nchildren);
+ // Set the number of children or writer threads we will be running,
+ // when they are all gone we terminate the reactor loop.
+
+ static int get_countdown (void);
+ // Get the number of children we are still waiting for.
+
+ virtual int open (void *);
+ virtual int handle_input (ACE_HANDLE h);
+ // The Svc_Handler callbacks.
+
+private:
+ static int waiting_;
+ // How many writers are we waiting for.
+
+ static int started_;
+ // How many readers have started.
+};
+
+class Write_Handler : public ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_SYNCH>
+ // = TITLE
+ // A simple writer.
+ //
+ // = DESCRIPTION
+ // This Svc_Handler simply connects to a server and sends some
+ // output to it. Its purpose is to feed the test.
+{
+public:
+ virtual int open (void *);
+ virtual int svc (void);
+};
+
+#endif /* ACE_TESTS_PRIORITY_REACTOR_TEST_H */
diff --git a/ACE/tests/Priority_Task_Test.cpp b/ACE/tests/Priority_Task_Test.cpp
new file mode 100644
index 00000000000..3c4cf5c7bd6
--- /dev/null
+++ b/ACE/tests/Priority_Task_Test.cpp
@@ -0,0 +1,251 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Priority_Task_Test.cpp
+//
+// = DESCRIPTION
+// This is a simple test to illustrate the priority mechanism of
+// ACE Tasks. The test requires no options, but the -d option
+// enables LM_DEBUG output.
+//
+// = AUTHOR
+// Carlos O'Ryan <coryan@cs.wustl.edu>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/Task.h"
+#include "ace/Sched_Params.h"
+#include "ace/OS_NS_errno.h"
+#include "ace/OS_NS_string.h"
+
+ACE_RCSID(tests, Priority_Task_Test, "$Id$")
+
+static const ACE_TCHAR *usage = ACE_TEXT ("usage: %s [-d]\n");
+
+#if defined (ACE_HAS_THREADS)
+
+class Priority_Task : public ACE_Task<ACE_MT_SYNCH>
+{
+ // = TITLE
+ // A simple Task that runs itself a different priorities.
+ //
+ // = DESCRIPTION
+ // This task uses the void* argument on open to run the svc()
+ // method at a different priority. The point is execise the thread
+ // priority features of ACE.
+public:
+ Priority_Task (void);
+ // The constructor
+
+ int open (void *);
+ // Receives the priority and run svc() on a separate thread at that
+ // priority.
+
+ int svc (void);
+ // Runs on a separate thread an checks the priority.
+
+ int succeeded (void) { return error_ == 0; }
+ // Returns 1 if priority was set properly, 0 otherwise.
+
+private:
+ int priority_;
+ u_int error_;
+};
+
+Priority_Task::Priority_Task (void)
+ : ACE_Task<ACE_MT_SYNCH> (ACE_Thread_Manager::instance ()),
+ priority_ (0),
+ error_ (0)
+{
+}
+
+int
+Priority_Task::open (void *arg)
+{
+ this->priority_ = *(int *) arg;
+
+ long flags = THR_NEW_LWP;
+
+ // To get FIFO scheduling with PTHREADS.
+ ACE_SET_BITS (flags,
+ THR_SCHED_FIFO);
+
+ // Become an active object.
+ if (this->activate (flags,
+ 1,
+ 0,
+ this->priority_) == -1)
+ {
+ // On Linux, for example, only the superuser can set the policy
+ // to other than ACE_SCHED_OTHER. But with ACE_SCHED_OTHER,
+ // there is only one thread priority value, for example, 0. So,
+ // let the superuser run an interesting test, but for other
+ // users use the minimum ACE_SCHED_OTHER thread priority.
+
+ long fallback_priority =
+ ACE_Sched_Params::priority_min (ACE_SCHED_OTHER,
+ ACE_SCOPE_THREAD);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) task activation at priority %d with ")
+ ACE_TEXT ("flags 0x%X failed; retry at priority %d with ")
+ ACE_TEXT ("flags 0x%X (errno is %d%p)\n"),
+ this->priority_,
+ flags,
+ fallback_priority,
+ THR_NEW_LWP,
+ errno,
+ ACE_TEXT ("")));
+
+ flags = THR_NEW_LWP;
+ this->priority_ = fallback_priority;
+
+ if (this->activate (flags,
+ 1,
+ 1,
+ this->priority_) == -1)
+ {
+#if !defined (ACE_HAS_WINCE)
+ if (ACE_OS::last_error () == EPERM)
+ ACE_ERROR_RETURN ((LM_INFO,
+ ACE_TEXT ("Insufficient privilege to run this test.\n")),
+ -1);
+ else
+#endif // ACE_HAS_WINCE
+ ACE_DEBUG ((LM_ERROR,
+ ACE_TEXT ("(%t) task activation at priority %d failed, ")
+ ACE_TEXT ("exiting!\n%a"),
+ this->priority_,
+ -1));
+ }
+ }
+ return 0;
+}
+
+int
+Priority_Task::svc (void)
+{
+ ACE_hthread_t thr_handle;
+ ACE_Thread::self (thr_handle);
+ int prio;
+
+ if (ACE_Thread::getprio (thr_handle, prio) == -1)
+ {
+ if (errno == ENOTSUP)
+ {
+ ACE_DEBUG((LM_DEBUG,
+ ACE_TEXT ("getprior not supported on this platform\n")
+ ));
+ return 0;
+ }
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("getprio failed")),
+ -1);
+ }
+
+ if (prio == this->priority_)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) actual prio of %d equals desired priority\n"),
+ prio));
+ else
+ {
+ ACE_DEBUG ((LM_ERROR,
+ ACE_TEXT ("(%t) actual prio = %d, desired priority_ = %d!\n"),
+ prio,
+ this->priority_));
+ ++error_;
+ }
+
+ return 0;
+}
+
+#endif /* ACE_HAS_THREADS */
+
+int
+run_main (int argc, ACE_TCHAR *argv[])
+{
+ ACE_START_TEST (ACE_TEXT ("Priority_Task_Test"));
+
+ if (argc <= 1)
+ // Disable LM_DEBUG messages.
+ ACE_Log_Msg::instance ()->priority_mask
+ (ACE_Log_Msg::instance ()->priority_mask () &~ LM_DEBUG);
+ else if (argc == 2)
+ {
+ if (ACE_OS::strcmp (argv[1],
+ ACE_TEXT ("-d")) != 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ usage,
+ argv [0]),
+ -1);
+ // else -d option: don't disable LM_DEBUG messages
+ }
+ else
+ ACE_ERROR_RETURN ((LM_ERROR,
+ usage,
+ argv [0]),
+ -1);
+
+ int status = 0;
+
+#if defined (ACE_HAS_THREADS)
+
+ Priority_Task tasks[ACE_MAX_ITERATIONS];
+
+ size_t i;
+
+ // Spawn off ACE_MAX_ITERATIONS of tasks, passing each one their
+ // iteration number as their priority.
+
+ // NOTE: on Solaris, for example, this requests the min FIFO
+ // priority. But, this test doesn't use the Realtime scheduling
+ // class. The FIFO priorities are used because they're all
+ // nonnegative.
+
+ ACE_Sched_Priority_Iterator priority (ACE_SCHED_FIFO,
+ ACE_SCOPE_THREAD);
+
+ for (i = 0; i < ACE_MAX_ITERATIONS; i++)
+ {
+ int p = priority.priority ();
+ if (tasks[i].open ((void *) &p) == -1)
+ break; // Out of enclosing loop.
+
+ // If there are more priorities get the next one...
+ if (priority.more ())
+ priority.next ();
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) %d tasks spawned, wait for them to exit . . .\n"),
+ ACE_MAX_ITERATIONS));
+
+ // Wait for all tasks to exit.
+ ACE_Thread_Manager::instance ()->wait ();
+
+ for (i = 0; i < ACE_MAX_ITERATIONS; i++)
+ if (!tasks[i].succeeded ())
+ {
+ ++status;
+ break;
+ }
+
+#else
+ ACE_ERROR ((LM_DEBUG,
+ ACE_TEXT ("threads not supported on this platform\n")));
+#endif /* ACE_HAS_THREADS */
+
+ // Re-enable LM_DEBUG messages.
+ ACE_Log_Msg::instance ()->priority_mask
+ (ACE_Log_Msg::instance ()->priority_mask () | LM_DEBUG);
+
+ ACE_END_TEST;
+ return status;
+}
diff --git a/ACE/tests/Proactor_Scatter_Gather_Test.cpp b/ACE/tests/Proactor_Scatter_Gather_Test.cpp
new file mode 100644
index 00000000000..a3cbb335a34
--- /dev/null
+++ b/ACE/tests/Proactor_Scatter_Gather_Test.cpp
@@ -0,0 +1,1485 @@
+// $Id$
+
+// ============================================================================
+/**
+ * @file Proactor_Scatter_Gather_Test.cpp
+ *
+ * The test runs on a single thread, and involves a single Sender,
+ * two Receivers and a single Writer. The Sender async-reads
+ * (scattered) from a file into chunks of <page size>. It
+ * async-sends (gathered) the odd chunks to the first receiver over a
+ * stream, and the even chunks to the second receiver over a
+ * different stream. The receivers async-read (scattered) from the
+ * socket streams into chunks in size of <page size>, and convey the
+ * data to the Writer. The Writer reconstructs the file using
+ * async-write (gathered). Then, the reconstructed file is compared
+ * to the original file to determine test success. So, It covers both
+ * async scatter/gather stream I/O and async scatter/gather file I/O.
+ * The wire transfer protocol is very naive (and totally non
+ * reliable...) - when both connections are closed, EOF is assumed.
+ * The test can be also run in a seperated sender and receiver mode,
+ * to test real network influences.
+ *
+ * This test is based upon some building blocks taken from the
+ * Proactor_Test.cpp.
+ *
+ * @author Edan Ayal <edanayal@yahoo.com> */
+// ============================================================================
+
+#include "test_config.h"
+
+#if ((defined (ACE_HAS_WINNT4) && (ACE_HAS_WINNT4 != 0)) && !defined (ACE_HAS_WINCE))
+ // This currently only works on Win32 platforms (NT SP2 and above).
+ // Support for Unix platforms supporting POSIX aio calls should be added in future.
+
+#include "ace/Get_Opt.h"
+
+#include "ace/Proactor.h"
+#include "ace/Asynch_Acceptor.h"
+#include "ace/Asynch_Connector.h"
+#include "ace/Mem_Map.h"
+#include "ace/Min_Max.h"
+#include "ace/OS_NS_math.h"
+#include "ace/OS_NS_sys_stat.h"
+#include "ace/OS_NS_fcntl.h"
+#include "ace/OS_NS_unistd.h"
+
+#include "ace/SOCK_Connector.h"
+
+// For the Acceptor/Connector handlers maintenance lists
+static const int SENDERS = 1;
+static const int RECEIVERS = 2;
+
+// Port that we're receiving connections on.
+static u_short port = ACE_DEFAULT_SERVER_PORT;
+
+static ACE_TCHAR *host = ACE_LOCALHOST;
+
+// File that we're sending.
+static ACE_TCHAR *input_file = ACE_TEXT("Proactor_Scatter_Gather_Test.cpp");
+
+// Name of the output file.
+static ACE_TCHAR *output_file = ACE_TEXT("output");
+
+static int client_only = 0;
+static int server_only = 0;
+static size_t chunk_size = 0;
+
+enum
+{
+ ODD = 0,
+ EVEN
+};
+
+// *************************************************************
+// Some chunks chain helper routines
+// *************************************************************
+static int allocate_chunks_chain (ACE_Message_Block *&head_mb,
+ size_t number_of_chunks)
+{
+ ACE_Message_Block *pre_mb = 0;
+
+ for (size_t index = 0; index < number_of_chunks; ++index)
+ {
+#if defined (ACE_WIN32)
+ void *addr = ::VirtualAlloc (0,
+ chunk_size,
+ MEM_COMMIT,
+ PAGE_READWRITE);
+#else
+ void *addr = new char[chunk_size];
+#endif /* ACE_WIN32 */
+ if (addr)
+ {
+ ACE_Message_Block *mb = new ACE_Message_Block (static_cast<char *> (addr),
+ chunk_size);
+ if (!head_mb)
+ head_mb = mb;
+
+ // chain them together
+ if (pre_mb)
+ pre_mb->cont (mb);
+ pre_mb = mb;
+ }
+ else
+ {
+ ACE_ASSERT (0);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static void
+free_chunks_chain (ACE_Message_Block *&mb)
+{
+ for (const ACE_Message_Block* msg = mb;
+ msg != 0;
+ msg = msg->cont ())
+ {
+#if defined (ACE_WIN32)
+ ::VirtualFree (msg->base (),
+ msg->size (),
+ MEM_DECOMMIT);
+#else
+ delete [] msg->base ();
+#endif /* ACE_WIN32 */
+ }
+
+ mb->release ();
+ mb = 0;
+}
+
+static int
+last_chunk (ACE_Message_Block *chain,
+ ACE_Message_Block *&last)
+{
+ if (!chain)
+ return 0;
+
+ int index = 1;
+ last = chain;
+ while (0 != last->cont ())
+ {
+ last = last->cont ();
+ ++index;
+ }
+
+ return index;
+}
+
+static void
+merge_odd_even_chains (ACE_Message_Block *odd_mb,
+ ACE_Message_Block *even_mb)
+{
+ ACE_Message_Block *pre_pre_mb = odd_mb;
+ ACE_Message_Block *pre_mb = even_mb;
+ ACE_Message_Block *curr_mb = odd_mb->cont ();
+
+ if (even_mb)
+ {
+ for (; curr_mb != 0; curr_mb = pre_pre_mb->cont ())
+ {
+ pre_pre_mb->cont (pre_mb);
+
+ // increment history pointers
+ pre_pre_mb = pre_mb;
+ pre_mb = curr_mb;
+ }
+
+ pre_pre_mb->cont (pre_mb);
+ pre_mb->cont (0);
+ }
+}
+
+static void
+split_odd_even_chains (ACE_Message_Block *odd_mb,
+ ACE_Message_Block *even_mb)
+{
+ ACE_Message_Block *pre_pre_mb = odd_mb;
+ ACE_Message_Block *pre_mb = even_mb;
+ ACE_Message_Block *curr_mb = (even_mb ? even_mb->cont () : 0);
+
+ for (; curr_mb != 0; curr_mb = curr_mb->cont ())
+ {
+ pre_pre_mb->cont (curr_mb);
+
+ // increment history pointers
+ pre_pre_mb = pre_mb;
+ pre_mb = curr_mb;
+ }
+
+ pre_pre_mb->cont (0);
+ if (pre_mb)
+ pre_mb->cont (0);
+}
+
+static void
+add_to_chunks_chain (ACE_Message_Block *&chunks_chain,
+ ACE_Message_Block *additional_chunks_chain)
+{
+ if (0 == chunks_chain)
+ chunks_chain = additional_chunks_chain;
+ else
+ {
+ ACE_Message_Block *last = 0;
+ last_chunk (chunks_chain, last);
+ if (last)
+ last->cont (additional_chunks_chain);
+ }
+}
+
+static void
+remove_empty_chunks (ACE_Message_Block *&chunks_chain)
+{
+ if (0 == chunks_chain)
+ return;
+
+ ACE_Message_Block *first_empty = chunks_chain;
+ ACE_Message_Block *pre_mb = 0;
+
+ while (first_empty->length () > 0 &&
+ 0 != first_empty->cont ())
+ {
+ pre_mb = first_empty;
+ first_empty = first_empty->cont ();
+ }
+
+ // break the chain there, and release the empty end (might be everything)
+ if (0 == first_empty->length ())
+ {
+ if (pre_mb) // might be 0, in case it's the entire chain
+ pre_mb->cont (0);
+
+ if (first_empty == chunks_chain)
+ chunks_chain = 0;
+
+ free_chunks_chain (first_empty);
+ }
+}
+
+// *************************************************************
+// Acceptor, Receiver and Writer
+// *************************************************************
+class Receiver;
+
+class Acceptor : public ACE_Asynch_Acceptor<Receiver>
+{
+ friend class Receiver;
+
+public:
+ Acceptor (void);
+ virtual ~Acceptor (void);
+
+ void stop (void);
+
+ // Virtual from ACE_Asynch_Acceptor
+ virtual Receiver *make_handler (void);
+
+ int get_number_sessions (void) { return this->sessions_; }
+
+private:
+ void on_new_receiver (Receiver &rcvr);
+ void on_delete_receiver (Receiver &rcvr);
+
+ int sessions_;
+ Receiver *list_receivers_[RECEIVERS];
+};
+
+class Writer;
+
+// The first instantiated take the role of the odd receiver
+class Receiver : public ACE_Service_Handler
+{
+ friend class Acceptor;
+ friend class Writer;
+
+public:
+ Receiver (Acceptor *acceptor = 0, int index = -1);
+ virtual ~Receiver (void);
+
+ /// This is called after the new connection has been accepted.
+ virtual void open (ACE_HANDLE handle,
+ ACE_Message_Block &message_block);
+protected:
+ /// This is called by the framework when asynchronous <read> operation from the
+ /// socket completes.
+ virtual void handle_read_stream (const ACE_Asynch_Read_Stream::Result &result);
+
+private:
+ int initiate_read_stream (void);
+
+ void check_destroy (void);
+
+ Acceptor *acceptor_;
+ int index_;
+
+ // Socket input
+ ACE_Asynch_Read_Stream rs_;
+ ACE_HANDLE socket_handle_;
+
+ // Writer
+ static Writer* writer_;
+
+ long io_count_;
+
+ char odd_;
+
+ // if we get non-page-size reminder, we will not send it to the writer
+ // until it is full (unless at end)
+ ACE_Message_Block *partial_chunk_;
+};
+
+class Writer : public ACE_Handler
+{
+ friend class Receiver;
+
+public:
+ Writer (void);
+ virtual ~Writer (void);
+
+ void open (void);
+
+ // this is *not* a callback from the framework
+ int handle_read_chunks_chain (ACE_Message_Block *mb,
+ int type);
+
+ // for determining when last receiver dies
+ void on_new_receiver ();
+ void on_delete_receiver ();
+
+protected:
+ /// This is called by the framework when an asynchronous <write> to the file
+ /// completes.
+ virtual void handle_write_file (const ACE_Asynch_Write_File::Result &result);
+
+private:
+ int initiate_write_file (void);
+
+private:
+ // Output file
+ ACE_Asynch_Write_File wf_;
+ ACE_HANDLE output_file_handle_;
+ u_long writing_file_offset_;
+ u_long reported_file_offset_;
+ ACE_Message_Block *odd_chain_;
+ ACE_Message_Block *even_chain_;
+ long io_count_;
+ char receiver_count_;
+};
+
+// *************************************************************
+// Receiver Impl
+// *************************************************************
+
+Writer *Receiver::writer_ = 0;
+
+Receiver::Receiver (Acceptor * acceptor, int index)
+ : acceptor_ (acceptor),
+ index_ (index),
+ socket_handle_ (ACE_INVALID_HANDLE),
+ io_count_ (0),
+ partial_chunk_ (0)
+{
+ // the first one is the odd one
+ this->odd_ = ((0 == index) ? 1 : 0);
+
+ if (this->odd_)
+ {
+ Receiver::writer_ = new Writer;
+ if (!Receiver::writer_)
+ {
+ ACE_ASSERT (0);
+ return;
+ }
+ }
+
+ Receiver::writer_->on_new_receiver ();
+
+ if (this->acceptor_ != 0)
+ this->acceptor_->on_new_receiver (*this);
+}
+
+Receiver::~Receiver (void)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Receiver::~Receiver\n")));
+
+ if (this->acceptor_ != 0)
+ this->acceptor_->on_delete_receiver (*this);
+
+ if (this->socket_handle_ != ACE_INVALID_HANDLE)
+ ACE_OS::closesocket (this->socket_handle_);
+
+ Receiver::writer_->on_delete_receiver ();
+
+ if (this->partial_chunk_)
+ {
+ ACE_ASSERT (0); // should not be getting here
+ this->partial_chunk_->release ();
+ }
+}
+
+void
+Receiver::check_destroy (void)
+{
+ if (this->io_count_ <= 0)
+ delete this;
+}
+
+void
+Receiver::open (ACE_HANDLE handle, ACE_Message_Block &)
+{
+ this->socket_handle_ = handle;
+
+ // Open the ACE_Asynch_Read_Stream
+ if (this->rs_.open (*this, this->socket_handle_) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("Receiver::ACE_Asynch_Read_Stream::open")));
+ else
+ {
+ if (this->odd_)
+ Receiver::writer_->open ();
+
+ this->initiate_read_stream ();
+ }
+
+ this->check_destroy ();
+}
+
+int
+Receiver::initiate_read_stream (void)
+{
+ if (!Receiver::writer_)
+ return -1;
+
+ // how many chunks to allocate?
+ size_t number_of_new_chunks = (this->partial_chunk_ ?
+ (ACE_IOV_MAX / RECEIVERS) - 1
+ : ACE_IOV_MAX / RECEIVERS);
+
+ // allocate chunks chain
+ ACE_Message_Block *head_mb = 0;
+ if (-1 == allocate_chunks_chain (head_mb, number_of_new_chunks))
+ {
+ ACE_ASSERT (0);
+ return -1;
+ }
+
+ // calculate how many bytes to read
+
+ // head_mb could be 0 (no new chunks allocated)
+ size_t bytes_to_read = head_mb ? head_mb->total_size () : 0;
+
+ // add the partial chunk at the front if appropriate, and update
+ // the number of bytes to read
+ if (this->partial_chunk_)
+ {
+ bytes_to_read += this->partial_chunk_->space ();
+ this->partial_chunk_->cont (head_mb);
+ head_mb = this->partial_chunk_;
+ this->partial_chunk_ = 0;
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Receiver::initiate_read_stream - (%s) readv %d\n"),
+ this->odd_ ? ACE_TEXT ("ODD ") : ACE_TEXT ("EVEN"),
+ bytes_to_read));
+
+ // perform the actual scattered read
+ if (this->rs_.readv (*head_mb,
+ bytes_to_read) == -1)
+ {
+ free_chunks_chain (head_mb);
+
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("Receiver::ACE_Asynch_Stream::read")),
+ -1);
+ }
+
+ ++this->io_count_;
+ return 0;
+}
+
+void
+Receiver::handle_read_stream (const ACE_Asynch_Read_Stream::Result &result)
+{
+ ACE_Message_Block *mb = &result.message_block ();
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Receiver::handle_read_stream - (%s) read %d\n"),
+ this->odd_ ? ACE_TEXT ("ODD ") : ACE_TEXT ("EVEN"),
+ result.bytes_transferred ()));
+
+ // Transfer only complete chunks to the writer.
+ // Save last partial chunk for the next call.
+ // On disconnect (error or 0 transferred), transfer whatever we have.
+
+ // at this stage there should not be anything there
+ ACE_ASSERT (!this->partial_chunk_);
+
+ // first, remove the empty chunks
+ remove_empty_chunks (mb);
+
+ if (mb && Receiver::writer_)
+ { // there's something to write, and who to write to
+
+ // write everything or only complete chunks?
+
+ // write everything - when no new bytes were transferred
+ int write_everything = 0;
+ if (!result.bytes_transferred ())
+ write_everything = 1;
+ if (write_everything)
+ Receiver::writer_->handle_read_chunks_chain (mb,
+ this->odd_ ? ODD : EVEN);
+ else
+ { // filter out the partial chunk at the end (if present)
+ // and save it for later before writing the full chunks
+
+ // have this->partial_chunk_ point to the last chunk in the chain
+ size_t last_index = last_chunk (mb, this->partial_chunk_);
+ if (this->partial_chunk_ &&
+ this->partial_chunk_->length () < chunk_size)
+ { // found partial chunk at end of chain
+ // detach it from the chain
+ if (last_index > 1) // chain bigger than 1
+ {
+ ACE_Message_Block *pre_last = mb;
+ for (size_t index = 1; index < last_index - 1; ++index)
+ pre_last = pre_last->cont ();
+
+ // detach partial chunk from chain
+ pre_last->cont (0);
+ }
+ else
+ // chain in length of 1 - so we need to zero mb
+ mb = 0;
+ }
+ else // last is a full chunk, so hand it over with the rest
+ this->partial_chunk_ = 0;
+
+ // transfer (if there's anything left)
+ if (mb && mb->total_length ())
+ Receiver::writer_->handle_read_chunks_chain (
+ mb,
+ this->odd_ ? ODD : EVEN);
+
+ // initiate more reads only if no error
+ if (!result.error ())
+ this->initiate_read_stream ();
+ else
+ ACE_ASSERT (0);
+ }
+ }
+ else if (mb && !Receiver::writer_)
+ // no one to write to
+ free_chunks_chain (mb);
+
+ --this->io_count_;
+
+ this->check_destroy ();
+}
+
+// *************************************************************
+// Acceptor Impl
+// *************************************************************
+
+Acceptor::Acceptor (void)
+ : sessions_ (0)
+{
+ for (int i = 0; i < RECEIVERS; ++i)
+ this->list_receivers_[i] = 0;
+}
+
+Acceptor::~Acceptor (void)
+{
+ this->stop ();
+}
+
+
+void
+Acceptor::stop (void)
+{
+ // This method can be called only after proactor event loop is done
+ // in all threads.
+ for (int i = 0; i < RECEIVERS; ++i)
+ {
+ delete this->list_receivers_[i];
+ this->list_receivers_[i] = 0;
+ }
+}
+
+void
+Acceptor::on_new_receiver (Receiver & rcvr)
+{
+ ++this->sessions_;
+ this->list_receivers_[rcvr.index_] = &rcvr;
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Receiver::CTOR sessions_ = %d\n"),
+ this->sessions_));
+}
+
+void
+Acceptor::on_delete_receiver (Receiver & rcvr)
+{
+ --this->sessions_;
+ if (rcvr.index_ >= 0
+ && rcvr.index_ < RECEIVERS
+ && this->list_receivers_[rcvr.index_] == &rcvr)
+ this->list_receivers_[rcvr.index_] = 0;
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Receiver::~DTOR sessions_ = %d\n"),
+ this->sessions_));
+}
+
+Receiver *
+Acceptor::make_handler (void)
+{
+ if (this->sessions_ >= RECEIVERS)
+ return 0;
+
+ for (int i = 0; i < RECEIVERS; ++i)
+ {
+ if (this->list_receivers_[i] == 0)
+ {
+ ACE_NEW_RETURN (this->list_receivers_[i],
+ Receiver (this, i),
+ 0);
+ return this->list_receivers_[i];
+ }
+ }
+
+ return 0;
+}
+
+// *************************************************************
+// Writer Impl
+// *************************************************************
+
+Writer::Writer (void)
+: output_file_handle_ (ACE_INVALID_HANDLE),
+ writing_file_offset_ (0),
+ reported_file_offset_ (0),
+ odd_chain_ (0),
+ even_chain_ (0),
+ io_count_ (0),
+ receiver_count_ (0)
+{
+}
+
+Writer::~Writer (void)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Writer::~Writer\n")));
+
+ if (this->output_file_handle_ != ACE_INVALID_HANDLE)
+ ACE_OS::close (this->output_file_handle_);
+
+ Receiver::writer_ = 0;
+}
+
+void
+Writer::on_new_receiver ()
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Writer::on_new_receiver\n")));
+
+ ++this->receiver_count_;
+}
+
+void
+Writer::on_delete_receiver ()
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Writer::on_delete_receiver\n")));
+
+ --this->receiver_count_;
+
+ if (0 == this->receiver_count_)
+ {
+ if (this->io_count_ <= 0)
+ // no pending io, so do the work oursleves
+ // (if pending io, they'll see the zero receiver count)
+ this->initiate_write_file ();
+ }
+}
+
+void
+Writer::open (void)
+{
+ // Open the file for output
+ if (ACE_INVALID_HANDLE == (this->output_file_handle_ = ACE_OS::open (output_file,
+ O_CREAT | _O_TRUNC | _O_WRONLY |\
+ FILE_FLAG_OVERLAPPED |\
+ FILE_FLAG_NO_BUFFERING,
+ ACE_DEFAULT_FILE_PERMS)))
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("Writer::open::ACE_OS::open")));
+ // Open the ACE_Asynch_Write_File
+ else if (this->wf_.open (*this, this->output_file_handle_) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("Writer::open::ACE_Asynch_Write_File::open")));
+}
+
+int
+Writer::handle_read_chunks_chain (ACE_Message_Block *mb,
+ int type)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Writer::handle_read_chunks_chain - (%s) %d bytes\n"),
+ (type == ODD) ? ACE_TEXT ("ODD ") : ACE_TEXT ("EVEN"),
+ mb->total_length ()));
+
+ add_to_chunks_chain (ODD == type ? this->odd_chain_ : this->even_chain_, mb);
+
+ this->initiate_write_file ();
+
+ return 0;
+}
+
+int
+Writer::initiate_write_file (void)
+{
+ // find out how much can we merge
+ ACE_Message_Block *dummy_last = 0;
+ size_t odd_count = last_chunk (this->odd_chain_, dummy_last);
+ size_t even_count = last_chunk (this->even_chain_, dummy_last);
+
+ size_t merge_size = ACE_MIN (ACE_MIN (odd_count, even_count),
+ (size_t) ACE_IOV_MAX);
+
+ // the options here are as follows:
+ // io_count_ can be zero or greater.
+ // merge_size can be zero or not.
+ // if non zero merge, write the merge. ASSERT receiver_count_ is non zero too.
+ // if zero merge:
+ // if receiver_count_ is non zero, NOOP.
+ // if zero receiver_count_, we should write whatever is left,
+ // and terminate the writer at completion.
+ // if nothing to write, and io_count_ is zero too, terminate here.
+
+ if (0 == merge_size &&
+ 0 != this->receiver_count_)
+ return 0;
+
+ if (0 == merge_size &&
+ 0 == this->receiver_count_ &&
+ 0 == odd_count &&
+ 0 == even_count &&
+ 0 == this->io_count_)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Writer::initiate_write_file")
+ ACE_TEXT (" - ending proactor event loop\n")));
+
+ ACE_Proactor::instance ()->end_event_loop ();
+
+ delete this;
+
+ return 0;
+ }
+
+ // if we reached nere and merge_size is zero, we should write whatever is
+ // in the queues (1 to 2 chunks together), so let's force the merge size to 1.
+ if (0 == merge_size)
+ {
+ ACE_ASSERT (1 == odd_count && 1 >= even_count);
+ merge_size = 1;
+ }
+
+ // Now that we found out what we want to do, prepare the chain
+ // that will be written, and update the remainders
+ ACE_Message_Block *new_odd_chain_head = this->odd_chain_;
+ ACE_Message_Block *new_even_chain_head = this->even_chain_;
+
+ // locate the place for detachment in the chains
+ ACE_Message_Block *pre_odd = 0;
+ ACE_Message_Block *pre_even = 0;
+ for (size_t index = 0; index < merge_size; ++index)
+ {
+ pre_odd = new_odd_chain_head;
+ if (new_odd_chain_head)
+ new_odd_chain_head = new_odd_chain_head->cont ();
+ pre_even = new_even_chain_head;
+ if (new_even_chain_head)
+ new_even_chain_head = new_even_chain_head->cont ();
+ }
+ // now detach the chain
+ if (pre_odd)
+ pre_odd->cont (0);
+ if (pre_even)
+ pre_even->cont (0);
+
+ // perform merge between the two chains
+ merge_odd_even_chains (this->odd_chain_, this->even_chain_);
+
+ // and now finally perform the write
+ ACE_Message_Block *united_mb = this->odd_chain_;
+ // update the remainders of the chains
+ this->odd_chain_ = new_odd_chain_head;
+ this->even_chain_ = new_even_chain_head;
+ size_t increment_writing_file_offset = united_mb->total_length ();
+
+ // Reconstruct the file
+ // Write the size, not the length, because we must write in chunks
+ // of <page size>
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Writer::initiate_write_file: write %d bytes at %d\n"),
+ united_mb->total_size (),
+ this->writing_file_offset_));
+ if (this->wf_.writev (*united_mb,
+ united_mb->total_size (),
+ this->writing_file_offset_) == -1)
+ {
+ free_chunks_chain (united_mb);
+
+ ACE_ERROR_RETURN((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("Writer::initiate_write_file::ACE_Asynch_Write_Stream::writev")),
+ -1);
+ }
+
+ // we update now because otherwise, we'd have error when performing
+ // pipelined writing (that is, mulitple calls to write before the callbacks
+ // to handle_x)
+ this->writing_file_offset_ +=
+ static_cast<u_long> (increment_writing_file_offset);
+ ++this->io_count_;
+ return 0;
+}
+
+void
+Writer::handle_write_file (const ACE_Asynch_Write_File::Result &result)
+{
+ ACE_Message_Block *mb = &result.message_block ();
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Writer::handle_write_file at offset %d wrote %d\n"),
+ this->reported_file_offset_,
+ result.bytes_transferred ()));
+
+ this->reported_file_offset_ +=
+ static_cast<u_long> (result.bytes_transferred ());
+
+ // Always truncate as required,
+ // because partial will always be the last write to a file
+ ACE_Message_Block *last_mb = mb;
+ last_chunk (mb, last_mb);
+
+ if (last_mb->space ())
+ ACE_OS::truncate (output_file,
+ this->reported_file_offset_ -
+ static_cast<u_long> (last_mb->space ()));
+
+ free_chunks_chain (mb);
+
+ --this->io_count_;
+
+ // end of process?
+ if (0 == this->receiver_count_ &&
+ 0 == this->io_count_)
+ {
+ ACE_ASSERT (0 == this->odd_chain_ && 0 == this->even_chain_);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Writer::handle_write_file")
+ ACE_TEXT (" - ending proactor event loop\n")));
+
+ ACE_Proactor::instance ()->end_event_loop ();
+
+ delete this;
+ }
+}
+
+// *************************************************************
+// Connector and Sender
+// *************************************************************
+class Sender;
+
+class Connector : public ACE_Asynch_Connector<Sender>
+{
+ friend class Sender;
+
+public:
+ Connector (void);
+ virtual ~Connector (void);
+
+ // Address to pass to Sender for secondary connect.
+ void set_address (const ACE_INET_Addr &addr);
+ const ACE_INET_Addr &get_address (void);
+
+ void stop (void);
+
+ // Virtual from ACE_Asynch_Connector
+ virtual Sender *make_handler (void);
+
+private:
+ void on_new_sender (Sender &rcvr);
+ void on_delete_sender (Sender &rcvr);
+
+ int sessions_;
+ ACE_INET_Addr addr_;
+ Sender *list_senders_[SENDERS];
+};
+
+class Sender : public ACE_Service_Handler
+{
+ friend class Connector;
+public:
+
+ Sender (Connector *connector = 0, int index = -1);
+
+ virtual ~Sender (void);
+
+ /// This is called after the new connection has been established.
+ virtual void open (ACE_HANDLE handle,
+ ACE_Message_Block &message_block);
+
+ // This is called by the framework when asynchronous reads from the
+ // file complete.
+ virtual void handle_read_file (const ACE_Asynch_Read_File::Result &result);
+
+ // This is called by the framework when asynchronous writes from the
+ // socket complete.
+ virtual void handle_write_stream (const ACE_Asynch_Write_Stream::Result &result);
+
+private:
+ void check_destroy (void);
+
+ int initiate_read_file (void);
+
+ int initiate_write_stream (ACE_Message_Block &mb);
+
+ int index_;
+ Connector * connector_;
+
+ // File to read from
+ ACE_Asynch_Read_File rf_;
+ ACE_HANDLE input_file_handle_;
+ u_long file_offset_;
+
+ // Sockets to send to
+ // odd and even socket output streams
+ ACE_Asynch_Write_Stream ws_[RECEIVERS];
+ ACE_HANDLE socket_handle_[RECEIVERS];
+
+ long io_count_;
+};
+
+// *************************************************************
+// Connector Impl
+// *************************************************************
+
+Connector::Connector (void)
+ : sessions_ (0)
+{
+ for (int i = 0; i < SENDERS; ++i)
+ this->list_senders_[i] = 0;
+}
+
+Connector::~Connector (void)
+{
+ this->stop ();
+}
+
+// Address to pass to Sender for secondary connect.
+void
+Connector::set_address (const ACE_INET_Addr &addr)
+{
+ this->addr_ = addr;
+}
+
+const ACE_INET_Addr &
+Connector::get_address (void)
+{
+ return this->addr_;
+}
+
+void
+Connector::stop (void)
+{
+ // This method can be called only after proactor event loop is done
+ // in all threads.
+
+ for (int i = 0; i < SENDERS; ++i)
+ {
+ delete this->list_senders_[i];
+ this->list_senders_[i] = 0;
+ }
+}
+
+void
+Connector::on_new_sender (Sender &sndr)
+{
+ ++this->sessions_;
+ this->list_senders_[sndr.index_] = &sndr;
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Sender::CTOR sessions_ = %d\n"),
+ this->sessions_));
+}
+
+void
+Connector::on_delete_sender (Sender &sndr)
+{
+ --this->sessions_;
+ if (sndr.index_ >= 0
+ && sndr.index_ < SENDERS
+ && this->list_senders_[sndr.index_] == &sndr)
+ this->list_senders_[sndr.index_] = 0;
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Sender::~DTOR sessions_ = %d\n"),
+ this->sessions_));
+}
+
+Sender *
+Connector::make_handler (void)
+{
+ if (this->sessions_ >= SENDERS)
+ return 0;
+
+ for (int i = 0; i < SENDERS; ++i)
+ {
+ if (this->list_senders_ [i] == 0)
+ {
+ ACE_NEW_RETURN (this->list_senders_[i],
+ Sender (this, i),
+ 0);
+ return this->list_senders_[i];
+ }
+ }
+
+ return 0;
+}
+
+// *************************************************************
+// Sender Impl
+// *************************************************************
+
+Sender::Sender (Connector * connector, int index)
+ : index_ (index),
+ connector_ (connector),
+ input_file_handle_ (ACE_INVALID_HANDLE),
+ file_offset_ (0),
+ io_count_ (0)
+{
+ socket_handle_[ODD] = socket_handle_[EVEN] = ACE_INVALID_HANDLE;
+
+ if (this->connector_ != 0)
+ this->connector_->on_new_sender (*this);
+}
+
+Sender::~Sender (void)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Sender::~Sender\n")));
+
+ if (this->connector_ != 0)
+ this->connector_->on_delete_sender (*this);
+
+ if (this->socket_handle_[ODD] != ACE_INVALID_HANDLE)
+ ACE_OS::closesocket (this->socket_handle_[ODD]);
+
+ if (this->socket_handle_[EVEN] != ACE_INVALID_HANDLE)
+ ACE_OS::closesocket (this->socket_handle_[EVEN]);
+
+ if (this->input_file_handle_ != ACE_INVALID_HANDLE)
+ ACE_OS::close (this->input_file_handle_);
+
+ if (client_only)
+ ACE_Proactor::instance ()->end_event_loop ();
+}
+
+// return true if we alive, false we commited suicide
+void
+Sender::check_destroy (void)
+{
+ if (this->io_count_ <= 0)
+ delete this;
+}
+
+void
+Sender::open (ACE_HANDLE handle, ACE_Message_Block &)
+{
+ this->socket_handle_[ODD] = handle;
+
+ // Open the input file
+ if (ACE_INVALID_HANDLE == (this->input_file_handle_ =
+ ACE_OS::open (input_file,
+ _O_RDONLY |\
+ FILE_FLAG_OVERLAPPED |\
+ FILE_FLAG_NO_BUFFERING,
+ ACE_DEFAULT_FILE_PERMS)))
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("Sender::open::ACE_OS::open")));
+ }
+ else
+ {
+ // Now connect (w/o the connector factory) to the even (=second)
+ // receiver. We don't connect thru the factory in order not to
+ // instantiate another Sender.
+ ACE_SOCK_Connector sock_connector;
+ ACE_SOCK_Stream sock_stream;
+ if (-1 == sock_connector.connect (sock_stream,
+ this->connector_->get_address ()))
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("Sender::open::ACE_SOCK_Connector::connect")));
+
+ else
+ {
+ this->socket_handle_[EVEN] = sock_stream.get_handle ();
+
+ // Open odd ACE_Asynch_Write_Stream
+ if (this->ws_[ODD].open (*this, this->socket_handle_[ODD]) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("Sender::open::ACE_Asynch_Write_Stream::open")));
+
+ // Open even ACE_Asynch_Write_Stream
+ else if (this->ws_[EVEN].open (*this, this->socket_handle_[EVEN]) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("Sender::open::ACE_Asynch_Write_Stream::open")));
+
+ // Open ACE_Asynch_Read_File
+ else if (this->rf_.open (*this, this->input_file_handle_) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("Sender::open::ACE_Asynch_Read_File::open")));
+ else
+ // Start an asynchronous read
+ this->initiate_read_file ();
+ }
+ }
+
+ this->check_destroy ();
+}
+
+int
+Sender::initiate_read_file (void)
+{
+ ACE_ASSERT (0 == this->file_offset_ % chunk_size);
+
+ static const size_t file_size = ACE_OS::filesize (input_file);
+
+ static const size_t number_of_chunks_needed_for_file =
+ static_cast<size_t> (ACE_OS::ceil ((double) file_size / chunk_size));
+
+ size_t relevant_number_of_chunks =
+ ACE_MIN ((size_t)ACE_IOV_MAX,
+ number_of_chunks_needed_for_file
+ - (size_t)(this->file_offset_ / chunk_size));
+
+ if (!relevant_number_of_chunks)
+ {
+ ACE_ASSERT (0); // Just 2 C it coming
+ return 0;
+ }
+
+ ACE_Message_Block *head_mb = 0;
+ if (-1 == allocate_chunks_chain (head_mb, relevant_number_of_chunks))
+ {
+ ACE_ASSERT (0);
+ return -1;
+ }
+
+ // Inititiate read
+ if (this->rf_.readv (*head_mb,
+ head_mb->total_size (),
+ this->file_offset_) == -1)
+ {
+ free_chunks_chain (head_mb);
+
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("Sender::initiate_read_file::")
+ ACE_TEXT ("ACE_Asynch_Read_Stream::readv")),
+ -1);
+ }
+
+ ++this->io_count_;
+ return 0;
+}
+
+int
+Sender::initiate_write_stream (ACE_Message_Block &mb)
+{
+ // send the odd to the first connection, and the even to the second
+ // connection.
+
+ ACE_Message_Block *odd_mb = &mb;
+ ACE_Message_Block *even_mb = mb.cont ();
+
+ split_odd_even_chains (odd_mb, even_mb);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Sender::initiate_write_stream - (ODD ) writev %d\n"),
+ odd_mb->total_length ()));
+
+ if (this->ws_[ODD].writev (*odd_mb, odd_mb->total_length ()) == -1)
+ {
+ free_chunks_chain (odd_mb);
+
+ if (even_mb)
+ free_chunks_chain (even_mb);
+
+ ACE_ERROR_RETURN((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("Sender::ACE_Asynch_Stream::writev")),
+ -1);
+ }
+
+ ++this->io_count_;
+
+ if (even_mb)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Sender::initiate_write_stream - (EVEN) writev %d\n"),
+ even_mb->total_length ()));
+
+ if (this->ws_[EVEN].writev (*even_mb, even_mb->total_length ()) == -1)
+ {
+ free_chunks_chain (even_mb);
+
+ ACE_ERROR_RETURN((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("Sender::ACE_Asynch_Stream::writev")),
+ -1);
+ }
+
+ ++this->io_count_;
+ }
+
+ return 0;
+}
+
+void
+Sender::handle_read_file (const ACE_Asynch_Read_File::Result &result)
+{
+ ACE_Message_Block *mb = &result.message_block ();
+
+ if (result.error () == 0 && result.bytes_transferred () != 0)
+ {
+ size_t bytes_transferred = result.bytes_transferred ();
+ size_t chunks_chain_size = mb->total_size ();
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Sender::handle_read_file, read %d, ")
+ ACE_TEXT ("chain total %d\n"),
+ bytes_transferred,
+ chunks_chain_size));
+
+ this->file_offset_ += static_cast<u_long> (bytes_transferred);
+
+ this->initiate_write_stream (*mb);
+
+ // and read more if required
+ if (bytes_transferred == chunks_chain_size)
+ this->initiate_read_file ();
+ }
+ else
+ free_chunks_chain (mb);
+
+ --this->io_count_;
+
+ this->check_destroy ();
+}
+
+void
+Sender::handle_write_stream (const ACE_Asynch_Write_Stream::Result &result)
+{
+ ACE_Message_Block *mb = &result.message_block ();
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Sender::handle_write_stream - wrote %d bytes\n"),
+ result.bytes_transferred ()));
+
+ if (result.error () == 0 && result.bytes_transferred () != 0)
+ // verify sent all
+ ACE_ASSERT (0 == mb->total_length ());
+ else
+ ACE_ASSERT (0);
+
+ free_chunks_chain (mb);
+
+ --this->io_count_;
+
+ this->check_destroy ();
+}
+
+// *************************************************************
+// Configuration helpers
+// *************************************************************
+int
+print_usage (int /* argc */, ACE_TCHAR *argv[])
+{
+ ACE_ERROR
+ ((LM_ERROR,
+ ACE_TEXT ("\nusage: %s")
+ ACE_TEXT ("\n-f <input file>\n")
+ ACE_TEXT ("\n-c client only (reader-sender)")
+ ACE_TEXT ("\n-s server only (receiver-writer)")
+ ACE_TEXT ("\n-h host to connect to")
+ ACE_TEXT ("\n-p port")
+ ACE_TEXT ("\n-u show this message")
+ ACE_TEXT ("\n"),
+ argv[0]
+ ));
+ return -1;
+}
+
+static int
+parse_args (int argc, ACE_TCHAR *argv[])
+{
+ if (argc == 1) // no arguments , so one button test
+ return 0;
+
+ ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("f:csh:p:u"));
+ int c;
+
+ while ((c = get_opt ()) != EOF)
+ {
+ switch (c)
+ {
+ case 'f':
+ input_file = get_opt.opt_arg ();
+ break;
+ case 'c':
+ client_only = 1;
+ server_only = 0;
+ break;
+ case 's':
+ server_only = 1;
+ client_only = 0;
+ break;
+ case 'h':
+ host = get_opt.opt_arg ();
+ break;
+ case 'p':
+ port = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'u':
+ default:
+ return print_usage (argc, argv);
+ } // switch
+ } // while
+
+ return 0;
+}
+
+int
+run_main (int argc, ACE_TCHAR *argv[])
+{
+ ACE_START_TEST (ACE_TEXT ("Proactor_Scatter_Gather_Test"));
+
+ if (::parse_args (argc, argv) == -1)
+ return -1;
+
+ chunk_size = ACE_OS::getpagesize ();
+
+ if (client_only)
+ ACE_DEBUG ((LM_INFO,
+ ACE_TEXT ("Running as client only, page size %d\n"),
+ chunk_size));
+ else if (server_only)
+ ACE_DEBUG ((LM_INFO,
+ ACE_TEXT ("Running as server only, page size %d\n"),
+ chunk_size));
+ else
+ ACE_DEBUG ((LM_INFO,
+ ACE_TEXT ("Running as server and client, page size %d\n"),
+ chunk_size));
+
+ Acceptor acceptor;
+ Connector connector;
+ ACE_INET_Addr addr (port);
+
+ if (!client_only)
+ {
+ // Simplify, initial read with zero size
+ if (-1 == acceptor.open (addr, 0, 1))
+ {
+ ACE_ASSERT (0);
+ return -1;
+ }
+ }
+
+ if (!server_only)
+ {
+ if (-1 == connector.open (1, ACE_Proactor::instance ()))
+ {
+ ACE_ASSERT (0);
+ return -1;
+ }
+
+ // connect to first destination
+ if (addr.set (port, host, 1, addr.get_type ()) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), host), -1);
+ connector.set_address (addr);
+ if (-1 == connector.connect (addr))
+ {
+ ACE_ASSERT (0);
+ return -1;
+ }
+ }
+
+ ACE_Proactor::instance ()->run_event_loop ();
+
+ // As Proactor event loop now is inactive it is safe to destroy all
+ // senders
+
+ connector.stop ();
+ acceptor.stop ();
+
+ ACE_Proactor::instance()->close_singleton ();
+
+ // now compare the files - available only when on same machine
+
+ int success = 0;
+ if (!client_only && !server_only)
+ {
+ ACE_DEBUG ((LM_INFO,
+ ACE_TEXT ("Comparing the input file and the output file...\n")));
+
+ success = -1;
+ // map the two files, then perform memcmp
+ {
+ ACE_Mem_Map original_file (input_file);
+ ACE_Mem_Map reconstructed_file (output_file);
+
+ if (original_file.addr () &&
+ original_file.addr () != MAP_FAILED &&
+ reconstructed_file.addr () &&
+ reconstructed_file.addr () != MAP_FAILED)
+ {
+ // compare lengths
+ if ((original_file.size () == reconstructed_file.size ()) &&
+ // and if same size, compare file data
+ (0 == ACE_OS::memcmp (original_file.addr (),
+ reconstructed_file.addr (),
+ original_file.size ())))
+ success = 0;
+ }
+ }
+
+ if (0 == success)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("input file and the output file identical!\n")));
+ else
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("input file and the output file are different!\n")));
+ }
+
+ if (!client_only)
+ ACE_OS::unlink (output_file);
+
+ ACE_END_TEST;
+
+ return success;
+}
+
+#else
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("Proactor_Scatter_Gather_Test"));
+
+ ACE_DEBUG ((LM_INFO,
+ ACE_TEXT ("Asynchronous Scatter/Gather IO is unsupported.\n")
+ ACE_TEXT ("Proactor_Scatter_Gather_Test will not be run.")));
+
+ ACE_END_TEST;
+
+ return 0;
+}
+
+#endif /* (ACE_HAS_WINNT4 && ACE_HAS_WINNT4 != 0) && !ACE_HAS_WINCE) */
diff --git a/ACE/tests/Proactor_Test.cpp b/ACE/tests/Proactor_Test.cpp
new file mode 100644
index 00000000000..9d739b2d5e3
--- /dev/null
+++ b/ACE/tests/Proactor_Test.cpp
@@ -0,0 +1,1937 @@
+// $Id$
+
+// ============================================================================
+/**
+ * @file Proactor_Test.cpp
+ *
+ * $Id$
+ *
+ * This program illustrates how the ACE_Proactor can be used to
+ * implement an application that does various asynchronous
+ * operations.
+ *
+ * @author Alexander Libman <alibman@baltimore.com>
+ */
+// ============================================================================
+
+#include "test_config.h"
+
+ACE_RCSID (tests,
+ Proactor_Test,
+ "$Id$")
+
+#if defined (ACE_HAS_THREADS) && ((defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)) || (defined (ACE_HAS_AIO_CALLS)))
+ // This only works on Win32 platforms and on Unix platforms
+ // supporting POSIX aio calls.
+
+#include "ace/Signal.h"
+
+#include "ace/Service_Config.h"
+#include "ace/INET_Addr.h"
+#include "ace/SOCK_Connector.h"
+#include "ace/SOCK_Acceptor.h"
+#include "ace/SOCK_Stream.h"
+#include "ace/Object_Manager.h"
+#include "ace/Get_Opt.h"
+
+#include "ace/Proactor.h"
+#include "ace/Asynch_Acceptor.h"
+#include "ace/Asynch_Connector.h"
+#include "ace/Task.h"
+#include "ace/Thread_Semaphore.h"
+#include "ace/OS_NS_ctype.h"
+#include "ace/OS_NS_errno.h"
+#include "ace/OS_NS_signal.h"
+#include "ace/OS_NS_string.h"
+#include "ace/OS_NS_unistd.h"
+#include "ace/OS_NS_sys_socket.h"
+#include "ace/os_include/netinet/os_tcp.h"
+
+#include "ace/Atomic_Op.h"
+#include "ace/Synch_Traits.h"
+
+#if defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)
+
+# include "ace/WIN32_Proactor.h"
+
+#elif defined (ACE_HAS_AIO_CALLS)
+
+# include "ace/POSIX_Proactor.h"
+# include "ace/POSIX_CB_Proactor.h"
+# include "ace/SUN_Proactor.h"
+
+#endif /* defined (ACE_WIN32) && !defined (ACE_HAS_WINCE) */
+
+#include "Proactor_Test.h"
+
+
+// Proactor Type (UNIX only, Win32 ignored)
+typedef enum { DEFAULT = 0, AIOCB, SIG, SUN, CB } ProactorType;
+static ProactorType proactor_type = DEFAULT;
+
+// POSIX : > 0 max number aio operations proactor,
+static size_t max_aio_operations = 0;
+
+// both: 0 run client or server / depends on host
+// != 0 run client and server
+static int both = 0;
+
+// Host that we're connecting to.
+static const ACE_TCHAR *host = 0;
+
+// number of Client instances
+static int clients = 1;
+const int MAX_CLIENTS = 1000;
+const int MAX_SERVERS = 1000;
+
+// duplex mode: == 0 half-duplex
+// != 0 full duplex
+static int duplex = 0;
+
+// number threads in the Proactor thread pool
+static int threads = 1;
+
+// Port that we're receiving connections on.
+static u_short port = ACE_DEFAULT_SERVER_PORT;
+
+// Log options
+static int loglevel; // 0 full , 1 only errors
+
+static size_t xfer_limit; // Number of bytes for Client to send.
+
+static char complete_message[] =
+ "GET / HTTP/1.1\r\n"
+ "Accept: */*\r\n"
+ "Accept-Language: C++\r\n"
+ "Accept-Encoding: gzip, deflate\r\n"
+ "User-Agent: Proactor_Test/1.0 (non-compatible)\r\n"
+ "Connection: Keep-Alive\r\n"
+ "\r\n";
+
+class LogLocker
+{
+public:
+
+ LogLocker () { ACE_LOG_MSG->acquire (); }
+ virtual ~LogLocker () { ACE_LOG_MSG->release (); }
+};
+
+
+
+// Function to remove signals from the signal mask.
+static int
+disable_signal (int sigmin, int sigmax)
+{
+#ifndef ACE_WIN32
+
+ sigset_t signal_set;
+ if (sigemptyset (&signal_set) == - 1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Error: (%P|%t):%p\n"),
+ ACE_TEXT ("sigemptyset failed")));
+
+ for (int i = sigmin; i <= sigmax; i++)
+ sigaddset (&signal_set, i);
+
+ // Put the <signal_set>.
+ if (ACE_OS::pthread_sigmask (SIG_BLOCK, &signal_set, 0) != 0)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Error: (%P|%t):%p\n"),
+ ACE_TEXT ("pthread_sigmask failed")));
+#else
+ ACE_UNUSED_ARG (sigmin);
+ ACE_UNUSED_ARG (sigmax);
+#endif /* ACE_WIN32 */
+
+ return 1;
+}
+
+
+// *************************************************************
+// MyTask is ACE_Task resposible for :
+// 1. creation and deletion of
+// Proactor and Proactor thread pool
+// 2. running Proactor event loop
+// *************************************************************
+
+/**
+ * @class MyTask
+ *
+ * MyTask plays role for Proactor threads pool
+ *
+ * MyTask is ACE_Task resposible for:
+ * 1. Creation and deletion of Proactor and Proactor thread pool
+ * 2. Running Proactor event loop
+ */
+class MyTask : public ACE_Task<ACE_MT_SYNCH>
+{
+public:
+ MyTask (void):
+ lock_ (),
+ sem_ ((unsigned int) 0),
+ proactor_(0) {}
+
+ virtual ~MyTask()
+ {
+ (void) this->stop ();
+ (void) this->delete_proactor();
+ }
+
+ virtual int svc (void);
+
+ int start (int num_threads,
+ ProactorType type_proactor,
+ size_t max_op );
+ int stop (void);
+
+private:
+ int create_proactor (ProactorType type_proactor,
+ size_t max_op);
+ int delete_proactor (void);
+
+ ACE_SYNCH_RECURSIVE_MUTEX lock_;
+ ACE_Thread_Semaphore sem_;
+ ACE_Proactor * proactor_;
+
+};
+
+int
+MyTask::create_proactor (ProactorType type_proactor, size_t max_op)
+{
+ ACE_GUARD_RETURN (ACE_SYNCH_RECURSIVE_MUTEX,
+ monitor,
+ this->lock_,
+ -1);
+
+ ACE_ASSERT (this->proactor_ == 0);
+
+#if defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)
+
+ ACE_UNUSED_ARG (type_proactor);
+ ACE_UNUSED_ARG (max_op);
+
+ ACE_WIN32_Proactor *proactor_impl = 0;
+
+ ACE_NEW_RETURN (proactor_impl,
+ ACE_WIN32_Proactor,
+ -1);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT("(%t) Create Proactor Type = WIN32\n")));
+
+#elif defined (ACE_HAS_AIO_CALLS)
+
+ ACE_POSIX_Proactor * proactor_impl = 0;
+
+ switch (type_proactor)
+ {
+ case AIOCB:
+ ACE_NEW_RETURN (proactor_impl,
+ ACE_POSIX_AIOCB_Proactor (max_op),
+ -1);
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Create Proactor Type = AIOCB\n")));
+ break;
+
+#if defined(ACE_HAS_POSIX_REALTIME_SIGNALS)
+ case SIG:
+ ACE_NEW_RETURN (proactor_impl,
+ ACE_POSIX_SIG_Proactor (max_op),
+ -1);
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Create Proactor Type = SIG\n")));
+ break;
+#endif /* ACE_HAS_POSIX_REALTIME_SIGNALS */
+
+# if defined (sun)
+ case SUN:
+ ACE_NEW_RETURN (proactor_impl,
+ ACE_SUN_Proactor (max_op),
+ -1);
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT("(%t) Create Proactor Type = SUN\n")));
+ break;
+# endif /* sun */
+
+# if !defined(__Lynx__)
+ case CB:
+ ACE_NEW_RETURN (proactor_impl,
+ ACE_POSIX_CB_Proactor (max_op),
+ -1);
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Create Proactor Type = CB\n")));
+ break;
+# endif /* __Lynx__ */
+
+ default:
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Create Proactor Type = DEFAULT\n")));
+ break;
+ }
+
+#endif // (ACE_WIN32) && !defined (ACE_HAS_WINCE)
+
+ // always delete implementation 1 , not !(proactor_impl == 0)
+ ACE_NEW_RETURN (this->proactor_,
+ ACE_Proactor (proactor_impl, 1 ),
+ -1);
+ // Set new singleton and delete it in close_singleton()
+ ACE_Proactor::instance (this->proactor_, 1);
+ return 0;
+}
+
+int
+MyTask::delete_proactor (void)
+{
+ ACE_GUARD_RETURN (ACE_SYNCH_RECURSIVE_MUTEX,
+ monitor,
+ this->lock_,
+ -1);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Delete Proactor\n")));
+
+ ACE_Proactor::close_singleton ();
+ this->proactor_ = 0;
+
+ return 0;
+}
+
+int
+MyTask::start (int num_threads,
+ ProactorType type_proactor,
+ size_t max_op)
+{
+ if (this->create_proactor (type_proactor, max_op) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p.\n"),
+ ACE_TEXT ("unable to create proactor")),
+ -1);
+
+ if (this->activate (THR_NEW_LWP, num_threads) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p.\n"),
+ ACE_TEXT ("unable to activate thread pool")),
+ -1);
+
+ for (; num_threads > 0; num_threads--)
+ {
+ sem_.acquire ();
+ }
+
+ return 0;
+}
+
+
+int
+MyTask::stop ()
+{
+ if (this->proactor_ != 0)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Calling End Proactor event loop\n")));
+
+ ACE_Proactor::end_event_loop ();
+ }
+
+ if (this->wait () == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("%p.\n"),
+ ACE_TEXT ("unable to stop thread pool")));
+
+ return 0;
+}
+
+int
+MyTask::svc (void)
+{
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) MyTask started\n")));
+
+ disable_signal (ACE_SIGRTMIN, ACE_SIGRTMAX);
+
+ // signal that we are ready
+ sem_.release (1);
+
+ ACE_Proactor::run_event_loop ();
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) MyTask finished\n")));
+ return 0;
+}
+
+
+// TestData collects and reports on test-related transfer and connection
+// statistics.
+class TestData
+{
+public:
+ TestData ();
+ bool testing_done (void);
+ Server *server_up (void);
+ Client *client_up (void);
+ void server_done (Server *s);
+ void client_done (Client *c);
+ void stop_all (void);
+ void report (void);
+
+private:
+ struct Local_Stats
+ {
+ // Track number of sessions that report start, and those that report
+ // their end (and stats).
+ ACE_Atomic_Op<ACE_SYNCH_MUTEX, int> sessions_up_;
+ ACE_Atomic_Op<ACE_SYNCH_MUTEX, int> sessions_down_;
+
+ // Total read and write bytes for all sessions.
+ ACE_Atomic_Op<ACE_SYNCH_MUTEX, size_t> w_cnt_;
+ ACE_Atomic_Op<ACE_SYNCH_MUTEX, size_t> r_cnt_;
+ // Total read and write operations issues for all sessions.
+ ACE_Atomic_Op<ACE_SYNCH_MUTEX, size_t> w_ops_;
+ ACE_Atomic_Op<ACE_SYNCH_MUTEX, size_t> r_ops_;
+ } servers_, clients_;
+
+ ACE_SYNCH_MUTEX list_lock_;
+ Server *server_list_[MAX_SERVERS];
+ Client *client_list_[MAX_CLIENTS];
+};
+
+TestData::TestData ()
+{
+ int i;
+ for (i = 0; i < MAX_SERVERS; ++i)
+ this->server_list_[i] = 0;
+ for (i = 0; i < MAX_CLIENTS; ++i)
+ this->client_list_[i] = 0;
+}
+
+bool
+TestData::testing_done (void)
+{
+ int svr_up = this->servers_.sessions_up_.value ();
+ int svr_dn = this->servers_.sessions_down_.value ();
+ int clt_up = this->clients_.sessions_up_.value ();
+ int clt_dn = this->clients_.sessions_down_.value ();
+
+ if (svr_up == 0 && clt_up == 0) // No connections up yet
+ return false;
+
+ return (svr_dn >= svr_up && clt_dn >= clt_up);
+}
+
+Server *
+TestData::server_up (void)
+{
+ ++this->servers_.sessions_up_;
+ ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, monitor, this->list_lock_, 0);
+
+ for (int i = 0; i < MAX_SERVERS; ++i)
+ {
+ if (this->server_list_[i] == 0)
+ {
+ ACE_NEW_RETURN (this->server_list_[i], Server (this, i), 0);
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Server %d up; now %d up, %d down.\n"),
+ i,
+ this->servers_.sessions_up_.value (),
+ this->servers_.sessions_down_.value ()));
+ return this->server_list_[i];
+ }
+ }
+ return 0;
+}
+
+Client *
+TestData::client_up (void)
+{
+ ++this->clients_.sessions_up_;
+ ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, monitor, this->list_lock_, 0);
+
+ for (int i = 0; i < MAX_CLIENTS; ++i)
+ {
+ if (this->client_list_[i] == 0)
+ {
+ ACE_NEW_RETURN (this->client_list_[i], Client (this, i), 0);
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Client %d up; now %d up, %d down.\n"),
+ i,
+ this->clients_.sessions_up_.value (),
+ this->clients_.sessions_down_.value ()));
+ return this->client_list_[i];
+ }
+ }
+ return 0;
+}
+
+void
+TestData::server_done (Server *s)
+{
+ this->servers_.w_cnt_ += s->get_total_snd ();
+ this->servers_.r_cnt_ += s->get_total_rcv ();
+ this->servers_.w_ops_ += s->get_total_w ();
+ this->servers_.r_ops_ += s->get_total_r ();
+ ++this->servers_.sessions_down_;
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Server %d gone; now %d up, %d down\n"),
+ s->id (),
+ this->servers_.sessions_up_.value (),
+ this->servers_.sessions_down_.value ()));
+
+ ACE_GUARD (ACE_SYNCH_MUTEX, monitor, this->list_lock_);
+ int i;
+ for (i = 0; i < MAX_SERVERS; ++i)
+ {
+ if (this->server_list_[i] == s)
+ {
+ if (s->id () != i)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Server %d is pos %d in list\n"),
+ s->id (),
+ i));
+ this->server_list_[i] = 0;
+ break;
+ }
+ }
+ if (i >= MAX_SERVERS)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("Server %@ done but not listed\n"), s));
+
+ return;
+}
+
+void
+TestData::client_done (Client *c)
+{
+ this->clients_.w_cnt_ += c->get_total_snd ();
+ this->clients_.r_cnt_ += c->get_total_rcv ();
+ this->clients_.w_ops_ += c->get_total_w ();
+ this->clients_.r_ops_ += c->get_total_r ();
+ ++this->clients_.sessions_down_;
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Client %d gone; now %d up, %d down\n"),
+ c->id (),
+ this->clients_.sessions_up_.value (),
+ this->clients_.sessions_down_.value ()));
+
+ ACE_GUARD (ACE_SYNCH_MUTEX, monitor, this->list_lock_);
+ int i;
+ for (i = 0; i < MAX_CLIENTS; ++i)
+ {
+ if (this->client_list_[i] == c)
+ {
+ if (c->id () != i)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Client %d is pos %d in list\n"),
+ c->id (),
+ i));
+ this->client_list_[i] = 0;
+ break;
+ }
+ }
+ if (i >= MAX_CLIENTS)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("Client %@ done but not listed\n"), c));
+
+ return;
+}
+
+void
+TestData::stop_all (void)
+{
+ int i;
+
+ // Lock and cancel everything. Then release the lock, possibly allowing
+ // cleanups, then grab it again and delete all Servers and Clients.
+ {
+ ACE_GUARD (ACE_SYNCH_MUTEX, monitor, this->list_lock_);
+ for (i = 0; i < MAX_CLIENTS; ++i)
+ {
+ if (this->client_list_[i] != 0)
+ this->client_list_[i]->cancel ();
+ }
+
+ for (i = 0; i < MAX_SERVERS; ++i)
+ {
+ if (this->server_list_[i] != 0)
+ this->server_list_[i]->cancel ();
+ }
+ }
+ {
+ ACE_GUARD (ACE_SYNCH_MUTEX, monitor, this->list_lock_);
+ for (i = 0; i < MAX_CLIENTS; ++i)
+ {
+ if (this->client_list_[i] != 0)
+ delete this->client_list_[i];
+ }
+
+ for (i = 0; i < MAX_SERVERS; ++i)
+ {
+ if (this->server_list_[i] != 0)
+ delete this->server_list_[i];
+ }
+ }
+}
+
+void
+TestData::report (void)
+{
+ // Print statistics
+ ACE_TCHAR bufs [256];
+ ACE_TCHAR bufr [256];
+
+ ACE_OS::sprintf (bufs,
+ ACE_SIZE_T_FORMAT_SPECIFIER
+ ACE_TEXT ("(") ACE_SIZE_T_FORMAT_SPECIFIER ACE_TEXT (")"),
+ this->clients_.w_cnt_.value (),
+ this->clients_.w_ops_.value ());
+
+ ACE_OS::sprintf (bufr,
+ ACE_SIZE_T_FORMAT_SPECIFIER
+ ACE_TEXT ("(") ACE_SIZE_T_FORMAT_SPECIFIER ACE_TEXT (")"),
+ this->clients_.r_cnt_.value (),
+ this->clients_.r_ops_.value ());
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Clients total bytes (ops): snd=%s rcv=%s\n"),
+ bufs,
+ bufr));
+
+ ACE_OS::sprintf (bufs,
+ ACE_SIZE_T_FORMAT_SPECIFIER
+ ACE_TEXT ("(") ACE_SIZE_T_FORMAT_SPECIFIER ACE_TEXT (")"),
+ this->servers_.w_cnt_.value (),
+ this->servers_.w_ops_.value ());
+
+ ACE_OS::sprintf (bufr,
+ ACE_SIZE_T_FORMAT_SPECIFIER
+ ACE_TEXT ("(") ACE_SIZE_T_FORMAT_SPECIFIER ACE_TEXT (")"),
+ this->servers_.r_cnt_.value (),
+ this->servers_.r_ops_.value ());
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Servers total bytes (ops): snd=%s rcv=%s\n"),
+ bufs,
+ bufr));
+
+ if (this->clients_.w_cnt_.value () == 0 ||
+ this->clients_.r_cnt_.value () == 0 ||
+ this->servers_.w_cnt_.value () == 0 ||
+ this->servers_.r_cnt_.value () == 0 )
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("It appears that this test didn't ")
+ ACE_TEXT ("really do anything. Something is very wrong.\n")));
+}
+
+
+class Acceptor : public ACE_Asynch_Acceptor<Server>
+{
+public:
+ Acceptor (TestData *tester);
+ virtual ~Acceptor (void);
+
+ // Virtual from ACE_Asynch_Acceptor
+ Server *make_handler (void);
+
+private:
+ TestData *tester_;
+};
+
+// *************************************************************
+Acceptor::Acceptor (TestData *tester)
+ : tester_ (tester)
+{
+}
+
+Acceptor::~Acceptor (void)
+{
+ this->cancel ();
+}
+
+Server *
+Acceptor::make_handler (void)
+{
+ return this->tester_->server_up ();
+}
+
+// ***************************************************
+Server::Server ()
+{
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("Shouldn't use this constructor!\n")));
+}
+
+Server::Server (TestData *tester, int id)
+ : tester_ (tester),
+ id_ (id),
+ handle_ (ACE_INVALID_HANDLE),
+ io_count_ (0),
+ flg_cancel_(0),
+ total_snd_(0),
+ total_rcv_(0),
+ total_w_ (0),
+ total_r_ (0)
+{
+}
+
+Server::~Server (void)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Server %d dtor; %d sends (%d bytes); ")
+ ACE_TEXT ("%d recvs (%d bytes)\n"),
+ this->id_,
+ this->total_w_, this->total_snd_,
+ this->total_r_, this->total_rcv_));
+ if (this->io_count_ != 0)
+ ACE_ERROR ((LM_WARNING,
+ ACE_TEXT ("(%t) Server %d deleted with ")
+ ACE_TEXT ("%d I/O outstanding\n"),
+ this->id_,
+ this->io_count_));
+
+ // This test bounces data back and forth between Clients and Servers.
+ // Therefore, if there was significantly more data in one direction, that's
+ // a problem. Remember, the byte counts are unsigned values.
+ int issue_data_warning = 0;
+ if (this->total_snd_ > this->total_rcv_)
+ {
+ if (this->total_rcv_ == 0)
+ issue_data_warning = 1;
+ else if (this->total_snd_ / this->total_rcv_ > 2)
+ issue_data_warning = 1;
+ }
+ else
+ {
+ if (this->total_snd_ == 0)
+ issue_data_warning = 1;
+ else if (this->total_rcv_ / this->total_snd_ > 2)
+ issue_data_warning = 1;
+ }
+ if (issue_data_warning)
+ ACE_DEBUG ((LM_WARNING,
+ ACE_TEXT ("(%t) Above byte counts look odd; need review\n")));
+
+ if (this->tester_ != 0)
+ this->tester_->server_done (this);
+
+ if (this->handle_ != ACE_INVALID_HANDLE)
+ ACE_OS::closesocket (this->handle_);
+
+ this->id_ = -1;
+ this->handle_= ACE_INVALID_HANDLE;
+}
+
+void
+Server::cancel ()
+{
+ ACE_GUARD (ACE_SYNCH_MUTEX, monitor, this->lock_);
+
+ this->flg_cancel_ = 1;
+ this->ws_.cancel ();
+ this->rs_.cancel ();
+ return;
+}
+
+
+void
+Server::addresses (const ACE_INET_Addr& peer, const ACE_INET_Addr&)
+{
+ ACE_TCHAR str[256];
+ if (0 == peer.addr_to_string (str, sizeof (str) / sizeof (ACE_TCHAR)))
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Server %d connection from %s\n"),
+ this->id_,
+ str));
+ else
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%t) Server %d %p\n"),
+ this->id_,
+ ACE_TEXT ("addr_to_string")));
+ return;
+}
+
+
+void
+Server::open (ACE_HANDLE handle, ACE_Message_Block &)
+{
+ {
+ ACE_GUARD (ACE_SYNCH_MUTEX, monitor, this->lock_);
+
+ // Don't buffer serial sends.
+ this->handle_ = handle;
+ int nodelay = 1;
+ ACE_SOCK_Stream option_setter (handle);
+ if (-1 == option_setter.set_option (ACE_IPPROTO_TCP,
+ TCP_NODELAY,
+ &nodelay,
+ sizeof (nodelay)))
+ ACE_ERROR ((LM_ERROR, "%p\n", "set_option"));
+
+ if (this->ws_.open (*this, this->handle_) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%t) %p\n"),
+ ACE_TEXT ("Server::ACE_Asynch_Write_Stream::open")));
+ else if (this->rs_.open (*this, this->handle_) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%t) %p\n"),
+ ACE_TEXT ("Server::ACE_Asynch_Read_Stream::open")));
+ else
+ this->initiate_read_stream ();
+
+ if (this->io_count_ > 0)
+ return;
+ }
+ delete this;
+}
+
+int
+Server::initiate_read_stream (void)
+{
+ if (this->flg_cancel_ != 0 || this->handle_ == ACE_INVALID_HANDLE)
+ return -1;
+
+ ACE_Message_Block *mb = 0;
+ ACE_NEW_RETURN (mb,
+ ACE_Message_Block (1024), //BUFSIZ + 1),
+ -1);
+
+ // Inititiate read
+ if (this->rs_.read (*mb, mb->size () - 1) == -1)
+ {
+ mb->release ();
+#if defined (ACE_WIN32)
+ // On peer close, ReadFile will yield ERROR_NETNAME_DELETED; won't get
+ // a 0-byte read as we would if underlying calls used WSARecv.
+ if (ACE_OS::last_error () == ERROR_NETNAME_DELETED)
+ ACE_ERROR_RETURN ((LM_DEBUG,
+ ACE_TEXT ("(%t) Server %d, peer closed\n"),
+ this->id_),
+ -1);
+#endif /* ACE_WIN32 */
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%t) Server %d, %p\n"),
+ this->id_,
+ ACE_TEXT ("read")),
+ -1);
+ }
+
+ this->io_count_++;
+ this->total_r_++;
+ return 0;
+}
+
+int
+Server::initiate_write_stream (ACE_Message_Block &mb, size_t nbytes)
+{
+ if (this->flg_cancel_ != 0 || this->handle_ == ACE_INVALID_HANDLE)
+ {
+ mb.release ();
+ return -1;
+ }
+
+ if (nbytes == 0)
+ {
+ mb.release ();
+ ACE_ERROR_RETURN((LM_ERROR,
+ ACE_TEXT ("(%t) Server::ACE_Asynch_Write_Stream::write nbytes <0 ")),
+ -1);
+ }
+
+ if (this->ws_.write (mb, nbytes) == -1)
+ {
+ mb.release ();
+#if defined (ACE_WIN32)
+ // On peer close, WriteFile will yield ERROR_NETNAME_DELETED.
+ if (ACE_OS::last_error () == ERROR_NETNAME_DELETED)
+ ACE_ERROR_RETURN ((LM_DEBUG,
+ ACE_TEXT ("(%t) Server %d, peer gone\n"),
+ this->id_),
+ -1);
+#endif /* ACE_WIN32 */
+ ACE_ERROR_RETURN((LM_ERROR,
+ ACE_TEXT ("(%t) Server %d, %p\n"),
+ this->id_,
+ ACE_TEXT ("write")),
+ -1);
+ }
+
+ this->io_count_++;
+ this->total_w_++;
+ return 0;
+}
+
+void
+Server::handle_read_stream (const ACE_Asynch_Read_Stream::Result &result)
+{
+ {
+ ACE_GUARD (ACE_SYNCH_MUTEX, monitor, this->lock_ );
+
+ ACE_Message_Block & mb = result.message_block ();
+
+ // Reset pointers.
+ mb.rd_ptr ()[result.bytes_transferred ()] = '\0';
+
+ if (loglevel > 1)
+ {
+ LogLocker log_lock;
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) **** Server %d: handle_read_stream() ****\n"),
+ this->id_));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%s = %d\n"),
+ ACE_TEXT ("bytes_to_read"),
+ result.bytes_to_read ()));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%s = %d\n"),
+ ACE_TEXT ("handle"),
+ result.handle ()));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%s = %d\n"),
+ ACE_TEXT ("bytes_transfered"),
+ result.bytes_transferred ()));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%s = %@\n"),
+ ACE_TEXT ("act"),
+ result.act ()));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%s = %d\n"),
+ ACE_TEXT ("success"),
+ result.success ()));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%s = %@\n"),
+ ACE_TEXT ("completion_key"),
+ result.completion_key ()));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%s = %d\n"),
+ ACE_TEXT ("error"),
+ result.error ()));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%s = %s\n"),
+ ACE_TEXT ("message_block"),
+ mb.rd_ptr ()));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("**** end of message ****************\n")));
+ }
+ else if (result.error () != 0)
+ {
+ ACE_Log_Priority prio;
+#if defined (ACE_WIN32)
+ if (result.error () == ERROR_OPERATION_ABORTED)
+ prio = LM_DEBUG;
+#else
+ if (result.error () == ECANCELED)
+ prio = LM_DEBUG;
+#endif /* ACE_WIN32 */
+ else
+ prio = LM_ERROR;
+ ACE_Log_Msg::instance ()->errnum (result.error ());
+ ACE_Log_Msg::instance ()->log (prio,
+ ACE_TEXT ("(%t) Server %d; %p\n"),
+ this->id_,
+ ACE_TEXT ("read"));
+ }
+ else if (loglevel > 0)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Server %d: read %d bytes\n"),
+ this->id_,
+ result.bytes_transferred ()));
+ }
+
+ if (result.error () == 0 && result.bytes_transferred () > 0)
+ {
+ this->total_rcv_ += result.bytes_transferred ();
+
+ if (this->initiate_write_stream (mb,
+ result.bytes_transferred ()) == 0)
+ {
+ if (duplex != 0) // Initiate new read from the stream.
+ this->initiate_read_stream ();
+ }
+ }
+ else
+ mb.release ();
+
+ this->io_count_--;
+ if (this->io_count_ > 0)
+ return;
+ }
+ delete this;
+}
+
+void
+Server::handle_write_stream (const ACE_Asynch_Write_Stream::Result &result)
+{
+ {
+ ACE_GUARD (ACE_SYNCH_MUTEX, monitor, this->lock_);
+
+ ACE_Message_Block & mb = result.message_block ();
+
+ if (loglevel > 1)
+ {
+ LogLocker log_lock;
+
+ //mb.rd_ptr () [0] = '\0';
+ mb.rd_ptr (mb.rd_ptr () - result.bytes_transferred ());
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) **** Server %d: handle_write_stream() ****\n"),
+ this->id_));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%s = %d\n"),
+ ACE_TEXT ("bytes_to_write"),
+ result.bytes_to_write ()));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%s = %d\n"),
+ ACE_TEXT ("handle"),
+ result.handle ()));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%s = %d\n"),
+ ACE_TEXT ("bytes_transfered"),
+ result.bytes_transferred ()));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%s = %@\n"),
+ ACE_TEXT ("act"),
+ result.act ()));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%s = %d\n"),
+ ACE_TEXT ("success"),
+ result.success ()));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%s = %@\n"),
+ ACE_TEXT ("completion_key"),
+ result.completion_key ()));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%s = %d\n"),
+ ACE_TEXT ("error"),
+ result.error ()));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%s = %s\n"),
+ ACE_TEXT ("message_block"),
+ mb.rd_ptr ()));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("**** end of message ****************\n")));
+ }
+ else if (result.error () != 0)
+ {
+ ACE_Log_Priority prio;
+#if defined (ACE_WIN32)
+ if (result.error () == ERROR_OPERATION_ABORTED)
+ prio = LM_DEBUG;
+#else
+ if (result.error () == ECANCELED)
+ prio = LM_DEBUG;
+#endif /* ACE_WIN32 */
+ else
+ prio = LM_ERROR;
+ ACE_Log_Msg::instance ()->errnum (result.error ());
+ ACE_Log_Msg::instance ()->log (prio,
+ ACE_TEXT ("(%t) Server %d; %p\n"),
+ this->id_,
+ ACE_TEXT ("write"));
+ }
+ else if (loglevel > 0)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Server %d: wrote %d bytes ok\n"),
+ this->id_,
+ result.bytes_transferred ()));
+ }
+
+ mb.release ();
+
+ if (result.error () == 0 && result.bytes_transferred () > 0)
+ {
+ this->total_snd_ += result.bytes_transferred ();
+
+ if (duplex == 0)
+ this->initiate_read_stream ();
+ }
+
+ this->io_count_--;
+ if (this->io_count_ > 0)
+ return;
+ }
+ delete this;
+}
+
+// *******************************************
+// Connector
+// *******************************************
+
+class Connector : public ACE_Asynch_Connector<Client>
+{
+public:
+ Connector (TestData *tester);
+ virtual ~Connector (void);
+
+ int start (const ACE_INET_Addr &addr, int num);
+
+ // Virtual from ACE_Asynch_Connector
+ Client *make_handler (void);
+
+private:
+ TestData *tester_;
+};
+
+// *************************************************************
+
+Connector::Connector (TestData *tester)
+ : tester_ (tester)
+{
+}
+
+Connector::~Connector (void)
+{
+ this->cancel ();
+}
+
+Client *
+Connector::make_handler (void)
+{
+ return this->tester_->client_up ();
+}
+
+
+int
+Connector::start (const ACE_INET_Addr& addr, int num)
+{
+ if (num > MAX_CLIENTS)
+ num = MAX_CLIENTS;
+
+ if (num < 0)
+ num = 1;
+
+ int rc = 0;
+
+ // int open ( int pass_addresses = 0,
+ // ACE_Proactor *proactor = 0,
+ // int validate_new_connection = 0 );
+
+ if (this->open (1, 0, 1) != 0)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("(%t) %p\n"),
+ ACE_LIB_TEXT ("Connector::open failed")));
+ return rc;
+ }
+
+ for (; rc < num; rc++)
+ {
+ if (this->connect (addr) != 0)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%t) %p\n"),
+ ACE_TEXT ("Connector::connect failed")));
+ break;
+ }
+ }
+ return rc;
+}
+
+
+Client::Client ()
+{
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("Shouldn't use this constructor!\n")));
+}
+
+Client::Client (TestData *tester, int id)
+ : tester_ (tester),
+ id_ (id),
+ handle_ (ACE_INVALID_HANDLE),
+ io_count_ (0),
+ stop_writing_ (0),
+ flg_cancel_ (0),
+ total_snd_ (0),
+ total_rcv_ (0),
+ total_w_ (0),
+ total_r_ (0)
+{
+}
+
+Client::~Client (void)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Client %d dtor; %d sends (%d bytes); ")
+ ACE_TEXT ("%d recvs (%d bytes)\n"),
+ this->id_,
+ this->total_w_, this->total_snd_,
+ this->total_r_, this->total_rcv_));
+ if (this->io_count_ != 0)
+ ACE_ERROR ((LM_WARNING,
+ ACE_TEXT ("(%t) Client %d deleted with %d I/O outstanding\n"),
+ this->id_,
+ this->io_count_));
+
+ // This test bounces data back and forth between Clients and Servers.
+ // Therefore, if there was significantly more data in one direction, that's
+ // a problem. Remember, the byte counts are unsigned values.
+ int issue_data_warning = 0;
+ if (this->total_snd_ > this->total_rcv_)
+ {
+ if (this->total_rcv_ == 0)
+ issue_data_warning = 1;
+ else if (this->total_snd_ / this->total_rcv_ > 2)
+ issue_data_warning = 1;
+ }
+ else
+ {
+ if (this->total_snd_ == 0)
+ issue_data_warning = 1;
+ else if (this->total_rcv_ / this->total_snd_ > 2)
+ issue_data_warning = 1;
+ }
+ if (issue_data_warning)
+ ACE_DEBUG ((LM_WARNING,
+ ACE_TEXT ("(%t) Above byte counts look odd; need review\n")));
+
+ if (this->tester_ != 0)
+ this->tester_->client_done (this);
+
+ this->id_ = -1;
+ this->handle_= ACE_INVALID_HANDLE;
+ if (this->handle_ != ACE_INVALID_HANDLE)
+ {
+ ACE_OS::closesocket (this->handle_);
+ }
+ this->handle_= ACE_INVALID_HANDLE;
+}
+
+void
+Client::cancel ()
+{
+ ACE_GUARD (ACE_SYNCH_MUTEX, monitor, this->lock_);
+
+ this->flg_cancel_ = 1;
+ this->ws_.cancel ();
+ this->rs_.cancel ();
+ return;
+}
+
+void
+Client::close ()
+{
+ // This must be called with the lock_ held.
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Closing Client %d writes; %d I/O outstanding\n"),
+ this->id_, this->io_count_));
+ ACE_OS::shutdown (this->handle_, ACE_SHUTDOWN_WRITE);
+ this->stop_writing_ = 1;
+ return;
+}
+
+
+void
+Client::addresses (const ACE_INET_Addr& /* peer */, const ACE_INET_Addr& local)
+{
+ ACE_TCHAR str[256];
+ if (0 == local.addr_to_string (str, sizeof (str) / sizeof (ACE_TCHAR)))
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Client %d connected on %s\n"),
+ this->id_,
+ str));
+ else
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%t) Client %d %p\n"),
+ this->id_,
+ ACE_TEXT ("addr_to_string")));
+ return;
+}
+
+
+void
+Client::open (ACE_HANDLE handle, ACE_Message_Block &)
+{
+ {
+ ACE_GUARD (ACE_SYNCH_MUTEX, monitor, this->lock_);
+
+ // Don't buffer serial sends.
+ this->handle_ = handle;
+ int nodelay = 1;
+ ACE_SOCK_Stream option_setter (handle);
+ if (option_setter.set_option (ACE_IPPROTO_TCP,
+ TCP_NODELAY,
+ &nodelay,
+ sizeof (nodelay)))
+ ACE_ERROR ((LM_ERROR, "%p\n", "set_option"));
+
+ // Open ACE_Asynch_Write_Stream
+ if (this->ws_.open (*this, this->handle_) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%t) %p\n"),
+ ACE_TEXT ("Client::ACE_Asynch_Write_Stream::open")));
+
+ // Open ACE_Asynch_Read_Stream
+ else if (this->rs_.open (*this, this->handle_) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%t) %p\n"),
+ ACE_TEXT ("Client::ACE_Asynch_Read_Stream::open")));
+
+ else if (this->initiate_write_stream () == 0)
+ {
+ if (duplex != 0) // Start an asynchronous read
+ this->initiate_read_stream ();
+ }
+
+ if (this->io_count_ > 0)
+ return;
+ }
+ delete this;
+}
+
+int
+Client::initiate_write_stream (void)
+{
+ if (this->flg_cancel_ != 0 ||
+ this->stop_writing_ ||
+ this->handle_ == ACE_INVALID_HANDLE)
+ return -1;
+
+ static const size_t complete_message_length = ACE_OS::strlen (complete_message);
+
+#if (defined (ACE_WIN32) && !defined (ACE_HAS_WINCE))
+
+ ACE_Message_Block *mb1 = 0,
+ *mb2 = 0,
+ *mb3 = 0;
+
+ // No need to allocate +1 for proper printing - the memory includes it already
+ ACE_NEW_RETURN (mb1,
+ ACE_Message_Block ((char *)complete_message,
+ complete_message_length),
+ -1);
+
+ ACE_NEW_RETURN (mb2,
+ ACE_Message_Block ((char *)complete_message,
+ complete_message_length),
+ -1);
+
+ ACE_NEW_RETURN (mb3,
+ ACE_Message_Block ((char *)complete_message,
+ complete_message_length),
+ -1);
+
+ mb1->wr_ptr (complete_message_length);
+ mb2->wr_ptr (complete_message_length);
+ mb3->wr_ptr (complete_message_length);
+
+ // chain them together
+ mb1->cont (mb2);
+ mb2->cont (mb3);
+
+ if (this->ws_.writev (*mb1, mb1->total_length ()) == -1)
+ {
+ mb1->release ();
+ ACE_ERROR_RETURN((LM_ERROR,
+ ACE_TEXT ("(%t) %p\n"),
+ ACE_TEXT ("Client::ACE_Asynch_Stream::writev")),
+ -1);
+ }
+#else /* (defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)) */
+
+ ACE_Message_Block *mb = 0;
+
+ // No need to allocate +1 for proper printing - the memory includes it already
+ ACE_NEW_RETURN (mb,
+ ACE_Message_Block (complete_message, complete_message_length),
+ -1);
+ mb->wr_ptr (complete_message_length);
+
+ if (this->ws_.write (*mb, mb->length ()) == -1)
+ {
+ mb->release ();
+#if defined (ACE_WIN32)
+ // On peer close, WriteFile will yield ERROR_NETNAME_DELETED.
+ if (ACE_OS::last_error () == ERROR_NETNAME_DELETED)
+ ACE_ERROR_RETURN ((LM_DEBUG,
+ ACE_TEXT ("(%t) Client %d, peer gone\n"),
+ this->id_),
+ -1);
+#endif /* ACE_WIN32 */
+ ACE_ERROR_RETURN((LM_ERROR,
+ ACE_TEXT ("(%t) Client %d, %p\n"),
+ this->id_,
+ ACE_TEXT ("write")),
+ -1);
+ }
+#endif /* (defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)) */
+
+ this->io_count_++;
+ this->total_w_++;
+ return 0;
+}
+
+int
+Client::initiate_read_stream (void)
+{
+ if (this->flg_cancel_ != 0 || this->handle_ == ACE_INVALID_HANDLE)
+ return -1;
+
+ static const size_t complete_message_length =
+ ACE_OS::strlen (complete_message);
+
+#if (defined (ACE_WIN32) && !defined (ACE_HAS_WINCE) && (ACE_HAS_WINNT4) && (ACE_HAS_WINNT4 != 0))
+ ACE_Message_Block *mb1 = 0,
+ *mb2 = 0,
+ *mb3 = 0,
+ *mb4 = 0,
+ *mb5 = 0,
+ *mb6 = 0;
+
+ // We allocate +1 only for proper printing - we can just set the last byte
+ // to '\0' before printing out
+ ACE_NEW_RETURN (mb1, ACE_Message_Block (complete_message_length + 1), -1);
+ ACE_NEW_RETURN (mb2, ACE_Message_Block (complete_message_length + 1), -1);
+ ACE_NEW_RETURN (mb3, ACE_Message_Block (complete_message_length + 1), -1);
+
+ // Let allocate memory for one more triplet,
+ // This improves performance
+ // as we can receive more the than one block at once
+ // Generally, we can receive more triplets ....
+ ACE_NEW_RETURN (mb4, ACE_Message_Block (complete_message_length + 1), -1);
+ ACE_NEW_RETURN (mb5, ACE_Message_Block (complete_message_length + 1), -1);
+ ACE_NEW_RETURN (mb6, ACE_Message_Block (complete_message_length + 1), -1);
+
+ mb1->cont (mb2);
+ mb2->cont (mb3);
+
+ mb3->cont (mb4);
+ mb4->cont (mb5);
+ mb5->cont (mb6);
+
+
+ // hide last byte in each message block, reserving it for later to set '\0'
+ // for proper printouts
+ mb1->size (mb1->size () - 1);
+ mb2->size (mb2->size () - 1);
+ mb3->size (mb3->size () - 1);
+
+ mb4->size (mb4->size () - 1);
+ mb5->size (mb5->size () - 1);
+ mb6->size (mb6->size () - 1);
+
+ // Inititiate read
+ if (this->rs_.readv (*mb1, mb1->total_size () - 1) == -1)
+ {
+ mb1->release ();
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%t) %p\n"),
+ ACE_TEXT ("Client::ACE_Asynch_Read_Stream::readv")),
+ -1);
+ }
+#else /* (defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)) */
+
+ // Try to read more chunks
+ size_t blksize = ( complete_message_length > BUFSIZ ) ?
+ complete_message_length : BUFSIZ;
+
+ ACE_Message_Block *mb = 0;
+
+ // We allocate +1 only for proper printing - we can just set the last byte
+ // to '\0' before printing out
+ ACE_NEW_RETURN (mb,
+ ACE_Message_Block (blksize + 1),
+ -1);
+
+ // Inititiate read
+ if (this->rs_.read (*mb, mb->size () - 1) == -1)
+ {
+ mb->release ();
+#if defined (ACE_WIN32)
+ // On peer close, ReadFile will yield ERROR_NETNAME_DELETED; won't get
+ // a 0-byte read as we would if underlying calls used WSARecv.
+ if (ACE_OS::last_error () == ERROR_NETNAME_DELETED)
+ ACE_ERROR_RETURN ((LM_DEBUG,
+ ACE_TEXT ("(%t) Client %d, peer closed\n"),
+ this->id_),
+ -1);
+#endif /* ACE_WIN32 */
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%t) Client %d, %p\n"),
+ this->id_,
+ ACE_TEXT ("read")),
+ -1);
+ }
+#endif /* (defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)) */
+
+ this->io_count_++;
+ this->total_r_++;
+ return 0;
+}
+
+void
+Client::handle_write_stream (const ACE_Asynch_Write_Stream::Result &result)
+{
+ {
+ ACE_GUARD (ACE_SYNCH_MUTEX, monitor, this->lock_);
+
+ ACE_Message_Block & mb = result.message_block ();
+
+ if (loglevel > 1)
+ {
+ LogLocker log_lock;
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) **** Client %d: handle_write_stream() ****\n"),
+ this->id_));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%s = %d\n"),
+ ACE_TEXT ("bytes_to_write"),
+ result.bytes_to_write ()));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%s = %d\n"),
+ ACE_TEXT ("handle"),
+ result.handle ()));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%s = %d\n"),
+ ACE_TEXT ("bytes_transfered"),
+ result.bytes_transferred ()));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%s = %@\n"),
+ ACE_TEXT ("act"),
+ result.act ()));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%s = %d\n"),
+ ACE_TEXT ("success"),
+ result.success ()));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%s = %@\n"),
+ ACE_TEXT ("completion_key"),
+ result.completion_key ()));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%s = %d\n"),
+ ACE_TEXT ("error"),
+ result.error ()));
+
+#if (defined (ACE_WIN32) && !defined (ACE_HAS_WINCE))
+ size_t bytes_transferred = result.bytes_transferred ();
+ char index = 0;
+ for (ACE_Message_Block* mb_i = &mb;
+ (mb_i != 0) && (bytes_transferred > 0);
+ mb_i = mb_i->cont ())
+ {
+ // write 0 at string end for proper printout (if end of mb, it's 0 already)
+ mb_i->rd_ptr()[0] = '\0';
+
+ size_t len = mb_i->rd_ptr () - mb_i->base ();
+
+ // move rd_ptr backwards as required for printout
+ if (len >= bytes_transferred)
+ {
+ mb_i->rd_ptr (0 - bytes_transferred);
+ bytes_transferred = 0;
+ }
+ else
+ {
+ mb_i->rd_ptr (0 - len);
+ bytes_transferred -= len;
+ }
+
+ ++index;
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%s%d = %s\n"),
+ ACE_TEXT ("message_block, part "),
+ index,
+ mb_i->rd_ptr ()));
+ }
+#else /* (defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)) */
+ // write 0 at string end for proper printout (if end of mb, it's 0 already)
+ mb.rd_ptr()[0] = '\0';
+ // move rd_ptr backwards as required for printout
+ mb.rd_ptr (- result.bytes_transferred ());
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%s = %s\n"),
+ ACE_TEXT ("message_block"),
+ mb.rd_ptr ()));
+#endif /* (defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)) */
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("**** end of message ****************\n")));
+ }
+ else if (result.error () != 0)
+ {
+ ACE_Log_Priority prio;
+#if defined (ACE_WIN32)
+ if (result.error () == ERROR_OPERATION_ABORTED)
+ prio = LM_DEBUG;
+#else
+ if (result.error () == ECANCELED)
+ prio = LM_DEBUG;
+#endif /* ACE_WIN32 */
+ else
+ prio = LM_ERROR;
+ ACE_Log_Msg::instance ()->errnum (result.error ());
+ ACE_Log_Msg::instance ()->log (prio,
+ ACE_TEXT ("(%t) Client %d; %p\n"),
+ this->id_,
+ ACE_TEXT ("write"));
+ }
+ else if (loglevel > 0)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Client %d: wrote %d bytes ok\n"),
+ this->id_,
+ result.bytes_transferred ()));
+ }
+
+ mb.release ();
+
+ if (result.error () == 0 && result.bytes_transferred () > 0)
+ {
+ this->total_snd_ += result.bytes_transferred ();
+ if (this->total_snd_ >= xfer_limit)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Client %d sent %d, limit %d\n"),
+ this->id_, this->total_snd_, xfer_limit));
+ this->close ();
+ }
+ if (duplex != 0) // full duplex, continue write
+ {
+ if ((this->total_snd_- this->total_rcv_) < 1024*32 ) //flow control
+ this->initiate_write_stream ();
+ }
+ else // half-duplex read reply, after read we will start write
+ this->initiate_read_stream ();
+ }
+
+ this->io_count_--;
+ if (this->io_count_ > 0)
+ return;
+ }
+ delete this;
+}
+
+void
+Client::handle_read_stream (const ACE_Asynch_Read_Stream::Result &result)
+{
+ {
+ ACE_GUARD (ACE_SYNCH_MUTEX, monitor, this->lock_);
+
+ ACE_Message_Block & mb = result.message_block ();
+
+ if (loglevel > 1)
+ {
+ LogLocker log_lock;
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) **** Client %d: handle_read_stream() ****\n"),
+ this->id_));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%s = %d\n"),
+ ACE_TEXT ("bytes_to_read"),
+ result.bytes_to_read ()));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%s = %d\n"),
+ ACE_TEXT ("handle"),
+ result.handle ()));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%s = %d\n"),
+ ACE_TEXT ("bytes_transfered"),
+ result.bytes_transferred ()));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%s = %@\n"),
+ ACE_TEXT ("act"),
+ result.act ()));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%s = %d\n"),
+ ACE_TEXT ("success"),
+ result.success ()));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%s = %@\n"),
+ ACE_TEXT ("completion_key"),
+ result.completion_key ()));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%s = %d\n"),
+ ACE_TEXT ("error"),
+ result.error ()));
+
+#if (defined (ACE_WIN32) && !defined (ACE_HAS_WINCE))
+ char index = 0;
+ for (ACE_Message_Block* mb_i = &mb;
+ mb_i != 0;
+ mb_i = mb_i->cont ())
+ {
+ ++index;
+ // write 0 at string end for proper printout
+ mb_i->wr_ptr()[0] = '\0';
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%s%d = %s\n"),
+ ACE_TEXT ("message_block, part "),
+ index,
+ mb_i->rd_ptr ()));
+ }
+#else /* (defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)) */
+ // write 0 at string end for proper printout
+ mb.rd_ptr()[result.bytes_transferred ()] = '\0'; // for proper printout
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%s = %s\n"),
+ ACE_TEXT ("message_block"),
+ mb.rd_ptr ()));
+#endif /* (defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)) */
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("**** end of message ****************\n")));
+ }
+ else if (result.error () != 0)
+ {
+ ACE_Log_Priority prio;
+#if defined (ACE_WIN32)
+ if (result.error () == ERROR_OPERATION_ABORTED)
+ prio = LM_DEBUG;
+#else
+ if (result.error () == ECANCELED)
+ prio = LM_DEBUG;
+#endif /* ACE_WIN32 */
+ else
+ prio = LM_ERROR;
+ ACE_Log_Msg::instance ()->errnum (result.error ());
+ ACE_Log_Msg::instance ()->log (prio,
+ ACE_TEXT ("(%t) Client %d; %p\n"),
+ this->id_,
+ ACE_TEXT ("read"));
+ }
+ else if (loglevel > 0)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Client %d: read %d bytes ok\n"),
+ this->id_,
+ result.bytes_transferred ()));
+ }
+
+ mb.release ();
+
+ if (result.error () == 0 && result.bytes_transferred () > 0)
+ {
+ this->total_rcv_ += result.bytes_transferred ();
+
+ if (duplex != 0 || this->stop_writing_) // full duplex, continue read
+ this->initiate_read_stream ();
+ else // half-duplex write, after write we will start read
+ this->initiate_write_stream ();
+ }
+
+ this->io_count_--;
+ if (this->io_count_ > 0)
+ return;
+ }
+ delete this;
+}
+
+// *************************************************************
+// Configuration helpers
+// *************************************************************
+int
+print_usage (int /* argc */, ACE_TCHAR *argv[])
+{
+ ACE_ERROR
+ ((LM_ERROR,
+ ACE_TEXT ("\nusage: %s")
+ ACE_TEXT ("\n-o <max number of started aio operations for Proactor>")
+ ACE_TEXT ("\n-t <Proactor type> UNIX-only, Win32-default always:")
+ ACE_TEXT ("\n a AIOCB")
+ ACE_TEXT ("\n i SIG")
+ ACE_TEXT ("\n c CB")
+ ACE_TEXT ("\n s SUN")
+ ACE_TEXT ("\n d default")
+ ACE_TEXT ("\n-d <duplex mode 1-on/0-off>")
+ ACE_TEXT ("\n-h <host> for Client mode")
+ ACE_TEXT ("\n-n <number threads for Proactor pool>")
+ ACE_TEXT ("\n-p <port to listen/connect>")
+ ACE_TEXT ("\n-c <number of client instances>")
+ ACE_TEXT ("\n-b run client and server at the same time")
+ ACE_TEXT ("\n f file")
+ ACE_TEXT ("\n c console")
+ ACE_TEXT ("\n-v log level")
+ ACE_TEXT ("\n 0 - log errors and highlights")
+ ACE_TEXT ("\n 1 - log level 0 plus progress information")
+ ACE_TEXT ("\n 2 - log level 1 plus operation parameters and results")
+ ACE_TEXT ("\n-x max transfer byte count per Client")
+ ACE_TEXT ("\n-u show this message")
+ ACE_TEXT ("\n"),
+ argv[0]
+ ));
+ return -1;
+}
+
+static int
+set_proactor_type (const ACE_TCHAR *ptype)
+{
+ if (!ptype)
+ return 0;
+
+ switch (ACE_OS::ace_toupper (*ptype))
+ {
+ case 'D':
+ proactor_type = DEFAULT;
+ return 1;
+ case 'A':
+ proactor_type = AIOCB;
+ return 1;
+ case 'I':
+ proactor_type = SIG;
+ return 1;
+#if defined (sun)
+ case 'S':
+ proactor_type = SUN;
+ return 1;
+#endif /* sun */
+#if !defined (__Lynx__)
+ case 'C':
+ proactor_type = CB;
+ return 1;
+#endif /* __Lynx__ */
+ default:
+ break;
+ }
+ return 0;
+}
+
+static int
+parse_args (int argc, ACE_TCHAR *argv[])
+{
+ // First, set up all the defaults then let any args change them.
+ both = 1; // client and server simultaneosly
+ duplex = 1; // full duplex is on
+ host = ACE_LOCALHOST; // server to connect
+ port = ACE_DEFAULT_SERVER_PORT; // port to connect/listen
+ max_aio_operations = 512; // POSIX Proactor params
+ proactor_type = DEFAULT; // Proactor type = default
+ threads = 3; // size of Proactor thread pool
+ clients = 10; // number of clients
+ loglevel = 0; // log level : only errors and highlights
+ // Default transfer limit 50 messages per Sender
+ xfer_limit = 50 * ACE_OS::strlen (complete_message);
+
+ if (argc == 1) // no arguments , so one button test
+ return 0;
+
+ ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("x:t:o:n:p:d:h:c:v:ub"));
+ int c;
+
+ while ((c = get_opt ()) != EOF)
+ {
+ switch (c)
+ {
+ case 'x': // xfer limit
+ xfer_limit = static_cast<size_t> (ACE_OS::atoi (get_opt.opt_arg ()));
+ if (xfer_limit == 0)
+ xfer_limit = 1; // Bare minimum.
+ break;
+ case 'b': // both client and server
+ both = 1;
+ break;
+ case 'v': // log level
+ loglevel = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'd': // duplex
+ duplex = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'h': // host for sender
+ host = get_opt.opt_arg ();
+ break;
+ case 'p': // port number
+ port = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'n': // thread pool size
+ threads = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'c': // number of clients
+ clients = ACE_OS::atoi (get_opt.opt_arg ());
+ if (clients > MAX_CLIENTS)
+ clients = MAX_CLIENTS;
+ break;
+ case 'o': // max number of aio for proactor
+ max_aio_operations = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 't': // Proactor Type
+ if (set_proactor_type (get_opt.opt_arg ()))
+ break;
+ return print_usage (argc, argv);
+ case 'u':
+ default:
+ return print_usage (argc, argv);
+ } // switch
+ } // while
+
+ if (proactor_type == SUN && threads > 1)
+ {
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Sun aiowait is not thread-safe; ")
+ ACE_TEXT ("changing to 1 thread\n")));
+ threads = 1;
+ }
+
+ return 0;
+}
+
+int
+run_main (int argc, ACE_TCHAR *argv[])
+{
+ ACE_START_TEST (ACE_TEXT ("Proactor_Test"));
+
+ if (::parse_args (argc, argv) == -1)
+ return -1;
+
+ disable_signal (ACE_SIGRTMIN, ACE_SIGRTMAX);
+ disable_signal (SIGPIPE, SIGPIPE);
+
+ MyTask task1;
+ TestData test;
+
+ if (task1.start (threads, proactor_type, max_aio_operations) == 0)
+ {
+ Acceptor acceptor (&test);
+ Connector connector (&test);
+ ACE_INET_Addr addr (port);
+
+ int rc = 0;
+
+ if (both != 0 || host == 0) // Acceptor
+ {
+ // Simplify, initial read with zero size
+ if (acceptor.open (addr, 0, 1) == 0)
+ rc = 1;
+ }
+
+ if (both != 0 || host != 0)
+ {
+ if (host == 0)
+ host = ACE_LOCALHOST;
+
+ if (addr.set (port, host, 1, addr.get_type ()) == -1)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), host));
+ else
+ rc += connector.start (addr, clients);
+ }
+
+ // Wait a few seconds to let things get going, then poll til
+ // all sessions are done. Note that when we exit this scope, the
+ // Acceptor and Connector will be destroyed, which should prevent
+ // further connections and also test how well destroyed handlers
+ // are handled.
+ ACE_OS::sleep (3);
+ }
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) Sleeping til sessions run down.\n")));
+ while (!test.testing_done ())
+ ACE_OS::sleep (1);
+
+ test.stop_all ();
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) Stop Thread Pool Task\n")));
+ task1.stop ();
+
+ ACE_END_TEST;
+
+ return 0;
+}
+
+#else
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("Proactor_Test"));
+
+ ACE_DEBUG ((LM_INFO,
+ ACE_TEXT ("Threads or Asynchronous IO is unsupported.\n")
+ ACE_TEXT ("Proactor_Test will not be run.")));
+
+ ACE_END_TEST;
+
+ return 0;
+}
+
+#endif /* ACE_WIN32 && !ACE_HAS_WINCE || ACE_HAS_AIO_CALLS */
diff --git a/ACE/tests/Proactor_Test.h b/ACE/tests/Proactor_Test.h
new file mode 100644
index 00000000000..044839a4cb5
--- /dev/null
+++ b/ACE/tests/Proactor_Test.h
@@ -0,0 +1,142 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Proactor_Test.h
+//
+// = DESCRIPTION
+// Define class needed for generating templates. IBM C++ requires this to
+// be in its own file for auto template instantiation.
+//
+// = AUTHOR
+// @author Alexander Libman <alibman@baltimore.com>
+//
+// ============================================================================
+
+#ifndef ACE_TESTS_PROACTOR_TEST_H
+#define ACE_TESTS_PROACTOR_TEST_H
+
+#include "ace/Synch_Traits.h"
+#include "ace/Thread_Mutex.h"
+
+// forward declaration
+class TestData;
+
+class Server : public ACE_Service_Handler
+{
+public:
+ Server ();
+ Server (TestData *tester, int id);
+ ~Server (void);
+
+ int id (void) { return this->id_; }
+ size_t get_total_snd (void) { return this->total_snd_; }
+ size_t get_total_rcv (void) { return this->total_rcv_; }
+ long get_total_w (void) { return this->total_w_; }
+ long get_total_r (void) { return this->total_r_; }
+
+ // This is called to pass the new connection's addresses.
+ virtual void addresses (const ACE_INET_Addr& peer,
+ const ACE_INET_Addr& local);
+
+ /// This is called after the new connection has been accepted.
+ virtual void open (ACE_HANDLE handle,
+ ACE_Message_Block &message_block);
+ void cancel ();
+
+protected:
+ /**
+ * @name AIO callback handling
+ *
+ * These methods are called by the framework
+ */
+ /// This is called when asynchronous <read> operation from the
+ /// socket completes.
+ virtual void handle_read_stream (const ACE_Asynch_Read_Stream::Result &result);
+
+ /// This is called when an asynchronous <write> to the socket
+ /// completes.
+ virtual void handle_write_stream (const ACE_Asynch_Write_Stream::Result &result);
+
+private:
+ int initiate_read_stream (void);
+ int initiate_write_stream (ACE_Message_Block &mb, size_t nbytes);
+
+ TestData *tester_;
+ int id_;
+
+ ACE_Asynch_Read_Stream rs_;
+ ACE_Asynch_Write_Stream ws_;
+ ACE_HANDLE handle_;
+ ACE_SYNCH_MUTEX lock_;
+
+ long io_count_; // Number of currently outstanding I/O requests
+ int flg_cancel_;
+ size_t total_snd_; // Number of bytes successfully sent
+ size_t total_rcv_; // Number of bytes successfully received
+ long total_w_; // Number of write operations
+ long total_r_; // Number of read operations
+};
+
+// *******************************************
+// Client
+// *******************************************
+
+class Client : public ACE_Service_Handler
+{
+public:
+
+ /// This is called after the new connection has been established.
+ virtual void open (ACE_HANDLE handle,
+ ACE_Message_Block &message_block);
+
+ Client ();
+ Client (TestData *tester, int id);
+ ~Client (void);
+
+ int id (void) { return this->id_; }
+ size_t get_total_snd (void) { return this->total_snd_; }
+ size_t get_total_rcv (void) { return this->total_rcv_; }
+ long get_total_w (void) { return this->total_w_; }
+ long get_total_r (void) { return this->total_r_; }
+
+ // This is called to pass the new connection's addresses.
+ virtual void addresses (const ACE_INET_Addr& peer,
+ const ACE_INET_Addr& local);
+
+ virtual void handle_read_stream (const ACE_Asynch_Read_Stream::Result &result);
+ // This is called when asynchronous reads from the socket complete
+
+ virtual void handle_write_stream (const ACE_Asynch_Write_Stream::Result &result);
+ // This is called when asynchronous writes from the socket complete
+
+ void cancel (void);
+
+private:
+ int initiate_read_stream (void);
+ int initiate_write_stream (void);
+ void close (void);
+
+ TestData *tester_;
+ int id_;
+
+ ACE_Asynch_Read_Stream rs_;
+ ACE_Asynch_Write_Stream ws_;
+ ACE_HANDLE handle_;
+
+ ACE_SYNCH_MUTEX lock_;
+
+ long io_count_;
+ int stop_writing_; // Writes are shut down; just read.
+ int flg_cancel_;
+ size_t total_snd_;
+ size_t total_rcv_;
+ long total_w_;
+ long total_r_;
+};
+
+#endif /* ACE_TESTS_PROACTOR_TEST_H */
diff --git a/ACE/tests/Proactor_Test_IPV6.cpp b/ACE/tests/Proactor_Test_IPV6.cpp
new file mode 100644
index 00000000000..7ac9443d0ae
--- /dev/null
+++ b/ACE/tests/Proactor_Test_IPV6.cpp
@@ -0,0 +1,1984 @@
+// $Id$
+// ============================================================================
+/**
+ * @file Proactor_Test_IPV6.cpp
+ *
+ * $Id$
+ *
+ * This program illustrates how the ACE_Proactor can be used to
+ * implement an application that does various asynchronous
+ * operations.
+ *
+ * @author Alexander Libman <alibman@baltimore.com>
+ * @author Brian Buesker <bbuesker@qualcomm.com> - modified for IPv6 operation
+ */
+// ============================================================================
+
+#include "test_config.h"
+
+ACE_RCSID (tests,
+ Proactor_Test,
+ "$Id$")
+
+#if defined (ACE_HAS_THREADS) && ((defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)) || (defined (ACE_HAS_AIO_CALLS)))
+ // This only works on Win32 platforms and on Unix platforms
+ // supporting POSIX aio calls.
+
+#include "ace/Signal.h"
+
+#include "ace/Service_Config.h"
+#include "ace/INET_Addr.h"
+#include "ace/SOCK_Connector.h"
+#include "ace/SOCK_Acceptor.h"
+#include "ace/SOCK_Stream.h"
+#include "ace/Object_Manager.h"
+#include "ace/Get_Opt.h"
+
+#include "ace/Proactor.h"
+#include "ace/Asynch_Acceptor.h"
+#include "ace/Asynch_Connector.h"
+#include "ace/Task.h"
+#include "ace/Thread_Semaphore.h"
+#include "ace/OS_NS_ctype.h"
+#include "ace/OS_NS_errno.h"
+#include "ace/OS_NS_signal.h"
+#include "ace/OS_NS_string.h"
+#include "ace/OS_NS_unistd.h"
+#include "ace/OS_NS_sys_socket.h"
+#include "ace/os_include/netinet/os_tcp.h"
+
+#include "ace/Atomic_Op.h"
+#include "ace/Synch_Traits.h"
+
+#if defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)
+
+# include "ace/WIN32_Proactor.h"
+
+#elif defined (ACE_HAS_AIO_CALLS)
+
+# include "ace/POSIX_Proactor.h"
+# include "ace/POSIX_CB_Proactor.h"
+# include "ace/SUN_Proactor.h"
+
+#endif /* defined (ACE_WIN32) && !defined (ACE_HAS_WINCE) */
+
+#include "Proactor_Test.h"
+
+
+// Proactor Type (UNIX only, Win32 ignored)
+typedef enum { DEFAULT = 0, AIOCB, SIG, SUN, CB } ProactorType;
+static ProactorType proactor_type = DEFAULT;
+
+// POSIX : > 0 max number aio operations proactor,
+static size_t max_aio_operations = 0;
+
+// both: 0 run client or server / depends on host
+// != 0 run client and server
+static int both = 0;
+
+// Host that we're connecting to.
+static const ACE_TCHAR *host = 0;
+
+// number of Client instances
+static int clients = 1;
+const int MAX_CLIENTS = 1000;
+const int MAX_SERVERS = 1000;
+
+// duplex mode: == 0 half-duplex
+// != 0 full duplex
+static int duplex = 0;
+
+// number threads in the Proactor thread pool
+static int threads = 1;
+
+// Port that we're receiving connections on.
+static u_short port = ACE_DEFAULT_SERVER_PORT;
+
+// Log options
+static int loglevel; // 0 full , 1 only errors
+
+static size_t xfer_limit; // Number of bytes for Client to send.
+
+static char complete_message[] =
+ "GET / HTTP/1.1\r\n"
+ "Accept: */*\r\n"
+ "Accept-Language: C++\r\n"
+ "Accept-Encoding: gzip, deflate\r\n"
+ "User-Agent: Proactor_Test_IPv6/1.0 (non-compatible)\r\n"
+ "Connection: Keep-Alive\r\n"
+ "\r\n";
+
+class LogLocker
+{
+public:
+
+ LogLocker () { ACE_LOG_MSG->acquire (); }
+ virtual ~LogLocker () { ACE_LOG_MSG->release (); }
+};
+
+
+
+// Function to remove signals from the signal mask.
+static int
+disable_signal (int sigmin, int sigmax)
+{
+#ifndef ACE_WIN32
+
+ sigset_t signal_set;
+ if (sigemptyset (&signal_set) == - 1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Error: (%P|%t):%p\n"),
+ ACE_TEXT ("sigemptyset failed")));
+
+ for (int i = sigmin; i <= sigmax; i++)
+ sigaddset (&signal_set, i);
+
+ // Put the <signal_set>.
+ if (ACE_OS::pthread_sigmask (SIG_BLOCK, &signal_set, 0) != 0)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Error: (%P|%t):%p\n"),
+ ACE_TEXT ("pthread_sigmask failed")));
+#else
+ ACE_UNUSED_ARG (sigmin);
+ ACE_UNUSED_ARG (sigmax);
+#endif /* ACE_WIN32 */
+
+ return 1;
+}
+
+
+// *************************************************************
+// MyTask is ACE_Task resposible for :
+// 1. creation and deletion of
+// Proactor and Proactor thread pool
+// 2. running Proactor event loop
+// *************************************************************
+
+/**
+ * @class MyTask
+ *
+ * MyTask plays role for Proactor threads pool
+ *
+ * MyTask is ACE_Task resposible for:
+ * 1. Creation and deletion of Proactor and Proactor thread pool
+ * 2. Running Proactor event loop
+ */
+class MyTask : public ACE_Task<ACE_MT_SYNCH>
+{
+public:
+ MyTask (void):
+ lock_ (),
+ sem_ ((unsigned int) 0),
+ proactor_(0) {}
+
+ virtual ~MyTask()
+ {
+ (void) this->stop ();
+ (void) this->delete_proactor();
+ }
+
+ virtual int svc (void);
+
+ int start (int num_threads,
+ ProactorType type_proactor,
+ size_t max_op );
+ int stop (void);
+
+private:
+ int create_proactor (ProactorType type_proactor,
+ size_t max_op);
+ int delete_proactor (void);
+
+ ACE_SYNCH_RECURSIVE_MUTEX lock_;
+ ACE_Thread_Semaphore sem_;
+ ACE_Proactor * proactor_;
+
+};
+
+int
+MyTask::create_proactor (ProactorType type_proactor, size_t max_op)
+{
+ ACE_GUARD_RETURN (ACE_SYNCH_RECURSIVE_MUTEX,
+ monitor,
+ this->lock_,
+ -1);
+
+ ACE_ASSERT (this->proactor_ == 0);
+
+#if defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)
+
+ ACE_UNUSED_ARG (type_proactor);
+ ACE_UNUSED_ARG (max_op);
+
+ ACE_WIN32_Proactor *proactor_impl = 0;
+
+ ACE_NEW_RETURN (proactor_impl,
+ ACE_WIN32_Proactor,
+ -1);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT("(%t) Create Proactor Type = WIN32\n")));
+
+#elif defined (ACE_HAS_AIO_CALLS)
+
+ ACE_POSIX_Proactor * proactor_impl = 0;
+
+ switch (type_proactor)
+ {
+ case AIOCB:
+ ACE_NEW_RETURN (proactor_impl,
+ ACE_POSIX_AIOCB_Proactor (max_op),
+ -1);
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Create Proactor Type = AIOCB\n")));
+ break;
+
+#if defined(ACE_HAS_POSIX_REALTIME_SIGNALS)
+ case SIG:
+ ACE_NEW_RETURN (proactor_impl,
+ ACE_POSIX_SIG_Proactor (max_op),
+ -1);
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Create Proactor Type = SIG\n")));
+ break;
+#endif /* ACE_HAS_POSIX_REALTIME_SIGNALS */
+
+# if defined (sun)
+ case SUN:
+ ACE_NEW_RETURN (proactor_impl,
+ ACE_SUN_Proactor (max_op),
+ -1);
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT("(%t) Create Proactor Type = SUN\n")));
+ break;
+# endif /* sun */
+
+# if !defined(__Lynx__)
+ case CB:
+ ACE_NEW_RETURN (proactor_impl,
+ ACE_POSIX_CB_Proactor (max_op),
+ -1);
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Create Proactor Type = CB\n")));
+ break;
+# endif /* __Lynx__ */
+
+ default:
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Create Proactor Type = DEFAULT\n")));
+ break;
+ }
+
+#endif // (ACE_WIN32) && !defined (ACE_HAS_WINCE)
+
+ // always delete implementation 1 , not !(proactor_impl == 0)
+ ACE_NEW_RETURN (this->proactor_,
+ ACE_Proactor (proactor_impl, 1 ),
+ -1);
+ // Set new singleton and delete it in close_singleton()
+ ACE_Proactor::instance (this->proactor_, 1);
+ return 0;
+}
+
+int
+MyTask::delete_proactor (void)
+{
+ ACE_GUARD_RETURN (ACE_SYNCH_RECURSIVE_MUTEX,
+ monitor,
+ this->lock_,
+ -1);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Delete Proactor\n")));
+
+ ACE_Proactor::close_singleton ();
+ this->proactor_ = 0;
+
+ return 0;
+}
+
+int
+MyTask::start (int num_threads,
+ ProactorType type_proactor,
+ size_t max_op)
+{
+ if (this->create_proactor (type_proactor, max_op) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p.\n"),
+ ACE_TEXT ("unable to create proactor")),
+ -1);
+
+ if (this->activate (THR_NEW_LWP, num_threads) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p.\n"),
+ ACE_TEXT ("unable to activate thread pool")),
+ -1);
+
+ for (; num_threads > 0; num_threads--)
+ {
+ sem_.acquire ();
+ }
+
+ return 0;
+}
+
+
+int
+MyTask::stop ()
+{
+ if (this->proactor_ != 0)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Calling End Proactor event loop\n")));
+
+ ACE_Proactor::end_event_loop ();
+ }
+
+ if (this->wait () == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("%p.\n"),
+ ACE_TEXT ("unable to stop thread pool")));
+
+ return 0;
+}
+
+int
+MyTask::svc (void)
+{
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) MyTask started\n")));
+
+ disable_signal (ACE_SIGRTMIN, ACE_SIGRTMAX);
+
+ // signal that we are ready
+ sem_.release (1);
+
+ ACE_Proactor::run_event_loop ();
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) MyTask finished\n")));
+ return 0;
+}
+
+
+// TestData collects and reports on test-related transfer and connection
+// statistics.
+class TestData
+{
+public:
+ TestData ();
+ bool testing_done (void);
+ Server *server_up (void);
+ Client *client_up (void);
+ void server_done (Server *s);
+ void client_done (Client *c);
+ void stop_all (void);
+ void report (void);
+
+private:
+ struct Local_Stats
+ {
+ // Track number of sessions that report start, and those that report
+ // their end (and stats).
+ ACE_Atomic_Op<ACE_SYNCH_MUTEX, int> sessions_up_;
+ ACE_Atomic_Op<ACE_SYNCH_MUTEX, int> sessions_down_;
+
+ // Total read and write bytes for all sessions.
+ ACE_Atomic_Op<ACE_SYNCH_MUTEX, size_t> w_cnt_;
+ ACE_Atomic_Op<ACE_SYNCH_MUTEX, size_t> r_cnt_;
+ // Total read and write operations issues for all sessions.
+ ACE_Atomic_Op<ACE_SYNCH_MUTEX, size_t> w_ops_;
+ ACE_Atomic_Op<ACE_SYNCH_MUTEX, size_t> r_ops_;
+ } servers_, clients_;
+
+ ACE_SYNCH_MUTEX list_lock_;
+ Server *server_list_[MAX_SERVERS];
+ Client *client_list_[MAX_CLIENTS];
+};
+
+TestData::TestData ()
+{
+ int i;
+ for (i = 0; i < MAX_SERVERS; ++i)
+ this->server_list_[i] = 0;
+ for (i = 0; i < MAX_CLIENTS; ++i)
+ this->client_list_[i] = 0;
+}
+
+bool
+TestData::testing_done (void)
+{
+ int svr_up = this->servers_.sessions_up_.value ();
+ int svr_dn = this->servers_.sessions_down_.value ();
+ int clt_up = this->clients_.sessions_up_.value ();
+ int clt_dn = this->clients_.sessions_down_.value ();
+
+ if (svr_up == 0 && clt_up == 0) // No connections up yet
+ return false;
+
+ return (svr_dn >= svr_up && clt_dn >= clt_up);
+}
+
+Server *
+TestData::server_up (void)
+{
+ ++this->servers_.sessions_up_;
+ ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, monitor, this->list_lock_, 0);
+
+ for (int i = 0; i < MAX_SERVERS; ++i)
+ {
+ if (this->server_list_[i] == 0)
+ {
+ ACE_NEW_RETURN (this->server_list_[i], Server (this, i), 0);
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Server %d up; now %d up, %d down.\n"),
+ i,
+ this->servers_.sessions_up_.value (),
+ this->servers_.sessions_down_.value ()));
+ return this->server_list_[i];
+ }
+ }
+ return 0;
+}
+
+Client *
+TestData::client_up (void)
+{
+ ++this->clients_.sessions_up_;
+ ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, monitor, this->list_lock_, 0);
+
+ for (int i = 0; i < MAX_CLIENTS; ++i)
+ {
+ if (this->client_list_[i] == 0)
+ {
+ ACE_NEW_RETURN (this->client_list_[i], Client (this, i), 0);
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Client %d up; now %d up, %d down.\n"),
+ i,
+ this->clients_.sessions_up_.value (),
+ this->clients_.sessions_down_.value ()));
+ return this->client_list_[i];
+ }
+ }
+ return 0;
+}
+
+void
+TestData::server_done (Server *s)
+{
+ this->servers_.w_cnt_ += s->get_total_snd ();
+ this->servers_.r_cnt_ += s->get_total_rcv ();
+ this->servers_.w_ops_ += s->get_total_w ();
+ this->servers_.r_ops_ += s->get_total_r ();
+ ++this->servers_.sessions_down_;
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Server %d gone; now %d up, %d down\n"),
+ s->id (),
+ this->servers_.sessions_up_.value (),
+ this->servers_.sessions_down_.value ()));
+
+ ACE_GUARD (ACE_SYNCH_MUTEX, monitor, this->list_lock_);
+ int i;
+ for (i = 0; i < MAX_SERVERS; ++i)
+ {
+ if (this->server_list_[i] == s)
+ {
+ if (s->id () != i)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Server %d is pos %d in list\n"),
+ s->id (),
+ i));
+ this->server_list_[i] = 0;
+ break;
+ }
+ }
+ if (i >= MAX_SERVERS)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("Server %@ done but not listed\n"), s));
+
+ return;
+}
+
+void
+TestData::client_done (Client *c)
+{
+ this->clients_.w_cnt_ += c->get_total_snd ();
+ this->clients_.r_cnt_ += c->get_total_rcv ();
+ this->clients_.w_ops_ += c->get_total_w ();
+ this->clients_.r_ops_ += c->get_total_r ();
+ ++this->clients_.sessions_down_;
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Client %d gone; now %d up, %d down\n"),
+ c->id (),
+ this->clients_.sessions_up_.value (),
+ this->clients_.sessions_down_.value ()));
+
+ ACE_GUARD (ACE_SYNCH_MUTEX, monitor, this->list_lock_);
+ int i;
+ for (i = 0; i < MAX_CLIENTS; ++i)
+ {
+ if (this->client_list_[i] == c)
+ {
+ if (c->id () != i)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Client %d is pos %d in list\n"),
+ c->id (),
+ i));
+ this->client_list_[i] = 0;
+ break;
+ }
+ }
+ if (i >= MAX_CLIENTS)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("Client %@ done but not listed\n"), c));
+
+ return;
+}
+
+void
+TestData::stop_all (void)
+{
+ int i;
+
+ // Lock and cancel everything. Then release the lock, possibly allowing
+ // cleanups, then grab it again and delete all Servers and Clients.
+ {
+ ACE_GUARD (ACE_SYNCH_MUTEX, monitor, this->list_lock_);
+ for (i = 0; i < MAX_CLIENTS; ++i)
+ {
+ if (this->client_list_[i] != 0)
+ this->client_list_[i]->cancel ();
+ }
+
+ for (i = 0; i < MAX_SERVERS; ++i)
+ {
+ if (this->server_list_[i] != 0)
+ this->server_list_[i]->cancel ();
+ }
+ }
+ {
+ ACE_GUARD (ACE_SYNCH_MUTEX, monitor, this->list_lock_);
+ for (i = 0; i < MAX_CLIENTS; ++i)
+ {
+ if (this->client_list_[i] != 0)
+ delete this->client_list_[i];
+ }
+
+ for (i = 0; i < MAX_SERVERS; ++i)
+ {
+ if (this->server_list_[i] != 0)
+ delete this->server_list_[i];
+ }
+ }
+}
+
+void
+TestData::report (void)
+{
+ // Print statistics
+ ACE_TCHAR bufs [256];
+ ACE_TCHAR bufr [256];
+
+ ACE_OS::sprintf (bufs,
+ ACE_SIZE_T_FORMAT_SPECIFIER
+ ACE_TEXT ("(") ACE_SIZE_T_FORMAT_SPECIFIER ACE_TEXT (")"),
+ this->clients_.w_cnt_.value (),
+ this->clients_.w_ops_.value ());
+
+ ACE_OS::sprintf (bufr,
+ ACE_SIZE_T_FORMAT_SPECIFIER
+ ACE_TEXT ("(") ACE_SIZE_T_FORMAT_SPECIFIER ACE_TEXT (")"),
+ this->clients_.r_cnt_.value (),
+ this->clients_.r_ops_.value ());
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Clients total bytes (ops): snd=%s rcv=%s\n"),
+ bufs,
+ bufr));
+
+ ACE_OS::sprintf (bufs,
+ ACE_SIZE_T_FORMAT_SPECIFIER
+ ACE_TEXT ("(") ACE_SIZE_T_FORMAT_SPECIFIER ACE_TEXT (")"),
+ this->servers_.w_cnt_.value (),
+ this->servers_.w_ops_.value ());
+
+ ACE_OS::sprintf (bufr,
+ ACE_SIZE_T_FORMAT_SPECIFIER
+ ACE_TEXT ("(") ACE_SIZE_T_FORMAT_SPECIFIER ACE_TEXT (")"),
+ this->servers_.r_cnt_.value (),
+ this->servers_.r_ops_.value ());
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Servers total bytes (ops): snd=%s rcv=%s\n"),
+ bufs,
+ bufr));
+
+ if (this->clients_.w_cnt_.value () == 0 ||
+ this->clients_.r_cnt_.value () == 0 ||
+ this->servers_.w_cnt_.value () == 0 ||
+ this->servers_.r_cnt_.value () == 0 )
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("It appears that this test didn't ")
+ ACE_TEXT ("really do anything. Something is very wrong.\n")));
+}
+
+
+class Acceptor : public ACE_Asynch_Acceptor<Server>
+{
+public:
+ Acceptor (TestData *tester);
+ virtual ~Acceptor (void);
+
+ // Virtual from ACE_Asynch_Acceptor
+ Server *make_handler (void);
+
+private:
+ TestData *tester_;
+};
+
+// *************************************************************
+Acceptor::Acceptor (TestData *tester)
+ : tester_ (tester)
+{
+}
+
+Acceptor::~Acceptor (void)
+{
+ this->cancel ();
+}
+
+Server *
+Acceptor::make_handler (void)
+{
+ return this->tester_->server_up ();
+}
+
+// ***************************************************
+Server::Server ()
+{
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("Shouldn't use this constructor!\n")));
+}
+
+Server::Server (TestData *tester, int id)
+ : tester_ (tester),
+ id_ (id),
+ handle_ (ACE_INVALID_HANDLE),
+ io_count_ (0),
+ flg_cancel_(0),
+ total_snd_(0),
+ total_rcv_(0),
+ total_w_ (0),
+ total_r_ (0)
+{
+}
+
+Server::~Server (void)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Server %d dtor; %d sends (%d bytes); ")
+ ACE_TEXT ("%d recvs (%d bytes)\n"),
+ this->id_,
+ this->total_w_, this->total_snd_,
+ this->total_r_, this->total_rcv_));
+ if (this->io_count_ != 0)
+ ACE_ERROR ((LM_WARNING,
+ ACE_TEXT ("(%t) Server %d deleted with ")
+ ACE_TEXT ("%d I/O outstanding\n"),
+ this->id_,
+ this->io_count_));
+
+ // This test bounces data back and forth between Clients and Servers.
+ // Therefore, if there was significantly more data in one direction, that's
+ // a problem. Remember, the byte counts are unsigned values.
+ int issue_data_warning = 0;
+ if (this->total_snd_ > this->total_rcv_)
+ {
+ if (this->total_rcv_ == 0)
+ issue_data_warning = 1;
+ else if (this->total_snd_ / this->total_rcv_ > 2)
+ issue_data_warning = 1;
+ }
+ else
+ {
+ if (this->total_snd_ == 0)
+ issue_data_warning = 1;
+ else if (this->total_rcv_ / this->total_snd_ > 2)
+ issue_data_warning = 1;
+ }
+ if (issue_data_warning)
+ ACE_DEBUG ((LM_WARNING,
+ ACE_TEXT ("(%t) Above byte counts look odd; need review\n")));
+
+ if (this->tester_ != 0)
+ this->tester_->server_done (this);
+
+ if (this->handle_ != ACE_INVALID_HANDLE)
+ ACE_OS::closesocket (this->handle_);
+
+ this->id_ = -1;
+ this->handle_= ACE_INVALID_HANDLE;
+}
+
+void
+Server::cancel ()
+{
+ ACE_GUARD (ACE_SYNCH_MUTEX, monitor, this->lock_);
+
+ this->flg_cancel_ = 1;
+ this->ws_.cancel ();
+ this->rs_.cancel ();
+ return;
+}
+
+
+void
+Server::addresses (const ACE_INET_Addr& peer, const ACE_INET_Addr&)
+{
+ ACE_TCHAR str[256];
+ if (0 == peer.addr_to_string (str, sizeof (str) / sizeof (ACE_TCHAR)))
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Server %d connection from %s\n"),
+ this->id_,
+ str));
+ else
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%t) Server %d %p\n"),
+ this->id_,
+ ACE_TEXT ("addr_to_string")));
+ return;
+}
+
+
+void
+Server::open (ACE_HANDLE handle, ACE_Message_Block &)
+{
+ {
+ ACE_GUARD (ACE_SYNCH_MUTEX, monitor, this->lock_);
+
+ // Don't buffer serial sends.
+ this->handle_ = handle;
+ int nodelay = 1;
+ ACE_SOCK_Stream option_setter (handle);
+ if (-1 == option_setter.set_option (ACE_IPPROTO_TCP,
+ TCP_NODELAY,
+ &nodelay,
+ sizeof (nodelay)))
+ ACE_ERROR ((LM_ERROR, "%p\n", "set_option"));
+
+ if (this->ws_.open (*this, this->handle_) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%t) %p\n"),
+ ACE_TEXT ("Server::ACE_Asynch_Write_Stream::open")));
+ else if (this->rs_.open (*this, this->handle_) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%t) %p\n"),
+ ACE_TEXT ("Server::ACE_Asynch_Read_Stream::open")));
+ else
+ this->initiate_read_stream ();
+
+ if (this->io_count_ > 0)
+ return;
+ }
+ delete this;
+}
+
+int
+Server::initiate_read_stream (void)
+{
+ if (this->flg_cancel_ != 0 || this->handle_ == ACE_INVALID_HANDLE)
+ return -1;
+
+ ACE_Message_Block *mb = 0;
+ ACE_NEW_RETURN (mb,
+ ACE_Message_Block (1024), //BUFSIZ + 1),
+ -1);
+
+ // Inititiate read
+ if (this->rs_.read (*mb, mb->size () - 1) == -1)
+ {
+ mb->release ();
+#if defined (ACE_WIN32)
+ // On peer close, ReadFile will yield ERROR_NETNAME_DELETED; won't get
+ // a 0-byte read as we would if underlying calls used WSARecv.
+ if (ACE_OS::last_error () == ERROR_NETNAME_DELETED)
+ ACE_ERROR_RETURN ((LM_DEBUG,
+ ACE_TEXT ("(%t) Server %d, peer closed\n"),
+ this->id_),
+ -1);
+#endif /* ACE_WIN32 */
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%t) Server %d, %p\n"),
+ this->id_,
+ ACE_TEXT ("read")),
+ -1);
+ }
+
+ this->io_count_++;
+ this->total_r_++;
+ return 0;
+}
+
+int
+Server::initiate_write_stream (ACE_Message_Block &mb, size_t nbytes)
+{
+ if (this->flg_cancel_ != 0 || this->handle_ == ACE_INVALID_HANDLE)
+ {
+ mb.release ();
+ return -1;
+ }
+
+ if (nbytes == 0)
+ {
+ mb.release ();
+ ACE_ERROR_RETURN((LM_ERROR,
+ ACE_TEXT ("(%t) Server::ACE_Asynch_Write_Stream::write nbytes <0 ")),
+ -1);
+ }
+
+ if (this->ws_.write (mb, nbytes) == -1)
+ {
+ mb.release ();
+#if defined (ACE_WIN32)
+ // On peer close, WriteFile will yield ERROR_NETNAME_DELETED.
+ if (ACE_OS::last_error () == ERROR_NETNAME_DELETED)
+ ACE_ERROR_RETURN ((LM_DEBUG,
+ ACE_TEXT ("(%t) Server %d, peer gone\n"),
+ this->id_),
+ -1);
+#endif /* ACE_WIN32 */
+ ACE_ERROR_RETURN((LM_ERROR,
+ ACE_TEXT ("(%t) Server %d, %p\n"),
+ this->id_,
+ ACE_TEXT ("write")),
+ -1);
+ }
+
+ this->io_count_++;
+ this->total_w_++;
+ return 0;
+}
+
+void
+Server::handle_read_stream (const ACE_Asynch_Read_Stream::Result &result)
+{
+ {
+ ACE_GUARD (ACE_SYNCH_MUTEX, monitor, this->lock_ );
+
+ ACE_Message_Block & mb = result.message_block ();
+
+ // Reset pointers.
+ mb.rd_ptr ()[result.bytes_transferred ()] = '\0';
+
+ if (loglevel > 1)
+ {
+ LogLocker log_lock;
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) **** Server %d: handle_read_stream() ****\n"),
+ this->id_));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%s = %d\n"),
+ ACE_TEXT ("bytes_to_read"),
+ result.bytes_to_read ()));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%s = %d\n"),
+ ACE_TEXT ("handle"),
+ result.handle ()));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%s = %d\n"),
+ ACE_TEXT ("bytes_transfered"),
+ result.bytes_transferred ()));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%s = %@\n"),
+ ACE_TEXT ("act"),
+ result.act ()));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%s = %d\n"),
+ ACE_TEXT ("success"),
+ result.success ()));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%s = %@\n"),
+ ACE_TEXT ("completion_key"),
+ result.completion_key ()));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%s = %d\n"),
+ ACE_TEXT ("error"),
+ result.error ()));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%s = %s\n"),
+ ACE_TEXT ("message_block"),
+ mb.rd_ptr ()));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("**** end of message ****************\n")));
+ }
+ else if (result.error () != 0)
+ {
+ ACE_Log_Priority prio;
+#if defined (ACE_WIN32)
+ if (result.error () == ERROR_OPERATION_ABORTED)
+ prio = LM_DEBUG;
+#else
+ if (result.error () == ECANCELED)
+ prio = LM_DEBUG;
+#endif /* ACE_WIN32 */
+ else
+ prio = LM_ERROR;
+ ACE_Log_Msg::instance ()->errnum (result.error ());
+ ACE_Log_Msg::instance ()->log (prio,
+ ACE_TEXT ("(%t) Server %d; %p\n"),
+ this->id_,
+ ACE_TEXT ("read"));
+ }
+ else if (loglevel > 0)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Server %d: read %d bytes\n"),
+ this->id_,
+ result.bytes_transferred ()));
+ }
+
+ if (result.error () == 0 && result.bytes_transferred () > 0)
+ {
+ this->total_rcv_ += result.bytes_transferred ();
+
+ if (this->initiate_write_stream (mb,
+ result.bytes_transferred ()) == 0)
+ {
+ if (duplex != 0) // Initiate new read from the stream.
+ this->initiate_read_stream ();
+ }
+ }
+ else
+ mb.release ();
+
+ this->io_count_--;
+ if (this->io_count_ > 0)
+ return;
+ }
+ delete this;
+}
+
+void
+Server::handle_write_stream (const ACE_Asynch_Write_Stream::Result &result)
+{
+ {
+ ACE_GUARD (ACE_SYNCH_MUTEX, monitor, this->lock_);
+
+ ACE_Message_Block & mb = result.message_block ();
+
+ if (loglevel > 1)
+ {
+ LogLocker log_lock;
+
+ //mb.rd_ptr () [0] = '\0';
+ mb.rd_ptr (mb.rd_ptr () - result.bytes_transferred ());
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) **** Server %d: handle_write_stream() ****\n"),
+ this->id_));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%s = %d\n"),
+ ACE_TEXT ("bytes_to_write"),
+ result.bytes_to_write ()));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%s = %d\n"),
+ ACE_TEXT ("handle"),
+ result.handle ()));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%s = %d\n"),
+ ACE_TEXT ("bytes_transfered"),
+ result.bytes_transferred ()));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%s = %@\n"),
+ ACE_TEXT ("act"),
+ result.act ()));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%s = %d\n"),
+ ACE_TEXT ("success"),
+ result.success ()));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%s = %@\n"),
+ ACE_TEXT ("completion_key"),
+ result.completion_key ()));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%s = %d\n"),
+ ACE_TEXT ("error"),
+ result.error ()));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%s = %s\n"),
+ ACE_TEXT ("message_block"),
+ mb.rd_ptr ()));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("**** end of message ****************\n")));
+ }
+ else if (result.error () != 0)
+ {
+ ACE_Log_Priority prio;
+#if defined (ACE_WIN32)
+ if (result.error () == ERROR_OPERATION_ABORTED)
+ prio = LM_DEBUG;
+#else
+ if (result.error () == ECANCELED)
+ prio = LM_DEBUG;
+#endif /* ACE_WIN32 */
+ else
+ prio = LM_ERROR;
+ ACE_Log_Msg::instance ()->errnum (result.error ());
+ ACE_Log_Msg::instance ()->log (prio,
+ ACE_TEXT ("(%t) Server %d; %p\n"),
+ this->id_,
+ ACE_TEXT ("write"));
+ }
+ else if (loglevel > 0)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Server %d: wrote %d bytes ok\n"),
+ this->id_,
+ result.bytes_transferred ()));
+ }
+
+ mb.release ();
+
+ if (result.error () == 0 && result.bytes_transferred () > 0)
+ {
+ this->total_snd_ += result.bytes_transferred ();
+
+ if (duplex == 0)
+ this->initiate_read_stream ();
+ }
+
+ this->io_count_--;
+ if (this->io_count_ > 0)
+ return;
+ }
+ delete this;
+}
+
+// *******************************************
+// Connector
+// *******************************************
+
+class Connector : public ACE_Asynch_Connector<Client>
+{
+public:
+ Connector (TestData *tester);
+ virtual ~Connector (void);
+
+ int start (const ACE_INET_Addr &addr, int num);
+
+ // Virtual from ACE_Asynch_Connector
+ Client *make_handler (void);
+
+private:
+ TestData *tester_;
+};
+
+// *************************************************************
+
+Connector::Connector (TestData *tester)
+ : tester_ (tester)
+{
+}
+
+Connector::~Connector (void)
+{
+ this->cancel ();
+}
+
+Client *
+Connector::make_handler (void)
+{
+ return this->tester_->client_up ();
+}
+
+
+int
+Connector::start (const ACE_INET_Addr& addr, int num)
+{
+ if (num > MAX_CLIENTS)
+ num = MAX_CLIENTS;
+
+ if (num < 0)
+ num = 1;
+
+ int rc = 0;
+
+ // int open ( int pass_addresses = 0,
+ // ACE_Proactor *proactor = 0,
+ // int validate_new_connection = 0 );
+
+ if (this->open (1, 0, 1) != 0)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_LIB_TEXT ("(%t) %p\n"),
+ ACE_LIB_TEXT ("Connector::open failed")));
+ return rc;
+ }
+
+ for (; rc < num; rc++)
+ {
+ ACE_INET_Addr localAddr;
+ if (this->connect (addr, localAddr) != 0)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%t) %p\n"),
+ ACE_TEXT ("Connector::connect failed for IPv6")));
+ break;
+ }
+ }
+ return rc;
+}
+
+
+Client::Client ()
+{
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("Shouldn't use this constructor!\n")));
+}
+
+Client::Client (TestData *tester, int id)
+ : tester_ (tester),
+ id_ (id),
+ handle_ (ACE_INVALID_HANDLE),
+ io_count_ (0),
+ stop_writing_ (0),
+ flg_cancel_ (0),
+ total_snd_ (0),
+ total_rcv_ (0),
+ total_w_ (0),
+ total_r_ (0)
+{
+}
+
+Client::~Client (void)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Client %d dtor; %d sends (%d bytes); ")
+ ACE_TEXT ("%d recvs (%d bytes)\n"),
+ this->id_,
+ this->total_w_, this->total_snd_,
+ this->total_r_, this->total_rcv_));
+ if (this->io_count_ != 0)
+ ACE_ERROR ((LM_WARNING,
+ ACE_TEXT ("(%t) Client %d deleted with %d I/O outstanding\n"),
+ this->id_,
+ this->io_count_));
+
+ // This test bounces data back and forth between Clients and Servers.
+ // Therefore, if there was significantly more data in one direction, that's
+ // a problem. Remember, the byte counts are unsigned values.
+ int issue_data_warning = 0;
+ if (this->total_snd_ > this->total_rcv_)
+ {
+ if (this->total_rcv_ == 0)
+ issue_data_warning = 1;
+ else if (this->total_snd_ / this->total_rcv_ > 2)
+ issue_data_warning = 1;
+ }
+ else
+ {
+ if (this->total_snd_ == 0)
+ issue_data_warning = 1;
+ else if (this->total_rcv_ / this->total_snd_ > 2)
+ issue_data_warning = 1;
+ }
+ if (issue_data_warning)
+ ACE_DEBUG ((LM_WARNING,
+ ACE_TEXT ("(%t) Above byte counts look odd; need review\n")));
+
+ if (this->tester_ != 0)
+ this->tester_->client_done (this);
+
+ this->id_ = -1;
+ this->handle_= ACE_INVALID_HANDLE;
+ if (this->handle_ != ACE_INVALID_HANDLE)
+ {
+ ACE_OS::closesocket (this->handle_);
+ }
+ this->handle_= ACE_INVALID_HANDLE;
+}
+
+void
+Client::cancel ()
+{
+ ACE_GUARD (ACE_SYNCH_MUTEX, monitor, this->lock_);
+
+ this->flg_cancel_ = 1;
+ this->ws_.cancel ();
+ this->rs_.cancel ();
+ return;
+}
+
+void
+Client::close ()
+{
+ // This must be called with the lock_ held.
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Closing Client %d writes; %d I/O outstanding\n"),
+ this->id_, this->io_count_));
+ ACE_OS::shutdown (this->handle_, ACE_SHUTDOWN_WRITE);
+ this->stop_writing_ = 1;
+ return;
+}
+
+
+void
+Client::addresses (const ACE_INET_Addr& peer, const ACE_INET_Addr& local)
+{
+ char my_name[256];
+ char peer_name[256];
+ ACE_TCHAR local_str[256];
+ ACE_INET_Addr addr ((u_short) 0, host);
+
+ // This checks to make sure the peer address given to us matches what
+ // we expect it to be.
+ if (0 != peer.get_host_addr (peer_name, sizeof (peer_name)))
+ {
+ if (0 != addr.get_host_addr (my_name, sizeof (my_name)))
+ {
+ if (0 != ACE_OS::strncmp (peer_name, my_name, sizeof (my_name)))
+ {
+ ACE_ERROR
+ ((LM_ERROR,
+ ACE_TEXT ("(%t) Sender %d peer address (%C) does not ")
+ ACE_TEXT ("match host address (%C)\n"),
+ this->id_,
+ peer_name, my_name));
+ return;
+ }
+ }
+ else
+ {
+ ACE_ERROR
+ ((LM_ERROR,
+ ACE_TEXT ("(%t) Sender %d unable to convert host addr\n"),
+ this->id_));
+ return;
+ }
+ }
+ else
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%t) Sender %d unable to convert peer addr\n"),
+ this->id_));
+ return;
+ }
+
+ if (0 == local.addr_to_string (local_str,
+ sizeof (local_str) / sizeof (ACE_TCHAR)))
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Client %d connected on %s\n"),
+ this->id_,
+ local_str));
+ else
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%t) Client %d %p\n"),
+ this->id_,
+ ACE_TEXT ("addr_to_string")));
+ return;
+}
+
+
+void
+Client::open (ACE_HANDLE handle, ACE_Message_Block &)
+{
+ {
+ ACE_GUARD (ACE_SYNCH_MUTEX, monitor, this->lock_);
+
+ // Don't buffer serial sends.
+ this->handle_ = handle;
+ int nodelay = 1;
+ ACE_SOCK_Stream option_setter (handle);
+ if (option_setter.set_option (ACE_IPPROTO_TCP,
+ TCP_NODELAY,
+ &nodelay,
+ sizeof (nodelay)))
+ ACE_ERROR ((LM_ERROR, "%p\n", "set_option"));
+
+ // Open ACE_Asynch_Write_Stream
+ if (this->ws_.open (*this, this->handle_) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%t) %p\n"),
+ ACE_TEXT ("Client::ACE_Asynch_Write_Stream::open")));
+
+ // Open ACE_Asynch_Read_Stream
+ else if (this->rs_.open (*this, this->handle_) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%t) %p\n"),
+ ACE_TEXT ("Client::ACE_Asynch_Read_Stream::open")));
+
+ else if (this->initiate_write_stream () == 0)
+ {
+ if (duplex != 0) // Start an asynchronous read
+ this->initiate_read_stream ();
+ }
+
+ if (this->io_count_ > 0)
+ return;
+ }
+ delete this;
+}
+
+int
+Client::initiate_write_stream (void)
+{
+ if (this->flg_cancel_ != 0 ||
+ this->stop_writing_ ||
+ this->handle_ == ACE_INVALID_HANDLE)
+ return -1;
+
+ static const size_t complete_message_length = ACE_OS::strlen (complete_message);
+
+#if (defined (ACE_WIN32) && !defined (ACE_HAS_WINCE))
+
+ ACE_Message_Block *mb1 = 0,
+ *mb2 = 0,
+ *mb3 = 0;
+
+ // No need to allocate +1 for proper printing - the memory includes it already
+ ACE_NEW_RETURN (mb1,
+ ACE_Message_Block ((char *)complete_message,
+ complete_message_length),
+ -1);
+
+ ACE_NEW_RETURN (mb2,
+ ACE_Message_Block ((char *)complete_message,
+ complete_message_length),
+ -1);
+
+ ACE_NEW_RETURN (mb3,
+ ACE_Message_Block ((char *)complete_message,
+ complete_message_length),
+ -1);
+
+ mb1->wr_ptr (complete_message_length);
+ mb2->wr_ptr (complete_message_length);
+ mb3->wr_ptr (complete_message_length);
+
+ // chain them together
+ mb1->cont (mb2);
+ mb2->cont (mb3);
+
+ if (this->ws_.writev (*mb1, mb1->total_length ()) == -1)
+ {
+ mb1->release ();
+ ACE_ERROR_RETURN((LM_ERROR,
+ ACE_TEXT ("(%t) %p\n"),
+ ACE_TEXT ("Client::ACE_Asynch_Stream::writev")),
+ -1);
+ }
+#else /* (defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)) */
+
+ ACE_Message_Block *mb = 0;
+
+ // No need to allocate +1 for proper printing - the memory includes it already
+ ACE_NEW_RETURN (mb,
+ ACE_Message_Block (complete_message, complete_message_length),
+ -1);
+ mb->wr_ptr (complete_message_length);
+
+ if (this->ws_.write (*mb, mb->length ()) == -1)
+ {
+ mb->release ();
+#if defined (ACE_WIN32)
+ // On peer close, WriteFile will yield ERROR_NETNAME_DELETED.
+ if (ACE_OS::last_error () == ERROR_NETNAME_DELETED)
+ ACE_ERROR_RETURN ((LM_DEBUG,
+ ACE_TEXT ("(%t) Client %d, peer gone\n"),
+ this->id_),
+ -1);
+#endif /* ACE_WIN32 */
+ ACE_ERROR_RETURN((LM_ERROR,
+ ACE_TEXT ("(%t) Client %d, %p\n"),
+ this->id_,
+ ACE_TEXT ("write")),
+ -1);
+ }
+#endif /* (defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)) */
+
+ this->io_count_++;
+ this->total_w_++;
+ return 0;
+}
+
+int
+Client::initiate_read_stream (void)
+{
+ if (this->flg_cancel_ != 0 || this->handle_ == ACE_INVALID_HANDLE)
+ return -1;
+
+ static const size_t complete_message_length =
+ ACE_OS::strlen (complete_message);
+
+#if (defined (ACE_WIN32) && !defined (ACE_HAS_WINCE))
+ ACE_Message_Block *mb1 = 0,
+ *mb2 = 0,
+ *mb3 = 0,
+ *mb4 = 0,
+ *mb5 = 0,
+ *mb6 = 0;
+
+ // We allocate +1 only for proper printing - we can just set the last byte
+ // to '\0' before printing out
+ ACE_NEW_RETURN (mb1, ACE_Message_Block (complete_message_length + 1), -1);
+ ACE_NEW_RETURN (mb2, ACE_Message_Block (complete_message_length + 1), -1);
+ ACE_NEW_RETURN (mb3, ACE_Message_Block (complete_message_length + 1), -1);
+
+ // Let allocate memory for one more triplet,
+ // This improves performance
+ // as we can receive more the than one block at once
+ // Generally, we can receive more triplets ....
+ ACE_NEW_RETURN (mb4, ACE_Message_Block (complete_message_length + 1), -1);
+ ACE_NEW_RETURN (mb5, ACE_Message_Block (complete_message_length + 1), -1);
+ ACE_NEW_RETURN (mb6, ACE_Message_Block (complete_message_length + 1), -1);
+
+ mb1->cont (mb2);
+ mb2->cont (mb3);
+
+ mb3->cont (mb4);
+ mb4->cont (mb5);
+ mb5->cont (mb6);
+
+
+ // hide last byte in each message block, reserving it for later to set '\0'
+ // for proper printouts
+ mb1->size (mb1->size () - 1);
+ mb2->size (mb2->size () - 1);
+ mb3->size (mb3->size () - 1);
+
+ mb4->size (mb4->size () - 1);
+ mb5->size (mb5->size () - 1);
+ mb6->size (mb6->size () - 1);
+
+ // Inititiate read
+ if (this->rs_.readv (*mb1, mb1->total_size () - 1) == -1)
+ {
+ mb1->release ();
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%t) %p\n"),
+ ACE_TEXT ("Client::ACE_Asynch_Read_Stream::readv")),
+ -1);
+ }
+#else /* (defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)) */
+
+ // Try to read more chunks
+ size_t blksize = ( complete_message_length > BUFSIZ ) ?
+ complete_message_length : BUFSIZ;
+
+ ACE_Message_Block *mb = 0;
+
+ // We allocate +1 only for proper printing - we can just set the last byte
+ // to '\0' before printing out
+ ACE_NEW_RETURN (mb,
+ ACE_Message_Block (blksize + 1),
+ -1);
+
+ // Inititiate read
+ if (this->rs_.read (*mb, mb->size () - 1) == -1)
+ {
+ mb->release ();
+#if defined (ACE_WIN32)
+ // On peer close, ReadFile will yield ERROR_NETNAME_DELETED; won't get
+ // a 0-byte read as we would if underlying calls used WSARecv.
+ if (ACE_OS::last_error () == ERROR_NETNAME_DELETED)
+ ACE_ERROR_RETURN ((LM_DEBUG,
+ ACE_TEXT ("(%t) Client %d, peer closed\n"),
+ this->id_),
+ -1);
+#endif /* ACE_WIN32 */
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%t) Client %d, %p\n"),
+ this->id_,
+ ACE_TEXT ("read")),
+ -1);
+ }
+#endif /* (defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)) */
+
+ this->io_count_++;
+ this->total_r_++;
+ return 0;
+}
+
+void
+Client::handle_write_stream (const ACE_Asynch_Write_Stream::Result &result)
+{
+ {
+ ACE_GUARD (ACE_SYNCH_MUTEX, monitor, this->lock_);
+
+ ACE_Message_Block & mb = result.message_block ();
+
+ if (loglevel > 1)
+ {
+ LogLocker log_lock;
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) **** Client %d: handle_write_stream() ****\n"),
+ this->id_));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%s = %d\n"),
+ ACE_TEXT ("bytes_to_write"),
+ result.bytes_to_write ()));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%s = %d\n"),
+ ACE_TEXT ("handle"),
+ result.handle ()));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%s = %d\n"),
+ ACE_TEXT ("bytes_transfered"),
+ result.bytes_transferred ()));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%s = %@\n"),
+ ACE_TEXT ("act"),
+ result.act ()));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%s = %d\n"),
+ ACE_TEXT ("success"),
+ result.success ()));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%s = %@\n"),
+ ACE_TEXT ("completion_key"),
+ result.completion_key ()));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%s = %d\n"),
+ ACE_TEXT ("error"),
+ result.error ()));
+
+#if (defined (ACE_WIN32) && !defined (ACE_HAS_WINCE))
+ size_t bytes_transferred = result.bytes_transferred ();
+ char index = 0;
+ for (ACE_Message_Block* mb_i = &mb;
+ (mb_i != 0) && (bytes_transferred > 0);
+ mb_i = mb_i->cont ())
+ {
+ // write 0 at string end for proper printout (if end of mb, it's 0 already)
+ mb_i->rd_ptr()[0] = '\0';
+
+ size_t len = mb_i->rd_ptr () - mb_i->base ();
+
+ // move rd_ptr backwards as required for printout
+ if (len >= bytes_transferred)
+ {
+ mb_i->rd_ptr (0 - bytes_transferred);
+ bytes_transferred = 0;
+ }
+ else
+ {
+ mb_i->rd_ptr (0 - len);
+ bytes_transferred -= len;
+ }
+
+ ++index;
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%s%d = %s\n"),
+ ACE_TEXT ("message_block, part "),
+ index,
+ mb_i->rd_ptr ()));
+ }
+#else /* (defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)) */
+ // write 0 at string end for proper printout (if end of mb, it's 0 already)
+ mb.rd_ptr()[0] = '\0';
+ // move rd_ptr backwards as required for printout
+ mb.rd_ptr (- result.bytes_transferred ());
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%s = %s\n"),
+ ACE_TEXT ("message_block"),
+ mb.rd_ptr ()));
+#endif /* (defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)) */
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("**** end of message ****************\n")));
+ }
+ else if (result.error () != 0)
+ {
+ ACE_Log_Priority prio;
+#if defined (ACE_WIN32)
+ if (result.error () == ERROR_OPERATION_ABORTED)
+ prio = LM_DEBUG;
+#else
+ if (result.error () == ECANCELED)
+ prio = LM_DEBUG;
+#endif /* ACE_WIN32 */
+ else
+ prio = LM_ERROR;
+ ACE_Log_Msg::instance ()->errnum (result.error ());
+ ACE_Log_Msg::instance ()->log (prio,
+ ACE_TEXT ("(%t) Client %d; %p\n"),
+ this->id_,
+ ACE_TEXT ("write"));
+ }
+ else if (loglevel > 0)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Client %d: wrote %d bytes ok\n"),
+ this->id_,
+ result.bytes_transferred ()));
+ }
+
+ mb.release ();
+
+ if (result.error () == 0 && result.bytes_transferred () > 0)
+ {
+ this->total_snd_ += result.bytes_transferred ();
+ if (this->total_snd_ >= xfer_limit)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Client %d sent %d, limit %d\n"),
+ this->id_, this->total_snd_, xfer_limit));
+ this->close ();
+ }
+ if (duplex != 0) // full duplex, continue write
+ {
+ if ((this->total_snd_- this->total_rcv_) < 1024*32 ) //flow control
+ this->initiate_write_stream ();
+ }
+ else // half-duplex read reply, after read we will start write
+ this->initiate_read_stream ();
+ }
+
+ this->io_count_--;
+ if (this->io_count_ > 0)
+ return;
+ }
+ delete this;
+}
+
+void
+Client::handle_read_stream (const ACE_Asynch_Read_Stream::Result &result)
+{
+ {
+ ACE_GUARD (ACE_SYNCH_MUTEX, monitor, this->lock_);
+
+ ACE_Message_Block & mb = result.message_block ();
+
+ if (loglevel > 1)
+ {
+ LogLocker log_lock;
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) **** Client %d: handle_read_stream() ****\n"),
+ this->id_));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%s = %d\n"),
+ ACE_TEXT ("bytes_to_read"),
+ result.bytes_to_read ()));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%s = %d\n"),
+ ACE_TEXT ("handle"),
+ result.handle ()));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%s = %d\n"),
+ ACE_TEXT ("bytes_transfered"),
+ result.bytes_transferred ()));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%s = %@\n"),
+ ACE_TEXT ("act"),
+ result.act ()));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%s = %d\n"),
+ ACE_TEXT ("success"),
+ result.success ()));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%s = %@\n"),
+ ACE_TEXT ("completion_key"),
+ result.completion_key ()));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%s = %d\n"),
+ ACE_TEXT ("error"),
+ result.error ()));
+
+#if (defined (ACE_WIN32) && !defined (ACE_HAS_WINCE))
+ char index = 0;
+ for (ACE_Message_Block* mb_i = &mb;
+ mb_i != 0;
+ mb_i = mb_i->cont ())
+ {
+ ++index;
+ // write 0 at string end for proper printout
+ mb_i->wr_ptr()[0] = '\0';
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%s%d = %s\n"),
+ ACE_TEXT ("message_block, part "),
+ index,
+ mb_i->rd_ptr ()));
+ }
+#else /* (defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)) */
+ // write 0 at string end for proper printout
+ mb.rd_ptr()[result.bytes_transferred ()] = '\0'; // for proper printout
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%s = %s\n"),
+ ACE_TEXT ("message_block"),
+ mb.rd_ptr ()));
+#endif /* (defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)) */
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("**** end of message ****************\n")));
+ }
+ else if (result.error () != 0)
+ {
+ ACE_Log_Priority prio;
+#if defined (ACE_WIN32)
+ if (result.error () == ERROR_OPERATION_ABORTED)
+ prio = LM_DEBUG;
+#else
+ if (result.error () == ECANCELED)
+ prio = LM_DEBUG;
+#endif /* ACE_WIN32 */
+ else
+ prio = LM_ERROR;
+ ACE_Log_Msg::instance ()->errnum (result.error ());
+ ACE_Log_Msg::instance ()->log (prio,
+ ACE_TEXT ("(%t) Client %d; %p\n"),
+ this->id_,
+ ACE_TEXT ("read"));
+ }
+ else if (loglevel > 0)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Client %d: read %d bytes ok\n"),
+ this->id_,
+ result.bytes_transferred ()));
+ }
+
+ mb.release ();
+
+ if (result.error () == 0 && result.bytes_transferred () > 0)
+ {
+ this->total_rcv_ += result.bytes_transferred ();
+
+ if (duplex != 0 || this->stop_writing_) // full duplex, continue read
+ this->initiate_read_stream ();
+ else // half-duplex write, after write we will start read
+ this->initiate_write_stream ();
+ }
+
+ this->io_count_--;
+ if (this->io_count_ > 0)
+ return;
+ }
+ delete this;
+}
+
+// *************************************************************
+// Configuration helpers
+// *************************************************************
+int
+print_usage (int /* argc */, ACE_TCHAR *argv[])
+{
+ ACE_ERROR
+ ((LM_ERROR,
+ ACE_TEXT ("\nusage: %s")
+ ACE_TEXT ("\n-o <max number of started aio operations for Proactor>")
+ ACE_TEXT ("\n-t <Proactor type> UNIX-only, Win32-default always:")
+ ACE_TEXT ("\n a AIOCB")
+ ACE_TEXT ("\n i SIG")
+ ACE_TEXT ("\n c CB")
+ ACE_TEXT ("\n s SUN")
+ ACE_TEXT ("\n d default")
+ ACE_TEXT ("\n-d <duplex mode 1-on/0-off>")
+ ACE_TEXT ("\n-h <host> for Client mode")
+ ACE_TEXT ("\n-n <number threads for Proactor pool>")
+ ACE_TEXT ("\n-p <port to listen/connect>")
+ ACE_TEXT ("\n-c <number of client instances>")
+ ACE_TEXT ("\n-b run client and server at the same time")
+ ACE_TEXT ("\n f file")
+ ACE_TEXT ("\n c console")
+ ACE_TEXT ("\n-v log level")
+ ACE_TEXT ("\n 0 - log errors and highlights")
+ ACE_TEXT ("\n 1 - log level 0 plus progress information")
+ ACE_TEXT ("\n 2 - log level 1 plus operation parameters and results")
+ ACE_TEXT ("\n-x max transfer byte count per Client")
+ ACE_TEXT ("\n-u show this message")
+ ACE_TEXT ("\n"),
+ argv[0]
+ ));
+ return -1;
+}
+
+static int
+set_proactor_type (const ACE_TCHAR *ptype)
+{
+ if (!ptype)
+ return 0;
+
+ switch (ACE_OS::ace_toupper (*ptype))
+ {
+ case 'D':
+ proactor_type = DEFAULT;
+ return 1;
+ case 'A':
+ proactor_type = AIOCB;
+ return 1;
+ case 'I':
+ proactor_type = SIG;
+ return 1;
+#if defined (sun)
+ case 'S':
+ proactor_type = SUN;
+ return 1;
+#endif /* sun */
+#if !defined (__Lynx__)
+ case 'C':
+ proactor_type = CB;
+ return 1;
+#endif /* __Lynx__ */
+ default:
+ break;
+ }
+ return 0;
+}
+
+static int
+parse_args (int argc, ACE_TCHAR *argv[])
+{
+ // First, set up all the defaults then let any args change them.
+ both = 1; // client and server simultaneosly
+ duplex = 1; // full duplex is on
+#if defined (ACE_HAS_IPV6)
+ host = ACE_IPV6_LOCALHOST; // server to connect (IPv6 localhost)
+#else
+ host = ACE_LOCALHOST;
+#endif /*ACE_HAS_IPV6*/
+ port = ACE_DEFAULT_SERVER_PORT; // port to connect/listen
+ max_aio_operations = 512; // POSIX Proactor params
+ proactor_type = DEFAULT; // Proactor type = default
+ threads = 3; // size of Proactor thread pool
+ clients = 10; // number of clients
+ loglevel = 0; // log level : only errors and highlights
+ // Default transfer limit 50 messages per Sender
+ xfer_limit = 50 * ACE_OS::strlen (complete_message);
+
+ if (argc == 1) // no arguments , so one button test
+ return 0;
+
+ ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("x:t:o:n:p:d:h:c:v:ub"));
+ int c;
+
+ while ((c = get_opt ()) != EOF)
+ {
+ switch (c)
+ {
+ case 'x': // xfer limit
+ xfer_limit = static_cast<size_t> (ACE_OS::atoi (get_opt.opt_arg ()));
+ if (xfer_limit == 0)
+ xfer_limit = 1; // Bare minimum.
+ break;
+ case 'b': // both client and server
+ both = 1;
+ break;
+ case 'v': // log level
+ loglevel = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'd': // duplex
+ duplex = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'h': // host for sender
+ host = get_opt.opt_arg ();
+ break;
+ case 'p': // port number
+ port = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'n': // thread pool size
+ threads = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'c': // number of clients
+ clients = ACE_OS::atoi (get_opt.opt_arg ());
+ if (clients > MAX_CLIENTS)
+ clients = MAX_CLIENTS;
+ break;
+ case 'o': // max number of aio for proactor
+ max_aio_operations = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 't': // Proactor Type
+ if (set_proactor_type (get_opt.opt_arg ()))
+ break;
+ return print_usage (argc, argv);
+ case 'u':
+ default:
+ return print_usage (argc, argv);
+ } // switch
+ } // while
+
+ if (proactor_type == SUN && threads > 1)
+ {
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Sun aiowait is not thread-safe; ")
+ ACE_TEXT ("changing to 1 thread\n")));
+ threads = 1;
+ }
+
+ return 0;
+}
+
+int
+run_main (int argc, ACE_TCHAR *argv[])
+{
+ ACE_START_TEST (ACE_TEXT ("Proactor_Test_IPV6"));
+
+ if (::parse_args (argc, argv) == -1)
+ return -1;
+
+#if defined (ACE_HAS_IPV6)
+ disable_signal (ACE_SIGRTMIN, ACE_SIGRTMAX);
+ disable_signal (SIGPIPE, SIGPIPE);
+
+ MyTask task1;
+ TestData test;
+
+ if (task1.start (threads, proactor_type, max_aio_operations) == 0)
+ {
+ Acceptor acceptor (&test);
+ Connector connector (&test);
+ ACE_INET_Addr addr (port, "::");
+
+ int rc = 0;
+
+ if (both != 0 || host == 0) // Acceptor
+ {
+ // Simplify, initial read with zero size
+ if (acceptor.open (addr, 0, 1) == 0)
+ rc = 1;
+ }
+
+ if (both != 0 || host != 0)
+ {
+ if (host == 0)
+ host = ACE_IPV6_LOCALHOST;
+
+ if (addr.set (port, host, 1, addr.get_type ()) == -1)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), host));
+ else
+ rc += connector.start (addr, clients);
+ }
+
+ // Wait a few seconds to let things get going, then poll til
+ // all sessions are done. Note that when we exit this scope, the
+ // Acceptor and Connector will be destroyed, which should prevent
+ // further connections and also test how well destroyed handlers
+ // are handled.
+ ACE_OS::sleep (3);
+ }
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) Sleeping til sessions run down.\n")));
+ while (!test.testing_done ())
+ ACE_OS::sleep (1);
+
+ test.stop_all ();
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) Stop Thread Pool Task\n")));
+ task1.stop ();
+
+#endif /* ACE_HAS_IPV6 */
+
+ ACE_END_TEST;
+
+ return 0;
+}
+
+#else
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("Proactor_Test_IPV6"));
+
+ ACE_DEBUG ((LM_INFO,
+ ACE_TEXT ("Threads or Asynchronous IO is unsupported.\n")
+ ACE_TEXT ("Proactor_Test will not be run.")));
+
+ ACE_END_TEST;
+
+ return 0;
+}
+
+#endif /* ACE_WIN32 && !ACE_HAS_WINCE || ACE_HAS_AIO_CALLS */
diff --git a/ACE/tests/Proactor_Timer_Test.cpp b/ACE/tests/Proactor_Timer_Test.cpp
new file mode 100644
index 00000000000..b93bc7dc78f
--- /dev/null
+++ b/ACE/tests/Proactor_Timer_Test.cpp
@@ -0,0 +1,343 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Proctor_Timer_Test.cpp
+//
+// = DESCRIPTION
+// This is a simple test that illustrates the timer mechanism of
+// the <ACE_Proactor>. Scheduling timers, handling expired timers and
+// cancelling scheduled timers are all exercised in this test.
+//
+// = AUTHOR
+// Prashant Jain <pjain@cs.wustl.edu>,
+// Douglas C. Schmidt <schmidt@cs.wustl.edu>, and
+// Miljenko Norsic <Miljenko.Norsic@etk.ericsson.se>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/Trace.h"
+
+ACE_RCSID (tests,
+ Proactor_Timer_Test,
+ "$Id$")
+
+#if ((defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)) || (defined (ACE_HAS_AIO_CALLS)))
+ // This only works on Win32 platforms and on Unix platforms
+ // supporting POSIX aio calls.
+
+#include "ace/OS_NS_unistd.h"
+#include "ace/Timer_Queue.h"
+#include "ace/Proactor.h"
+#include "ace/High_Res_Timer.h"
+#include "ace/Asynch_IO.h"
+
+static int done = 0;
+static size_t count = 0;
+static int odd = 0;
+
+class Time_Handler : public ACE_Handler
+{
+public:
+ Time_Handler ();
+ // Default constructor
+
+ virtual void handle_time_out (const ACE_Time_Value &tv, const void *arg);
+ // Handle the timeout.
+
+ long timer_id (void) const;
+ // Return our timer id.
+
+ void timer_id (long);
+ // Set our timer id;
+
+private:
+ long timer_id_;
+ // Stores the id of this timer.
+};
+
+/*
+ * Need a variant of this that will track if a repeating timer is working
+ * correctly. This class should be scheduled with a repeating timer that
+ * repeats on a specified number of seconds. This class will let two
+ * expirations happen then wait in handle_time_out() longer than the repeat
+ * time to cause at least one timer expiration to be queued up while we're
+ * waiting; then cancel the timer.
+ */
+class Repeat_Timer_Handler : public ACE_Handler
+{
+public:
+ static const int REPEAT_INTERVAL = 2;
+
+ // Constructor arg tells how many seconds we intend to do the repeat with.
+ // The internals will use this to tell how long to wait in order to cause
+ // a timer expiration to be missed and queued up.
+ Repeat_Timer_Handler (const int repeat_time = REPEAT_INTERVAL)
+ : repeat_secs_ (repeat_time), expirations_ (0) {};
+
+ ~Repeat_Timer_Handler ();
+
+ // Handle the timeout.
+ virtual void handle_time_out (const ACE_Time_Value &tv, const void *arg);
+
+private:
+ int repeat_secs_;
+ int expirations_;
+};
+
+
+Time_Handler::Time_Handler (void)
+ : timer_id_ (-1)
+{
+ // Nothing
+}
+
+void
+Time_Handler::handle_time_out (const ACE_Time_Value &, const void *arg)
+{
+ size_t current_count = *(reinterpret_cast<const size_t *> (arg));
+ if (current_count != count)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Expected timer %d, not %d\n"),
+ count,
+ current_count));
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("[%@] Timer id %d with count #%d|%d expired.\n"),
+ this,
+ this->timer_id (),
+ count,
+ current_count));
+
+ if (current_count == (ACE_MAX_TIMERS - 1))
+ done = 1;
+ else if (count == ACE_MAX_TIMERS - 1)
+ {
+ done = 1;
+ return;
+ }
+
+ count += (1 + odd);
+ return;
+}
+
+long
+Time_Handler::timer_id (void) const
+{
+ return this->timer_id_;
+}
+
+void
+Time_Handler::timer_id (long t)
+{
+ this->timer_id_ = t;
+}
+
+Repeat_Timer_Handler::~Repeat_Timer_Handler ()
+{
+ if (this->expirations_ == 2)
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Repeater expired twice; correct\n")));
+ else
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Repeater expired %d times; should be 2\n"),
+ this->expirations_));
+}
+
+void
+Repeat_Timer_Handler::handle_time_out (const ACE_Time_Value &, const void *)
+{
+ // Let the first one go.
+ if (++this->expirations_ == 1)
+ return;
+
+ if (this->expirations_ == 2)
+ {
+ ACE_OS::sleep (this->repeat_secs_ + 1);
+ int canceled = this->proactor ()->cancel_timer (*this);
+ if (canceled != 1)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Repeater cancel timer: %d; should be 1\n"),
+ canceled));
+ }
+ delete this;
+ }
+ else
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Repeater expiration #%d; should get only 2\n"),
+ this->expirations_));
+ }
+ return;
+}
+
+static void
+test_registering_all_handlers (void)
+{
+ ACE_Trace t (ACE_TEXT ("test_registering_all_handler"),
+ __LINE__,
+ ACE_TEXT_CHAR_TO_TCHAR (__FILE__));
+ Time_Handler rt[ACE_MAX_TIMERS];
+ long t_id[ACE_MAX_TIMERS];
+ size_t which[ACE_MAX_TIMERS];
+ long secs = 0;
+ size_t i = 0;
+ for ( ; i < ACE_MAX_TIMERS; i++, secs++)
+ {
+ which[i] = i;
+ t_id[i] =
+ ACE_Proactor::instance ()->schedule_timer
+ (rt[i], &which[i], ACE_Time_Value (2 * secs + 1));
+ if (t_id[i] == -1)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("schedule_timer")));
+ rt[i].timer_id (t_id[i]);
+ }
+
+ while (!done)
+ ACE_Proactor::instance ()->handle_events ();
+}
+
+static void
+test_registering_one_handler (void)
+{
+ ACE_Trace t (ACE_TEXT ("test_registering_one_handler"),
+ __LINE__,
+ ACE_TEXT_CHAR_TO_TCHAR (__FILE__));
+ Time_Handler rt[ACE_MAX_TIMERS];
+ long t_id[ACE_MAX_TIMERS];
+ size_t which[ACE_MAX_TIMERS];
+
+ done = 0;
+ count = 0;
+ long secs = 0;
+ size_t i = 0;
+ for ( ; i < ACE_MAX_TIMERS; i++, secs++)
+ {
+ which[i] = i;
+ t_id[i] =
+ ACE_Proactor::instance ()->schedule_timer
+ (rt[0], &which[i], ACE_Time_Value (2 * secs + 1));
+ if (t_id[i] == -1)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("schedule_timer")));
+ }
+
+ while (!done)
+ ACE_Proactor::instance ()->handle_events ();
+}
+
+static void
+test_canceling_odd_timers (void)
+{
+ ACE_Trace t (ACE_TEXT ("test_canceling_odd_timers"),
+ __LINE__,
+ ACE_TEXT_CHAR_TO_TCHAR (__FILE__));
+ Time_Handler rt[ACE_MAX_TIMERS];
+ long t_id[ACE_MAX_TIMERS];
+ size_t which[ACE_MAX_TIMERS];
+
+ done = 0;
+ count = 1;
+ odd = 1;
+ size_t i = 0;
+ long secs = 0;
+ for ( ; i < ACE_MAX_TIMERS; i++, secs++)
+ {
+ which[i] = i;
+ t_id[i] = ACE_Proactor::instance ()->schedule_timer
+ (rt[i], &which[i], ACE_Time_Value (2 * secs + 1));
+ if (t_id[i] == -1)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("schedule_timer")));
+ rt[i].timer_id (t_id[i]);
+ }
+
+ for (i = 0; i < ACE_MAX_TIMERS; i++)
+ // Cancel handlers with odd numbered timer ids.
+ if (ACE_ODD (rt[i].timer_id ()))
+ {
+ if (ACE_Proactor::instance ()->cancel_timer (rt[i].timer_id ()) == -1)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("cancel_timer")));
+ }
+
+ while (!done)
+ ACE_Proactor::instance ()->handle_events ();
+}
+
+static void
+test_cancel_repeat_timer (void)
+{
+ Repeat_Timer_Handler *handler = new Repeat_Timer_Handler;
+ ACE_Time_Value timeout (Repeat_Timer_Handler::REPEAT_INTERVAL);
+ long t_id = ACE_Proactor::instance ()->schedule_repeating_timer
+ (*handler, 0, timeout);
+ if (t_id == -1)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("schedule_repeating_timer")));
+ delete handler;
+ return;
+ }
+
+ ACE_Time_Value test_timer (4 * Repeat_Timer_Handler::REPEAT_INTERVAL);
+ if (-1 == ACE_Proactor::instance ()->proactor_run_event_loop (test_timer))
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("proactor loop fail")));
+
+ // handler should be deleted by its own handle_time_out().
+ return;
+}
+
+
+// If any command line arg is given, run the test with high res timer
+// queue. Else run it normally.
+int
+run_main (int argc, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("Proactor_Timer_Test"));
+
+ if (argc > 1)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Running with high-res timer queue\n")));
+ ACE_Proactor *r = ACE_Proactor::instance ();
+ (void) ACE_High_Res_Timer::global_scale_factor ();
+ r->timer_queue ()->gettimeofday (&ACE_High_Res_Timer::gettimeofday_hr);
+ }
+
+ // Register all different handlers, i.e., one per timer.
+ test_registering_all_handlers ();
+
+ // Now try multiple timers for ONE event handler (should produce the
+ // same result).
+ test_registering_one_handler ();
+
+ // Try canceling handlers with odd numbered timer ids.
+ test_canceling_odd_timers ();
+
+ test_cancel_repeat_timer ();
+
+ ACE_END_TEST;
+ return 0;
+}
+
+#else
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("Proactor_Timer_Test"));
+
+ ACE_DEBUG ((LM_INFO,
+ ACE_TEXT ("Asynchronous IO is unsupported.\n")
+ ACE_TEXT ("Proactor_Timer_Test will not be run.")));
+
+ ACE_END_TEST;
+
+ return 0;
+}
+
+#endif /* ACE_WIN32 && !ACE_HAS_WINCE || ACE_HAS_AIO_CALLS */
diff --git a/ACE/tests/Process_Manager_Test.cpp b/ACE/tests/Process_Manager_Test.cpp
new file mode 100644
index 00000000000..3ceb16c51cb
--- /dev/null
+++ b/ACE/tests/Process_Manager_Test.cpp
@@ -0,0 +1,320 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Process_Manager_Test.cpp
+//
+// = DESCRIPTION
+// This program tests the various methods provided by
+// <ACE_Process_Manager>. It illustrates both the explicit <wait>
+// functions and the Reactor-style auto-reaping. There's an
+// Exit_Handler class that can print out (in Debug mode) when a
+// child has been reaped.
+//
+// The child processes spawned are simply this program itself, with
+// an integer argument specifying how long to "process" (actually,
+// the child just sleeps for the specified length of time).
+//
+// = AUTHOR
+// Douglas C. Schmidt <schmidt@cs.wustl.edu> and
+// Dave Madden <dhm@mersenne.com>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/OS_NS_unistd.h"
+#include "ace/Process_Manager.h"
+#include "ace/Get_Opt.h"
+#include "ace/Thread.h"
+#include "ace/Reactor.h"
+
+ACE_RCSID(tests, Process_Manager_Test, "Process_Manager_Test.cpp,v 4.11 1999/09/02 04:36:30 schmidt Exp")
+
+static u_int debug_test = 0;
+
+class Exit_Handler : public ACE_Event_Handler
+{
+public:
+ Exit_Handler (const char *msg): msg_ (msg) { }
+
+ virtual ~Exit_Handler (void) { }
+
+ virtual int handle_close (ACE_HANDLE, ACE_Reactor_Mask)
+ {
+ delete this;
+ return 0;
+ }
+
+ virtual int handle_exit (ACE_Process *proc)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P) Exit_Handler(%s) got %d: %d\n"),
+ msg_,
+ int (proc->getpid ()),
+ int (proc->exit_code ()) ));
+ return 0;
+ }
+private:
+ const char *msg_;
+};
+
+static void
+usage (const ACE_TCHAR *argv0)
+{
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("usage: %s [-d] [sleep-seconds]\n"),
+ argv0));
+ ACE_OS::exit (0);
+}
+
+static pid_t
+spawn_child (const ACE_TCHAR *argv0,
+ ACE_Process_Manager &mgr,
+ int sleep_time = 0)
+{
+#if defined (ACE_WIN32)
+const ACE_TCHAR *cmdline_format = ACE_TEXT("\"%s\" %s %d");
+#elif !defined (ACE_USES_WCHAR)
+const ACE_TCHAR *cmdline_format = ACE_TEXT (".") ACE_DIRECTORY_SEPARATOR_STR ACE_TEXT("%s %s %d");
+#else
+const ACE_TCHAR *cmdline_format = ACE_TEXT (".") ACE_DIRECTORY_SEPARATOR_STR ACE_TEXT("%ls %ls %d");
+#endif
+ ACE_Process_Options opts;
+
+ opts.command_line (cmdline_format,
+ argv0,
+ debug_test ? ACE_TEXT ("-d") : ACE_TEXT (""),
+ sleep_time);
+
+ pid_t result = mgr.spawn (opts);
+
+ if (result != ACE_INVALID_PID)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P) spawned child: pid %d time %d\n"),
+ int (result), sleep_time));
+ else
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("spawn failed")));
+
+ return result;
+}
+
+int
+run_main (int argc, ACE_TCHAR *argv[])
+{
+ ACE_Get_Opt args (argc, argv, ACE_TEXT ("d"));
+
+ for (int arg = args (); arg != EOF; arg = args ())
+ switch (arg)
+ {
+ case 'd':
+ debug_test = 1u;
+ break;
+ default:
+ usage (argv[0]);
+ break;
+ }
+
+ if (args.opt_ind () == argc - 1)
+ {
+ // child process: sleep & exit
+ ACE_TCHAR lognm[MAXPATHLEN];
+ int mypid (ACE_OS::getpid ());
+ ACE_OS::sprintf(lognm, ACE_TEXT ("Process_Manager_Test-child-%d"), mypid);
+
+ ACE_START_TEST (lognm);
+ int secs = ACE_OS::atoi (argv[args.opt_ind ()]);
+ ACE_OS::sleep (secs ? secs : 1);
+ if (debug_test)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%T: pid %P about to exit with code %d\n"),
+ secs));
+ ACE_END_LOG;
+
+ return secs;
+ }
+
+ if (args.opt_ind () != argc) // incorrect usage
+ usage (argv[0]);
+
+ ACE_START_TEST (ACE_TEXT ("Process_Manager_Test"));
+
+ // Try the explicit <ACE_Process_Manager::wait> functions
+
+ int result = 0, test_status = 0;
+ ACE_Process_Manager mgr;
+
+ mgr.register_handler (new Exit_Handler ("default"));
+
+ ACE_exitcode exitcode;
+
+ // --------------------------------------------------
+ // wait for a specific PID
+ pid_t child1 = spawn_child (argv[0],
+ mgr,
+ 1);
+ result = mgr.wait (child1,
+ &exitcode);
+
+ if (result != child1)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Error: expected to reap child1 (%d); got %d\n"),
+ child1,
+ result));
+ if (result == ACE_INVALID_PID)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("error")));
+ test_status = 1;
+ }
+ else
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P) reaped child1, pid %d: %d\n"),
+ child1,
+ exitcode));
+
+ // --------------------------------------------------
+ // wait for a specific PID; another should finish first
+ pid_t child2 = spawn_child (argv[0],
+ mgr,
+ 1);
+ pid_t child3 = spawn_child (argv[0],
+ mgr,
+ 4);
+ result = mgr.wait (child3,
+ &exitcode);
+
+ if (result != child3)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Error: expected to reap child3 (%d); got %d\n"),
+ child3,
+ result));
+ if (result == ACE_INVALID_PID)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("error")));
+ test_status = 1;
+ }
+ else
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P) reaped child 3, pid %d: %d\n"),
+ child3,
+ exitcode));
+
+ // Now wait for any...should get the one that finished earlier.
+
+ result = mgr.wait (0, &exitcode);
+
+ if (result != child2)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Error: expected to reap child2 (%d); got %d\n"),
+ child2,
+ result));
+ if (result == ACE_INVALID_PID)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("error")));
+ test_status = 1;
+ }
+ else
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P) reaped child 2, pid %d: %d\n"),
+ result,
+ exitcode));
+
+ // --------------------------------------------------
+ // Try the timed wait functions
+
+ // This one shouldn't timeout:
+ pid_t child4 = spawn_child (argv[0],
+ mgr,
+ 1);
+ result = mgr.wait (0, ACE_Time_Value (4), &exitcode);
+
+ if (result != child4)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Error: expected to reap child4 (%d); got %d\n"),
+ child4,
+ result));
+ if (result == ACE_INVALID_PID)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("error")));
+ test_status = 1;
+ }
+ else
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P) reaped child 4 pid %d: %d\n"),
+ result,
+ exitcode));
+
+ // This one should timeout:
+ pid_t child5 = spawn_child (argv[0],
+ mgr,
+ 4);
+ result = mgr.wait (0, ACE_Time_Value (1), &exitcode);
+ if (result != 0)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Error: expected wait to time out; got %d\n"),
+ result));
+ if (result == ACE_INVALID_PID)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("error")));
+ test_status = 1;
+ }
+ else
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P) Correctly timed out wait at child 5\n")));
+
+ // Now wait indefinitely to clean up...
+ result = mgr.wait (0, &exitcode);
+
+ if (result != child5)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Error: expected to reap child5 pid %d; got %d\n"),
+ child5,
+ result));
+ if (result == ACE_INVALID_PID)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("error")));
+ test_status = 1;
+ }
+ else
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P) reaped child 5, pid %d: %d\n"),
+ result,
+ exitcode));
+
+#if !defined (ACE_OPENVMS)
+ // --------------------------------------------------
+ // Finally, try the reactor stuff...
+ mgr.open (ACE_Process_Manager::DEFAULT_SIZE,
+ ACE_Reactor::instance ());
+
+ pid_t child6 = spawn_child (argv[0],
+ mgr,
+ 5);
+ /* pid_t child7 = */ spawn_child (argv[0],
+ mgr,
+ 6);
+
+ mgr.register_handler (new Exit_Handler ("specific"),
+ child6);
+
+ ACE_Time_Value how_long (10);
+
+ ACE_Reactor::instance ()->run_reactor_event_loop (how_long);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P) Reactor loop done!\n") ));
+
+ size_t nr_procs = mgr.managed ();
+ if (nr_procs != 0)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P) %d processes left in manager\n"),
+ nr_procs));
+
+#endif
+ ACE_END_TEST;
+ return test_status;
+}
+
diff --git a/ACE/tests/Process_Manual_Event_Test.cpp b/ACE/tests/Process_Manual_Event_Test.cpp
new file mode 100644
index 00000000000..b697743273b
--- /dev/null
+++ b/ACE/tests/Process_Manual_Event_Test.cpp
@@ -0,0 +1,241 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Process_Manual_Event_Test.cpp
+//
+// = DESCRIPTION
+// This test verifies the functionality of the <ACE_Manual_Event>
+// process-shared implementation.
+//
+// = AUTHOR
+// Martin Corino <mcorino@remedy.nl>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/Process.h"
+#include "ace/Manual_Event.h"
+#include "ace/Time_Value.h"
+#include "ace/Get_Opt.h"
+#include "ace/ACE.h"
+#include "ace/OS_NS_stdio.h"
+#include "ace/OS_NS_string.h"
+#include "ace/OS_NS_sys_time.h"
+#include "ace/os_include/os_dirent.h"
+
+
+#if (!defined (ACE_LACKS_FORK) || defined (ACE_WIN32)) && \
+ (defined (ACE_WIN32) || \
+ (defined (ACE_HAS_PTHREADS) && defined (_POSIX_THREAD_PROCESS_SHARED) && \
+ !defined (ACE_LACKS_MUTEXATTR_PSHARED) && !defined (ACE_LACKS_CONDATTR_PSHARED)) || \
+ defined (ACE_USES_FIFO_SEM) || \
+ (defined (ACE_HAS_POSIX_SEM) && defined (ACE_HAS_POSIX_SEM_TIMEOUT) && !defined (ACE_LACKS_NAMED_POSIX_SEM)))
+static int iterations = 10;
+static int child_process = 0;
+static const ACE_TCHAR *event_ping_name = ACE_TEXT ("ACE_Ping_Event");
+static const ACE_TCHAR *event_pong_name = ACE_TEXT ("ACE_Pong_Event");
+
+// Explain usage and exit.
+static void
+print_usage_and_die (void)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("usage: %n [-i #iterations] [-c (child process)]\n")));
+ ACE_OS::exit (1);
+}
+
+// Parse the command-line arguments and set options.
+static void
+parse_args (int argc, ACE_TCHAR *argv[])
+{
+ ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("i:c"));
+
+ int c;
+
+ while ((c = get_opt ()) != -1)
+ switch (c)
+ {
+ case 'i':
+ iterations = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'c':
+ child_process = 1;
+ break;
+ default:
+ print_usage_and_die ();
+ break;
+ }
+}
+
+static void
+acquire_release (void)
+{
+ ACE_Manual_Event event_ping (0, USYNC_PROCESS, event_ping_name);
+ ACE_Manual_Event event_pong (0, USYNC_PROCESS, event_pong_name);
+
+ // Make sure the constructor succeeded
+ ACE_ASSERT (ACE_LOG_MSG->op_status () == 0);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P) Begin ping-pong\n")));
+
+ int i;
+ if (child_process)
+ {
+ for (i = 0; i < iterations; ++i)
+ {
+ event_ping.signal ();
+
+ if (event_pong.wait ())
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P) %p\n"),
+ ACE_TEXT ("Failed acquiring pong")));
+ else
+ {
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P) Pong\n")));
+ event_pong.reset ();
+ }
+ }
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P) Testing timeouts\n")));
+
+ // test timed wait
+ ACE_Time_Value wait = ACE_OS::gettimeofday ();
+ wait.sec (wait.sec () + 3); // timeout in 3 secs
+
+ if (event_pong.wait (&wait))
+ {
+ if (errno != ETIME)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P) %p, but expected ETIME\n"),
+ ACE_TEXT ("event_pong.wait()")));
+ }
+ else
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P) Acquired pong without release()\n")));
+
+ event_ping.signal (); // release waiting parent before timeout
+ }
+ else
+ {
+ for (i = 0; i < iterations; ++i)
+ {
+ if (event_ping.wait ())
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P) %p\n"),
+ ACE_TEXT ("Failed acquiring ping")));
+ else
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P) Ping\n")));
+ event_ping.reset ();
+ }
+
+ event_pong.signal ();
+ }
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P) Testing timeouts\n")));
+
+ // test timed wait
+ ACE_Time_Value wait = ACE_OS::gettimeofday ();
+ wait.sec (wait.sec () + 10); // timeout in 10 secs
+
+ if (event_ping.wait (&wait))
+ {
+ if (errno != ETIME)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P) %p but should be ETIME\n"),
+ ACE_TEXT ("Acquire pong")));
+
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%P) Acquire pong timed out\n")));
+ }
+ }
+}
+#endif /* ! ACE_LACKS_FORK */
+
+int
+run_main (int argc, ACE_TCHAR *argv[])
+{
+#if defined (ACE_LACKS_FORK) && !defined (ACE_WIN32)
+ ACE_UNUSED_ARG (argc);
+ ACE_UNUSED_ARG (argv);
+
+ ACE_START_TEST (ACE_TEXT ("Process_Manual_Event_Test"));
+ ACE_ERROR ((LM_INFO,
+ ACE_TEXT ("fork is not supported on this platform\n")));
+ ACE_END_TEST;
+#elif defined (ACE_WIN32) || \
+ (defined (ACE_HAS_PTHREADS) && defined (_POSIX_THREAD_PROCESS_SHARED) && \
+ !defined (ACE_LACKS_MUTEXATTR_PSHARED) && !defined (ACE_LACKS_CONDATTR_PSHARED)) || \
+ defined (ACE_USES_FIFO_SEM) || \
+ (defined (ACE_HAS_POSIX_SEM) && defined (ACE_HAS_POSIX_SEM_TIMEOUT) && !defined (ACE_LACKS_NAMED_POSIX_SEM))
+
+ parse_args (argc, argv);
+
+ // Child process code.
+ if (child_process)
+ {
+ ACE_START_TEST (ACE_TEXT ("Process_Manual_Event_Test-child"));
+ acquire_release ();
+ ACE_END_LOG;
+ }
+ else
+ {
+ ACE_START_TEST (ACE_TEXT ("Process_Manual_Event_Test"));
+#if defined (ACE_WIN32)
+ const ACE_TCHAR *cmdline_format = ACE_TEXT("\"%s\" -c -i %d");
+#elif !defined (ACE_USES_WCHAR)
+const ACE_TCHAR *cmdline_format = ACE_TEXT (".") ACE_DIRECTORY_SEPARATOR_STR ACE_TEXT("%s -c -i %d");
+#else
+const ACE_TCHAR *cmdline_format = ACE_TEXT (".") ACE_DIRECTORY_SEPARATOR_STR ACE_TEXT("%ls -c -i %d");
+#endif
+
+ ACE_Process_Options options;
+ options.command_line (cmdline_format,
+ argv[0],
+ iterations);
+ // Spawn a child process that will contend for the
+ // lock.
+ ACE_Process child;
+
+ // Spawn the child process.
+ int result = child.spawn (options);
+ ACE_ASSERT (result != -1);
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Parent spawned child process with pid = %d.\n"),
+ child.getpid ()));
+
+ // start test
+ acquire_release ();
+
+ ACE_exitcode child_status;
+ // Wait for the child processes we created to exit.
+ int wait_result = child.wait (&child_status);
+ ACE_ASSERT (wait_result != -1);
+ if (child_status == 0)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Child %d finished ok\n"),
+ child.getpid ()));
+ else
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Child %d finished with status %d\n"),
+ child.getpid (), child_status));
+ ACE_END_TEST;
+ }
+#else /* !ACE_LACKS_FORK */
+ ACE_UNUSED_ARG (argc);
+ ACE_UNUSED_ARG (argv);
+
+ ACE_START_TEST (ACE_TEXT ("Process_Manual_Event_Test"));
+ ACE_ERROR ((LM_INFO,
+ ACE_TEXT ("Process shared events are not supported on this platform\n")));
+ ACE_END_TEST;
+#endif /* ! ACE_LACKS_FORK */
+
+ return 0;
+}
diff --git a/ACE/tests/Process_Mutex_Test.cpp b/ACE/tests/Process_Mutex_Test.cpp
new file mode 100644
index 00000000000..e70cd8adede
--- /dev/null
+++ b/ACE/tests/Process_Mutex_Test.cpp
@@ -0,0 +1,218 @@
+// $Id$
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Process_Mutex_Test.cpp
+//
+// = DESCRIPTION
+// Tests an <ACE_Process_Mutex> shared between multiple child processes.
+//
+// = AUTHOR
+// Irfan Pyarali <irfan@cs.wustl.edu>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/Mutex.h"
+#include "ace/Process.h"
+#include "ace/Process_Mutex.h"
+#include "ace/Get_Opt.h"
+#include "ace/ACE.h"
+#include "ace/OS_NS_stdio.h"
+#include "ace/OS_NS_string.h"
+#include "ace/OS_NS_fcntl.h"
+#include "ace/os_include/os_dirent.h"
+
+ACE_RCSID(tests, Process_Mutex_Test, "$Id$")
+
+static int release_mutex = 1;
+static int child_process = 0;
+static const ACE_TCHAR *mutex_name = ACE_DEFAULT_MUTEX;
+#if defined (__Lynx__)
+static const u_int n_processes = 4;
+#else /* ! __Lynx__ */
+static const u_int n_processes = ACE_MAX_PROCESSES;
+#endif /* ! __Lynx__ */
+
+// Explain usage and exit.
+static void
+print_usage_and_die (void)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("usage: %n [-d (don't release mutex)] ")
+ ACE_TEXT ("[-c (child process)] [-n mutex name]\n")));
+ ACE_OS::exit (1);
+}
+
+// Parse the command-line arguments and set options.
+static void
+parse_args (int argc, ACE_TCHAR *argv[])
+{
+ ACE_Get_Opt get_opt (argc, argv, ACE_TEXT("dcn:"));
+
+ int c;
+
+ while ((c = get_opt ()) != -1)
+ switch (c)
+ {
+ case 'd':
+ release_mutex = 0;
+ break;
+ case 'c':
+ child_process = 1;
+ break;
+ case 'n':
+ mutex_name = get_opt.opt_arg ();
+ break;
+ default:
+ print_usage_and_die ();
+ break;
+ }
+}
+
+static void
+acquire_release (void)
+{
+ ACE_Process_Mutex mutex (mutex_name);
+
+ // Make sure the constructor succeeded
+ ACE_ASSERT (ACE_LOG_MSG->op_status () == 0);
+
+ // To see if we really are the only holder of the mutex below,
+ // we'll try to create a file with exclusive access. If the file
+ // already exists, we're not the only one holding the mutex.
+ ACE_TCHAR mutex_check[MAXPATHLEN+1];
+ ACE_OS::strncpy (mutex_check, mutex_name, MAXPATHLEN);
+ ACE_OS::strncat (mutex_check, ACE_TEXT ("_checker"), MAXPATHLEN);
+
+ // Grab the lock
+ int mutex_acq = mutex.acquire ();
+ ACE_ASSERT (mutex_acq == 0);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P) Mutex acquired %s\n"),
+ mutex_name));
+
+ ACE_HANDLE checker_handle = ACE_OS::open (mutex_check, O_CREAT | O_EXCL);
+ if (checker_handle == ACE_INVALID_HANDLE)
+ {
+ ACE_ASSERT (errno != EEXIST);
+ ACE_DEBUG ((LM_WARNING, ACE_TEXT ("(%P): %p\n"),
+ ACE_TEXT ("checker file open")));
+ }
+ else
+ ACE_OS::close (checker_handle);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P) Working....\n")));
+
+ // Do some "work", i.e., just sleep for a couple of seconds.
+ ACE_OS::sleep (2);
+
+ // Free up the check file for the next acquirer.
+ ACE_OS::unlink (mutex_check);
+
+ // Check if we need to release the mutex
+ if (release_mutex == 1)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P) Releasing the mutex %s\n"),
+ mutex_name));
+ int mutex_release = mutex.release ();
+ ACE_ASSERT (mutex_release == 0);
+ }
+}
+
+int
+run_main (int argc, ACE_TCHAR *argv[])
+{
+ parse_args (argc, argv);
+
+ // Child process code.
+ if (child_process)
+ {
+ ACE_TCHAR lognm[MAXPATHLEN];
+ int mypid (ACE_OS::getpid ());
+ ACE_OS::sprintf(lognm, ACE_TEXT ("Process_Mutex_Test-child-%d"), mypid);
+
+ ACE_START_TEST (lognm);
+ acquire_release ();
+ ACE_END_LOG;
+ }
+ else
+ {
+ ACE_START_TEST (ACE_TEXT ("Process_Mutex_Test"));
+# if !defined( ACE_HAS_SYSV_IPC) || defined( ACE_USES_MUTEX_FOR_PROCESS_MUTEX )
+ // When Process_Mutex is pthreads based, then the owner of mutex destroys it
+ // in destructor. This may disturb the other processes which still uses the
+ // mutex. It is safer then to hold the mutex in main process, and destroy it after
+ // children finish. This is temporary solution, and in future pthread base
+ // Process_Mutex shall control the destruction of mutex better.
+ ACE_Process_Mutex mutex( mutex_name );
+# endif
+
+#if !defined (ACE_WIN32) && defined (ACE_USES_WCHAR)
+ static const ACE_TCHAR* format = ACE_TEXT ("%ls -c -n %ls%ls");
+#else
+ static const ACE_TCHAR* format = ACE_TEXT ("%s -c -n %s%s");
+#endif /* !ACE_WIN32 && ACE_USES_WCHAR */
+ ACE_Process_Options options;
+ options.command_line (format, argv[0], mutex_name,
+ release_mutex == 0 ? ACE_TEXT (" -d") : ACE_TEXT (""));
+
+ // Spawn <n_processes> child processes that will contend for the
+ // lock.
+ ACE_Process children[n_processes];
+ size_t i;
+
+ for (i = 0;
+ i < n_processes;
+ i++)
+ {
+ // Spawn the child process.
+ if (children[i].spawn (options) == -1)
+ {
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("spawn of client %d failed\n"),
+ i),
+ -1);
+ }
+ else
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Parent spawned child process with pid = %d.\n"),
+ children[i].getpid ()));
+ }
+
+ // Give the newly spawned child process a chance to start...
+ // David Levine thinks this sleep() is required because
+ // calling ::waitpid () before a fork'ed child has actually
+ // been created may be a problem on some platforms. It's
+ // not enough for fork() to have returned to the parent.
+ ACE_OS::sleep (1);
+ }
+
+ for (i = 0; i < n_processes; i++)
+ {
+ ACE_exitcode child_status;
+ // Wait for the child processes we created to exit.
+ int wait_result = children[i].wait (&child_status);
+ ACE_ASSERT (wait_result != -1);
+ if (child_status == 0)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Child %d finished ok\n"),
+ children[i].getpid ()));
+ else
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Child %d finished with status %d\n"),
+ children[i].getpid (), child_status));
+ }
+
+ ACE_END_TEST;
+ }
+
+ return 0;
+}
diff --git a/ACE/tests/Process_Semaphore_Test.cpp b/ACE/tests/Process_Semaphore_Test.cpp
new file mode 100644
index 00000000000..af08108ad75
--- /dev/null
+++ b/ACE/tests/Process_Semaphore_Test.cpp
@@ -0,0 +1,230 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Process_Semaphore_Test.cpp
+//
+// = DESCRIPTION
+// Tests an ACE Semaphore shared between multiple child processes.
+//
+// = AUTHOR
+// Martin Corino <mcorino@remedy.nl>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/Mutex.h"
+#include "ace/Process.h"
+#if defined (ACE_WIN32) || \
+ defined (ACE_USES_FIFO_SEM) || \
+ (defined (ACE_HAS_POSIX_SEM) && !defined (ACE_LACKS_NAMED_POSIX_SEM))
+# include "ace/Time_Value.h"
+# include "ace/OS_NS_sys_time.h"
+# include "ace/Semaphore.h"
+#else
+# include "ace/Process_Semaphore.h"
+#endif
+#include "ace/Get_Opt.h"
+#include "ace/ACE.h"
+#include "ace/OS_NS_stdio.h"
+#include "ace/OS_NS_string.h"
+#include "ace/os_include/os_dirent.h"
+
+ACE_RCSID(tests, Process_Semaphore_Test, "Process_Semaphore_Test.cpp,v 4.42 2003/12/26 21:59:35 shuston Exp")
+
+#if !defined (ACE_LACKS_FORK)
+static int iterations = 10;
+static int child_process = 0;
+static const char *sema_ping_name = "ACE_Ping_Semaphore";
+static const char *sema_pong_name = "ACE_Pong_Semaphore";
+
+// Explain usage and exit.
+static void
+print_usage_and_die (void)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("usage: %n [-i #iterations] [-c (child process)]\n")));
+ ACE_OS::exit (1);
+}
+
+// Parse the command-line arguments and set options.
+static void
+parse_args (int argc, ACE_TCHAR *argv[])
+{
+ ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("i:c"));
+
+ int c;
+
+ while ((c = get_opt ()) != -1)
+ switch (c)
+ {
+ case 'i':
+ iterations = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'c':
+ child_process = 1;
+ break;
+ default:
+ print_usage_and_die ();
+ break;
+ }
+}
+
+static void
+acquire_release (void)
+{
+#if defined (ACE_WIN32) || \
+ defined (ACE_USES_FIFO_SEM) || \
+ (defined (ACE_HAS_POSIX_SEM) && !defined (ACE_LACKS_NAMED_POSIX_SEM))
+ ACE_Semaphore sema_ping (0, USYNC_PROCESS, ACE_TEXT_CHAR_TO_TCHAR (sema_ping_name));
+ ACE_Semaphore sema_pong (0, USYNC_PROCESS, ACE_TEXT_CHAR_TO_TCHAR (sema_pong_name));
+#else
+ ACE_Process_Semaphore sema_ping (0, ACE_TEXT_CHAR_TO_TCHAR (sema_ping_name));
+ ACE_Process_Semaphore sema_pong (0, ACE_TEXT_CHAR_TO_TCHAR (sema_pong_name));
+#endif
+
+ // Make sure the constructor succeeded
+ ACE_ASSERT (ACE_LOG_MSG->op_status () == 0);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P) Begin ping-pong\n")));
+
+ if (child_process)
+ {
+ for (int i=0; i<iterations ;++i)
+ {
+ sema_ping.release ();
+
+ if (sema_pong.acquire ())
+ ACE_DEBUG ((LM_ERROR,
+ ACE_TEXT ("(%P) Failed acquiring pong\n")));
+ else
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P) Pong\n")));
+ }
+
+#if defined (ACE_WIN32) || \
+ defined (ACE_USES_FIFO_SEM) || \
+ (defined (ACE_HAS_POSIX_SEM) && defined (ACE_HAS_POSIX_SEM_TIMEOUT) && \
+ !defined (ACE_LACKS_NAMED_POSIX_SEM))
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P) Testing timeouts\n")));
+
+ // test timed wait
+ ACE_Time_Value wait = ACE_OS::gettimeofday ();
+ wait.sec (wait.sec () + 3); // timeout in 3 secs
+
+ if (sema_pong.acquire (wait))
+ ACE_ASSERT(errno == ETIME);
+ else
+ ACE_DEBUG ((LM_ERROR,
+ ACE_TEXT ("(%P) Acquired pong without release()\n")));
+
+ sema_ping.release (); // release waiting parent before timeout
+#endif
+ }
+ else
+ {
+ for (int i=0; i<iterations ;++i)
+ {
+ if (sema_ping.acquire ())
+ ACE_DEBUG ((LM_ERROR,
+ ACE_TEXT ("(%P) Failed acquiring ping\n")));
+ else
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P) Ping\n")));
+
+ sema_pong.release ();
+ }
+
+#if defined (ACE_WIN32) || \
+ defined (ACE_USES_FIFO_SEM) || \
+ (defined (ACE_HAS_POSIX_SEM) && defined (ACE_HAS_POSIX_SEM_TIMEOUT) && \
+ !defined (ACE_LACKS_NAMED_POSIX_SEM))
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P) Testing timeouts\n")));
+
+ // test timed wait
+ ACE_Time_Value wait = ACE_OS::gettimeofday ();
+ wait.sec (wait.sec () + 10); // timeout in 10 secs
+
+ if (sema_ping.acquire (wait))
+ {
+ ACE_ASSERT(errno == ETIME);
+ ACE_DEBUG ((LM_ERROR,
+ ACE_TEXT ("(%P) Acquiring pong timed out\n")));
+ }
+#endif
+ }
+}
+#endif /* ! ACE_LACKS_FORK */
+
+int
+run_main (int argc, ACE_TCHAR *argv[])
+{
+#if defined (ACE_LACKS_FORK)
+ ACE_UNUSED_ARG (argc);
+ ACE_UNUSED_ARG (argv);
+
+ ACE_START_TEST (ACE_TEXT ("Process_Semaphore_Test"));
+ ACE_ERROR ((LM_INFO,
+ ACE_TEXT ("fork is not supported on this platform\n")));
+ ACE_END_TEST;
+#else
+
+ parse_args (argc, argv);
+
+ // Child process code.
+ if (child_process)
+ {
+ ACE_START_TEST (ACE_TEXT ("Process_Semaphore_Test-child"));
+ acquire_release ();
+ ACE_END_LOG;
+ }
+ else
+ {
+ ACE_START_TEST (ACE_TEXT ("Process_Semaphore_Test"));
+
+ ACE_Process_Options options;
+ options.command_line (ACE_TEXT (".") ACE_DIRECTORY_SEPARATOR_STR
+ ACE_TEXT ("Process_Semaphore_Test")
+ ACE_PLATFORM_EXE_SUFFIX
+ ACE_TEXT (" -c -i %d"),
+ iterations);
+
+ // Spawn a child process that will contend for the
+ // lock.
+ ACE_Process child;
+
+ // Spawn the child process.
+ int result = child.spawn (options);
+ ACE_ASSERT (result != -1);
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Parent spawned child process with pid = %d.\n"),
+ child.getpid ()));
+
+ // start test
+ acquire_release ();
+
+ ACE_exitcode child_status;
+ // Wait for the child processes we created to exit.
+ ACE_ASSERT (child.wait (&child_status) != -1);
+ if (child_status == 0)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Child %d finished ok\n"),
+ child.getpid ()));
+ else
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Child %d finished with status %d\n"),
+ child.getpid (), child_status));
+
+ ACE_END_TEST;
+ }
+#endif /* ! ACE_LACKS_FORK */
+
+ return 0;
+}
diff --git a/ACE/tests/Process_Strategy_Test.cpp b/ACE/tests/Process_Strategy_Test.cpp
new file mode 100644
index 00000000000..aca7cc2e7de
--- /dev/null
+++ b/ACE/tests/Process_Strategy_Test.cpp
@@ -0,0 +1,714 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Process_Strategy_Test.cpp
+//
+// = DESCRIPTION
+// This is a test of the <ACE_Strategy_Acceptor> and
+// <ACE_File_Lock> classes. The <ACE_Strategy_Acceptor> uses
+// either the <ACE_Process_Strategy> (which forks a
+// process-per-connection and runs as a concurrent server
+// process), the <ACE_Thread_Strategy> (which spawns a
+// thread-per-connection and runs as a concurrent server thread),
+// or <ACE_Reactive_Strategy> (which register the <Svc_Handler>
+// with the <Reactor> and runs in the main thread of control as an
+// iterative server). This server queries and increments a
+// "counting value" in a file.
+//
+// This test program can be run in the following ways:
+//
+// # Run the server "reactively" (i.e., iteratively)
+// % Process_Strategy_Test -c REACTIVE
+//
+// # Run the server in multi-threads.
+// % Process_Strategy_Test -c THREAD
+//
+// # Run the server in multi-processes
+// % Process_Strategy_Test -c PROCESS
+//
+// = AUTHOR
+// Douglas C. Schmidt <schmidt@cs.wustl.edu>
+// and Kevin Boyle <kboyle@sanwafp.com>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/OS_NS_string.h"
+#include "ace/OS_NS_unistd.h"
+#include "ace/Acceptor.h"
+#include "ace/Handle_Set.h"
+#include "ace/Get_Opt.h"
+#include "ace/Null_Condition.h"
+#include "ace/Null_Mutex.h"
+#include "ace/SOCK_Acceptor.h"
+#include "ace/SOCK_Connector.h"
+#include "ace/Strategies_T.h"
+#include "ace/Singleton.h"
+#include "ace/Synch_Traits.h"
+#include "ace/File_Lock.h"
+
+// Counting_Service and Options in here
+#include "Process_Strategy_Test.h"
+
+ACE_RCSID(tests, Process_Strategy_Test, "$Id$")
+
+// This test does not function properly when fork() is used on HP-UX
+#if defined(__hpux)
+#define ACE_LACKS_FORK
+#endif /* __hpux */
+
+#if defined (ACE_HAS_EXPLICIT_STATIC_TEMPLATE_MEMBER_INSTANTIATION)
+
+template ACE_Singleton<Options, ACE_Null_Mutex> *
+ ACE_Singleton<Options, ACE_Null_Mutex>::singleton_;
+
+#endif /* ACE_HAS_EXPLICIT_STATIC_TEMPLATE_MEMBER_INSTANTIATION */
+
+// Define a <Strategy_Acceptor> that's parameterized by the
+// <Counting_Service>.
+
+typedef ACE_Strategy_Acceptor <Counting_Service, ACE_SOCK_ACCEPTOR> ACCEPTOR;
+
+// Create an Options Singleton.
+typedef ACE_Singleton<Options, ACE_Null_Mutex> OPTIONS;
+
+// counter for connections
+static int connections = 0;
+
+// Use this to show down the process gracefully.
+static void
+connection_completed (void)
+{
+ // Increment connection counter.
+ connections++;
+
+ // If all connections have been serviced.
+ if (connections == ACE_MAX_ITERATIONS + 1)
+ // Make sure that the event loop is interrupted.
+ ACE_Reactor::instance()->wakeup_all_threads ();
+}
+
+// Constructor
+Process_Strategy::Process_Strategy (size_t n_processes,
+ ACE_Event_Handler *acceptor,
+ ACE_Reactor *r,
+ int avoid_zombies)
+ : ACE_Process_Strategy<Counting_Service> (n_processes,
+ acceptor,
+ r,
+ avoid_zombies)
+{
+}
+
+// Destructor. g++ 2.7.2.3 gets very confused ("Internal compiler
+// error") without it.
+
+Process_Strategy::~Process_Strategy (void)
+{
+}
+
+// Overwrite the process creation method to include connection
+// counting.
+
+int
+Process_Strategy::activate_svc_handler (Counting_Service *svc_handler,
+ void *arg)
+{
+ // Call down to the base class
+ int result =
+ ACE_Process_Strategy<Counting_Service>::activate_svc_handler (svc_handler,
+ arg);
+ // Connection is now complete
+ connection_completed ();
+
+ return result;
+}
+
+ACE_File_Lock &
+Options::file_lock (void)
+{
+ return this->file_lock_;
+}
+
+ACE_Concurrency_Strategy <Counting_Service> *
+Options::concurrency_strategy (void)
+{
+ return this->concurrency_strategy_;
+}
+
+const ACE_TCHAR *
+Options::filename (void)
+{
+ return this->filename_;
+}
+
+Options::Options (void)
+ :
+ // Choose to use processes by default.
+#if !defined (ACE_LACKS_FORK)
+ concurrency_type_ (PROCESS)
+#elif defined (ACE_HAS_THREADS)
+ concurrency_type_ (THREAD)
+#else
+ concurrency_type_ (REACTIVE)
+#endif /* !ACE_LACKS_FORK */
+{
+}
+
+Options::~Options (void)
+{
+ delete this->concurrency_strategy_;
+ this->concurrency_strategy_ = 0;
+}
+
+int
+Options::parse_args (int argc, ACE_TCHAR *argv[])
+{
+ ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("p:c:f:"));
+
+ // - 26 is for the "process_strategy_test_temp" that is appended
+ if (ACE::get_temp_dir (this->filename_, MAXPATHLEN - 26) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("Temporary path too long\n")),
+ -1);
+
+ ACE_OS::strcat (this->filename_, ACE_TEXT ("process_strategy_test_temp"));
+
+ for (int c; (c = get_opt ()) != -1; )
+ switch (c)
+ {
+ case 'c':
+ if (ACE_OS::strcmp (get_opt.opt_arg (),
+ ACE_TEXT ("REACTIVE")) == 0)
+ OPTIONS::instance ()->concurrency_type (Options::REACTIVE);
+#if !defined (ACE_LACKS_FORK)
+ else if (ACE_OS::strcmp (get_opt.opt_arg (),
+ ACE_TEXT ("PROCESS")) == 0)
+ OPTIONS::instance ()->concurrency_type (Options::PROCESS);
+#endif /* !ACE_LACKS_FORK */
+#if defined (ACE_HAS_THREADS)
+ else if (ACE_OS::strcmp (get_opt.opt_arg (),
+ ACE_TEXT ("THREAD")) == 0)
+ OPTIONS::instance ()->concurrency_type (Options::THREAD);
+#endif /* ACE_HAS_THREADS */
+ else
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("WARNING: concurrency strategy \"%s\" ")
+ ACE_TEXT ("is not supported\n"),
+ get_opt.opt_arg ()));
+ break;
+ case 'f':
+ ACE_OS::strcpy (this->filename_, get_opt.opt_arg ());
+ break;
+ default:
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("usage: %n [-f (filename)] ")
+ ACE_TEXT ("[-c (concurrency strategy)]\n%a"), 1));
+ /* NOTREACHED */
+ }
+
+ // Initialize the file lock. Note that this object lives beyond the
+ // lifetime of the Acceptor.
+ if (this->file_lock_.open (this->filename_,
+ O_RDWR | O_CREAT,
+ ACE_DEFAULT_FILE_PERMS) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("open")),
+ -1);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) opening %s on handle %d.\n"),
+ this->filename_,
+ this->file_lock_.get_handle ()));
+
+ int count = 0;
+
+ // Store the initial value of the count in the file.
+ if (ACE_OS::write (this->file_lock_.get_handle (),
+ (const void *) &count,
+ sizeof count) != sizeof count)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n"),
+ ACE_TEXT ("write")));
+
+ // Initialize the Concurrency strategy.
+ switch (this->concurrency_type_)
+ {
+ case Options::PROCESS:
+#if !defined (ACE_LACKS_FORK)
+ ACE_NEW_RETURN (this->concurrency_strategy_,
+ Process_Strategy (1,
+ this,
+ ACE_Reactor::instance (),
+ 1), // Avoid zombies.
+ -1);
+ break;
+#else
+# if defined (ACE_PSOS_DIAB)
+ // Workaround for compiler confusion with strings in assertions.
+ const int PROCESS_INVALID_ON_THIS_PLATFORM = 1;
+ ACE_ASSERT (PROCESS_INVALID_ON_THIS_PLATFORM == 0);
+# else /* ! defined (ACE_PSOS_DIAB) */
+ ACE_ASSERT ("PROCESS invalid on this platform" == 0);
+# endif /* defined (ACE_PSOS_DIAB) */
+#endif /* !defined (ACE_LACKS_FORK) */
+ case Options::THREAD:
+#if defined (ACE_HAS_THREADS)
+ ACE_NEW_RETURN (this->concurrency_strategy_,
+ ACE_Thread_Strategy<Counting_Service>
+ (ACE_Thread_Manager::instance (),
+ THR_NEW_LWP,
+ 1),
+ -1);
+ break;
+#else
+ ACE_ASSERT (!"THREAD invalid on this platform");
+#endif /* !ACE_HAS_THREADS */
+ case Options::REACTIVE:
+ // Settle for the purely Reactive strategy.
+ ACE_NEW_RETURN (this->concurrency_strategy_,
+ ACE_Reactive_Strategy<Counting_Service>
+ (ACE_Reactor::instance ()),
+ -1);
+ break;
+ }
+
+ return 0;
+}
+
+Options::Concurrency_Type
+Options::concurrency_type (void)
+{
+ return this->concurrency_type_;
+}
+
+void
+Options::concurrency_type (Options::Concurrency_Type cs)
+{
+ this->concurrency_type_ = cs;
+}
+
+Counting_Service::Counting_Service (ACE_Thread_Manager *)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) creating the Counting_Service\n")));
+}
+
+// Read the current value from the shared file and return it to the
+// client.
+
+int
+Counting_Service::read (void)
+{
+ ACE_READ_GUARD_RETURN (ACE_File_Lock, ace_mon, OPTIONS::instance ()->file_lock (), -1);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) reading on handle %d.\n"),
+ OPTIONS::instance ()->file_lock ().get_handle ()));
+
+ int count;
+ if (ACE_OS::pread (OPTIONS::instance ()->file_lock ().get_handle (),
+ (void *) &count,
+ sizeof count,
+ 0) != sizeof count)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n"),
+ ACE_TEXT ("read")),
+ -1);
+ char buf[BUFSIZ];
+
+ int n = ACE_OS::sprintf (buf,
+ "count = %d\n",
+ count);
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) count = %d\n"),
+ count));
+
+ if (this->peer ().send_n (buf, n) != n)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n"),
+ ACE_TEXT ("send_n")),
+ -1);
+ return 0;
+}
+
+// Increment the current value in the shared file by 1.
+
+int
+Counting_Service::inc (void)
+{
+ ACE_WRITE_GUARD_RETURN (ACE_File_Lock, ace_mon,
+ OPTIONS::instance ()->file_lock (), -1);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) incrementing on handle %d.\n"),
+ OPTIONS::instance ()->file_lock ().get_handle ()));
+
+ int count;
+ if (ACE_OS::pread (OPTIONS::instance ()->file_lock ().get_handle (),
+ (void *) &count,
+ sizeof count,
+ 0) != sizeof count)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n"),
+ ACE_TEXT ("read")),
+ -1);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) incrementing count from %d to %d\n"),
+ count,
+ count + 1));
+ count++;
+
+ if (ACE_OS::pwrite (OPTIONS::instance ()->file_lock ().get_handle (),
+ (const void *) &count,
+ sizeof count,
+ 0) != sizeof count)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n"),
+ ACE_TEXT ("write")),
+ -1);
+ return 0;
+}
+
+// Receive the request from the client and call the appropriate
+// operation.
+
+int
+Counting_Service::handle_input (ACE_HANDLE)
+{
+ char buf[BUFSIZ];
+ ACE_Time_Value* timeout = 0;
+#if defined (__hpux)
+ // Even though we're in handle_input, there seems to be a
+ // situation on HP-UX where there is nothing to recv just yet.
+ // So, we recv() with a timeout and everything works.
+ ACE_Time_Value hpux_timeout (3);
+ timeout = &hpux_timeout;
+#endif /* __hpux */
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) reading from peer on %d\n"),
+ this->peer ().get_handle ()));
+ size_t len;
+ // Read the PDU length first.
+ ssize_t bytes = this->peer ().recv ((void *) &len,
+ sizeof len,
+ timeout);
+ if (bytes <= 0)
+ return -1;
+
+ bytes = this->peer ().recv (buf, len);
+
+ if (bytes <= 0 || buf[0] == (char) EOF)
+ return -1;
+ else
+ {
+ buf[len] = '\0';
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) %d bytes of input on %d is %*s\n"),
+ bytes,
+ this->peer ().get_handle (),
+ bytes,
+ ACE_TEXT_CHAR_TO_TCHAR (buf)));
+ // Read and return the current value in the file.
+ if (ACE_OS::strncmp (buf,
+ "read",
+ 4) == 0)
+ return this->read ();
+ // Increment the current value in the file.
+ else if (ACE_OS::strncmp (buf, "inc", 3) == 0)
+ return this->inc ();
+ else
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) no match...\n")));
+ return 0;
+ }
+}
+
+int
+Counting_Service::svc (void)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) handling thread\n")));
+
+ while (this->handle_input () >= 0)
+ continue;
+
+ return 0;
+}
+
+int
+Counting_Service::handle_close (ACE_HANDLE,
+ ACE_Reactor_Mask)
+{
+ // Done with another connection.
+ connection_completed ();
+
+ // Call down to base class
+ return ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH>::handle_close ();
+}
+
+// This method is called back by the <Acceptor> once the client has
+// connected and the process is forked or spawned.
+
+int
+Counting_Service::open (void *)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) opening service\n")));
+
+ if (OPTIONS::instance ()->concurrency_type () == Options::PROCESS)
+ {
+ // We need to rerun the event loop here since we ended up here
+ // due to being fork'd and we can't just return to our context
+ // because it's in the middle of a different event loop that
+ // won't behave properly since it's meant to handle connection
+ // establishment, *not* data transfer.
+ while (this->handle_input () >= 0)
+ continue;
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) About to exit from the child\n")));
+
+ // Exit the child.
+ ACE_OS::exit (0);
+ }
+ else if (OPTIONS::instance ()->concurrency_type () == Options::THREAD)
+ // We need to set this to 0 so that our <shutdown> method doesn't
+ // try to deregister <this> from the Reactor.
+ this->reactor (0);
+ return 0;
+}
+
+#if !defined (ACE_LACKS_FORK) || defined (ACE_HAS_THREADS)
+
+// Execute the client tests.
+
+static void *
+client (void *arg)
+{
+ ACE_INET_Addr *remote_addr =
+ reinterpret_cast<ACE_INET_Addr *> (arg);
+ ACE_INET_Addr server_addr (remote_addr->get_port_number (),
+ ACE_DEFAULT_SERVER_HOST);
+ ACE_SOCK_Stream stream;
+ ACE_SOCK_Connector connector;
+
+ char buf[BUFSIZ];
+ const char *command;
+ size_t command_len;
+ size_t i;
+
+ for (i = 0; i < ACE_MAX_ITERATIONS; i++)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) client iteration %d\n"),
+ i));
+ if (connector.connect (stream,
+ server_addr) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("open")),
+ 0);
+ command = "inc";
+ command_len = ACE_OS::strlen (command);
+
+ if (stream.send (4,
+ &command_len, sizeof command_len,
+ command, command_len) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("send")),
+ 0);
+ command = "read";
+ command_len = ACE_OS::strlen (command);
+
+ if (stream.send (4,
+ &command_len, sizeof command_len,
+ command, command_len) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("send")),
+ 0);
+ else if (stream.recv (buf, sizeof buf) <= 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n"),
+ ACE_TEXT ("recv")),
+ 0);
+
+ // ACE_DEBUG ((LM_DEBUG,
+ // ACE_TEXT ("(%P|%t) client iteration %d, buf = %s\n"),
+ // i, buf));
+
+ if (stream.close () == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("close")),
+ 0);
+ }
+
+ command = "read";
+ command_len = ACE_OS::strlen (command);
+ ssize_t bytes_read = 0;
+
+ if (connector.connect (stream, server_addr) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("open")),
+ 0);
+ else if (stream.send (4,
+ &command_len, sizeof command_len,
+ command, command_len) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("send")),
+ 0);
+ else if ((bytes_read = stream.recv (buf, sizeof buf)) <= 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("recv")),
+ 0);
+ else
+ {
+ // Null terminate buf to avoid an uninitialized memory read in
+ // the call to ACE_OS::strrchr ().
+ buf [bytes_read] = '\0';
+
+ size_t count = ACE_OS::atoi (ACE_OS::strrchr (ACE_TEXT_CHAR_TO_TCHAR (buf),
+ ACE_TEXT (' ')));
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) count = %d\n"),
+ count));
+ // Make sure that the count is correct.
+ ACE_ASSERT (count == ACE_MAX_ITERATIONS);
+ }
+
+ if (stream.close () == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("close")),
+ 0);
+
+ // Remove the filename.
+ ACE_OS::unlink (OPTIONS::instance ()->filename ());
+
+ return 0;
+}
+
+// Performs the server activities.
+
+// Have all connections been serviced?
+
+static int
+done (void)
+{
+ return connections == ACE_MAX_ITERATIONS + 1;
+}
+
+static void *
+server (void *)
+{
+ int result = 0;
+ ACE_Reactor::instance ()->owner (ACE_Thread::self ());
+
+ while (!done () && result != -1)
+ // Run the main event loop.
+ result = ACE_Reactor::instance ()->handle_events ();
+
+ return 0;
+}
+
+#endif /* !ACE_LACKS_FORK || ACE_HAS_THREADS */
+
+int
+run_main (int argc, ACE_TCHAR *argv[])
+{
+ ACE_START_TEST (ACE_TEXT ("Process_Strategy_Test"));
+
+ if (OPTIONS::instance ()->parse_args (argc, argv) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("parse_args")),
+ -1);
+
+ ACCEPTOR acceptor;
+
+ ACE_INET_Addr server_addr;
+
+ // Bind acceptor to any port and then find out what the port was.
+ // Note that this implicitly creates the Reactor singleton.
+ if (acceptor.open (ACE_sap_any_cast (const ACE_INET_Addr &),
+ ACE_Reactor::instance(),
+ 0,
+ 0,
+ OPTIONS::instance ()->concurrency_strategy ()) == -1
+ || acceptor.acceptor ().get_local_addr (server_addr) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("open")),
+ -1);
+ else
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) starting server at port %d\n"),
+ server_addr.get_port_number ()));
+
+#if !defined (ACE_LACKS_FORK)
+ // We're running the client and serve as separate processes.
+ pid_t pid = ACE::fork (ACE_TEXT ("child"),
+ 1); // Avoid zombies.
+
+ switch (pid)
+ {
+ case -1:
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n%a"),
+ ACE_TEXT ("fork failed")));
+ exit (-1);
+ /* NOTREACHED */
+ case 0:
+ client (&server_addr);
+ break;
+ /* NOTREACHED */
+ default:
+ server (0);
+ break;
+ /* NOTREACHED */
+ }
+#elif defined (ACE_HAS_THREADS)
+ if (ACE_Thread_Manager::instance ()->spawn
+ (ACE_THR_FUNC (server),
+ (void *) 0,
+ THR_NEW_LWP | THR_DETACHED) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n%a"),
+ ACE_TEXT ("thread create failed")));
+
+ if (ACE_Thread_Manager::instance ()->spawn
+ (ACE_THR_FUNC (client),
+ (void *) &server_addr,
+ THR_NEW_LWP | THR_DETACHED) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n%a"),
+ ACE_TEXT ("thread create failed")));
+
+ // Wait for the threads to exit.
+ ACE_Thread_Manager::instance ()->wait ();
+#else
+ ACE_ERROR ((LM_INFO,
+ ACE_TEXT ("(%P|%t) only one thread may be run ")
+ ACE_TEXT ("in a process on this platform\n")));
+#endif /* ACE_HAS_THREADS */
+ }
+
+ ACE_END_TEST;
+ return 0;
+}
diff --git a/ACE/tests/Process_Strategy_Test.h b/ACE/tests/Process_Strategy_Test.h
new file mode 100644
index 00000000000..9278e37404a
--- /dev/null
+++ b/ACE/tests/Process_Strategy_Test.h
@@ -0,0 +1,141 @@
+/* -*- C++ -*- */
+// $Id$
+
+// ============================================================================
+// = FILENAME
+// Process_Strategy_Test.h
+//
+// = DESCRIPTION
+// This file contains the definition of Counting_Service and
+// Options. Some compilers need it in a .h file for template
+// instantiation (such as AIX C Set ++).
+//
+// = AUTHOR
+// Doug Schmidt <schmidt@cs.wustl.edu> and
+// Kevin Boyle <kboyle@sanwafp.com>
+//
+// ============================================================================
+
+#ifndef ACE_TESTS_PROCESS_STRATEGY_TEST_H
+#define ACE_TESTS_PROCESS_STRATEGY_TEST_H
+
+#include "ace/Event_Handler.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "ace/File_Lock.h"
+#include "ace/SOCK_Stream.h"
+#include "ace/Svc_Handler.h"
+#include "ace/Strategies_T.h"
+
+class Counting_Service : public ACE_Svc_Handler <ACE_SOCK_STREAM, ACE_NULL_SYNCH>
+ // = TITLE
+ // Reads and increments the count in a shared file.
+ //
+ // = DESCRIPTION
+ // Objects of this class execute in a separate process as a
+ // result of the <ACE_Strategy_Acceptor> and
+ // <ACE_Process_Strategy>.
+{
+public:
+ Counting_Service (ACE_Thread_Manager * = 0);
+ // Constructor.
+
+ virtual int open (void *v);
+ // Hook that is used to initialize the service (called by the
+ // <ACE_Strategy_Acceptor::handle_input> Template Method).
+
+protected:
+ // = Methods invoked via "pointer to method" table entry.
+
+ virtual int svc (void);
+ // Handle the THREAD case.
+
+ // = Operations corresponding to requests from the client.
+ int read (void);
+ // Execute the read operation on the file.
+
+ int inc (void);
+ // Execute the increment operation on the file.
+
+ // = Hooks called by <Reactor> and <Strategy_Acceptor>.
+
+ virtual int handle_input (ACE_HANDLE p = ACE_INVALID_HANDLE);
+ // Hook called by the <Reactor> when data arrives from the client.
+
+ virtual int handle_close (ACE_HANDLE = ACE_INVALID_HANDLE,
+ ACE_Reactor_Mask = ACE_Event_Handler::ALL_EVENTS_MASK);
+ // Closing down
+};
+
+class Process_Strategy : public ACE_Process_Strategy<Counting_Service>
+{
+public:
+
+ // Constructor
+ Process_Strategy (size_t n_processes = 1,
+ ACE_Event_Handler *acceptor = 0,
+ ACE_Reactor * = 0,
+ int flags = 0);
+
+ // Destructor
+ ~Process_Strategy (void);
+
+ // Overwrite the process creation method to include connection
+ // counting
+ virtual int activate_svc_handler (Counting_Service *svc_handler,
+ void *arg = 0);
+};
+
+class Options : public ACE_Event_Handler
+ // = TITLE
+ // Maintains the options for this program.
+{
+public:
+ Options (void);
+ // Constructor.
+
+ ~Options (void);
+ // Destructor.
+
+ int parse_args (int argc, ACE_TCHAR *argv[]);
+ // Read command-line arguments and initialize options.
+
+ enum Concurrency_Type
+ {
+ PROCESS, // Run the test in separate processes.
+ REACTIVE, // Run the test reactively in one thread.
+ THREAD // Run the test as in separate threads.
+ };
+
+ // = Get/set concurrency type.
+ Concurrency_Type concurrency_type (void);
+ void concurrency_type (Concurrency_Type);
+
+ ACE_File_Lock &file_lock (void);
+ // Returns the file lock.
+
+ const ACE_TCHAR *filename (void);
+ // Returns the filename that we're using as the lock.
+
+ ACE_Concurrency_Strategy <Counting_Service> *concurrency_strategy (void);
+ // Returns the concurrency strategy.
+
+private:
+ Concurrency_Type concurrency_type_;
+ // Concurrency strategy that we're running.
+
+ ACE_File_Lock file_lock_;
+ // Lock for the counting file.
+
+ ACE_Concurrency_Strategy<Counting_Service> *concurrency_strategy_;
+ // Activation strategy that either forks a new process or spawns a
+ // new thread for each client connection.
+
+ ACE_TCHAR filename_[MAXPATHLEN + 1];
+ // Name of the counting file.
+};
+
+#endif /* ACE_TESTS_PROCESS_STRATEGY_TEST_H */
diff --git a/ACE/tests/QtReactor_Test.cpp b/ACE/tests/QtReactor_Test.cpp
new file mode 100644
index 00000000000..c228802988b
--- /dev/null
+++ b/ACE/tests/QtReactor_Test.cpp
@@ -0,0 +1,927 @@
+/* -*- C++ -*- */
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// QtReactor_Test.cpp
+//
+// = DESCRIPTION
+// Simple test of QtReactor. Test is intended to verify if QtReactor
+// correctly cooperates with Qt event loop in typical application. Test
+// creates a number of timers which send datagrams. These datagrams are
+// expected by datagram_handlers registered in reactor. Test asynchronously
+// establishes also a number of loopback tcp connections using ACE_Acceptors
+// and ACE_Connectors. Socket activities are handled asynchronously to ensure
+// that reactor does not lose events in traffic transmission. Moreover, test
+// registers and removes handlers frequently to cover register/remove_handler
+// method of QtReactor which are known (10/07/2004) to be buggy.
+//
+// Classes:
+// QTestApplication - main qt application running event loop for a
+// finite time
+// Dgram_Handler - responsible for sending and receiving datagrams as
+// well as handling timeouts. Datagrams are sent in
+// handle_timeout method.
+// TCPConnectionHandler - connection handler responsible for sending and
+// receiving data using tcp streams.
+// TCPAcceptorHandler - acceptor responsible for acceptance and
+// registration of connections in HandlersRegister
+// class.
+// HandlersRegister - register of event_handlers, responsible also for
+// the analysis of test results.
+//
+// = AUTHOR
+// Marek Brudka <mbrudka@elka.pw.edu.pl>
+//
+// ============================================================================
+
+#include "test_config.h"
+
+ACE_RCSID (tests,
+ QtReactor_Test,
+ "$Id$")
+
+#include <assert.h>
+#include <qapplication.h>
+#include <qtimer.h>
+
+#include "ace/OS_NS_time.h"
+#include "ace/Time_Value.h"
+#include "ace/QtReactor.h"
+#include "ace/Event_Handler.h"
+#include "ace/Acceptor.h"
+#include "ace/Connector.h"
+#include "ace/SOCK_Acceptor.h"
+#include "ace/SOCK_Connector.h"
+#include "ace/SOCK_Dgram.h"
+
+// Qt specific code
+#include "QtReactor_Test.h"
+
+/*
+ QTestApplication class implementation
+*/
+
+QTestApplication::QTestApplication (int argc, char *argv[]):
+ QApplication (argc, argv, FALSE) /* do not enable GUI */
+ {
+ connect (&finishTimer_, SIGNAL (timeout ()), this, SLOT (finishTest ()));
+}
+
+void QTestApplication::finishTest ()
+{
+ exit ();
+}
+
+void QTestApplication::exec (int msec)
+{
+ finishTimer_.stop ();
+ if (0 < msec )
+ finishTimer_.start (msec, TRUE);
+ inherited::exec ();
+}
+
+
+// maximum time for testing QtReactor (msec)
+const int TotalTestTime = 8000;
+
+// how many handlers for each event handler class should be started ?
+#ifndef __QNXNTO__
+const int HandlersNo = 8 ;
+#else /* __QNXNTO__ */
+// it seems that Qt 3.1 for NTO 6.2 is compiled with rather small FD_SETSIZE
+// Nevertheless, test works fine with native select reactor
+const int HandlersNo = 4;
+#endif
+// base port for sending datagrams
+const u_short BaseDgramPort = 5931;
+
+// port for TCP connections
+const u_short BaseTCPPort = 5931;
+
+// how many datagrams should be sent for a single handler
+const int DgramsToSend = 64;
+
+// how many bytes to send vie TCP
+const int TCPBytesToSend = 1024;
+
+// how many times to reply tcp recv
+const int TCPClientPings = 16;
+
+// total number of bytes in TCP transmission
+const int TCPTotalBytesToSend = TCPClientPings * TCPBytesToSend;
+
+/**
+ \class DgramHandler
+ \brief Simple event handler that receives and counts datagrams
+ as well as sends dgrams using timeouts.
+*/
+class DgramHandler: public ACE_Event_Handler
+{
+public:
+ DgramHandler (ACE_Reactor *p_reactor = 0);
+ virtual ~DgramHandler ();
+
+ int open (const ACE_INET_Addr &local,
+ int protocol_family=ACE_PROTOCOL_FAMILY_INET,
+ int protocol=0,
+ int reuse_addr=0);
+ virtual ACE_HANDLE get_handle () const;
+ virtual int handle_input (ACE_HANDLE handle);
+ virtual int handle_close (ACE_HANDLE handle,ACE_Reactor_Mask close_mask);
+ virtual int handle_timeout (const ACE_Time_Value &current_time, const void *act=0);
+ int dgramsSent () const;
+ int dgramsReceived () const;
+ int timeoutsTriggered () const;
+ int expectedTriggers () const;
+ void expectedTriggers (int);
+private:
+ int dgramsSent_; //!< the number of sent datagrams
+ int dgramsReceived_; //!< the number of received datagrams
+ int timeoutsTriggered_;
+ int expectedTriggers_;
+ ACE_SOCK_Dgram peer_; //!< datagram socket we listen to
+};
+
+/**
+ \class TCPConnectionHandler
+ \brief TCP stream handler for both sides of connection.
+*/
+class TCPConnectionHandler : public ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH>
+{
+public:
+ typedef ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH> inherited;
+public:
+ TCPConnectionHandler (bool p_serverSide = false);
+ virtual ~TCPConnectionHandler ();
+
+ virtual int handle_output (ACE_HANDLE handle);
+ virtual int handle_input (ACE_HANDLE handle);
+ virtual int handle_close (ACE_HANDLE handle,ACE_Reactor_Mask close_mask);
+ virtual int open (void * = 0);
+
+ int scheduleSend (ACE_Message_Block *);
+ int sendBuffers ();
+ int totalReceived () const;
+ int totalSent () const;
+private:
+ ACE_Message_Block *buffers_;
+ int totalReceived_; //!< total number of received bytes
+ int totalSent_; //!< total number of send bytes
+ bool serverSide_; //!< if true, echo received data
+ int pingsNo_; //!< number of pings client should make
+};
+
+typedef ACE_Connector< TCPConnectionHandler, ACE_SOCK_CONNECTOR > TCPConnectorHandler;
+class TCPAcceptorHandler; // forward declaration
+
+/* \class HandlersRegister
+ \brief The collection of test tools. Here ACE classes bind to Qt application
+*/
+class HandlersRegister
+{
+public:
+ HandlersRegister (ACE_Reactor *p_reactor);
+ virtual ~HandlersRegister ();
+ int scheduleTimers (const ACE_Time_Value &p_TestTime); //!< schedule ace timers
+ int registerDgramHandlers (); //!< open dgrams socket and register in reactor
+ int registerTCPHandlers (); //!< creates TCP acceptors and connector
+ int analyze () const; //!< analyze results
+ int analyzeTimeouts () const; //!< analyze triggered timeouts
+ int analyzeDgrams () const; //!< analyze collected dgrams
+ int analyzeTCP () const; //!< analyze TCP transmission
+ int registerTCPServer (TCPConnectionHandler *);
+ int TCPServersNo () const; //!< return the number of accepted connections
+
+private:
+ ACE_Reactor *reactor_; //!< reactor for this application
+ DgramHandler *DgramHandlers_[ HandlersNo] ;//!< dgram input handlers
+ int TCPServersNo_; //!< number of accepted connections
+ TCPConnectionHandler *TCPServers_[ HandlersNo ];
+ TCPConnectionHandler *TCPClients_[ HandlersNo ];
+ TCPAcceptorHandler *acceptor_;
+ TCPConnectorHandler *connectors_[ HandlersNo ];
+};
+
+class TCPAcceptorHandler : public ACE_Acceptor< TCPConnectionHandler, ACE_SOCK_ACCEPTOR >
+{
+public:
+ typedef ACE_Acceptor< TCPConnectionHandler, ACE_SOCK_ACCEPTOR > inherited;
+public:
+ TCPAcceptorHandler (HandlersRegister *p_handlersRegister);
+ virtual ~TCPAcceptorHandler ();
+ virtual int make_svc_handler (TCPConnectionHandler *& sh);
+ virtual int activate_svc_handler (TCPConnectionHandler * sh);
+private:
+ HandlersRegister *handlersRegister_;
+};
+
+/*
+ DgramHandler class implementation
+*/
+
+DgramHandler::DgramHandler (ACE_Reactor *p_reactor):
+ ACE_Event_Handler (p_reactor),
+ dgramsSent_ (0),
+ dgramsReceived_ (0),
+ timeoutsTriggered_ (0),
+ expectedTriggers_ (0)
+{
+ reference_counting_policy ().value (Reference_Counting_Policy::ENABLED);
+}
+
+DgramHandler::~DgramHandler ()
+{
+ ACE_TRACE ("DgramHandler::~DgramHandler");
+}
+
+int DgramHandler::open (const ACE_INET_Addr &local,
+ int protocol_family,
+ int protocol,
+ int reuse_addr)
+{
+ if (0 > peer_.open (local,
+ protocol_family,
+ protocol,
+ reuse_addr))
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT (" (%P) %p \n"),
+ ACE_TEXT ("Cannot oper dgram socket")),
+ -1);
+
+ return 0;
+}
+
+ACE_HANDLE DgramHandler::get_handle () const
+{
+ return peer_.get_handle ();
+}
+
+int DgramHandler::handle_input (ACE_HANDLE handle)
+{
+ ACE_UNUSED_ARG (handle);
+ int recvBuffer;
+ ACE_INET_Addr peerAddress;
+ int result;
+
+ result = peer_.recv (&recvBuffer, sizeof (recvBuffer) , peerAddress);
+
+ if (0 >= result)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT (" (%P) %p \n"),
+ ACE_TEXT ("While reading datagram from socket"))
+ , -1);
+ else
+ ++dgramsReceived_;
+
+ return 0;
+}
+
+int DgramHandler::handle_timeout (const ACE_Time_Value &current_time, const void *act)
+{
+ ACE_UNUSED_ARG (current_time);
+ ACE_UNUSED_ARG (act);
+ int sendBuffer = 0;
+
+ if (++timeoutsTriggered_ >= expectedTriggers_)
+ reactor ()->cancel_timer (this, 1);
+
+ ACE_SOCK_Dgram socket;
+ if (-1 == socket.open (
+ ACE_INET_Addr (static_cast< u_short > (0),
+ static_cast< ACE_UINT32 > (INADDR_ANY)),
+ ACE_PROTOCOL_FAMILY_INET, 0, 1))
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT (" (%P) %p \n"),
+ ACE_TEXT ("Cannot open socket for sending Qt dgrams")));
+
+ ACE_INET_Addr peerAddr;
+ peer_.get_local_addr (peerAddr);
+
+ if (sizeof (sendBuffer) != socket.send (&sendBuffer,
+ sizeof (sendBuffer), peerAddr))
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT (" (%P) %p \n"),
+ ACE_TEXT ("Cannot send dgram")));
+ else
+ ++dgramsSent_;
+
+ socket.close ();
+
+ return 0;
+}
+
+int DgramHandler::handle_close (ACE_HANDLE handle, ACE_Reactor_Mask close_mask)
+{
+ if (peer_.get_handle () != handle )
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Unknown handle %d DgramHandler::handle_close "
+ "with mask %x. My handle is %d\n"),
+ handle,
+ close_mask,
+ peer_.get_handle ()));
+ else
+ peer_.close ();
+
+ return 0;
+}
+
+int DgramHandler::dgramsSent () const
+{
+ return dgramsSent_;
+}
+
+int DgramHandler::dgramsReceived () const
+{
+ return dgramsReceived_;
+}
+
+int DgramHandler::timeoutsTriggered () const
+{
+ return timeoutsTriggered_;
+}
+
+void DgramHandler::expectedTriggers (int triggers)
+{
+ expectedTriggers_ = triggers;
+}
+
+int DgramHandler::expectedTriggers () const
+{
+ return expectedTriggers_;
+}
+
+/*
+ TCPConnectionHandler class implementation
+*/
+
+TCPConnectionHandler::TCPConnectionHandler (bool p_serverSide):
+ buffers_ (0),
+ totalReceived_ (0),
+ totalSent_ (0),
+ serverSide_ (p_serverSide),
+ pingsNo_ (TCPClientPings)
+{
+ reference_counting_policy ().value (Reference_Counting_Policy::ENABLED);
+}
+
+TCPConnectionHandler::~TCPConnectionHandler ()
+{
+ ACE_TRACE ("TCPConnectionHandler::~TCPConnectionHandler");
+}
+
+int TCPConnectionHandler::handle_input (ACE_HANDLE handle)
+{
+ ACE_UNUSED_ARG (handle);
+ ACE_Message_Block *buffer = new ACE_Message_Block (TCPBytesToSend);
+ int bytesReceived = peer_.recv (buffer->wr_ptr (), buffer->space ());
+
+ if (bytesReceived > 0)
+ {
+ totalReceived_ += bytesReceived;
+ if (serverSide_ || --pingsNo_ > 0) // echo received buffer
+ {
+ buffer->wr_ptr (bytesReceived);
+ int result = scheduleSend (buffer);
+ if (0 > result)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT (" (%P) %p \n"),
+ ACE_TEXT ("Cannot schedule TCP reply")),
+ -1);
+ }
+ else
+ buffer->release ();
+
+ return 0;
+ }
+
+ if (errno != EWOULDBLOCK)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT (" (%P:%p (%d)\n"),
+ ACE_TEXT ("TCPConnectionHandler::handle_input call with no data on handle "), handle),
+ -1);
+
+ ACE_ERROR ((LM_WARNING,
+ ACE_TEXT (" (%P:%p (%d)\n"),
+ ACE_TEXT ("TCPConnectionHandler::handle_input call with no data on handle "), handle));
+
+ return 0;
+}
+
+int TCPConnectionHandler::handle_output (ACE_HANDLE handle)
+{
+ ACE_UNUSED_ARG (handle);
+ if (!buffers_)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("TCPConnectionHandler::handle_output call for empty buffers (%d)\n"), handle));
+ if (0 > sendBuffers ()) // socket broken, kill yourself
+ return -1;
+
+ if (!buffers_) // everything already send, unregister
+ {
+ reactor ()->cancel_wakeup (this,
+ ACE_Event_Handler::WRITE_MASK | ACE_Event_Handler::DONT_CALL);
+ reactor ()->remove_handler (this,
+ ACE_Event_Handler::WRITE_MASK | ACE_Event_Handler::DONT_CALL);
+ }
+
+ return 0;
+}
+
+int TCPConnectionHandler::open (void * )
+{
+ int result = inherited::open ();
+
+ if (!serverSide_)
+ {
+ ACE_Message_Block *buffer = new ACE_Message_Block (TCPBytesToSend);
+ char *bufferData = buffer->wr_ptr ();
+ int i;
+
+ for (i = buffer->size () - 1; i >= 0; --i)
+ bufferData[ i ] = static_cast< char > (i);
+ buffer->wr_ptr (buffer->size ());
+ if (0 != (scheduleSend (buffer)))
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("Cannot schedule initial send\n")),
+ -1);
+ }
+
+ return result;
+}
+
+int TCPConnectionHandler::scheduleSend (ACE_Message_Block * buffer)
+{
+ // link buffer to the end of buffers list
+ if (buffers_)
+ {
+ ACE_Message_Block *lastBuffer = buffers_;
+ while (lastBuffer->cont ())
+ lastBuffer = lastBuffer->cont () ;
+ lastBuffer->cont (buffer);
+ }
+ else
+ buffers_ = buffer;
+
+ if (0 > sendBuffers ())
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT (" (%P) %p \n"),
+ ACE_TEXT ("Cannot schedule TCP send.")),
+ -1);
+ return 0;
+}
+
+int TCPConnectionHandler::sendBuffers ()
+{
+ int result = 0;
+
+ if (buffers_)
+ if (0 < (result = peer_.send_n (buffers_))) // remove sent blocks
+ {
+ totalSent_ += result;
+ while (buffers_ &&
+ static_cast< size_t > (result) >= buffers_->length ())
+ {
+ ACE_Message_Block *buffer = buffers_;
+ result -= buffers_->length ();
+ buffers_= buffers_->cont ();
+ buffer->cont (0);
+ buffer->release ();
+ }
+
+ if (buffers_) // some buffers were not sent, truncate data
+ buffers_->rd_ptr (result);
+ }
+
+ return result;
+}
+
+int TCPConnectionHandler::handle_close (ACE_HANDLE handle,ACE_Reactor_Mask close_mask)
+{
+ if (peer_.get_handle () != handle )
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Unknown handle %d TCPConnectionHandler::handle_close "
+ "with mask %x. My handle is %d\n"),
+ handle,
+ close_mask,
+ peer_.get_handle ()));
+ else
+ peer_.close ();
+
+ return 0;
+}
+
+int TCPConnectionHandler::totalReceived () const
+{
+ return totalReceived_;
+}
+
+int TCPConnectionHandler::totalSent () const
+{
+ return totalSent_;
+}
+
+
+/*
+ HandlersRegister class implementation
+*/
+
+HandlersRegister::HandlersRegister (ACE_Reactor *p_reactor):
+ reactor_ (p_reactor),
+ TCPServersNo_ (0)
+{
+ int i;
+
+ for (i = 0; i < HandlersNo; ++i)
+ {
+ // create dgram input handler
+ DgramHandlers_[ i ] = new DgramHandler (p_reactor);
+
+ TCPServers_[ i ] = 0;
+
+ TCPClients_[ i ] = new TCPConnectionHandler (false);
+
+ connectors_[ i ] =new TCPConnectorHandler (p_reactor, ACE_NONBLOCK);
+ connectors_[ i ]->reference_counting_policy ().value (
+ ACE_Event_Handler::Reference_Counting_Policy::ENABLED) ;
+ }
+
+ acceptor_ = new TCPAcceptorHandler (this);
+ acceptor_->reactor (p_reactor);
+}
+
+HandlersRegister::~HandlersRegister ()
+{
+ int i;
+ if (acceptor_)
+ {
+ reactor_->remove_handler (acceptor_, ACE_Event_Handler::ALL_EVENTS_MASK);
+ acceptor_->close ();
+ acceptor_->remove_reference ();
+ }
+
+ for (i = 0; i < HandlersNo; ++i)
+ {
+ reactor_->cancel_timer (DgramHandlers_[ i ], 1);
+ reactor_->remove_handler (DgramHandlers_[ i ],
+ ACE_Event_Handler::ALL_EVENTS_MASK);
+ DgramHandlers_[ i ]->remove_reference ();
+
+ if (TCPServers_[ i ])
+ {
+ reactor_->remove_handler (TCPServers_[ i ],
+ ACE_Event_Handler::ALL_EVENTS_MASK);
+ TCPServers_[ i ]->remove_reference ();
+ }
+
+ reactor_->remove_handler (connectors_[ i ],
+ ACE_Event_Handler::ALL_EVENTS_MASK);
+ connectors_[ i ]->close ();
+ connectors_[ i ]->remove_reference ();
+
+ if (TCPClients_[ i ])
+ {
+ reactor_->remove_handler (TCPClients_[ i ],
+ ACE_Event_Handler::ALL_EVENTS_MASK);
+ TCPClients_[ i ]->remove_reference ();
+ }
+ }
+}
+
+int HandlersRegister::TCPServersNo () const
+{
+ return TCPServersNo_;
+}
+
+int HandlersRegister::scheduleTimers (const ACE_Time_Value &p_TestTime)
+{
+ int i;
+
+ for (i = 0; i < HandlersNo; ++i)
+ {
+ if (-1 == reactor_->schedule_timer (DgramHandlers_[ i ],
+ (const void *) 0,
+ ACE_Time_Value::zero,
+ p_TestTime * (0.5 / DgramsToSend)))
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT (" (%P) %p \n"),
+ ACE_TEXT ("Cannot schedule ACE timer")),
+ -1);
+
+ DgramHandlers_[ i ] ->expectedTriggers (DgramsToSend);
+
+ }
+
+ return 0;
+}
+
+int HandlersRegister::registerDgramHandlers ()
+{
+ int i;
+
+ // open dgram handlers for all ports
+ for (i = 0; i < HandlersNo; ++i)
+ if (-1 == DgramHandlers_[ i ]->open (
+ ACE_INET_Addr (i + BaseDgramPort,
+ ACE_TEXT ("127.0.0.1"),
+ ACE_PROTOCOL_FAMILY_INET)))
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT (" (%P) %p \n"),
+ ACE_TEXT ("Cannot open dgram handler")),
+ -1);
+
+ // register dgram handlers
+ for (i = 0; i < HandlersNo; ++i)
+ if (-1 == reactor_->register_handler (DgramHandlers_[ i ],
+ ACE_Event_Handler::READ_MASK))
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT (" (%P) %p \n"),
+ ACE_TEXT ("Cannot register dgram handler")),
+ -1);
+ return 0;
+}
+
+int HandlersRegister::registerTCPHandlers ()
+{
+ ACE_INET_Addr addr (BaseTCPPort);
+
+ if (-1 == acceptor_->open (addr, reactor_, 1))
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT (" (%P) %p \n"),
+ ACE_TEXT ("Cannot open acceptor port")),
+ -1);
+
+ int i;
+ addr.set (BaseTCPPort, ACE_TEXT ("127.0.0.1"));
+
+ for (i = 0; i < HandlersNo; ++i)
+ {
+ if (-1 == connectors_[ i ]->connect (
+ TCPClients_[ i ],
+ addr,
+ ACE_Synch_Options::asynch))
+ if (errno != EWOULDBLOCK )
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT (" (%P) %p (%d)\n"),
+ ACE_TEXT ("Cannot connect connector"),
+ i),
+ -1);
+ }
+
+ return 0;
+}
+
+int HandlersRegister::registerTCPServer (TCPConnectionHandler *handler)
+{
+ if (TCPServersNo_ < HandlersNo)
+ {
+ TCPServers_[ TCPServersNo_++ ] = handler;
+ return 0;
+ }
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Too many servers registered (%d). ACE_Reactor or ACE_Acceptor broken?\n"),
+ handler->get_handle ()));
+ return -1;
+}
+
+int HandlersRegister::analyze () const
+{
+ int result = 0;
+
+ if (0 > analyzeTimeouts ())
+ result = -1;
+
+ if (0 > analyzeDgrams ())
+ result = -1;
+
+ if (0 > analyzeTCP ())
+ result = -1;
+
+ return result;
+}
+
+int HandlersRegister::analyzeTimeouts () const
+{
+ int i;
+ int result = 0;
+
+ for (i = 0; i < HandlersNo; ++i)
+ if (DgramHandlers_[ i ]->expectedTriggers () !=
+ DgramHandlers_[ i ]->timeoutsTriggered ())
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Dgram_Handlers (%d) expected %d timeouts"
+ " but triggered only %d.\n"),
+ i,
+ DgramHandlers_[ i ]->expectedTriggers (),
+ DgramHandlers_[ i ]->timeoutsTriggered ()));
+ result = -1;
+ }
+
+ return result;
+}
+
+int HandlersRegister::analyzeDgrams () const
+{
+ int result = 0;
+ int i;
+
+ for (i = 0; i < HandlersNo; ++i)
+ if (DgramHandlers_[ i ]->dgramsSent () !=
+ DgramHandlers_[ i ]->dgramsReceived ())
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("DgramsHandler (%d) sent %d dgrams but received only %d."
+ "Either reactor failed or system lost local dgrams..\n"),
+ DgramHandlers_[ i ]->dgramsSent (),
+ DgramHandlers_[ i ]->dgramsReceived ()));
+ result = -1 ;
+ }
+
+ return result;
+}
+
+int HandlersRegister::analyzeTCP () const
+{
+ int i;
+ int result = 0;
+
+ for (i = 0; i < HandlersNo; ++i)
+ {
+ if (TCPClients_[ i ]->totalSent () != TCPTotalBytesToSend )
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("TCPClient (%d): wanted to send %d but sent only (%d).\n"),
+ i,
+ TCPTotalBytesToSend,
+ TCPClients_[ i ]->totalSent ()));
+ result = -1;
+ }
+
+ if (TCPClients_[ i ]->totalReceived () != TCPTotalBytesToSend )
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("TCPClient (%d): expected %d bytes but received only (%d).\n"),
+ i,
+ TCPTotalBytesToSend,
+ TCPClients_[ i ]->totalReceived ()));
+ result = -1;
+ }
+
+ if (TCPServers_[ i ])
+ {
+ if (TCPServers_[ i ]->totalSent () != TCPTotalBytesToSend )
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("TCPServer (%d): wanted to send %d bytes "
+ "but sent only (%d).\n"),
+ i,
+ TCPTotalBytesToSend,
+ TCPServers_[ i ]->totalSent ()));
+ result = -1;
+ }
+
+ if (TCPServers_[ i ]->totalReceived () != TCPTotalBytesToSend )
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("TCPServer (%d): expected %d bytes but received only (%d).\n"),
+ i,
+ TCPTotalBytesToSend,
+ TCPServers_[ i ]->totalReceived ()));
+ result = -1;
+ }
+
+ }
+ else
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("TCPServer (%d): not connected.\n"),
+ i));
+ result = -1;
+ }
+ }
+
+ return result;
+}
+
+
+/*
+ TCPAcceptorHandler class implementation
+*/
+
+TCPAcceptorHandler::TCPAcceptorHandler (HandlersRegister *p_handlersRegister):
+ handlersRegister_ (p_handlersRegister)
+{
+ reference_counting_policy ().value (Reference_Counting_Policy::ENABLED);
+}
+
+int TCPAcceptorHandler::make_svc_handler (TCPConnectionHandler *& sh)
+{
+ sh = new TCPConnectionHandler (true);
+ sh->reactor (reactor ());
+ if (handlersRegister_->TCPServersNo () >= HandlersNo)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("TCPAcceptorHandler::make_svc_handler called to many times!\n")));
+ else
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("TCPAcceptorHandler::make_svc_handler new TCP server created\n")));
+
+ return 0;
+}
+
+int TCPAcceptorHandler::activate_svc_handler (TCPConnectionHandler * sh)
+{
+ if (0 == inherited::activate_svc_handler (sh) )
+ {
+ if (0 != handlersRegister_->registerTCPServer (sh)) // for analysis
+ {
+ // release event handler
+ reactor ()->remove_handler (sh, ACE_Event_Handler::ALL_EVENTS_MASK);
+ sh->remove_reference ();
+ // report error
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("Cannot register server TCPConnectionHandler\n")),
+ -1);
+ }
+
+ }
+ else
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("Failed to create server TCPConnectionHandler\n")),
+ -1);
+
+ return 0;
+}
+
+TCPAcceptorHandler::~TCPAcceptorHandler ()
+{
+ ACE_TRACE ("TCPAcceptorHandler::~TCPAcceptorHandler");
+}
+
+void testNativeReactor (int argc, ACE_TCHAR *argv[])
+{
+ ACE_UNUSED_ARG (argc);
+ ACE_UNUSED_ARG (argv);
+
+ ACE_DEBUG ((LM_INFO, ACE_TEXT ("Testing autotest using native reactor\n")));
+
+ ACE_Reactor reactor;
+ HandlersRegister handlersRegister (&reactor);
+ ACE_Time_Value testTime (TotalTestTime / 1000, (TotalTestTime % 1000) * 1000);
+
+ if (0 <= handlersRegister.scheduleTimers (testTime) &&
+ 0 <= handlersRegister.registerDgramHandlers () &&
+ 0 <= handlersRegister.registerTCPHandlers ())
+ {
+ reactor.run_reactor_event_loop (testTime);
+
+ if (0 != handlersRegister.analyze ())
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Test failed for native reactor. "
+ "Fix QtReactor_Test or ACE_Reactor.\n")));
+ else
+ ACE_ERROR ((LM_INFO, ACE_TEXT ("Test seems to work with native reactor.\n")));
+ }
+}
+
+void testQtReactor (int argc, ACE_TCHAR *argv[])
+{
+ // Qt specific code
+ ACE_DEBUG ((LM_INFO, ACE_TEXT ("Testing QtReactor\n")));
+
+ QTestApplication app (argc, argv);
+ ACE_QtReactor qtReactor (&app);
+ ACE_Reactor reactor (&qtReactor);
+ HandlersRegister handlersRegister (&reactor);
+ ACE_Time_Value testTime (TotalTestTime / 1000, (TotalTestTime % 1000) * 1000);
+
+ if (0 <= handlersRegister.scheduleTimers (testTime) &&
+ 0 <= handlersRegister.registerDgramHandlers () &&
+ 0 <= handlersRegister.registerTCPHandlers ())
+ {
+
+ app.exec (TotalTestTime);
+
+ if (0 != handlersRegister.analyze ())
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("QtReactor_Test failed.\n")));
+ else
+ ACE_ERROR ((LM_INFO, ACE_TEXT ("QtReactor_Test passed.\n")));
+ }
+}
+
+int
+run_main (int argc, ACE_TCHAR *argv[])
+{
+ ACE_START_TEST (ACE_TEXT ("QtReactor_Test"));
+
+ testNativeReactor (argc, argv);
+ testQtReactor (argc, argv);
+
+ ACE_END_TEST;
+
+ return 0;
+}
diff --git a/ACE/tests/QtReactor_Test.h b/ACE/tests/QtReactor_Test.h
new file mode 100644
index 00000000000..f2be9a5331c
--- /dev/null
+++ b/ACE/tests/QtReactor_Test.h
@@ -0,0 +1,23 @@
+/* -*- C++ -*- */
+// $Id$
+#ifndef QTREACTOR_TEST_H
+#define QTREACTOR_TEST_H
+
+#include <qapplication.h>
+#include <qtimer.h>
+
+class QTestApplication: public QApplication
+{
+ Q_OBJECT
+public:
+ typedef QApplication inherited;
+public:
+ QTestApplication( int argc, char *argv[] );
+ virtual void exec( int msec = 0 );
+public slots:
+ virtual void finishTest(); //!< slot to finish the test, connected to finishTimer_
+private:
+ QTimer finishTimer_; //!< timer to finish the test
+};
+
+#endif /*QTREACTOR_TEST_H*/
diff --git a/ACE/tests/RB_Tree_Test.cpp b/ACE/tests/RB_Tree_Test.cpp
new file mode 100644
index 00000000000..c276a96cafd
--- /dev/null
+++ b/ACE/tests/RB_Tree_Test.cpp
@@ -0,0 +1,597 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// RB_Tree_Test.cpp
+//
+// = DESCRIPTION
+// This is a test to verify and illustrate the use of the
+// <ACE_RB_Tree ACE_RB_Tree_Iterator> and
+// <ACE_RB_Tree_Reverse_Iterator> classes. Two different key and
+// item types are used in order to demonstrate specialization of
+// the <ACE_Less_Than> comparison function object template: int
+// (for which the native < operator is sufficient), and const char
+// * (for which < operator semantics must be replaced by strcmp
+// semantics). An RB tree for each of the four possible type
+// parameter permutations over int and const char * is constructed
+// and filled in, and the resulting order is checked via an
+// iterator over each.
+//
+// = AUTHOR
+// Chris Gill <cdgill@cs.wustl.edu>
+//
+// ============================================================================
+
+#include "test_config.h" /* Include first to enable ACE_ASSERT. */
+#include "ace/RB_Tree.h"
+#include "ace/SString.h"
+#include "ace/Null_Mutex.h"
+
+#include "RB_Tree_Test.h"
+
+ACE_RCSID(tests, RB_Tree_Test, "$Id$")
+
+// Type definitions for the four distinct parameterizations of the
+// test.
+
+typedef ACE_RB_Tree_Test<int, int, ACE_Less_Than<int>, ACE_Null_Mutex> INT_INT_RB_TREE_TEST;
+typedef ACE_RB_Tree_Test<int, const char *, ACE_Less_Than<int>, ACE_Null_Mutex> INT_STR_RB_TREE_TEST;
+typedef ACE_RB_Tree_Test<const char *, int, ACE_Less_Than<const char *>, ACE_Null_Mutex> STR_INT_RB_TREE_TEST;
+typedef ACE_RB_Tree_Test<const char *, const char *, ACE_Less_Than<const char *>, ACE_Null_Mutex> STR_STR_RB_TREE_TEST;
+
+// Number of entries placed in each tree.
+static int RB_TREE_TEST_ENTRIES = 8;
+
+// These arrays of numbers as ints and character strings are used to
+// instantiate key and item arrays in the tests.
+static const char *number_strings [] =
+{
+ "10", "20", "30", "40", "50", "60", "70", "80"
+};
+
+static int number_integers [] =
+{
+ 10, 20, 30, 40, 50, 60, 70, 80
+};
+
+// These arrays of ints are used to shuffle the order of insertion and
+// deletaion of keys and items for the various tests.
+static int int_int_index [] = {0, 1, 2, 3, 4, 5, 6, 7}; // LR inorder
+static int int_str_index [] = {7, 6, 5, 4, 3, 2, 1, 0}; // RL inorder
+static int str_int_index [] = {4, 6, 2, 7, 5, 3, 1, 0}; // RL BFS
+static int str_str_index [] = {4, 2, 1, 0, 3, 6, 5, 7}; // LR preorder
+
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("RB_Tree_Test"));
+
+ // Construct and run four distinctly parameterized tests. Note that
+ // specialization of the ACE_Less_Than template for character
+ // strings performs strcmp style string comparisons rather than <
+ // operator comparison of the const char * pointers themselves.
+
+ INT_INT_RB_TREE_TEST int_int_test (RB_TREE_TEST_ENTRIES,
+ number_integers,
+ number_integers,
+ int_int_index);
+ INT_STR_RB_TREE_TEST int_str_test (RB_TREE_TEST_ENTRIES,
+ number_integers,
+ number_strings,
+ int_str_index);
+ STR_INT_RB_TREE_TEST str_int_test (RB_TREE_TEST_ENTRIES,
+ number_strings,
+ number_integers,
+ str_int_index);
+ STR_STR_RB_TREE_TEST str_str_test (RB_TREE_TEST_ENTRIES,
+ number_strings,
+ number_strings,
+ str_str_index);
+ int_int_test.run_test ();
+ int_str_test.run_test ();
+ str_int_test.run_test ();
+ str_str_test.run_test ();
+
+// ======= Stress Test contributed by Klaus H. Wolf <hw@cyland.com> ==================
+
+ ACE_RB_Tree<ACE_CString, int, ACE_Less_Than<ACE_CString>, ACE_Null_Mutex> tree;
+
+ tree.bind (ACE_CString ("51"), 1);
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.bind (ACE_CString ("13"), 2);
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.bind (ACE_CString ("36"), 3);
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.bind (ACE_CString ("15"), 4);
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.bind (ACE_CString ("22"), 5);
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.bind (ACE_CString ("25"), 6);
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.bind (ACE_CString ("42"), 7);
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.bind (ACE_CString ("48"), 8);
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.bind (ACE_CString ("03"), 9);
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.bind (ACE_CString ("56"), 10);
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.bind (ACE_CString ("28"), 11);
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.bind (ACE_CString ("55"), 12);
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.bind (ACE_CString ("21"), 13);
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.bind (ACE_CString ("62"), 14);
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.bind (ACE_CString ("18"), 15);
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.bind (ACE_CString ("20"), 16);
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.bind (ACE_CString ("26"), 17);
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.bind (ACE_CString ("29"), 18);
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.bind (ACE_CString ("50"), 19);
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.bind (ACE_CString ("05"), 20);
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.bind (ACE_CString ("59"), 21);
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.bind (ACE_CString ("65"), 22);
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.bind (ACE_CString ("66"), 23);
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.bind (ACE_CString ("45"), 24);
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.bind (ACE_CString ("34"), 25);
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.bind (ACE_CString ("27"), 26);
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.bind (ACE_CString ("40"), 27);
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.bind (ACE_CString ("30"), 28);
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.bind (ACE_CString ("64"), 29);
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.bind (ACE_CString ("11"), 30);
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.bind (ACE_CString ("16"), 31);
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.bind (ACE_CString ("47"), 32);
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.bind (ACE_CString ("10"), 33);
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.bind (ACE_CString ("37"), 34);
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.bind (ACE_CString ("09"), 35);
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.bind (ACE_CString ("54"), 36);
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.bind (ACE_CString ("23"), 37);
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.bind (ACE_CString ("44"), 38);
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.bind (ACE_CString ("19"), 39);
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.bind (ACE_CString ("00"), 40);
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.bind (ACE_CString ("04"), 41);
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.bind (ACE_CString ("63"), 42);
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.bind (ACE_CString ("08"), 43);
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.bind (ACE_CString ("39"), 44);
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.bind (ACE_CString ("31"), 45);
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.bind (ACE_CString ("02"), 46);
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.bind (ACE_CString ("33"), 47);
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.bind (ACE_CString ("60"), 48);
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.bind (ACE_CString ("61"), 49);
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.bind (ACE_CString ("57"), 50);
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.bind (ACE_CString ("43"), 51);
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.bind (ACE_CString ("46"), 52);
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.bind (ACE_CString ("38"), 53);
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.bind (ACE_CString ("01"), 54);
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.bind (ACE_CString ("12"), 55);
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.bind (ACE_CString ("24"), 56);
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.bind (ACE_CString ("52"), 57);
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.bind (ACE_CString ("07"), 58);
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.bind (ACE_CString ("14"), 59);
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.bind (ACE_CString ("06"), 60);
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.bind (ACE_CString ("58"), 61);
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.bind (ACE_CString ("49"), 62);
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.bind (ACE_CString ("17"), 63);
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.bind (ACE_CString ("53"), 64);
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.bind (ACE_CString ("32"), 65);
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.bind (ACE_CString ("35"), 66);
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.bind (ACE_CString ("41"), 67);
+ ACE_ASSERT (tree.test_invariant () == 0);
+
+ tree.unbind (ACE_CString ("51"));
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.unbind (ACE_CString ("13"));
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.unbind (ACE_CString ("36"));
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.unbind (ACE_CString ("15"));
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.unbind (ACE_CString ("22"));
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.unbind (ACE_CString ("25"));
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.unbind (ACE_CString ("42"));
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.unbind (ACE_CString ("48"));
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.unbind (ACE_CString ("03"));
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.unbind (ACE_CString ("56"));
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.unbind (ACE_CString ("28"));
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.unbind (ACE_CString ("55"));
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.unbind (ACE_CString ("21"));
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.unbind (ACE_CString ("62"));
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.unbind (ACE_CString ("18"));
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.unbind (ACE_CString ("20"));
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.unbind (ACE_CString ("26"));
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.unbind (ACE_CString ("29"));
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.unbind (ACE_CString ("50"));
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.unbind (ACE_CString ("05"));
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.unbind (ACE_CString ("59"));
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.unbind (ACE_CString ("65"));
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.unbind (ACE_CString ("66"));
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.unbind (ACE_CString ("45"));
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.unbind (ACE_CString ("34"));
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.unbind (ACE_CString ("27"));
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.unbind (ACE_CString ("40"));
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.unbind (ACE_CString ("30"));
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.unbind (ACE_CString ("64"));
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.unbind (ACE_CString ("11"));
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.unbind (ACE_CString ("16"));
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.unbind (ACE_CString ("47"));
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.unbind (ACE_CString ("10"));
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.unbind (ACE_CString ("37"));
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.unbind (ACE_CString ("09"));
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.unbind (ACE_CString ("54"));
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.unbind (ACE_CString ("23"));
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.unbind (ACE_CString ("44"));
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.unbind (ACE_CString ("19"));
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.unbind (ACE_CString ("00"));
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.unbind (ACE_CString ("04"));
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.unbind (ACE_CString ("63"));
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.unbind (ACE_CString ("08"));
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.unbind (ACE_CString ("39"));
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.unbind (ACE_CString ("31"));
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.unbind (ACE_CString ("02"));
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.unbind (ACE_CString ("33"));
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.unbind (ACE_CString ("60"));
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.unbind (ACE_CString ("61"));
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.unbind (ACE_CString ("57"));
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.unbind (ACE_CString ("43"));
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.unbind (ACE_CString ("46"));
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.unbind (ACE_CString ("38"));
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.unbind (ACE_CString ("01"));
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.unbind (ACE_CString ("12"));
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.unbind (ACE_CString ("24"));
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.unbind (ACE_CString ("52"));
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.unbind (ACE_CString ("07"));
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.unbind (ACE_CString ("14"));
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.unbind (ACE_CString ("06"));
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.unbind (ACE_CString ("58"));
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.unbind (ACE_CString ("49"));
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.unbind (ACE_CString ("17"));
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.unbind (ACE_CString ("53"));
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.unbind (ACE_CString ("32"));
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.unbind (ACE_CString ("35"));
+ ACE_ASSERT (tree.test_invariant () == 0);
+ tree.unbind (ACE_CString ("41"));
+ ACE_ASSERT (tree.test_invariant () == 0);
+
+// ======== End Stress Test ===================
+
+ ACE_END_TEST;
+ return 0;
+}
+
+// Constructor.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK>
+ACE_RB_Tree_Test<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::ACE_RB_Tree_Test
+ (int entry_count,
+ EXT_ID key_array [],
+ INT_ID item_array [],
+ int order_index [])
+ : stable_fwd_iter_ (stable_tree_),
+ stable_rev_iter_ (stable_tree_),
+ deprecated_fwd_iter_ (deprecated_tree_),
+ deprecated_rev_iter_ (deprecated_tree_),
+ entry_count_ (entry_count),
+ key_array_ (key_array),
+ item_array_ (item_array),
+ order_index_ (order_index)
+{
+}
+
+// Destructor.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK>
+ACE_RB_Tree_Test<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::~ACE_RB_Tree_Test (void)
+{
+}
+
+// Run the interface and iteration tests.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK> void
+ACE_RB_Tree_Test<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::run_test (void)
+{
+ // Run the individual portions of the test, in order.
+
+ test_tree_insertion ();
+ test_post_insertion_iteration ();
+ test_partial_iteration();
+ test_tree_deletion ();
+ test_post_deletion_iteration ();
+}
+
+
+// Tests stable and deprecated insertion interfaces.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK> void
+ACE_RB_Tree_Test<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::test_tree_insertion (void)
+{
+ // Fill in each tree with the key and item from the appropriate
+ // arrays, using the shuffle index to create the appropriate
+ // insertion orders. Then, make sure the inserted item can be found
+ // using the insertion key.
+
+ for (int i = 0; i < entry_count_; ++i)
+ {
+ INT_ID item;
+ int k = order_index_ [i];
+ ACE_ASSERT (k >= 0 && k < entry_count_);
+
+ // Test the new stable ACE_Hash_Map_Manager_Ex compliant interface.
+ ACE_ASSERT (stable_tree_.bind (key_array_ [k],
+ item_array_ [k]) == 0);
+ ACE_ASSERT (stable_tree_.find (key_array_ [k], item) == 0
+ && item == item_array_ [k]);
+
+ // Test the deprecated interface.
+ ACE_ASSERT (deprecated_tree_.insert (key_array_ [k],
+ item_array_ [k]) != 0);
+ ACE_ASSERT (deprecated_tree_.find (key_array_ [k]) != 0
+ && *deprecated_tree_.find (key_array_ [k]) ==
+ item_array_ [k]);
+ }
+}
+
+// Tests forward and reverse iteration after insertion in both trees.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK> void
+ACE_RB_Tree_Test<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::test_post_insertion_iteration (void)
+{
+ // Reset iterators.
+
+ stable_fwd_iter_ = stable_tree_.begin ();
+ stable_rev_iter_ = stable_tree_.rbegin ();
+ deprecated_fwd_iter_ = deprecated_tree_.begin ();
+ deprecated_rev_iter_ = deprecated_tree_.rbegin ();
+
+ // Iterate over each of the trees, making sure their entries are in
+ // the same relative order (i.e., the integers and strings represent
+ // the same values at each respective position in the tree).
+ for (int i = 0; i < entry_count_; ++i)
+ {
+ INT_ID item;
+
+ item = (*stable_fwd_iter_).item ();
+ ACE_ASSERT (item == item_array_ [i]);
+
+ item = (*stable_rev_iter_).item ();
+ ACE_ASSERT (item == item_array_ [entry_count_ - i - 1]);
+
+ item = (*deprecated_fwd_iter_).item ();
+ ACE_ASSERT (item == item_array_ [i]);
+
+ item = (*deprecated_rev_iter_).item ();
+ ACE_ASSERT (item == item_array_ [entry_count_ - i - 1]);
+
+ // Advance each iterator.
+ ++stable_fwd_iter_;
+ ++stable_rev_iter_;
+ ++deprecated_fwd_iter_;
+ ++deprecated_rev_iter_;
+ }
+
+ // Advance each iterator again - should be a no-op.
+ ++stable_fwd_iter_;
+ ++stable_rev_iter_;
+ ++deprecated_fwd_iter_;
+ ++deprecated_rev_iter_;
+
+
+ // Make sure each item in each tree has been visited
+ ACE_ASSERT (stable_fwd_iter_.done () == 1);
+ ACE_ASSERT (stable_rev_iter_.done () == 1);
+ ACE_ASSERT (deprecated_fwd_iter_.done () == 1);
+ ACE_ASSERT (deprecated_rev_iter_.done () == 1);
+
+}
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK> void
+ACE_RB_Tree_Test<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::test_partial_iteration(void)
+{
+ ACE_RB_Tree_Node<EXT_ID, INT_ID> *tree_node = 0;
+
+ stable_tree_.find(key_array_ [2], tree_node);
+ part_rev_iter_ = ACE_RB_Tree_Reverse_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK> (stable_tree_, tree_node);
+ for (int i=2; i >= 0 ; --i)
+ {
+ INT_ID item;
+
+ item = (*part_rev_iter_).item ();
+ ACE_ASSERT (item == item_array_ [i]);
+ part_rev_iter_++;
+ }
+
+ part_fwd_iter_ = ACE_RB_Tree_Iterator<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK> (key_array_ [5], stable_tree_);
+ for (int k = 5; k < entry_count_; ++k)
+ {
+ INT_ID item;
+
+ item = (*part_fwd_iter_).item ();
+ ACE_ASSERT (item == item_array_ [k]);
+ part_fwd_iter_++;
+ }
+}
+
+// Tests stable and deprecated deletion interfaces.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK> void
+ACE_RB_Tree_Test<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::test_tree_deletion (void)
+{
+ // Remove the even numbered entries from each of the trees.
+
+ for (int i = 0; i < entry_count_; i += 2)
+ {
+ // Test the new stable ACE_Hash_Map_Manager_Ex compliant
+ // interface.
+ ACE_ASSERT (stable_tree_.unbind (key_array_ [i]) == 0);
+
+ // Test the deprecated interface.
+ ACE_ASSERT (deprecated_tree_.remove (key_array_ [i]) == 1);
+ }
+}
+
+// Tests forward and reverse iteration after deletions in both trees.
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK> void
+ACE_RB_Tree_Test<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>::test_post_deletion_iteration (void)
+{
+ // Reset iterators
+
+ stable_fwd_iter_ = stable_tree_.begin ();
+ stable_rev_iter_ = stable_tree_.rbegin ();
+ deprecated_fwd_iter_ = deprecated_tree_.begin ();
+ deprecated_rev_iter_ = deprecated_tree_.rbegin ();
+
+ // Iterate over each of the trees, making sure their entries are
+ // still in the same relative order (i.e., the integers and strings
+ // represent the same values at each respective position in the
+ // tree).
+ for (int i = 1; i < entry_count_; i += 2)
+ {
+ INT_ID item;
+
+ item = (*stable_fwd_iter_).item ();
+ ACE_ASSERT (item == item_array_ [i]);
+
+
+ item = (*stable_rev_iter_).item ();
+ ACE_ASSERT (item == item_array_ [entry_count_ - i]);
+
+ item = (*deprecated_fwd_iter_).item ();
+ ACE_ASSERT (item == item_array_ [i]);
+
+ item = (*deprecated_rev_iter_).item ();
+ ACE_ASSERT (item == item_array_ [entry_count_ - i]);
+
+ // Advance each iterator via postfix increment.
+ stable_fwd_iter_++;
+ stable_rev_iter_++;
+ deprecated_fwd_iter_++;
+ deprecated_rev_iter_++;
+ }
+
+ // Make sure each item in each tree has been visited a second time.
+ ACE_ASSERT (stable_fwd_iter_.done () == 1);
+ ACE_ASSERT (stable_rev_iter_.done () == 1);
+ ACE_ASSERT (deprecated_fwd_iter_.done () == 1);
+ ACE_ASSERT (deprecated_rev_iter_.done () == 1);
+}
+
+
diff --git a/ACE/tests/RB_Tree_Test.h b/ACE/tests/RB_Tree_Test.h
new file mode 100644
index 00000000000..4f20674a17f
--- /dev/null
+++ b/ACE/tests/RB_Tree_Test.h
@@ -0,0 +1,112 @@
+/* -*- C++ -*- */
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// RB_Tree_Test.cpp
+//
+// = DESCRIPTION
+// Header file for a test to verify and illustrate the use of the
+// ACE_RB_Tree ACE_RB_Tree_Iterator, and
+// ACE_RB_Tree_Reverse_Iterator classes.
+// iterator over each.
+//
+// = AUTHOR
+// Chris Gill <cdgill@cs.wustl.edu>
+//
+// ============================================================================
+
+template <class EXT_ID, class INT_ID, class COMPARE_KEYS, class ACE_LOCK>
+class ACE_RB_Tree_Test
+{
+ // = TITLE
+ // Implements a templatized test class for the RB_Tree ADT and its
+ // iterators.
+ //
+ // = DESCRIPTION
+
+ // To run the test class on a particular type instantiation of the
+ // RB_Tree, simply instantiate the test class template with the
+ // same type parameters, and invoke the run_test method.
+public:
+ // = Traits
+
+ typedef ACE_RB_Tree<EXT_ID, INT_ID, COMPARE_KEYS, ACE_LOCK>
+ TREE;
+ 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.
+
+ ACE_RB_Tree_Test (int entry_count,
+ EXT_ID key_array [],
+ INT_ID item_array [],
+ int order_index []);
+ // Constructor.
+
+ ~ACE_RB_Tree_Test (void);
+ // Destructor.
+
+ void run_test (void);
+ // Run the individual interface and iteration tests in order.
+
+private:
+
+ void test_tree_insertion (void);
+ // Tests stable and deprecated insertion interfaces.
+
+ void test_post_insertion_iteration (void);
+ // Tests forward and reverse iteration after insertion in both
+ // trees.
+
+ void test_partial_iteration(void);
+ //Tests forward and reverse partial iteration
+
+ void test_tree_deletion (void);
+ // Tests stable and deprecated deletion interfaces.
+
+ void test_post_deletion_iteration (void);
+ // Tests forward and reverse iteration after deletions in both
+ // trees.
+
+ TREE stable_tree_;
+ // Tree for testing stable interface.
+
+ ITERATOR stable_fwd_iter_;
+ // Forward iterator for tree for testing stable interface.
+
+ ITERATOR part_fwd_iter_;
+
+ REVERSE_ITERATOR part_rev_iter_;
+
+ REVERSE_ITERATOR stable_rev_iter_;
+ // Forward iterator for tree for testing stable interface.
+
+ TREE deprecated_tree_;
+ // Tree for testing deprecated interface.
+
+ ITERATOR deprecated_fwd_iter_;
+ // Forward iterator for tree for testing deprecated interface.
+
+ REVERSE_ITERATOR deprecated_rev_iter_;
+ // Forward iterator for tree for testing deprecated interface.
+
+ int entry_count_;
+ // Number of entries in the key, item, and index arrays.
+
+ EXT_ID *key_array_;
+ // Array of EXT_IDs (keys) with which to test.
+
+ INT_ID *item_array_;
+ // Array of INT_IDs (items) with which to test.
+
+ int *order_index_;
+ // Order of indices in the key and item arrays.
+
+};
diff --git a/ACE/tests/README b/ACE/tests/README
new file mode 100644
index 00000000000..17476a3ae5e
--- /dev/null
+++ b/ACE/tests/README
@@ -0,0 +1,82 @@
+$Id$
+
+This directory contains a battery of tests that exercise many
+capabilities of ACE on the numerous platforms upon which it runs. In
+addition to providing an automated regression testing facility, these
+tests also illustrate how to program many of the ACE features. The
+tests can be executed in a single pass via the perl script
+run_test.pl.
+
+By default, all the output from the tests will be stored in separate
+files in the ./log/ (or .\log\) directory. However, you can override
+this by setting the ACE_TEST_DIR environment variable to another
+prefix.
+
+________________________________________
+
+Please follow these directions when adding a new test to
+$ACE_ROOT/tests:
+
+1. Use appropriate ACE_START_TEST and ACE_END_TEST macros in main ()
+
+2. Add new project entry to the tests.mpc file.
+
+3. Add test to Makefile. *
+
+4. Add a new MS project file, e.g., <test>.dsp, then add and entry for
+ it to the tests.dsw file. *
+
+5. Add test to run_test.lst.
+
+* Steps 3 and 4 will go away once the mpc architecture is fully integrated,
+ since the Makefile and project files can be created on-the-fly by mpc.
+________________________________________
+
+
+The tests have been run on a wide range of platforms (e.g., UNIX,
+pSOS, VxWorks, LynxOS, Windows NT/2000/95/98/etc.) and they all work
+with the following exceptions:
+
+1. UPIPE_Test and SPIPE_Test on Windows 95: these tests don't run on
+ Windows 95 since Windows 95 does not support the server side
+ functionality of accepting connections from clients using named pipes.
+
+2. Proactor_Test (to be added) on Windows 95: this test does not run on
+ Windows 95 since Windows 95 does not support I/O completion ports.
+
+3. Of the tests (believed) relevant to the single threaded port to pSOSim,
+ Sigset_Ops_Test, Sock_Connector_Test, Priority_Reactor_Test,
+ Process_Strategy_Test, and Service_Config_Test are still failing.
+ These are being debugged and will either be corrected or, if there
+ are unsupported features in these tests, removed from the test suite for
+ pSOSim.
+
+4. The set of tests for pSOSim will be expanded to include those that require
+ multiple threads, with the release of the multi-threaded port to pSOSim.
+
+Notes:
+
+1. Each test creates a log file and writes it to the ./log/
+ directory. The default log directory can be changed in the test_config.h
+ file.
+
+2. Each log file contains a time stamp of when the test began and also
+ a time stamp indicating when the test ended. If the ending time stamp
+ is missing, you can assume that the test did not succeed.
+
+3. None of the tests require any command line parameters. This is in
+ accordance with the keeping the test-suite a "one-button" test. If
+ any of the tests require any variable parameters these are
+ specified in test_config.h.
+
+4. Time_Service_Test executes the Time Server and Clerk components as
+ two processes and so the executable "main" need to be present in
+ the netsvcs/servers directory. Be sure you build
+ $ACE_ROOT/netsvcs/lib/ and $ACE_ROOT/netsvcs/servers before running
+ this test. These components rely on config files. Two sample
+ config files are also present in the test-suite, namely
+ UNIXserver.conf and UNIXclerk.conf (and for Win32, Win32server.conf
+ and Win32clerk.conf).
+
+If you have any questions/suggestions, please send email to
+ace-users@cs.wustl.edu.
diff --git a/ACE/tests/Reactor_Dispatch_Order_Test.cpp b/ACE/tests/Reactor_Dispatch_Order_Test.cpp
new file mode 100644
index 00000000000..d6263f091d3
--- /dev/null
+++ b/ACE/tests/Reactor_Dispatch_Order_Test.cpp
@@ -0,0 +1,206 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Reactor_Dispatch_Order_Test.cpp
+//
+// = DESCRIPTION
+// This is a simple test that checks the order of dispatching of
+// ACE Reactors. Order should be: timeout, output, and then input.
+//
+// = AUTHOR
+// Irfan Pyarali <irfan@cs.wustl.edu>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/OS_NS_string.h"
+#include "ace/Reactor.h"
+#include "ace/Select_Reactor.h"
+#include "ace/WFMO_Reactor.h"
+#include "ace/Pipe.h"
+#include "ace/ACE.h"
+
+ACE_RCSID(tests, Reactor_Dispatch_Order_Test, "$Id$")
+
+static const char *message =
+"Hello there! Hope you get this message";
+
+class Handler : public ACE_Event_Handler
+{
+public:
+ Handler (ACE_Reactor &reactor);
+
+ ~Handler();
+
+ int handle_timeout (const ACE_Time_Value &tv,
+ const void *arg);
+
+ int handle_input (ACE_HANDLE fd);
+
+ int handle_output (ACE_HANDLE fd);
+
+ // We need to add MSG_OOB data transfer to this test to check the
+ // order of when <handle_exception> gets called. I tried with
+ // Windows 2000 but only one byte of the message came across as
+ // urgent data. The rest of the data was treated as normal! There
+ // was some explanation of Microsoft's TCP/IP deals with out-of-band
+ // data in "Out-of-Band Data and Push Bit in TCP/IP" in the MSDN
+ // library. However, I did not comprehend that well enough. If
+ // someone can make this work, please check the order of
+ // <handle_exception> getting called.
+ // int handle_exception (ACE_HANDLE fd);
+
+ ACE_Pipe pipe_;
+
+ int dispatch_order_;
+};
+
+Handler::Handler (ACE_Reactor &reactor)
+ : ACE_Event_Handler (&reactor),
+ dispatch_order_ (1)
+{
+ // Create the pipe.
+ bool ok = true;
+ if (0 != this->pipe_.open ())
+ {
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("pipe")));
+ ok = false;
+ }
+ else
+ {
+ // Register for all events.
+ if (0 != this->reactor ()->register_handler
+ (this->pipe_.read_handle (),
+ this,
+ ACE_Event_Handler::ALL_EVENTS_MASK))
+ {
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("register")));
+ ok = false;
+ }
+ }
+ ACE_ASSERT (ok);
+}
+
+Handler::~Handler (void)
+{
+ this->pipe_.close ();
+}
+
+int
+Handler::handle_timeout (const ACE_Time_Value &,
+ const void *)
+{
+ int me = this->dispatch_order_++;
+ if (me != 1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("handle_timeout should be #1; it's %d\n"),
+ me));
+ else
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Handler::handle_timeout\n")));
+
+ return 0;
+}
+
+int
+Handler::handle_output (ACE_HANDLE)
+{
+ int me = this->dispatch_order_++;
+ if (me != 2)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("handle_output should be #2; it's %d\n"),
+ me));
+ else
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Handler::handle_output\n")));
+
+#if defined (__OpenBSD__) || defined (ACE_VXWORKS) || defined (__Lynx__)
+ // All that we need written has been written, so don't
+ // call handle_output again.
+ this->reactor ()->mask_ops (this->pipe_.read_handle (),
+ ACE_Event_Handler::WRITE_MASK,
+ ACE_Reactor::CLR_MASK);
+#endif /* __OpenBSD__ || ACE_VXWORKS || __Lynx__ */
+
+ return 0;
+}
+
+int
+Handler::handle_input (ACE_HANDLE fd)
+{
+ int me = this->dispatch_order_++;
+ if (me != 3)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("handle_timeout should be #3; it's %d\n"),
+ me));
+
+ char buffer[BUFSIZ];
+ ssize_t result = ACE::recv (fd, buffer, sizeof buffer);
+
+ ACE_ASSERT (result == ssize_t (ACE_OS::strlen (message)));
+ buffer[result] = '\0';
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Handler::handle_input: %C\n"), buffer));
+
+ ACE_ASSERT (ACE_OS::strcmp (buffer,
+ message) == 0);
+
+ this->reactor ()->end_reactor_event_loop ();
+
+ return 0;
+}
+
+static void
+test_reactor_dispatch_order (ACE_Reactor &reactor)
+{
+ Handler handler (reactor);
+
+ // This should trigger a call to <handle_input>.
+ ssize_t result =
+ ACE::send_n (handler.pipe_.write_handle (),
+ message,
+ ACE_OS::strlen (message));
+ ACE_ASSERT (result == ssize_t (ACE_OS::strlen (message)));
+
+ // This should trigger a call to <handle_timeout>.
+ long retn =
+ reactor.schedule_timer (&handler,
+ 0,
+ ACE_Time_Value (0));
+ ACE_ASSERT (retn != -1);
+
+ reactor.run_reactor_event_loop ();
+
+ result =
+ reactor.remove_handler (handler.pipe_.read_handle (),
+ ACE_Event_Handler::ALL_EVENTS_MASK |
+ ACE_Event_Handler::DONT_CALL);
+ ACE_ASSERT (result == 0);
+}
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("Reactor_Dispatch_Order_Test"));
+
+ ACE_Select_Reactor select_reactor_impl;
+ ACE_Reactor select_reactor (&select_reactor_impl);
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Testing ACE_Select_Reactor\n")));
+ test_reactor_dispatch_order (select_reactor);
+
+ // WinCE can't do the necessary Winsock 2 things for WFMO_Reactor.
+#if defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)
+
+ ACE_WFMO_Reactor wfmo_reactor_impl;
+ ACE_Reactor wfmo_reactor (&wfmo_reactor_impl);
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Testing ACE_WFMO_Reactor\n")));
+ test_reactor_dispatch_order (wfmo_reactor);
+
+#endif /* ACE_WIN32 && !ACE_HAS_WINCE */
+
+ ACE_END_TEST;
+ return 0;
+}
diff --git a/ACE/tests/Reactor_Exceptions_Test.cpp b/ACE/tests/Reactor_Exceptions_Test.cpp
new file mode 100644
index 00000000000..ad39ee0cf09
--- /dev/null
+++ b/ACE/tests/Reactor_Exceptions_Test.cpp
@@ -0,0 +1,228 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Reactor_Exceptions_Test.cpp
+//
+// = DESCRIPTION
+// This is a test that makes sure the <ACE_Reactor> works
+// correctly in the face of C++ exceptions and threads.
+//
+// = AUTHOR
+// Luca Priorelli <lucapri@mbox.vol.it> and Douglas C. Schmidt <schmidt@cs.wustl.edu>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/Reactor.h"
+#include "ace/SOCK_Dgram.h"
+#include "ace/INET_Addr.h"
+#include "ace/Thread_Manager.h"
+
+ACE_RCSID(tests, Reactor_Exceptions_Test, "$Id$")
+
+#if defined (ACE_HAS_EXCEPTIONS)
+
+#if defined (ACE_WIN32) && defined (ACE_HAS_WIN32_STRUCTURAL_EXCEPTIONS)
+static void
+throw_exception (void)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) throw exception\n")));
+
+ // Cause a Win32 structured exception.
+ *(char *) 0 = 0;
+}
+#else
+// Just need a simple exception class.
+class Except {};
+
+static void
+throw_exception (void)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) throw exception\n")));
+ throw Except ();
+}
+#endif /* ACE_WIN32 && ACE_HAS_WIN32_STRUCTURAL_EXCEPTIONS */
+
+class My_Handler : public ACE_Event_Handler, public ACE_SOCK_Dgram
+{
+public:
+ My_Handler (const ACE_INET_Addr &local_addr);
+
+ virtual ACE_HANDLE get_handle (void) const;
+ virtual int handle_input (ACE_HANDLE handle);
+};
+
+My_Handler::My_Handler (const ACE_INET_Addr &local_addr)
+ : ACE_SOCK_Dgram (local_addr)
+{
+}
+
+ACE_HANDLE
+My_Handler::get_handle (void) const
+{
+ return ACE_SOCK_Dgram::get_handle ();
+}
+
+int
+My_Handler::handle_input (ACE_HANDLE)
+{
+ ACE_TCHAR buf[BUFSIZ];
+ ACE_INET_Addr from_addr;
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Activity occurred on handle %d!\n"),
+ ACE_SOCK_Dgram::get_handle ()));
+
+ ssize_t n = ACE_SOCK_Dgram::recv (buf,
+ sizeof buf,
+ from_addr);
+ if (n == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("handle_input")));
+ else
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("got buf = %s\n"),
+ buf));
+
+ throw_exception ();
+ return 0;
+}
+
+class My_Reactor : public ACE_Reactor
+{
+public:
+ virtual int handle_events (ACE_Time_Value *max_wait_time)
+ {
+ int ret = 0;
+
+ try
+ {
+# if defined (ACE_WIN32) && defined (__BORLANDC__)
+ // BCB does not catch structured exceptions with catch (...).
+ // Actually, the ANSI spec says that system exceptions are not
+ // supposed to be caught with catch. Borland may add this, and
+ // make it "switchable" in the future...
+ try
+ {
+# endif /* defined (ACE_WIN32 && __BORLANDC__) */
+
+ ret = ACE_Reactor::handle_events (max_wait_time);
+
+# if defined (ACE_WIN32) && defined (__BORLANDC__)
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ // Probably should handle the details of the exception
+ // and throw something that represents the structured exception
+ throw "Win32 Structured Exception";
+ }
+# endif /* defined (ACE_WIN32 &&__BORLANDC__) */
+ }
+ catch (...)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT (" (%t) catch exception\n")));
+ ret = -1;
+ // do your thing, etc.
+ }
+ return ret;
+ }
+
+ virtual int handle_events (ACE_Time_Value &max_wait_time)
+ {
+ return this->handle_events (&max_wait_time);
+ }
+};
+
+#if defined (ACE_HAS_THREADS)
+static int
+worker (void)
+{
+ ACE_Reactor::instance ()->owner (ACE_OS::thr_self ());
+
+ for (;;)
+ if (ACE_Reactor::instance ()->handle_events () == -1)
+ {
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT (" (%t) exception return\n")));
+ break;
+ }
+
+ return 0;
+}
+#endif /* ACE_HAS_THREADS */
+
+#endif /* ACE_HAS_EXCEPTIONS */
+
+int
+run_main (int argc, ACE_TCHAR *argv[])
+{
+ ACE_START_TEST (ACE_TEXT ("Reactor_Exceptions_Test"));
+
+#if defined (ACE_HAS_EXCEPTIONS)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Starting tracing\n")));
+
+ u_short port = argc > 1 ? ACE_OS::atoi (argv[1]) : ACE_DEFAULT_SERVER_PORT;
+
+ ACE_INET_Addr local_addr (port);
+ ACE_INET_Addr remote_addr (port, ACE_LOCALHOST, PF_INET);
+ My_Reactor reactor;
+
+ ACE_Reactor::instance (&reactor);
+ ACE_Thread_Manager *thr_mgr = ACE_Thread_Manager::instance ();
+
+ {
+ // Make sure handler gets cleaned up before reactor by putting it in its
+ // own scope
+ My_Handler handler (local_addr);
+
+
+ if (ACE_Reactor::instance ()->register_handler
+ (&handler,
+ ACE_Event_Handler::READ_MASK) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("register_handler")),
+ -1);
+
+#if defined (ACE_HAS_THREADS)
+ thr_mgr->spawn (ACE_THR_FUNC (worker));
+#else
+ // Need to figure out how to implement this test.
+ ACE_ERROR ((LM_INFO,
+ ACE_TEXT ("threads not supported on this platform\n")));
+#endif /* ACE_HAS_THREADS */
+
+ ACE_SOCK_Dgram dgram (ACE_sap_any_cast (ACE_INET_Addr &), PF_INET);
+
+ for (size_t i = 0; i < ACE_MAX_ITERATIONS; i++)
+ dgram.send (ACE_TEXT ("Hello"),
+ sizeof (ACE_TEXT ("Hello")),
+ remote_addr);
+ // Barrier to wait for the other thread to return.
+ thr_mgr->wait ();
+
+ handler.close ();
+ dgram.close ();
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT (" (%t) exiting main\n")));
+#else
+ ACE_UNUSED_ARG (argc);
+ ACE_UNUSED_ARG (argv);
+ ACE_ERROR ((LM_INFO,
+ ACE_TEXT ("C++ exception support not enabled on this platform\n")));
+#endif /* ACE_HAS_EXCEPTIONS */
+
+ ACE_END_TEST;
+ return 0;
+}
diff --git a/ACE/tests/Reactor_Notification_Queue_Test.cpp b/ACE/tests/Reactor_Notification_Queue_Test.cpp
new file mode 100644
index 00000000000..26dfb59e426
--- /dev/null
+++ b/ACE/tests/Reactor_Notification_Queue_Test.cpp
@@ -0,0 +1,223 @@
+/**
+ * @file Reactor_Notification_Queue_Test.cpp
+ *
+ * $Id$
+ *
+ * Verify that the notification queue can be used with large numbers
+ * of events.
+ *
+ * Normally the ACE_Reactor uses a pipe to implement the notify()
+ * methods. ACE can be compiled with
+ * ACE_HAS_REACTOR_NOTIFICATION_QUEUE, with this configuration flag
+ * the Reactor uses a user-space queue to contain the notifications.
+ * A single message is sent through the pipe to indicate "pipe not
+ * empty."
+ *
+ * @author Carlos O'Ryan <coryan@atdesk.com>
+ *
+ */
+
+#include "test_config.h"
+#include "ace/Reactor.h"
+#include "ace/TP_Reactor.h"
+#include "ace/Select_Reactor.h"
+#include "ace/WFMO_Reactor.h"
+
+ACE_RCSID(tests,
+ Reactor_Notification_Queue_Test, "$Id$")
+
+class Event_Handler : public ACE_Event_Handler
+{
+public:
+ Event_Handler(ACE_Reactor * reactor,
+ int max_notifications,
+ char const *test_name);
+
+ /// Run the test
+ void run(void);
+
+ /// Receive the notifications.
+ virtual int handle_exception(ACE_HANDLE);
+
+private:
+ /**
+ * @brief Implement a single iteration.
+ *
+ * Each iteration of the test consists of sending multiple
+ * notifications simultaneously.
+ */
+ void send_notifications (void);
+
+ /**
+ * @brief Return true if the test is finished.
+ */
+ bool done (void) const;
+
+private:
+ /**
+ * @brief The maximum number of notifications in any single
+ * iteration.
+ */
+ int max_notifications_;
+
+ /**
+ * @brief The name of the test
+ */
+ char const * test_name_;
+ /**
+ * @brief Number of notifications received
+ */
+ int notifications_sent_;
+ /**
+ * @brief Number of notifications sent
+ */
+ int notifications_recv_;
+
+ /**
+ * @brief Number of notifications sent on each iteration
+ */
+ int notifications_curr_;
+};
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("Reactor_Notification_Queue_Test"));
+
+#if !defined(ACE_HAS_REACTOR_NOTIFICATION_QUEUE)
+ ACE_DEBUG ((LM_INFO,
+ ACE_TEXT ("Notification queue disabled, ")
+ ACE_TEXT ("small test version, ")
+ ACE_TEXT ("which is of no practical use\n")));
+
+ int max_notifications = 16;
+#else
+ int max_notifications = 1024 * 1024;
+#endif /* ACE_HAS_THREADS */
+
+ {
+ ACE_Reactor select_reactor (
+ new ACE_Select_Reactor,
+ 1);
+
+ Event_Handler handler(&select_reactor,
+ max_notifications,
+ "Select_Reactor");
+
+ handler.run ();
+ }
+
+ {
+ ACE_Reactor tp_reactor (new ACE_TP_Reactor,
+ 1);
+ Event_Handler handler(&tp_reactor,
+ max_notifications,
+ "TP_Reactor");
+ handler.run();
+ }
+
+#if 0
+ /// @@todo: Need to talk to Irfan to see how the WFMO handles this.
+#if defined (ACE_WIN32)
+ {
+ ACE_Reactor wfmo_reactor (new ACE_WFMO_Reactor,
+ 1);
+
+ Event_Handler handler(&wfmo_reactor,
+ max_notifications,
+ "WFMO_Reactor");
+ handler.run();
+ }
+#endif /*ACE_WIN32*/
+#endif /*if 0 */
+ ACE_END_TEST;
+ return 0;
+}
+
+Event_Handler::Event_Handler (
+ ACE_Reactor * reactor,
+ int max_notifications,
+ char const * test_name)
+ : ACE_Event_Handler(reactor)
+ , max_notifications_(max_notifications)
+ , test_name_(test_name)
+ , notifications_sent_(0)
+ , notifications_recv_(0)
+ , notifications_curr_(1)
+{
+}
+
+void
+Event_Handler::run (void)
+{
+ send_notifications ();
+
+ // Run for 30 seconds or until the test is done.
+ for(int i = 0; i != 30 && !done(); ++i)
+ {
+ ACE_Time_Value tv (1,0);
+ reactor ()->run_reactor_event_loop(tv);
+ }
+
+ if(!done())
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Test %s failed due to timeout ")
+ ACE_TEXT (" sent=%d,recv=%d \n"),
+ test_name_,
+ notifications_sent_,
+ notifications_recv_));
+ }
+ else
+ {
+ ACE_DEBUG ((LM_INFO,
+ ACE_TEXT ("Test %s passed sent=%d, recv=%d\n"),
+ test_name_,
+ notifications_sent_,
+ notifications_recv_));
+ }
+}
+
+int
+Event_Handler::handle_exception (ACE_HANDLE)
+{
+ ++notifications_recv_;
+ if(notifications_recv_ == notifications_sent_)
+ {
+ if(notifications_curr_ >= max_notifications_)
+ {
+
+ return 0;
+ }
+ send_notifications();
+ }
+ return 0;
+}
+
+void
+Event_Handler::send_notifications (void)
+{
+ for (int i = 0; i != notifications_curr_; ++i)
+ {
+ if(reactor()->notify (this) == -1)
+ {
+ ACE_ERROR((LM_ERROR,
+ ACE_TEXT ("Cannot send notifications in %s test (%d/%d)\n"),
+ test_name_, i, notifications_curr_));
+ return;
+ }
+
+ ++notifications_sent_;
+ }
+ // ACE_ERROR((LM_ERROR,
+ // "Started iteration with %d notify() calls in test %s\n",
+ // notifications_curr_, test_name_));
+ notifications_curr_ *= 2;
+}
+
+bool
+Event_Handler::done (void) const
+{
+ return (notifications_curr_ >= max_notifications_)
+ && (notifications_sent_ == notifications_recv_);
+}
diff --git a/ACE/tests/Reactor_Notify_Test.cpp b/ACE/tests/Reactor_Notify_Test.cpp
new file mode 100644
index 00000000000..a24bf4770a8
--- /dev/null
+++ b/ACE/tests/Reactor_Notify_Test.cpp
@@ -0,0 +1,493 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Reactor_Notify_Test.cpp
+//
+// = DESCRIPTION
+// This is a test that illustrates how the <ACE_Reactor>'s
+// <notify> method works under various <max_notify_iterations>
+// settings. It also tests that the <disable_notify_pipe> option
+// works correctly. Moreover, if the $ACE_ROOT/ace/config.h file
+// has the ACE_HAS_REACTOR_NOTIFICATION_QUEUE option enabled this
+// test will also exercise this feature.
+//
+// = AUTHOR
+// Douglas C. Schmidt <schmidt@cs.wustl.edu>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/OS_NS_unistd.h"
+#include "ace/Synch_Traits.h"
+#include "ace/Task.h"
+#include "ace/Pipe.h"
+#include "ace/Auto_Ptr.h"
+#include "ace/Reactor.h"
+#include "ace/Select_Reactor.h"
+#include "ace/Thread_Semaphore.h"
+
+ACE_RCSID(tests, Reactor_Notify_Test, "$Id$")
+
+#if defined (ACE_HAS_THREADS)
+
+static const int LONG_TIMEOUT = 10;
+static const int SHORT_TIMEOUT = 2;
+
+class Supplier_Task : public ACE_Task<ACE_MT_SYNCH>
+{
+public:
+ Supplier_Task (int disable_notify_pipe,
+ const ACE_Time_Value &tv);
+ // Constructor.
+
+ ~Supplier_Task (void);
+ // Destructor.
+
+ virtual int open (void * = 0);
+ // Make this an Active Object.
+
+ virtual int close (u_long);
+ // Close down the supplier.
+
+ virtual int svc (void);
+ // Generates events and sends them to the <Reactor>'s <notify>
+ // method.
+
+ virtual int handle_exception (ACE_HANDLE);
+ // Releases the <waiter_> semaphore when called by the <Reactor>'s
+ // notify handler.
+
+ virtual int handle_output (ACE_HANDLE);
+ // Called every time through the main <ACE_Reactor> event loop to
+ // illustrate the difference between "limited" and "unlimited"
+ // notification.
+
+ void release (void);
+ // Release the <waiter_>.
+
+private:
+ int perform_notifications (int notifications);
+ // Perform the notifications.
+
+ ACE_Thread_Semaphore waiter_;
+ // Used to hand-shake between the <Supplier_Task> and the
+ // <Reactor>'s notify mechanism.
+
+ ACE_Pipe pipe_;
+ // We use this pipe just to get a handle that is always "active,"
+ // i.e., the <ACE_Reactor> will always dispatch its <handle_output>
+ // method.
+
+ int disable_notify_pipe_;
+ // Keeps track of whether the notification pipe in the <ACE_Reactor>
+ // has been diabled or not.
+
+ int long_timeout_;
+ // Keeps track of whether we're running with a <LONG_TIMEOUT>, which
+ // is used for the ACE_HAS_REACTOR_NOTIFICATION_QUEUE portion of
+ // this test.
+};
+
+void
+Supplier_Task::release (void)
+{
+ this->waiter_.release ();
+}
+
+Supplier_Task::Supplier_Task (int disable_notify_pipe,
+ const ACE_Time_Value &tv)
+ : waiter_ ((unsigned int) 0), // Make semaphore "locked" by default.
+ disable_notify_pipe_ (disable_notify_pipe),
+ long_timeout_ (tv.sec () == LONG_TIMEOUT)
+{
+}
+
+int
+Supplier_Task::open (void *)
+{
+ // Create the pipe.
+ int result;
+
+ result = this->pipe_.open ();
+ ACE_ASSERT (result != -1);
+
+ // Register the pipe's write handle with the <Reactor> for writing.
+ // This should mean that it's always "active."
+ if (long_timeout_ == 0)
+ {
+ result = ACE_Reactor::instance ()->register_handler
+ (this->pipe_.write_handle (),
+ this,
+ ACE_Event_Handler::WRITE_MASK);
+ ACE_ASSERT (result != -1);
+ }
+
+ // Make this an Active Object.
+ result = this->activate (THR_BOUND | THR_DETACHED);
+ ACE_ASSERT (result != -1);
+ return 0;
+}
+
+int
+Supplier_Task::close (u_long)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Supplier_Task::close\n")));
+
+ int result;
+
+ if (long_timeout_ == 0)
+ {
+ result = ACE_Reactor::instance ()->remove_handler
+ (this->pipe_.write_handle (),
+ ACE_Event_Handler::WRITE_MASK);
+ ACE_ASSERT (result != -1);
+ }
+ else
+ {
+ // Wait to be told to shutdown by the main thread.
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) waiting to be shutdown by main thread\n")));
+ result = this->waiter_.acquire ();
+ ACE_ASSERT (result != -1);
+ }
+ return 0;
+}
+
+Supplier_Task::~Supplier_Task (void)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) ~Supplier_Task\n")));
+ this->pipe_.close ();
+}
+
+int
+Supplier_Task::perform_notifications (int notifications)
+{
+ ACE_Reactor::instance ()->max_notify_iterations (notifications);
+
+ size_t iterations = ACE_MAX_ITERATIONS;
+
+ if (this->long_timeout_)
+ {
+ iterations *= (iterations * iterations * 2);
+#if defined (ACE_VXWORKS)
+ // scale down otherwise the test won'y finish in time
+ iterations /= 4;
+#endif
+ }
+
+ for (size_t i = 0; i < iterations; i++)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) notifying reactor on iteration %d\n"),
+ i));
+
+ int result;
+
+ // Notify the Reactor, which will call <handle_exception>.
+ result = ACE_Reactor::instance ()->notify (this);
+ if (result == -1)
+ {
+ if (errno == ETIME)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) %p\n"),
+ ACE_TEXT ("notify")));
+ else
+ ACE_ASSERT (result != -1);
+ }
+
+ // Wait for our <handle_exception> method to release the
+ // semaphore.
+ if (this->long_timeout_ == 0
+ && this->disable_notify_pipe_ == 0)
+ {
+ result = this->waiter_.acquire ();
+ ACE_ASSERT (result != -1);
+ }
+ }
+
+ return 0;
+}
+
+int
+Supplier_Task::svc (void)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) **** starting unlimited notifications test\n")));
+
+ // Allow an unlimited number of iterations per
+ // <ACE_Reactor::notify>.
+ this->perform_notifications (-1);
+
+ if (this->long_timeout_ == 0)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) **** starting limited notifications test\n")));
+
+ // Only allow 1 iteration per <ACE_Reactor::notify>
+ this->perform_notifications (1);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) **** exiting thread test\n")));
+ }
+ return 0;
+}
+
+int
+Supplier_Task::handle_exception (ACE_HANDLE handle)
+{
+ ACE_ASSERT (handle == ACE_INVALID_HANDLE);
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) handle_exception\n")));
+
+ this->waiter_.release ();
+ return 0;
+}
+
+int
+Supplier_Task::handle_output (ACE_HANDLE handle)
+{
+ ACE_ASSERT (handle == this->pipe_.write_handle ());
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) handle_output\n")));
+
+ // This function is called by the main thread, believe it or not :-)
+ // That's because the pipe's write handle is always active. Thus,
+ // we can give the <Supplier_Task> a chance to run in its own
+ // thread.
+ ACE_OS::thr_yield ();
+
+ return 0;
+}
+
+static int
+run_test (int disable_notify_pipe,
+ const ACE_Time_Value &tv)
+{
+ // Create special reactors with the appropriate flags enabled.
+
+ ACE_Select_Reactor *reactor_impl = 0;
+ if (disable_notify_pipe)
+ ACE_NEW_RETURN (reactor_impl,
+ ACE_Select_Reactor (0, 0, 1),
+ -1);
+ else
+ ACE_NEW_RETURN (reactor_impl,
+ ACE_Select_Reactor,
+ -1);
+
+ ACE_Reactor *reactor;
+ ACE_NEW_RETURN (reactor,
+ ACE_Reactor (reactor_impl, 1), // Delete implementation
+ -1);
+
+ // Make sure this stuff gets cleaned up when this function exits.
+ auto_ptr<ACE_Reactor> r (reactor);
+
+ // Set the Singleton Reactor.
+ ACE_Reactor *orig_reactor = ACE_Reactor::instance (reactor);
+ ACE_ASSERT (ACE_LOG_MSG->op_status () != -1);
+ ACE_ASSERT (ACE_Reactor::instance () == reactor);
+
+ Supplier_Task task (disable_notify_pipe,
+ tv);
+ ACE_ASSERT (ACE_LOG_MSG->op_status () != -1);
+
+ int result;
+
+ result = task.open ();
+ ACE_ASSERT (result != -1);
+
+ if (tv.sec () == LONG_TIMEOUT)
+ // Sleep for a while so that the <ACE_Reactor>'s notification
+ // buffers will fill up!
+ ACE_OS::sleep (tv);
+
+ int shutdown = 0;
+
+ // Run the event loop that handles the <handle_output> and
+ // <handle_exception> notifications.
+ for (int iteration = 1;
+ shutdown == 0;
+ iteration++)
+ {
+ ACE_Time_Value timeout (tv);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) starting handle_events() on iteration %d")
+ ACE_TEXT (" with time-out = %d seconds\n"),
+ iteration,
+ timeout.sec ()));
+
+ // Use a timeout to inform the Reactor when to shutdown.
+ switch (ACE_Reactor::instance ()->handle_events (timeout))
+ {
+ case -1:
+ if (! disable_notify_pipe)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%t) %p\n"),
+ ACE_TEXT ("reactor")));
+ shutdown = 1;
+ break;
+ /* NOTREACHED */
+ case 0:
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) handle_events timed out\n")));
+ shutdown = 1;
+ break;
+ /* NOTREACHED */
+ default:
+ break;
+ /* NOTREACHED */
+ }
+ }
+
+ if (tv.sec () == LONG_TIMEOUT)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) releasing supplier task thread\n")));
+ task.release ();
+ }
+ ACE_Reactor::instance (orig_reactor);
+ return 0;
+}
+
+#endif /* ACE_HAS_THREADS */
+
+class Purged_Notify : public ACE_Event_Handler
+{
+ // = TITLE
+ // <run_notify_purge_test> tests the reactor's
+ // purge_pending_notifications function. It does 2 notifications,
+ // and explicitly cancels one, and deletes the other's event
+ // handler, which should cause it to be cancelled as well.
+
+ virtual int handle_exception (ACE_HANDLE = ACE_INVALID_HANDLE)
+ {
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("Got a notify that should have been purged!\n")),
+ 0);
+ }
+};
+
+static int
+run_notify_purge_test (void)
+{
+ int status;
+ ACE_Reactor *r = ACE_Reactor::instance ();
+ {
+ Purged_Notify n1;
+ Purged_Notify *n2;
+
+ ACE_NEW_RETURN (n2, Purged_Notify, -1);
+ auto_ptr<Purged_Notify> ap (n2);
+
+ // First test:
+ // Notify EXCEPT, and purge ALL
+ r->notify (&n1); // the mask is EXCEPT_MASK
+
+ status = r->purge_pending_notifications (&n1);
+ if (status == -1 && errno == ENOTSUP)
+ return 0; // Select Reactor w/o ACE_HAS_REACTOR_NOTIFICATION_QUEUE
+ if (status != 1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Purged %d notifies; expected 1\n"),
+ status));
+ // Second test:
+ // Notify READ twice, and WRITE once, and purge READ and WRITE - should purge 3 times.
+ r->notify (&n1, ACE_Event_Handler::READ_MASK);
+ r->notify (&n1, ACE_Event_Handler::READ_MASK);
+ r->notify (&n1, ACE_Event_Handler::WRITE_MASK);
+ status = r->purge_pending_notifications
+ (&n1, ACE_Event_Handler::READ_MASK | ACE_Event_Handler::WRITE_MASK);
+ if (status != 3)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Purged %d notifies; expected 3\n"),
+ status));
+ // Third test:
+ // Notify READ on 2 handlers, and purge READ|WRITE on all handlers. Should purge 2
+ r->notify (&n1, ACE_Event_Handler::READ_MASK);
+ r->notify (n2, ACE_Event_Handler::READ_MASK);
+ status = r->purge_pending_notifications
+ (0, ACE_Event_Handler::READ_MASK | ACE_Event_Handler::WRITE_MASK);
+ if (status != 2)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Purged %d notifies; expected 2\n"),
+ status));
+ // Forth test:
+ // Notify EXCEPT and WRITE, purge READ. Should not purge
+ r->notify (&n1); // the mask is EXCEPT_MASK
+ r->notify (&n1, ACE_Event_Handler::WRITE_MASK);
+ status = r->purge_pending_notifications
+ (&n1, ACE_Event_Handler::READ_MASK);
+ if (status != 0)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Purged %d notifies; expected 0\n"),
+ status));
+ // Fifth test:
+ r->notify (n2);
+ // <ap> destructor should cause n2's notify to be cancelled.
+ }
+
+ ACE_Time_Value t (1);
+ status = r->handle_events (t); // Should be nothing to do, and time out
+ return status < 0 ? 1 : 0; // Return 0 for all ok, else error
+}
+
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("Reactor_Notify_Test"));
+
+ // To automatically delete the ACE_Reactor instance at program
+ // termination:
+ auto_ptr<ACE_Reactor> r (ACE_Reactor::instance ());
+
+ int test_result = 0; // Innocent until proven guilty
+
+ test_result = run_notify_purge_test ();
+ if (test_result == 0)
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("purge_pending_notifications test OK\n")));
+ else
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("purge_pending_notifications test FAIL\n")));
+
+#if defined (ACE_HAS_THREADS)
+ ACE_Time_Value timeout (SHORT_TIMEOUT);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) running tests with notify pipe enabled")
+ ACE_TEXT (" and time-out = %d seconds\n"),
+ timeout.sec ()));
+ run_test (0, timeout);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) running tests with notify pipe disabled")
+ ACE_TEXT (" and time-out = %d seconds\n"),
+ timeout.sec ()));
+ run_test (1, timeout);
+
+ timeout.set (LONG_TIMEOUT, 0);
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) running tests with reactor notification ")
+ ACE_TEXT ("pipe enabled\n")
+ ACE_TEXT (" and time-out = %d seconds\n"),
+ timeout.sec ()));
+ run_test (0, timeout);
+
+#else
+ ACE_ERROR ((LM_INFO,
+ ACE_TEXT ("threads not supported on this platform\n")));
+#endif /* ACE_HAS_THREADS */
+ ACE_END_TEST;
+ return test_result;
+}
+
diff --git a/ACE/tests/Reactor_Performance_Test.cpp b/ACE/tests/Reactor_Performance_Test.cpp
new file mode 100644
index 00000000000..7d5aacc6456
--- /dev/null
+++ b/ACE/tests/Reactor_Performance_Test.cpp
@@ -0,0 +1,418 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Reactor_Performance_Test.cpp
+//
+// = DESCRIPTION
+// This test is used to time the dispatching mechanisms of the
+// <ACE_Reactor>s. Both the <ACE_WFMO_Reactor> and
+// <ACE_Select_Reactor> can be tested.
+//
+// = AUTHOR
+// Irfan Pyarali <irfan@cs.wustl.edu>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "Reactor_Performance_Test.h"
+#include "ace/Profile_Timer.h"
+#include "ace/Get_Opt.h"
+#include "ace/SOCK_Connector.h"
+#include "ace/SOCK_Acceptor.h"
+#include "ace/Acceptor.h"
+#include "ace/Connector.h"
+#include "ace/Reactor.h"
+#include "ace/WFMO_Reactor.h"
+#include "ace/Select_Reactor.h"
+#include "ace/Auto_Ptr.h"
+
+ACE_RCSID(tests, Reactor_Performance_Test, "$Id$")
+
+#if defined (ACE_HAS_THREADS)
+
+static const char ACE_ALPHABET[] = "abcdefghijklmnopqrstuvwxyz";
+
+// Number of client (user) threads
+static int opt_nconnections = 5;
+
+// Number of data exchanges
+static int opt_nloops = 200;
+
+// Use the WFMO_Reactor
+static int opt_wfmo_reactor = 0;
+
+// Use the Select_Reactor
+static int opt_select_reactor = 0;
+
+// Extra debug messages
+static int opt_debug = 0;
+
+int Read_Handler::waiting_ = 0;
+
+void
+Read_Handler::set_countdown (int nconnections)
+{
+ Read_Handler::waiting_ = nconnections;
+}
+
+// Initialize the Svc_Handler
+int
+Read_Handler::open (void *)
+{
+ if (this->peer ().enable (ACE_NONBLOCK) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%t) Read_Handler::open, cannot set non blocking mode\n")),
+ -1);
+
+ if (reactor ()->register_handler (this, READ_MASK) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%t) Read_Handler::open, cannot register handler\n")),
+ -1);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) created svc_handler for handle %d\n"),
+ get_handle ()));
+ return 0;
+}
+
+// Handle incoming data
+int
+Read_Handler::handle_input (ACE_HANDLE handle)
+{
+ ACE_UNUSED_ARG (handle);
+ char buf[BUFSIZ];
+
+ while (1)
+ {
+ ssize_t result = this->peer ().recv (buf, sizeof (buf) - 1);
+
+ if (result > 0)
+ {
+ if (opt_debug)
+ {
+ buf[result] = 0;
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Read_Handler::handle_input: %s\n"),
+ buf));
+ }
+ }
+ else if (result < 0)
+ {
+ if (errno == EWOULDBLOCK)
+ return 0;
+ else
+ {
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("handle_input: %p (errno: %d)\n"),
+ ACE_TEXT ("recv"), errno));
+
+ // This will cause handle_close to get called.
+ return -1;
+ }
+ }
+ else // result == 0
+ {
+ // This will cause handle_close to get called.
+ return -1;
+ }
+ }
+
+ ACE_NOTREACHED (return 0);
+}
+
+// Handle connection shutdown.
+
+int
+Read_Handler::handle_close (ACE_HANDLE handle,
+ ACE_Reactor_Mask close_mask)
+{
+ ACE_UNUSED_ARG (handle);
+ ACE_UNUSED_ARG (close_mask);
+
+ // Reduce count.
+ waiting_--;
+
+ // If no connections are open.
+ if (waiting_ == 0)
+ ACE_Reactor::instance ()->end_reactor_event_loop ();
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Read_Handler::handle_close closing down\n")));
+
+ // Shutdown
+ this->destroy ();
+ return 0;
+}
+
+int
+Write_Handler::open (void *)
+{
+ return 0;
+}
+
+int
+Write_Handler::send_data (void)
+{
+ int send_size = sizeof (ACE_ALPHABET) - 1;
+
+ if (this->peer ().send_n (ACE_ALPHABET,
+ send_size) != send_size)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%t) %p\n"),
+ ACE_TEXT ("send_n")),
+ -1);
+ return 0;
+}
+
+// Connection factories
+typedef ACE_Connector<Write_Handler, ACE_SOCK_CONNECTOR> CONNECTOR;
+typedef ACE_Acceptor<Read_Handler, ACE_SOCK_ACCEPTOR> ACCEPTOR;
+
+// Execute the client tests.
+void *
+client (void *arg)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) running client\n")));
+
+ ACE_INET_Addr *connection_addr =
+ reinterpret_cast<ACE_INET_Addr *> (arg);
+ CONNECTOR connector;
+
+ int i;
+
+ // Automagic memory cleanup.
+ Write_Handler **temp_writers = 0;
+ ACE_NEW_RETURN (temp_writers,
+ Write_Handler *[opt_nconnections],
+ 0);
+ ACE_Auto_Basic_Array_Ptr <Write_Handler *> writers (temp_writers);
+
+ ACE_TCHAR *temp_failed = 0;
+ ACE_NEW_RETURN (temp_failed,
+ ACE_TCHAR[opt_nconnections],
+ 0);
+ ACE_Auto_Basic_Array_Ptr <ACE_TCHAR> failed_svc_handlers (temp_failed);
+
+ // Automagic memory cleanup.
+ ACE_INET_Addr *temp_addresses;
+ ACE_NEW_RETURN (temp_addresses,
+ ACE_INET_Addr [opt_nconnections],
+ 0);
+ ACE_Auto_Array_Ptr <ACE_INET_Addr> addresses (temp_addresses);
+
+ // Initialize array.
+ for (i = 0; i < opt_nconnections; i++)
+ {
+ writers[i] = 0;
+ addresses[i] = *connection_addr;
+ }
+
+ // Connection all <opt_nconnections> svc_handlers
+ int result = connector.connect_n (opt_nconnections,
+ writers.get (),
+ addresses.get (),
+ failed_svc_handlers.get ());
+ if (result == -1)
+ {
+ // Print out the connections that failed...
+ for (i = 0; i < opt_nconnections; i++)
+ if (failed_svc_handlers.get ()[i])
+ {
+ ACE_INET_Addr failed_addr = addresses.get()[i];
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%t) connection failed to %s, %d\n"),
+ failed_addr.get_host_name (),
+ failed_addr.get_port_number ()));
+ }
+ return 0;
+ }
+
+ // If no connections failed (result == 0) then there should be valid
+ // ACE_Svc_handler pointers in each writers[] position. Iterate to
+ // send data
+ for (int j = 0; j < opt_nloops; j++)
+ for (i = 0; i < opt_nconnections; i++)
+ if (writers[i]->send_data () == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%t) %p\n"),
+ ACE_TEXT ("writer::send_data")),
+ 0);
+ // Cleanup
+ for (i = 0; i < opt_nconnections; i++)
+ writers[i]->destroy ();
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) finishing client\n")));
+ return 0;
+}
+
+// Sets up the correct reactor (based on platform and options).
+
+void
+create_reactor (void)
+{
+ ACE_Reactor_Impl *impl = 0;
+
+ if (opt_wfmo_reactor)
+ {
+#if defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)
+ ACE_NEW (impl,
+ ACE_WFMO_Reactor);
+#endif /* ACE_WIN32 */
+ }
+ else if (opt_select_reactor)
+ ACE_NEW (impl,
+ ACE_Select_Reactor);
+
+ ACE_Reactor *reactor = 0;
+ ACE_NEW (reactor,
+ ACE_Reactor (impl));
+ ACE_Reactor::instance (reactor);
+}
+
+// Print stats.
+
+void
+print_results (ACE_Profile_Timer::ACE_Elapsed_Time &et)
+{
+ const ACE_TCHAR *reactor_type = 0;
+
+ if (opt_wfmo_reactor)
+ reactor_type = ACE_TEXT ("WFMO_Reactor");
+ else if (opt_select_reactor)
+ reactor_type = ACE_TEXT ("Select_Reactor");
+ else
+ reactor_type = ACE_TEXT ("Platform's default Reactor");
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\n\tReactor_Performance Test statistics:\n\n")));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\tReactor Type: %s\n"),
+ reactor_type));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\tConnections: %d\n"),
+ opt_nconnections));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\tIteration per connection: %d\n"),
+ opt_nloops));
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\n\tTiming results:\n")));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\t\treal time = %f secs \n\t\tuser time = %f secs \n\t\tsystem time = %f secs\n\n"),
+ et.real_time,
+ et.user_time,
+ et.system_time));
+}
+
+int
+run_main (int argc, ACE_TCHAR *argv[])
+{
+ ACE_START_TEST (ACE_TEXT ("Reactor_Performance_Test"));
+
+ ACE_Get_Opt getopt (argc, argv, ACE_TEXT ("dswc:l:"), 1);
+ for (int c; (c = getopt ()) != -1; )
+ switch (c)
+ {
+ case 's':
+ opt_select_reactor = 1;
+ break;
+ case 'w':
+ opt_wfmo_reactor = 1;
+ break;
+ case 'c':
+ opt_nconnections = ACE_OS::atoi (getopt.opt_arg ());
+ break;
+ case 'l':
+ opt_nloops = ACE_OS::atoi (getopt.opt_arg ());
+ break;
+ case 'd':
+ opt_debug = 1;
+ break;
+ }
+
+ // Sets up the correct reactor (based on platform and options).
+ create_reactor ();
+
+ // Manage memory automagically.
+ auto_ptr<ACE_Reactor> reactor (ACE_Reactor::instance ());
+ auto_ptr<ACE_Reactor_Impl> impl;
+
+ // If we are using other that the default implementation, we must
+ // clean up.
+ if (opt_select_reactor || opt_wfmo_reactor)
+ {
+ auto_ptr<ACE_Reactor_Impl> auto_impl (ACE_Reactor::instance ()->implementation ());
+ impl = auto_impl;
+ }
+
+ Read_Handler::set_countdown (opt_nconnections);
+
+ // Acceptor
+ ACCEPTOR acceptor;
+ ACE_INET_Addr server_addr;
+
+ // Bind acceptor to any port and then find out what the port was.
+ if (acceptor.open (ACE_sap_any_cast (const ACE_INET_Addr &)) == -1
+ || acceptor.acceptor ().get_local_addr (server_addr) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%t) %p\n"),
+ ACE_TEXT ("open")),
+ -1);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) starting server at port %d\n"),
+ server_addr.get_port_number ()));
+
+ ACE_INET_Addr connection_addr (server_addr.get_port_number (),
+ ACE_DEFAULT_SERVER_HOST);
+
+ if (ACE_Thread_Manager::instance ()->spawn
+ (ACE_THR_FUNC (client),
+ (void *) &connection_addr,
+ THR_NEW_LWP | THR_DETACHED) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%t) %p\n"),
+ ACE_TEXT ("thread create failed")));
+
+ ACE_Time_Value run_limit (opt_nloops / 10);
+
+ ACE_Profile_Timer timer;
+ timer.start ();
+ const int status =
+ ACE_Reactor::instance ()->run_reactor_event_loop (run_limit);
+ timer.stop ();
+
+ ACE_Profile_Timer::ACE_Elapsed_Time et;
+ timer.elapsed_time (et);
+
+ // Print results
+ print_results (et);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) waiting for the client thread...\n")));
+
+ ACE_Thread_Manager::instance ()->wait ();
+
+ ACE_END_TEST;
+ return status;
+}
+
+#else
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("Reactor_Performance_Test"));
+
+ ACE_ERROR ((LM_INFO,
+ ACE_TEXT ("threads not supported on this platform\n")));
+
+ ACE_END_TEST;
+ return 0;
+}
+#endif /* ACE_HAS_THREADS */
diff --git a/ACE/tests/Reactor_Performance_Test.h b/ACE/tests/Reactor_Performance_Test.h
new file mode 100644
index 00000000000..bde943c2951
--- /dev/null
+++ b/ACE/tests/Reactor_Performance_Test.h
@@ -0,0 +1,62 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Reactor_Performance_Test.h
+//
+// = DESCRIPTION
+// This file includes template class definitions for the
+// Reactor_Performance_Test.cpp program. This class gets its own
+// header file to work around AIX C++ compiler "features" related
+// to template instantiation...
+//
+// = AUTHOR
+// Irfan Pyarali <irfan@cs.wustl.edu> and
+// Steve Huston <shuston@riverace.com>
+//
+// ============================================================================
+
+#ifndef ACE_TESTS_REACTOR_PERFORMANCE_TEST_H
+#define ACE_TESTS_REACTOR_PERFORMANCE_TEST_H
+
+#include "ace/SOCK_Stream.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "ace/Svc_Handler.h"
+
+class Read_Handler : public ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_SYNCH>
+{
+ // = TITLE
+ // Simple class for reading in the data
+public:
+ static void set_countdown (int nconnections);
+
+ virtual int open (void *);
+ virtual int handle_input (ACE_HANDLE h);
+ virtual int handle_close (ACE_HANDLE handle,
+ ACE_Reactor_Mask close_mask);
+ // The Svc_Handler callbacks.
+
+private:
+ static int waiting_;
+ // How many connections are we waiting for.
+};
+
+class Write_Handler : public ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_SYNCH>
+{
+ // = TITLE
+ // This Svc_Handler simply connects to a server and sends some
+ // output to it. Its purpose is to feed the test.
+public:
+ virtual int open (void *);
+ virtual int send_data (void);
+};
+
+#endif /* ACE_TESTS_REACTOR_PERFORMANCE_TEST_H */
diff --git a/ACE/tests/Reactor_Registration_Test.cpp b/ACE/tests/Reactor_Registration_Test.cpp
new file mode 100644
index 00000000000..c44d21881c0
--- /dev/null
+++ b/ACE/tests/Reactor_Registration_Test.cpp
@@ -0,0 +1,181 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Reactor_Registration_Test.cpp
+//
+// = DESCRIPTION
+// This is a test of registering handlers with the Reactor.
+//
+// = AUTHOR
+// Irfan Pyarali <irfan@oomworks.com>
+//
+// ============================================================================
+
+#include "tests/test_config.h"
+#include "ace/Pipe.h"
+#include "ace/Reactor.h"
+#include "ace/Select_Reactor.h"
+#include "ace/TP_Reactor.h"
+#include "ace/WFMO_Reactor.h"
+#include "ace/ACE.h"
+
+ACE_RCSID(tests, Reactor_Registration_Test, "$Id$")
+
+static const char message[] = "abcdefghijklmnopqrstuvwxyz";
+static const size_t message_size = 26;
+static int iteration = 1;
+
+class Event_Handler : public ACE_Event_Handler
+{
+public:
+
+ Event_Handler (ACE_Reactor &reactor,
+ ACE_HANDLE read,
+ ACE_HANDLE write);
+
+ ~Event_Handler (void);
+
+ int handle_input (ACE_HANDLE fd = ACE_INVALID_HANDLE);
+
+ int handle_close (ACE_HANDLE handle,
+ ACE_Reactor_Mask close_mask);
+
+ ACE_Pipe pipe_;
+};
+
+Event_Handler::Event_Handler (ACE_Reactor &reactor,
+ ACE_HANDLE read,
+ ACE_HANDLE write)
+ : ACE_Event_Handler (&reactor),
+ pipe_ (read, write)
+{
+ ssize_t result = 0;
+
+ if (read == ACE_INVALID_HANDLE)
+ {
+ result = this->pipe_.open ();
+ ACE_ASSERT (result == 0);
+ ACE_UNUSED_ARG (result);
+ }
+
+ result =
+ this->reactor ()->register_handler (this->pipe_.read_handle (),
+ this,
+ ACE_Event_Handler::READ_MASK);
+ ACE_ASSERT (result == 0);
+ ACE_UNUSED_ARG (result);
+
+ result =
+ ACE::send_n (this->pipe_.write_handle (),
+ message,
+ message_size);
+ ACE_ASSERT (result == static_cast<ssize_t> (message_size));
+ ACE_UNUSED_ARG (result);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Event_Handler::Event_Handler for %@\n"),
+ this));
+}
+
+Event_Handler::~Event_Handler (void)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Event_Handler::~Event_Handler for %@\n"),
+ this));
+}
+
+int
+Event_Handler::handle_input (ACE_HANDLE handle)
+{
+ char buf[message_size + 1];
+
+ ssize_t result =
+ ACE::recv_n (handle,
+ buf,
+ sizeof buf - 1);
+ ACE_ASSERT (result == static_cast<ssize_t> (message_size));
+ ACE_UNUSED_ARG (result);
+
+ buf[message_size] = '\0';
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Message %C received for %@\n"),
+ buf,
+ this));
+
+ return -1;
+}
+
+int
+Event_Handler::handle_close (ACE_HANDLE,
+ ACE_Reactor_Mask)
+{
+ switch (iteration)
+ {
+ case 1:
+ new Event_Handler (*this->reactor (),
+ ACE_INVALID_HANDLE,
+ ACE_INVALID_HANDLE);
+ break;
+ case 2:
+ new Event_Handler (*this->reactor (),
+ this->pipe_.read_handle (),
+ this->pipe_.write_handle ());
+ break;
+ case 3:
+ this->reactor ()->end_reactor_event_loop ();
+ break;
+ }
+
+ iteration++;
+ delete this;
+
+ return 0;
+}
+
+void
+test (ACE_Reactor_Impl &reactor_impl,
+ const char *reactor_type)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\nTesting with %C\n\n"),
+ reactor_type));
+
+ ACE_Reactor reactor (&reactor_impl,
+ 0);
+
+ new Event_Handler (reactor,
+ ACE_INVALID_HANDLE,
+ ACE_INVALID_HANDLE);
+
+ reactor.run_reactor_event_loop ();
+}
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("Reactor_Registration_Test"));
+
+ iteration = 1;
+ ACE_Select_Reactor select_reactor;
+ test (select_reactor, "ACE_Select_Reactor");
+
+ iteration = 1;
+ ACE_TP_Reactor tp_reactor;
+ test (tp_reactor, "ACE_TP_Reactor");
+
+#if defined (ACE_WIN32)
+ iteration = 1;
+ ACE_WFMO_Reactor wfmo_reactor;
+ test (wfmo_reactor, "ACE_WFMO_Reactor");
+#endif /* ACE_WIN32 */
+
+ ACE_END_TEST;
+
+ return 0;
+}
diff --git a/ACE/tests/Reactor_Timer_Test.cpp b/ACE/tests/Reactor_Timer_Test.cpp
new file mode 100644
index 00000000000..2225fd2fd31
--- /dev/null
+++ b/ACE/tests/Reactor_Timer_Test.cpp
@@ -0,0 +1,271 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Reactor_Timer_Test.cpp
+//
+// = DESCRIPTION
+// This is a simple test that illustrates the timer mechanism of
+// the reactor. Scheduling timers, resetting timer intervals,
+// handling expired timers and cancelling scheduled timers are
+// all exercised in this test.
+//
+// = AUTHOR
+// Prashant Jain <pjain@cs.wustl.edu> and Douglas C. Schmidt
+// <schmidt@cs.wustl.edu>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/Timer_Queue.h"
+#include "ace/Reactor.h"
+#include "ace/High_Res_Timer.h"
+#include "ace/Trace.h"
+#include "ace/Recursive_Thread_Mutex.h"
+
+ACE_RCSID(tests, Reactor_Timer_Test, "$Id$")
+
+static int done = 0;
+static int count = 0;
+static int odd = 0;
+
+class Time_Handler : public ACE_Event_Handler
+{
+public:
+ Time_Handler ();
+ // Default constructor
+
+ virtual int handle_timeout (const ACE_Time_Value &tv,
+ const void *arg);
+ // Handle the timeout.
+
+ virtual int handle_close (ACE_HANDLE handle,
+ ACE_Reactor_Mask close_mask);
+ // Called when <Time_Handler> is removed.
+
+ long timer_id (void) const;
+ // Return our timer id.
+
+ void timer_id (long);
+ // Set our timer id;
+
+private:
+ long timer_id_;
+ // Stores the id of this timer.
+};
+
+Time_Handler::Time_Handler ()
+: timer_id_ (-1)
+{
+ // Nothing
+}
+
+int
+Time_Handler::handle_close (ACE_HANDLE handle,
+ ACE_Reactor_Mask close_mask)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("[%x] handle = %d, close_mask = %d, timer id = %d\n"),
+ this,
+ handle,
+ close_mask,
+ this->timer_id ()));
+ return 0;
+}
+
+int
+Time_Handler::handle_timeout (const ACE_Time_Value &tv,
+ const void *arg)
+{
+ long current_count = static_cast<long> (reinterpret_cast<size_t> (arg));
+ if (current_count >= 0)
+ ACE_ASSERT (current_count == count);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("[%x] Timer id %d with count #%d|%d timed out at %d!\n"),
+ this,
+ this->timer_id (),
+ count,
+ current_count,
+ tv.sec ()));
+
+ if (current_count == long (ACE_MAX_TIMERS - 1))
+ done = 1;
+ else if (count == ACE_MAX_TIMERS - 1)
+ {
+ done = 1;
+ return -1;
+ }
+ else if (current_count == -1)
+ {
+ int result = ACE_Reactor::instance ()->reset_timer_interval (this->timer_id (),
+ ACE_Time_Value (count + 1));
+ if (result == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Error resetting timer interval\n")));
+ }
+ count += (1 + odd);
+ return 0;
+}
+
+long
+Time_Handler::timer_id (void) const
+{
+ return this->timer_id_;
+}
+
+void
+Time_Handler::timer_id (long t)
+{
+ this->timer_id_ = t;
+}
+
+static void
+test_registering_all_handlers (void)
+{
+ ACE_Trace t (ACE_TEXT ("test_registering_all_handler"),
+ __LINE__,
+ ACE_TEXT_CHAR_TO_TCHAR (__FILE__));
+ Time_Handler rt[ACE_MAX_TIMERS];
+ long t_id[ACE_MAX_TIMERS];
+
+ for (size_t i = 0; i < ACE_MAX_TIMERS; i++)
+ {
+ t_id[i] =
+ ACE_Reactor::instance ()->schedule_timer (&rt[i],
+ (const void *) i,
+ ACE_Time_Value (2 * i + 1));
+ ACE_ASSERT (t_id[i] != -1);
+ rt[i].timer_id (t_id[i]);
+ }
+
+ while (!done)
+ ACE_Reactor::instance ()->handle_events ();
+}
+
+static void
+test_registering_one_handler (void)
+{
+ ACE_Trace t (ACE_TEXT ("test_registering_one_handler"),
+ __LINE__,
+ ACE_TEXT_CHAR_TO_TCHAR (__FILE__));
+ Time_Handler rt[ACE_MAX_TIMERS];
+ long t_id[ACE_MAX_TIMERS];
+
+ done = 0;
+ count = 0;
+
+ for (size_t i = 0; i < ACE_MAX_TIMERS; i++)
+ {
+ t_id[i] =
+ ACE_Reactor::instance ()->schedule_timer (&rt[0],
+ (const void *) i,
+ ACE_Time_Value (2 * i + 1));
+ ACE_ASSERT (t_id[i] != -1);
+ }
+
+ while (!done)
+ ACE_Reactor::instance ()->handle_events ();
+}
+
+static void
+test_canceling_odd_timers (void)
+{
+ ACE_Trace t (ACE_TEXT ("test_canceling_odd_timers"),
+ __LINE__,
+ ACE_TEXT_CHAR_TO_TCHAR (__FILE__));
+ Time_Handler rt[ACE_MAX_TIMERS];
+ long t_id[ACE_MAX_TIMERS];
+
+ done = 0;
+ count = 1;
+ odd = 1;
+
+ for (size_t i = 0; i < ACE_MAX_TIMERS; i++)
+ {
+ t_id[i] = ACE_Reactor::instance ()->schedule_timer (&rt[i],
+ (const void *) i,
+ ACE_Time_Value (2 * i + 1));
+ ACE_ASSERT (t_id[i] != -1);
+ rt[i].timer_id (t_id[i]);
+ }
+
+ for (size_t j = 0; (u_long) j < ACE_MAX_TIMERS; j++)
+ // Cancel handlers with odd numbered timer ids.
+ if (ACE_ODD (rt[j].timer_id ()))
+ {
+ int result =
+ ACE_Reactor::instance ()->cancel_timer (rt[j].timer_id ());
+ if (result == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Error cancelling timer\n")));
+ }
+
+ while (!done)
+ ACE_Reactor::instance ()->handle_events ();
+}
+
+static void
+test_resetting_timer_intervals (void)
+{
+ ACE_Trace t (ACE_TEXT ("test_resetting_timer_intervals"),
+ __LINE__,
+ ACE_TEXT_CHAR_TO_TCHAR (__FILE__));
+ Time_Handler rt;
+ long t_id;
+
+ done = 0;
+ count = 0;
+ odd = 0;
+
+ t_id =
+ ACE_Reactor::instance ()->schedule_timer
+ (&rt,
+ (const void *) -1,
+ ACE_Time_Value (1),
+ // Start off by making this an interval timer.
+ ACE_Time_Value (1));
+
+ ACE_ASSERT (t_id != -1);
+ rt.timer_id (t_id);
+
+ while (!done)
+ ACE_Reactor::instance ()->handle_events ();
+}
+
+// If any command line arg is given, run the test with high res timer
+// queue. Else run it normally.
+int
+run_main (int argc, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("Reactor_Timer_Test"));
+
+ if (argc > 1)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Running with high-res timer queue\n")));
+ ACE_Reactor *r = ACE_Reactor::instance ();
+ (void) ACE_High_Res_Timer::global_scale_factor ();
+ r->timer_queue ()->gettimeofday (&ACE_High_Res_Timer::gettimeofday_hr);
+ }
+
+ // Register all different handlers, i.e., one per timer.
+ test_registering_all_handlers ();
+
+ // Now try multiple timers for ONE event handler (should produce the
+ // same result).
+ test_registering_one_handler ();
+
+ // Try canceling handlers with odd numbered timer ids.
+ test_canceling_odd_timers ();
+
+ // Make sure <reset_timer_inverval> works.
+ test_resetting_timer_intervals ();
+
+ ACE_END_TEST;
+ return 0;
+}
diff --git a/ACE/tests/Reactors_Test.cpp b/ACE/tests/Reactors_Test.cpp
new file mode 100644
index 00000000000..f1daf382a18
--- /dev/null
+++ b/ACE/tests/Reactors_Test.cpp
@@ -0,0 +1,261 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Reactors_Test.cpp
+//
+// = DESCRIPTION
+// This is a test that performs a torture test of multiple
+// <ACE_Reactors> and <ACE_Tasks> in the same process.
+//
+// = AUTHOR
+// Prashant Jain <pjain@cs.wustl.edu>,
+// Detlef Becker <Detlef.Becker@med.siemens.de>, and
+// Douglas C. Schmidt <schmidt@cs.wustl.edu>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/Task.h"
+#include "ace/Reactor.h"
+#include "ace/Atomic_Op.h"
+#include "ace/Recursive_Thread_Mutex.h"
+
+ACE_RCSID(tests, Reactors_Test, "$Id$")
+
+#if defined (ACE_HAS_THREADS)
+
+ACE_Thread_Manager *thr_mgr;
+
+static const int MAX_TASKS = 20;
+
+class Test_Task : public ACE_Task<ACE_MT_SYNCH>
+ // = TITLE
+ // Exercise the tasks.
+{
+public:
+ // = Initialization and termination methods.
+ Test_Task (void);
+ ~Test_Task (void);
+
+ // = Task hooks.
+ virtual int open (void *args = 0);
+ virtual int close (u_long flags = 0);
+ virtual int svc (void);
+
+ // = Event Handler hooks.
+ virtual int handle_input (ACE_HANDLE handle);
+ virtual int handle_close (ACE_HANDLE fd,
+ ACE_Reactor_Mask close_mask);
+private:
+ size_t handled_;
+ // Number of iterations handled.
+
+ static int task_count_;
+ // Number of tasks running.
+};
+
+// Static data member initialization.
+int Test_Task::task_count_ = 0;
+
+static ACE_Atomic_Op<ACE_Thread_Mutex, int> done_count = MAX_TASKS * 2;
+
+
+
+static ACE_Recursive_Thread_Mutex recursive_lock;
+
+Test_Task::Test_Task (void)
+ : handled_ (0)
+{
+ ACE_GUARD (ACE_Recursive_Thread_Mutex, ace_mon, recursive_lock);
+
+ Test_Task::task_count_++;
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) TT+ Test_Task::task_count_ = %d\n"),
+ Test_Task::task_count_));
+}
+
+Test_Task::~Test_Task (void)
+{
+ ACE_GUARD (ACE_Recursive_Thread_Mutex, ace_mon, recursive_lock);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) TT- Test_Task::task_count_ = %d\n"),
+ Test_Task::task_count_));
+
+ ACE_ASSERT (Test_Task::task_count_ == 0);
+}
+
+int
+Test_Task::open (void *args)
+{
+ this->reactor (reinterpret_cast<ACE_Reactor *> (args));
+ return this->activate (THR_NEW_LWP);
+}
+
+int
+Test_Task::close (u_long)
+{
+ ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, recursive_lock, -1);
+
+ Test_Task::task_count_--;
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) close Test_Task::task_count_ = %d\n"),
+ Test_Task::task_count_));
+
+ ACE_ASSERT (Test_Task::task_count_ >= 0);
+
+ return 0;
+}
+
+int
+Test_Task::svc (void)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) svc\n")));
+
+ for (size_t i = 0; i < ACE_MAX_ITERATIONS; i++)
+ {
+ ACE_OS::thr_yield ();
+
+ // Only wait up to 10 milliseconds to notify the Reactor.
+ ACE_Time_Value timeout (0, 10 * 1000);
+
+ if (this->reactor ()->notify (this,
+ ACE_Event_Handler::READ_MASK,
+ &timeout) == -1)
+ {
+ if (errno == ETIME)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) %p\n"),
+ ACE_TEXT ("notify() timed out")));
+ else
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%t) %p\n"),
+ ACE_TEXT ("notify")),
+ -1);
+ }
+ }
+
+ return 0;
+}
+
+int
+Test_Task::handle_close (ACE_HANDLE, ACE_Reactor_Mask)
+{
+ return 0;
+}
+
+int
+Test_Task::handle_input (ACE_HANDLE)
+{
+ this->handled_++;
+
+ if (this->handled_ == ACE_MAX_ITERATIONS)
+ {
+ done_count--;
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) handle_input, handled_ = %d, done_count = %d\n"),
+ this->handled_,
+ done_count.value ()));
+ }
+
+ ACE_OS::thr_yield ();
+ return -1;
+}
+
+static void *
+worker (void *args)
+{
+ ACE_Reactor *reactor = reinterpret_cast<ACE_Reactor *> (args);
+
+ // Make this thread the owner of the Reactor's event loop.
+ reactor->owner (ACE_Thread::self ());
+
+ // Use a timeout to inform the Reactor when to shutdown.
+ ACE_Time_Value timeout (4);
+
+ for (;;)
+ switch (reactor->handle_events (timeout))
+ {
+ case -1:
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%t) %p\n"),
+ ACE_TEXT ("reactor")),
+ 0);
+ /* NOTREACHED */
+ case 0:
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) Reactor shutdown\n")));
+ return 0;
+ }
+
+ ACE_NOTREACHED (return 0);
+}
+
+#endif /* ACE_HAS_THREADS */
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("Reactors_Test"));
+
+#if defined (ACE_HAS_THREADS)
+ ACE_ASSERT (ACE_LOG_MSG->op_status () != -1);
+
+ thr_mgr = ACE_Thread_Manager::instance ();
+
+ ACE_Reactor reactor;
+ ACE_ASSERT (ACE_LOG_MSG->op_status () != -1);
+
+ Test_Task tt1[MAX_TASKS];
+ Test_Task tt2[MAX_TASKS];
+
+ // Activate all of the Tasks.
+
+ for (int i = 0; i < MAX_TASKS; i++)
+ {
+ tt1[i].open (ACE_Reactor::instance ());
+ tt2[i].open (&reactor);
+ }
+
+ // Spawn two threads each running a different reactor.
+
+ if (ACE_Thread_Manager::instance ()->spawn
+ (ACE_THR_FUNC (worker),
+ (void *) ACE_Reactor::instance (),
+ THR_BOUND | THR_DETACHED) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("spawn")),
+ -1);
+
+ else if (ACE_Thread_Manager::instance ()->spawn
+ (ACE_THR_FUNC (worker), (void *) &reactor,
+ THR_BOUND | THR_DETACHED) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("spawn")),
+ -1);
+
+ if (ACE_Thread_Manager::instance ()->wait () == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("wait")),
+ -1);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) all threads are finished \n")));
+
+#else
+ ACE_ERROR ((LM_INFO,
+ ACE_TEXT ("threads not supported on this platform\n")));
+#endif /* ACE_HAS_THREADS */
+ ACE_END_TEST;
+ return 0;
+}
diff --git a/ACE/tests/Reader_Writer_Test.cpp b/ACE/tests/Reader_Writer_Test.cpp
new file mode 100644
index 00000000000..4c18681d8f9
--- /dev/null
+++ b/ACE/tests/Reader_Writer_Test.cpp
@@ -0,0 +1,293 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Reader_Writer_Test.cpp
+//
+// = DESCRIPTION
+// This test program verifies the functionality of the ACE_OS
+// implementation of readers/writer locks on Win32 and Posix
+// pthreads.
+//
+// = AUTHOR
+// Prashant Jain <pjain@cs.wustl.edu> and Doug C. Schmidt <schmidt@cs.wustl.edu>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/Thread.h"
+#include "ace/Thread_Manager.h"
+#include "ace/Get_Opt.h"
+#include "ace/Atomic_Op.h"
+#include "ace/OS_NS_unistd.h"
+#include "ace/Guard_T.h"
+#include "ace/RW_Thread_Mutex.h"
+#include "ace/Time_Value.h"
+
+ACE_RCSID(tests, Reader_Writer_Test, "$Id$")
+
+#if defined (ACE_HAS_THREADS)
+
+// Default number of iterations.
+#if defined (VXWORKS)
+ // So the test doesn't run for too long . . .
+ static size_t n_iterations = 25;
+#else
+ static size_t n_iterations = 50;
+#endif /* VXWORKS */
+
+// Default number of loops.
+#if defined (VXWORKS)
+ // thr_yield () and/or thr_equal () are expensive on VxWorks, apparently.
+ static size_t n_loops = 10;
+#else
+ static size_t n_loops = 100;
+#endif /* VXWORKS */
+
+// Default number of readers.
+static size_t n_readers = 6;
+
+// Default number of writers.
+static size_t n_writers = 4;
+
+// Thread id of last writer.
+static ACE_thread_t shared_data;
+
+// Lock for shared_data.
+static ACE_RW_Thread_Mutex rw_mutex;
+
+// Count of the number of readers and writers.
+static ACE_Atomic_Op<ACE_Thread_Mutex, int> current_readers;
+static ACE_Atomic_Op<ACE_Thread_Mutex, int> current_writers;
+
+// Explain usage and exit.
+static void
+print_usage_and_die (void)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("usage: %n [-r n_readers] [-w n_writers] [-n iteration_count]\n")));
+ ACE_OS::exit (1);
+}
+
+static void
+parse_args (int argc, ACE_TCHAR *argv[])
+{
+ ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("r:w:n:"));
+
+ int c;
+
+ while ((c = get_opt ()) != -1)
+ switch (c)
+ {
+ case 'r':
+ n_readers = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'w':
+ n_writers = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'n':
+ n_iterations = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ default:
+ print_usage_and_die ();
+ break;
+ }
+}
+
+// Iterate <n_iterations> each time checking that nobody modifies the data
+// while we have a read lock.
+
+static void *
+reader (void *)
+{
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT (" (%t) reader starting\n")));
+
+ // We use a random pause, around 2msec with 1msec jittering.
+ int usecs = 1000 + ACE_OS::rand() % 2000;
+ ACE_Time_Value pause(0, usecs);
+
+ for (size_t iterations = 1; iterations <= n_iterations; iterations++)
+ {
+ ACE_OS::sleep (pause);
+ ACE_Read_Guard<ACE_RW_Thread_Mutex> g (rw_mutex);
+ // int n = ++current_readers;
+ // ACE_DEBUG ((LM_DEBUG, ACE_TEXT (" (%t) I'm reader number %d\n"), n));
+
+ if (current_writers > 0)
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT (" (%t) writers found!!!\n")));
+
+ ACE_thread_t data = shared_data;
+
+ for (size_t loop = 1; loop <= n_loops; loop++)
+ {
+ ACE_Thread::yield ();
+
+ if (!ACE_OS::thr_equal (shared_data, data))
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT (" (%t) somebody changed %d to %d\n"),
+ data, shared_data));
+ }
+
+ int result = rw_mutex.tryacquire_write_upgrade ();
+
+ if (result == 0)
+ {
+ current_readers--;
+ current_writers++;
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) upgraded to write lock!\n")));
+
+ ACE_thread_t self = ACE_Thread::self ();
+
+ shared_data = self;
+ data = self;
+
+ for (size_t loop = 1; loop <= n_loops; loop++)
+ {
+ if (ACE_OS::thr_equal (shared_data, data) == 0)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) upgraded writer error: somebody changed %d to %d\n"),
+ data,
+ shared_data));
+ }
+
+ current_writers--;
+ // we were a writer
+ }
+ else if (result == -1 && errno == EBUSY)
+ {
+ current_readers--;
+ // we were still a reader
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) could not upgrade to write lock!\n")));
+
+ }
+ else // result == -1
+ {
+ // These #ifs should generally match the logic in OS_NS_Thread.inl.
+
+# if defined (ACE_HAS_PTHREADS_UNIX98_EXT) || !defined (ACE_LACKS_RWLOCK_T)
+ // In this case we have native RW locks support, but native RW
+ // locks may not support upgrading!
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) %p\n"),
+ ACE_TEXT ("can't upgrade write lock"),
+ 1));
+# else
+ // In this case we do not have native RW locks, but therefore the
+ // emulation, which supports upgradable write locks.
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%t) %p\n"),
+ ACE_TEXT ("failure in upgrading to write lock"),
+ 1));
+# endif /* ACE_HAS_PTHREADS_UNIX98_EXT || !ACE_LACKS_RWLOCK_T */
+ }
+ //ACE_DEBUG ((LM_DEBUG, ACE_TEXT (" (%t) done with reading guarded data\n")));
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) reader finished %d iterations at %T\n"),
+ iterations));
+ }
+ return 0;
+}
+
+// Iterate <n_iterations> each time modifying the global data
+// and checking that nobody steps on it while we can write it.
+
+static void *
+writer (void *)
+{
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT (" (%t) writer starting\n")));
+
+ // We use a random pause, around 2msec with 1msec jittering.
+ int usecs = 1000 + ACE_OS::rand() % 2000;
+ ACE_Time_Value pause(0, usecs);
+
+ for (size_t iterations = 1; iterations <= n_iterations; iterations++)
+ {
+ ACE_OS::sleep (pause);
+
+ ACE_Write_Guard<ACE_RW_Thread_Mutex> g (rw_mutex);
+
+ current_writers++;
+
+ if (current_writers > 1)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT (" (%t) other writers found!!!\n")));
+
+ if (current_readers > 0)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT (" (%t) readers found!!!\n")));
+
+ ACE_thread_t self = ACE_Thread::self ();
+
+ shared_data = self;
+
+ for (size_t loop = 1; loop <= n_loops; loop++)
+ {
+ ACE_Thread::yield ();
+
+ if (!ACE_OS::thr_equal (shared_data, self))
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT (" (%t) somebody wrote on my data %d\n"),
+ shared_data));
+ }
+
+ current_writers--;
+
+ ACE_DEBUG((LM_DEBUG, ACE_TEXT (" (%t) write %d done at %T\n"), iterations));
+ }
+ return 0;
+}
+
+#endif /* ACE_HAS_THREADS */
+
+// Spawn off threads.
+
+int run_main (int argc, ACE_TCHAR *argv[])
+{
+ ACE_START_TEST (ACE_TEXT ("Reader_Writer_Test"));
+
+#if defined (ACE_HAS_THREADS)
+ parse_args (argc, argv);
+
+ current_readers = 0; // Possibly already done
+ current_writers = 0; // Possibly already done
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT (" (%t) main thread starting\n")));
+
+ if (ACE_Thread_Manager::instance ()->spawn_n (n_readers,
+ ACE_THR_FUNC (reader),
+ 0,
+ THR_NEW_LWP) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("spawn_n")), 1);
+ else if (ACE_Thread_Manager::instance ()->spawn_n (n_writers,
+ ACE_THR_FUNC (writer),
+ 0,
+ THR_NEW_LWP) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("spawn_n")), 1);
+
+ ACE_Thread_Manager::instance ()->wait ();
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT (" (%t) exiting main thread\n")));
+#else
+ ACE_UNUSED_ARG (argc);
+ ACE_UNUSED_ARG (argv);
+ ACE_ERROR ((LM_INFO,
+ ACE_TEXT ("threads not supported on this platform\n")));
+#endif /* ACE_HAS_THREADS */
+ ACE_END_TEST;
+ return 0;
+}
diff --git a/ACE/tests/Recursive_Condition_Bug_Test.cpp b/ACE/tests/Recursive_Condition_Bug_Test.cpp
new file mode 100644
index 00000000000..f74e9ac94e0
--- /dev/null
+++ b/ACE/tests/Recursive_Condition_Bug_Test.cpp
@@ -0,0 +1,191 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Recursive_Condition_Bug_Test.cpp
+//
+// = DESCRIPTION
+// This test program validates the functionality of the
+// ACE_Condition<ACE_Recursive_Thread_Mutex> template
+// specialization when combined with the
+// ACE_Thread_Timer_Queue_Adapter on Win32 and Posix pthreads.
+// It was added to test for bugs with the ACE_OS recursive
+// condition implementation.
+//
+// = AUTHOR
+// Leonid Kvetnyi <leonidk@nice.com> and
+// Douglas C. Schmidt <schmidt@cs.wustl.edu>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/OS_NS_sys_time.h"
+#include "ace/Task_T.h"
+#include "ace/Activation_Queue.h"
+#include "ace/Timer_Heap.h"
+#include "ace/Timer_Queue_Adapters.h"
+#include "ace/Condition_Recursive_Thread_Mutex.h"
+
+ACE_RCSID (tests,
+ Recursive_Condition_Bug_Test,
+ "$Id$")
+
+#if defined (ACE_HAS_THREADS)
+
+// Number of iterations for the performance tests.
+static int max_iterations = 30;
+
+typedef ACE_Thread_Timer_Queue_Adapter<ACE_Timer_Heap> Thread_Timer_Queue;
+
+class Test_Handler;
+
+class Test_Task : public ACE_Task<ACE_MT_SYNCH>
+{
+public:
+ virtual int svc (void)
+ {
+ while (--max_iterations > 0)
+ {
+ // dequeue the next object
+ ACE_Message_Block * mb = 0;
+
+ if (this->getq (mb) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%t) %p\n"),
+ ACE_TEXT ("getq failed")),
+ -1);
+
+ Test_Handler *handler = reinterpret_cast<Test_Handler *> (mb->base ());
+ mb->release ();
+
+ ACE_Time_Value timeout = ACE_OS::gettimeofday () + ACE_Time_Value (1, 0);
+
+ if (timer_queue_.schedule (reinterpret_cast<ACE_Event_Handler *> (handler),
+ this,
+ timeout) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%t) %p\n"),
+ ACE_TEXT ("schedule failed")),
+ -1);
+
+ ACE_DEBUG ((LM_INFO,
+ ACE_TEXT ("(%t) %d iteration(s) remain\n"),
+ max_iterations));
+ }
+
+ timer_queue_.deactivate ();
+ ACE_DEBUG ((LM_INFO,
+ ACE_TEXT ("(%t) leaving the Test_task\n")));
+ return 0;
+ }
+
+ virtual int open (void * = 0)
+ {
+ if (ACE_Task<ACE_MT_SYNCH>::activate (THR_NEW_LWP, 1) != 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%t) %p\n"),
+ ACE_TEXT ("Test_Task::activate")),
+ -1);
+ if (0 != timer_queue_.activate ())
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%t) %p\n"),
+ ACE_TEXT ("Test_Task::queue activate")),
+ -1);
+ return 0;
+ }
+
+private:
+ Thread_Timer_Queue timer_queue_;
+};
+
+class Test_Handler : public ACE_Event_Handler
+{
+public:
+ virtual int handle_timeout (const ACE_Time_Value &,
+ const void *arg)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Test_Handler::handle_timeout\n")));
+
+ void *nc_arg = const_cast<void *> (arg);
+ Test_Task *test_task =
+ reinterpret_cast<Test_Task *> (nc_arg);
+ ACE_Message_Block *mb = 0;
+ ACE_NEW_MALLOC_RETURN (mb,
+ static_cast<ACE_Message_Block *> (ACE_Allocator::instance()->malloc (sizeof (ACE_Message_Block))),
+ ACE_Message_Block (sizeof (*this), // size
+ ACE_Message_Block::MB_DATA, // type
+ 0, // cont
+ (char *) this, // data
+ 0,
+ 0,
+ ACE_DEFAULT_MESSAGE_BLOCK_PRIORITY,
+ ACE_Time_Value::zero,
+ ACE_Time_Value::max_time,
+ 0,
+ ACE_Allocator::instance()), // data
+ -1);
+
+ test_task->putq (mb);
+ return 0;
+ }
+};
+
+#endif /* ACE_HAS_THREADS */
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("Recursive_Condition_Bug_Test"));
+
+#if defined (ACE_HAS_THREADS)
+
+ // Timer queue usage.
+
+ Test_Handler handler;
+ Test_Task task;
+
+ if (0 != task.open ())
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%t) %p\n"),
+ ACE_TEXT ("open")),
+ -1);
+
+ ACE_Message_Block *mb = 0;
+ ACE_NEW_MALLOC_RETURN (mb,
+ static_cast<ACE_Message_Block *> (ACE_Allocator::instance()->malloc (sizeof (ACE_Message_Block))),
+ ACE_Message_Block (sizeof (handler), // size
+ ACE_Message_Block::MB_DATA, // type
+ 0, // cont
+ (char *) &handler,
+ 0,
+ 0,
+ ACE_DEFAULT_MESSAGE_BLOCK_PRIORITY,
+ ACE_Time_Value::zero,
+ ACE_Time_Value::max_time,
+ 0,
+ ACE_Allocator::instance()), // data
+ -1);
+
+ if (-1 == task.putq (mb))
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%t) %p\n"),
+ ACE_TEXT ("putq")),
+ -1);
+
+ if (ACE_Thread_Manager::instance ()->wait () == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "wait on Thread_Manager failed"),
+ -1);
+#else
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("ACE doesn't support recursive condition variables on this platform\n")));
+#endif /* ACE_HAS_THREADS */
+ ACE_END_TEST;
+ return 0;
+}
+
diff --git a/ACE/tests/Recursive_Condition_Test.cpp b/ACE/tests/Recursive_Condition_Test.cpp
new file mode 100644
index 00000000000..5576b2cf674
--- /dev/null
+++ b/ACE/tests/Recursive_Condition_Test.cpp
@@ -0,0 +1,308 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Recursive_Condition_Test.cpp
+//
+// = DESCRIPTION
+// This test program validates the functionality of the
+// ACE_Condition<ACE_Recursive_Thread_Mutex> template
+// specialization when combined with the
+// ACE_Thread_Timer_Queue_Adapter on Win32 and Posix pthreads.
+//
+// = AUTHOR
+// Stephen Howard <stephen.e.howard@lmco.com> and
+// Douglas C. Schmidt <schmidt@cs.wustl.edu>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/OS_NS_unistd.h"
+#include "ace/OS_NS_sys_time.h"
+#include "ace/Event_Handler.h"
+#include "ace/Log_Msg.h"
+#include "ace/Thread_Manager.h"
+#include "ace/Timer_Heap.h"
+#include "ace/Timer_Queue_Adapters.h"
+
+ACE_RCSID(tests, Recursive_Condition_Test, "$Id$")
+
+#if defined (ACE_HAS_THREADS)
+
+typedef ACE_Thread_Timer_Queue_Adapter<ACE_Timer_Heap> Thread_Timer_Queue;
+
+class Test_Handler : public ACE_Event_Handler
+{
+public:
+ Test_Handler (void) : nr_expirations_ (0) {}
+ int nr_expirations (void) { return this->nr_expirations_; }
+
+ virtual int handle_timeout (const ACE_Time_Value &,
+ const void *arg)
+ {
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) Test_Handler::handle_timeout\n")));
+ ++this->nr_expirations_;
+
+ void *nc_arg = const_cast<void *> (arg);
+ Thread_Timer_Queue *timer_queue =
+ reinterpret_cast<Thread_Timer_Queue *> (nc_arg);
+
+ ACE_Time_Value timeout = ACE_OS::gettimeofday () + ACE_Time_Value (1, 0);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) scheduling new timer 1 sec from now\n")));
+ if (timer_queue->schedule (this, timer_queue, timeout) == -1)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%t) %p\n"),
+ ACE_TEXT ("schedule failed")));
+
+ return 0;
+ }
+
+private:
+ int nr_expirations_;
+};
+
+// These are for the basic functionality tests.
+ACE_SYNCH_RECURSIVE_MUTEX mutex_;
+ACE_SYNCH_RECURSIVE_CONDITION condition_(mutex_);
+// Test driver sets this to non-zero before spawning and to zero for waiter.
+int protected_int = 0;
+
+static ACE_THR_FUNC_RETURN
+waiter (void *)
+{
+ if (mutex_.acquire () != 0)
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("(%t) %p\n"),
+ ACE_TEXT ("acquire")), 0);
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) waiting for cv signal...\n")));
+ if (condition_.wait () == 0)
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) woken up!!!\n")));
+ else
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%t) %p\n"), ACE_TEXT ("wait")));
+
+ int copy_int = protected_int; // Copy it in case it's erroneously changing
+ if (copy_int != 0)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%t) waiter found protected_int %d\n"),
+ copy_int));
+
+ if (mutex_.release () != 0)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%t) %p\n"), ACE_TEXT ("release")));
+
+ return 0;
+}
+
+static int
+test_1 (void)
+{
+ protected_int = 1;
+ if (ACE_Thread_Manager::instance()->spawn (waiter) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("(%t) %p\n"),
+ ACE_TEXT ("test 1 spawn")),
+ 1);
+
+ ACE_OS::sleep (2);
+ if (mutex_.acquire () == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("(%t) %p\n"),
+ ACE_TEXT ("test 1 mutex acquire")),
+ 1);
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) signaling condition...\n")));
+ protected_int = 0;
+ if (condition_.signal () == -1)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%t) %p\n"),
+ ACE_TEXT ("test 1 signal")));
+
+ if (mutex_.release () == -1)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%t) %p\n"),
+ ACE_TEXT ("test 1 release")));
+
+ ACE_Thread_Manager::instance ()->wait ();
+ return 0;
+}
+
+static int
+test_2 (void)
+{
+ protected_int = 1;
+ if (ACE_Thread_Manager::instance()->spawn (waiter) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("(%t) %p\n"),
+ ACE_TEXT ("test 2 spawn")),
+ 1);
+
+ ACE_OS::sleep (2);
+ if (mutex_.acquire () == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("(%t) %p\n"),
+ ACE_TEXT ("test 2 mutex acquire")),
+ 1);
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) signaling condition...\n")));
+ if (condition_.signal () == -1)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("test 2 signal")));
+
+ // Wait to clear protected_int to be sure cv properly reacquires the
+ // mutex before returning control to caller.
+ ACE_OS::sleep(2);
+ protected_int = 0;
+ if (mutex_.release () == -1)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%t) %p\n"),
+ ACE_TEXT ("test 2 release")));
+
+ ACE_Thread_Manager::instance ()->wait ();
+ return 0;
+}
+
+static int
+test_3 (void)
+{
+ protected_int = 1;
+ if (ACE_Thread_Manager::instance()->spawn_n (4, waiter) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"),
+ ACE_TEXT ("test 3 spawn")), 1);
+
+ ACE_OS::sleep (2);
+ if (mutex_.acquire () == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("(%t) %p\n"),
+ ACE_TEXT ("test 3 mutex acquire")),
+ 1);
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) broadcasting condition...\n")));
+ if (condition_.broadcast () == -1)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%t) %p\n"),
+ ACE_TEXT ("test 3 broadcast")));
+ protected_int = 0;
+ if (mutex_.release () == -1)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%t) %p\n"),
+ ACE_TEXT ("test 3 release")));
+
+ ACE_Thread_Manager::instance ()->wait ();
+
+ return 0;
+}
+
+static int
+test_4 (void)
+{
+ const int recurse_count = 3;
+
+ protected_int = recurse_count;
+ if (ACE_Thread_Manager::instance()->spawn (waiter) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("(%t) %p\n"),
+ ACE_TEXT ("spawn")), 1);
+
+ ACE_OS::sleep (2);
+ int i;
+ for (i = 0; i < recurse_count; ++i)
+ if (mutex_.acquire () == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("pass %d, %p\n"),
+ i + 1,
+ ACE_TEXT ("recursive acquire")),
+ 1);
+
+ // Don't report a failure if the mutex doesn't offer a view of the
+ // recursion count.
+ int nesting_level = mutex_.get_nesting_level ();
+ if (!(nesting_level == -1 && errno == ENOTSUP) && nesting_level != i)
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT("test 4 nesting level %d;")
+ ACE_TEXT (" should be %d\n"),
+ nesting_level, i),
+ 1);
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) signaling condition...\n")));
+ if (condition_.signal () == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("(%t) %p\n"),
+ ACE_TEXT ("test 4 signal")),
+ 1);
+
+ for (i = 0; i < recurse_count; ++i)
+ {
+ // Only decrement - be sure all the waiting threads are not released
+ // before we release the mutex the correct number of times.
+ --protected_int;
+ mutex_.release ();
+ }
+
+ // The waiter thread will acquire the mutex as a result of the releases
+ // above... don't check the nesting level until waiter() has had a chance
+ // to wake up, acquire, and release the mutex.
+ ACE_Thread_Manager::instance ()->wait ();
+
+ nesting_level = mutex_.get_nesting_level ();
+ if (!(nesting_level == -1 && errno == ENOTSUP) && nesting_level != 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT("(%t) nesting level %d; should be 0\n"),
+ nesting_level),
+ 1);
+
+ return 0;
+}
+#endif /* ACE_HAS_THREADS */
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("Recursive_Condition_Test"));
+
+#if defined (ACE_HAS_THREADS)
+
+ int status = 0;
+
+ /* Test 1 - Simple test */
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Test 1...\n")));
+ if (test_1 () != 0)
+ ++status;
+
+ /* Test #2 - Sleep 2 seconds before releasing mutex */
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Test 2...\n")));
+ if (test_2 () != 0)
+ ++status;
+
+ /* Test #3 - One main thread - 4 subthreads */
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Test 3...\n")));
+ if (test_3 () != 0)
+ ++status;
+
+ /* Test #4 - Multiple calls to mutex_.acquire and mutex_.release */
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Test 4...\n")));
+ if (test_4 () != 0)
+ ++status;
+
+ // Timer queue usage.
+ Thread_Timer_Queue timer_queue;
+ Test_Handler handler;
+ if (0 != timer_queue.activate ())
+ {
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%t) %p\n"), ACE_TEXT ("activate")));
+ ++status;
+ }
+
+ ACE_Time_Value timeout =
+ ACE_OS::gettimeofday() + ACE_Time_Value (1, 0);
+
+ if (-1 == timer_queue.schedule (&handler, &timer_queue, timeout))
+ {
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%t) %p\n"), ACE_TEXT ("schedule")));
+ ++status;
+ }
+
+ ACE_OS::sleep (10);
+ timer_queue.deactivate ();
+ timer_queue.wait ();
+ // Scheduling every second, waiting 10 seconds, should get at least 9
+ int expirations = handler.nr_expirations ();
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Caught %d timer expirations\n"),
+ expirations));
+ if (expirations < 9)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("Should have caught at least 9\n")));
+
+#else
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("ACE doesn't support recursive condition variables on this platform\n")));
+#endif /* ACE_HAS_THREADS */
+ ACE_END_TEST;
+ return 0;
+}
+
diff --git a/ACE/tests/Recursive_Mutex_Test.cpp b/ACE/tests/Recursive_Mutex_Test.cpp
new file mode 100644
index 00000000000..f99dba58ff0
--- /dev/null
+++ b/ACE/tests/Recursive_Mutex_Test.cpp
@@ -0,0 +1,340 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Recursive_Mutex_Test.cpp
+//
+// = DESCRIPTION
+// This test program verifies the functionality of the ACE_OS
+// implementation of recursive mutexes on Win32 and Posix
+// pthreads.
+//
+// = AUTHOR
+// Prashant Jain <pjain@cs.wustl.edu> and Douglas C. Schmidt <schmidt@cs.wustl.edu>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/Get_Opt.h"
+#include "ace/Thread_Manager.h"
+#include "ace/OS_NS_time.h"
+#include "ace/OS_NS_sys_time.h"
+#include "ace/OS_NS_unistd.h"
+#include "ace/Recursive_Thread_Mutex.h"
+
+ACE_RCSID(tests, Recursive_Mutex_Test, "$Id$")
+
+#if defined (ACE_HAS_THREADS)
+
+#include "ace/Guard_T.h"
+
+// For all platforms except for Windows use the
+// ACE_Recursive_Thread_Mutex. Since Windows only supports timed
+// recursive process mutexes and not timed recursive thread mutexes,
+// use ACE_Process_Mutex.
+#if defined (ACE_HAS_WTHREADS)
+# include "ace/Process_Mutex.h"
+ typedef ACE_Process_Mutex ACE_TEST_MUTEX;
+#else
+# include "ace/Thread_Mutex.h"
+ typedef ACE_Recursive_Thread_Mutex ACE_TEST_MUTEX;
+#endif
+
+#if !defined (ACE_HAS_MUTEX_TIMEOUTS)
+static int reported_notsup = 0;
+#endif /* ACE_HAS_MUTEX_TIMEOUTS */
+
+// Total number of iterations.
+static int n_iterations = 100;
+static size_t n_threads = ACE_MAX_THREADS;
+
+static void
+test_recursion_depth (int nesting_level,
+ ACE_TEST_MUTEX *rm)
+{
+ if (nesting_level < n_iterations)
+ {
+ int result = rm->acquire ();
+ ACE_ASSERT (result == 0);
+#if !defined (ACE_HAS_WTHREADS)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) = acquired, nesting = %d, thread id = %u\n"),
+ rm->get_nesting_level (),
+ rm->get_thread_id ()));
+#endif /* !ACE_HAS_WTHREADS */
+
+ test_recursion_depth (nesting_level + 1,
+ rm);
+
+ result = rm->release ();
+ ACE_ASSERT (result == 0);
+#if !defined (ACE_HAS_WTHREADS)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) = released, nesting = %d, thread id = %u\n"),
+ rm->get_nesting_level (),
+ rm->get_thread_id ()));
+#endif /* !ACE_HAS_WTHREADS */
+ }
+}
+
+static void
+test_timed_wait (int nesting_level,
+ ACE_TEST_MUTEX *rm)
+{
+ // Make sure that we're inside of a recursive level.
+ if (nesting_level == 0)
+ test_timed_wait (nesting_level + 1,
+ rm);
+ else
+ {
+ ACE_OS::srand (ACE_OS::time (0));
+
+ for (size_t i = 0; i < ACE_MAX_ITERATIONS / 2; i++)
+ {
+ int result = 0;
+
+ // First attempt to acquire the mutex with a timeout to verify
+ // that mutex timeouts are working.
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) = trying timed acquire on ")
+ ACE_TEXT ("iteration %d\n"),
+ i));
+
+ ACE_Time_Value delta (1, 0); // One second timeout
+ ACE_Time_Value timeout = ACE_OS::gettimeofday ();
+ timeout += delta; // Must pass absolute time to acquire().
+
+ if (rm->acquire (timeout) != 0)
+ {
+ if (errno == ETIME)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) = mutex acquisition ")
+ ACE_TEXT ("timed out\n")));
+ else if (errno == ENOTSUP)
+ {
+#if !defined (ACE_HAS_MUTEX_TIMEOUTS)
+ if (!reported_notsup)
+ {
+ ACE_DEBUG ((LM_INFO,
+ ACE_TEXT ("(%P|%t) %p, but ACE_HAS_MUTEX_TIMEOUTS is not defined - Ok\n"),
+ ACE_TEXT ("mutex timed acquire")));
+ reported_notsup = 1;
+ }
+#else
+ ACE_DEBUG ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p - maybe ACE_HAS_MUTEX_TIMEOUTS should not be defined?\n"),
+ ACE_TEXT ("mutex timed acquire")));
+#endif /* ACE_HAS_MUTEX_TIMEOUTS */
+ }
+ else
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n%a"),
+ ACE_TEXT ("mutex timeout failed\n")));
+ return;
+ }
+ }
+ else
+ {
+ result = rm->release ();
+ ACE_ASSERT (result == 0);
+ }
+
+ // Now try the standard mutex.
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) = trying to acquire on iteration %d\n"),
+ i));
+ result = rm->acquire ();
+ ACE_ASSERT (result == 0);
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) = acquired on iteration %d\n"),
+ i));
+
+ // Sleep for a random amount of time between 0 and 2 seconds.
+ // Note that it's ok to use rand() here because we are running
+ // within the critical section defined by the Thread_Mutex.
+ ACE_OS::sleep (ACE_OS::rand () % 2);
+
+ result = rm->release ();
+ ACE_ASSERT (result == 0);
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) = released on iteration %d\n"),
+ i));
+
+ // Basic ACE_Guard usage - automatically acquire the mutex on
+ // guard construction and automatically release it on
+ // destruction.
+ {
+ // Construct an ACE_Guard to implicitly acquire the mutex.
+ ACE_Guard<ACE_TEST_MUTEX> guard (*rm);
+ ACE_ASSERT (guard.locked () != 0);
+
+ // Perform some operation which might exit the current scope
+ // prematurely, e.g. by returning or throwing an exception.
+ // ...
+
+ // ACE_Guard object is destroyed when exiting scope and guard
+ // destructor automatically releases mutex.
+ }
+
+ // Use an ACE_Guard to automatically acquire a mutex, but release
+ // the mutex early.
+ {
+ // Construct an ACE_Guard to implicitly acquire the mutex.
+ ACE_Guard<ACE_TEST_MUTEX> guard (*rm);
+ ACE_ASSERT (guard.locked () != 0);
+
+ // Perform some operation which might exit the current scope
+ // prematurely, e.g. by returning or throwing an exception.
+ // ...
+
+ // Release the mutex since we no longer need it.
+ guard.release ();
+ ACE_ASSERT (guard.locked () == 0);
+
+ // Do something else which does not require the mutex to be locked.
+ // ...
+
+ // ACE_Guard object's destructor will not release the mutex.
+ }
+
+ // Use an ACE_Guard to automatically acquire a mutex, but
+ // relinquish ownership of the lock so that the mutex is not
+ // automatically released on guard destruction. This is useful
+ // when an operation might not release the mutex in some
+ // conditions, in which case responsibility for releasing it is
+ // passed to someone else.
+ {
+ // Construct an ACE_Guard to implicitly acquire the mutex.
+ ACE_Guard<ACE_TEST_MUTEX> guard (*rm);
+ ACE_ASSERT (guard.locked () != 0);
+
+ // Perform some operation which might exit the current scope
+ // prematurely, e.g. by returning or throwing an exception.
+ // ...
+
+ // Relinquish ownership of the mutex lock. Someone else must
+ // now release it.
+ guard.disown ();
+ ACE_ASSERT (guard.locked () == 0);
+
+ // ACE_Guard object's destructor will not release the mutex.
+ }
+ // We are now responsible for releasing the mutex.
+ result = rm->release ();
+ ACE_ASSERT (result == 0);
+
+ // Construct an ACE_Guard without automatically acquiring the lock.
+ {
+ // Construct an ACE_Guard object without automatically
+ // acquiring the mutex or taking ownership of an existing
+ // lock. The third parameter tells the guard that the mutex
+ // has not been locked.
+ ACE_Guard<ACE_TEST_MUTEX> guard (*rm, 0, 0);
+ ACE_ASSERT (guard.locked () == 0);
+
+ // Conditionally acquire the mutex.
+ if (i % 2 == 0)
+ {
+ guard.acquire ();
+ ACE_ASSERT (guard.locked () != 0);
+ }
+
+ // Perform some operation that might exit the current scope
+ // prematurely, e.g. by returning or throwing an exception.
+ // ...
+
+ // ACE_Guard object is destroyed when exiting scope and guard
+ // destructor automatically releases if it was acquired above.
+ }
+
+ // Use an ACE_Guard to take ownership of a previously acquired
+ // mutex.
+ timeout = ACE_OS::gettimeofday ();
+ timeout += delta; // Must pass absolute time to acquire().
+ if (rm->acquire (timeout) == 0)
+ {
+ // Construct an ACE_Guard object without automatically
+ // acquiring the mutex, but instead take ownership of the
+ // existing lock. The third parameter tells the guard that
+ // the mutex has already been locked.
+ ACE_Guard<ACE_TEST_MUTEX> guard (*rm, 0, 1);
+ ACE_ASSERT (guard.locked () != 0);
+
+ // Perform some operation which might exit the current scope
+ // prematurely, e.g. by returning or throwing an exception.
+ // ...
+
+ // ACE_Guard object is destroyed when exiting scope and guard
+ // destructor automatically releases mutex.
+ }
+ }
+
+ return;
+ }
+}
+
+static void *
+recursion_worker (void *arg)
+{
+ ACE_TEST_MUTEX *rm =
+ reinterpret_cast<ACE_TEST_MUTEX *> (arg);
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("%P|%t) Starting test of recursion depth\n")));
+ test_recursion_depth (0, rm);
+
+ return 0;
+}
+
+static void *
+timed_worker (void *arg)
+{
+ ACE_TEST_MUTEX *rm =
+ reinterpret_cast<ACE_TEST_MUTEX *> (arg);
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("%P|%t) Starting test of timed wait\n")));
+ test_timed_wait (0, rm);
+
+ return 0;
+}
+
+#endif /* ACE_HAS_THREADS */
+
+int
+run_main (int argc, ACE_TCHAR *argv[])
+{
+ ACE_START_TEST (ACE_TEXT ("Recursive_Mutex_Test"));
+
+#if defined (ACE_HAS_THREADS)
+ if (argc > 1)
+ {
+ n_threads = ACE_OS::atoi (argv[1]);
+ }
+
+ ACE_TEST_MUTEX rm;
+
+ ACE_Thread_Manager::instance ()->spawn_n (n_threads,
+ ACE_THR_FUNC (recursion_worker),
+ (void *) &rm);
+ ACE_Thread_Manager::instance ()->wait ();
+
+ ACE_Thread_Manager::instance ()->spawn_n (n_threads,
+ ACE_THR_FUNC (timed_worker),
+ (void *) &rm);
+ ACE_Thread_Manager::instance ()->wait ();
+#else
+ ACE_UNUSED_ARG (argc);
+ ACE_UNUSED_ARG (argv);
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("ACE doesn't support recursive process ")
+ ACE_TEXT ("mutexes on this platform\n")));
+#endif /* ACE_HAS_THREADS */
+ ACE_END_TEST;
+ return 0;
+}
diff --git a/ACE/tests/Refcounted_Auto_Ptr_Test.cpp b/ACE/tests/Refcounted_Auto_Ptr_Test.cpp
new file mode 100644
index 00000000000..fd6552a89b1
--- /dev/null
+++ b/ACE/tests/Refcounted_Auto_Ptr_Test.cpp
@@ -0,0 +1,497 @@
+// $Id$
+
+//=============================================================================
+/**
+ * @file Refcounted_Auto_Ptr_Test.cpp
+ *
+ * $Id$
+ *
+ * This example tests the <ACE_Refcounted_Auto_Ptr> and illustrates
+ * how they may be dispersed between multiple threads using an
+ * implementation of the Active Object pattern, which is available
+ * at <http://www.cs.wustl.edu/~schmidt/PDF/Act-Obj.pdf>.
+ *
+ *
+ * @author Johnny Tucker <johnny_tucker@yahoo.com>
+ */
+//=============================================================================
+
+
+#include "test_config.h"
+#include "ace/ACE.h"
+#include "ace/Task.h"
+#include "ace/Message_Queue.h"
+#include "ace/Method_Request.h"
+#include "ace/Null_Mutex.h"
+#include "ace/Activation_Queue.h"
+#include "ace/Refcounted_Auto_Ptr.h"
+#include "Refcounted_Auto_Ptr_Test.h"
+
+ACE_RCSID (tests,
+ Refcounted_Auto_Ptr_Test,
+ "$Id$")
+
+ACE_Atomic_Op<ACE_SYNCH_MUTEX, unsigned int> Printer::current_instance_ (0);
+ACE_Atomic_Op<ACE_SYNCH_MUTEX, long> Printer::instance_count_ (0);
+
+Printer::Printer (const char *message)
+ : message_ (message)
+{
+ this->which_ = ++Printer::current_instance_;
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Creating Printer object %d (%C)\n"),
+ this->which_,
+ this->message_));
+ ++Printer::instance_count_;
+}
+
+Printer::~Printer (void)
+{
+ --Printer::instance_count_;
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Deleting Printer object %d (%C)\n"),
+ this->which_,
+ this->message_));
+}
+
+void
+Printer::print (void)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) %C\n"),
+ this->message_));
+}
+
+#if defined (ACE_HAS_THREADS)
+
+typedef ACE_Refcounted_Auto_Ptr<Printer, ACE_Thread_Mutex> Printer_var;
+
+/**
+ * @class Scheduler
+ *
+ * @brief The scheduler for the Active Object.
+ *
+ * This class also plays the role of the Proxy and the Servant
+ * in the Active Object pattern. Naturally, these roles could
+ * be split apart from the Scheduler.
+ */
+class Scheduler : public ACE_Task<ACE_SYNCH>
+{
+
+ friend class Method_Request_print;
+ friend class Method_Request_end;
+public:
+ // = Initialization and termination methods.
+ /// Constructor.
+ Scheduler (Scheduler * = 0);
+
+ /// Initializer.
+ virtual int open (void *args = 0);
+
+ /// Terminator.
+ virtual int close (u_long flags = 0);
+
+ /// Destructor.
+ virtual ~Scheduler (void);
+
+ // = These methods are part of the Active Object Proxy interface.
+ void print (Printer_var &printer);
+ void end (void);
+
+protected:
+ /// Runs the Scheduler's event loop, which dequeues <Method_Requests>
+ /// and dispatches them.
+ virtual int svc (void);
+
+private:
+ // = These are the <Scheduler> implementation details.
+ ACE_Activation_Queue activation_queue_;
+ Scheduler *scheduler_;
+};
+
+/**
+ * @class Method_Request_print
+ *
+ * @brief Reification of the <print> method.
+ */
+class Method_Request_print : public ACE_Method_Request
+{
+public:
+ Method_Request_print (Scheduler *,
+ Printer_var &printer);
+ virtual ~Method_Request_print (void);
+
+ /// This is the entry point into the Active Object method.
+ virtual int call (void);
+
+private:
+ Scheduler *scheduler_;
+ Printer_var printer_;
+};
+
+Method_Request_print::Method_Request_print (Scheduler *new_scheduler,
+ Printer_var &printer)
+ : scheduler_ (new_scheduler),
+ printer_ (printer)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Method_Request_print created\n")));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Printer reference count: %d\n"),
+ printer_.count ()));
+}
+
+Method_Request_print::~Method_Request_print (void)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Method_Request_print will be deleted.\n")));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Printer reference count: %d\n"),
+ printer_.count ()));
+}
+
+int
+Method_Request_print::call (void)
+{
+ // Dispatch the Servant's operation and store the result into the
+ // Future.
+ Printer_var temp = printer_;
+
+ temp->print ();
+
+ return 0;
+}
+
+/**
+ * @class Method_Request_end
+ *
+ * @brief Reification of the <end> method.
+ */
+class Method_Request_end : public ACE_Method_Request
+{
+public:
+ Method_Request_end (Scheduler *new_Prime_Scheduler);
+ virtual ~Method_Request_end (void);
+ virtual int call (void);
+
+private:
+ Scheduler *scheduler_;
+};
+
+Method_Request_end::Method_Request_end (Scheduler *scheduler)
+ : scheduler_ (scheduler)
+{
+}
+
+Method_Request_end::~Method_Request_end (void)
+{
+}
+
+int
+Method_Request_end::call (void)
+{
+ // Shut down the scheduler by deactivating the activation queue's
+ // underlying message queue - should pop all worker threads off their
+ // wait and they'll exit.
+ this->scheduler_->msg_queue ()->deactivate ();
+ return -1;
+}
+
+// Constructor
+// Associates the activation queue with this task's message queue,
+// allowing easy access to the message queue for shutting it down
+// when it's time to stop this object's service threads.
+Scheduler::Scheduler (Scheduler *new_scheduler)
+ : activation_queue_ (msg_queue ()), scheduler_ (new_scheduler)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Scheduler created\n")));
+}
+
+// Destructor
+
+Scheduler::~Scheduler (void)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Scheduler will be destroyed\n")));
+}
+
+// open
+
+int
+Scheduler::open (void *)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Scheduler open\n")));
+ // Become an Active Object.
+ int num_threads = 3;
+ return this->activate (THR_BOUND | THR_JOINABLE, num_threads);
+}
+
+// close
+
+int
+Scheduler::close (u_long)
+{
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) rundown\n")));
+ return 0;
+}
+
+// Service..
+
+int
+Scheduler::svc (void)
+{
+ for (;;)
+ {
+ // Dequeue the next method request (we use an auto pointer in
+ // case an exception is thrown in the <call>).
+ ACE_Method_Request *mo_p = this->activation_queue_.dequeue ();
+ if (0 == mo_p)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) activation queue shut down\n")));
+ break;
+ }
+ auto_ptr<ACE_Method_Request> mo (mo_p);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) calling method request\n")));
+ // Call it.
+ if(mo->call () == -1)
+ break;
+
+ // Destructor automatically deletes it.
+ }
+
+ return 0;
+}
+
+void
+Scheduler::end (void)
+{
+ this->activation_queue_.enqueue (new Method_Request_end (this));
+}
+
+// Here's where the work takes place.
+
+void
+Scheduler::print (Printer_var &printer)
+{
+ this->activation_queue_.enqueue
+ (new Method_Request_print (this,
+ printer));
+}
+
+// Total number of loops.
+static int n_loops = 10;
+
+#endif /* ACE_HAS_THREADS */
+
+
+// This will be used in a single thread to test the reset and release
+// methods. See Bugzilla #1925 for history.
+
+typedef ACE_Refcounted_Auto_Ptr <Printer, ACE_Null_Mutex> Printer_Ptr;
+
+static bool expect (const ACE_TCHAR *name,
+ const Printer_Ptr &ptr,
+ bool expect_null,
+ unsigned int expect_which,
+ int expect_count)
+{
+ if (ptr.null () != expect_null)
+ {
+ if (expect_null)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Expecting: %s null:: ")
+ ACE_TEXT ("Actual: Printer: %u; Count %d\n"),
+ name,
+ ptr->which_,
+ ptr.count ()));
+ else
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Expecting: %s Printer: %u; Count %d:: ")
+ ACE_TEXT ("Actual: Null.\n"),
+ name,
+ expect_which,
+ expect_count));
+ return false;
+ }
+ if (ptr.null ())
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Expecting: %s null:: Actual: Null.\n"),
+ name));
+ return true;
+ }
+
+ // Note that count is zero based (0 means one reference, etc.)
+ bool fail = (expect_which != ptr->which_) || (expect_count != ptr.count ());
+ ACE_DEBUG ((fail ? LM_ERROR : LM_DEBUG,
+ ACE_TEXT ("Expecting: %s Printer: %u; Count %d:: ")
+ ACE_TEXT ("Actual: Printer: %u; Count %d\n"),
+ name,
+ expect_which,
+ expect_count,
+ ptr->which_,
+ ptr.count ()));
+ return !fail;
+}
+
+static int test_reset_release (void)
+{
+ int errors = 0;
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Test copy constructor\n")));
+ Printer_Ptr bar = new Printer ("1");
+ Printer_Ptr fum = bar;
+ if (!expect (ACE_TEXT ("bar"), bar, false, 1, 1))
+ ++errors;
+ if (!expect (ACE_TEXT ("fum"), fum, false, 1, 1))
+ ++errors;
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Test reset to a new value\n")));
+ bar.reset (new Printer ("2"));
+ if (!expect (ACE_TEXT ("bar"), bar, false, 2, 0))
+ ++errors;
+ if (!expect (ACE_TEXT ("fum"), fum, false, 1, 0))
+ ++errors;
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Test release\n")));
+ Printer_Ptr fie = new Printer ("3");
+ Printer_Ptr foe = fie;
+ foe.release();
+ if (!expect (ACE_TEXT ("fie"), fie, false, 3, 0))
+ ++errors;
+ if (!expect (ACE_TEXT ("foe"), foe, true, 0, 0))
+ ++errors;
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Test assignment to null\n")));
+ Printer_Ptr fee = new Printer ("4");
+ Printer_Ptr eraser;
+ fee = eraser;
+ if (!expect (ACE_TEXT ("fee"), fee, true, 0, 0))
+ ++errors;
+ if (!expect (ACE_TEXT ("eraser"), eraser, true, 0, 0))
+ ++errors;
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Test assignment to value\n")));
+ Printer_Ptr fix = new Printer ("5");
+ Printer_Ptr fax = new Printer ("6");
+ fix = fax;
+ if (!expect (ACE_TEXT ("fix"), fix, false, 6, 1))
+ ++errors;
+ if (!expect (ACE_TEXT ("fax"), fax, false, 6, 1))
+ ++errors;
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Test reset to null\n")));
+ Printer_Ptr fey = new Printer ("7");
+ Printer_Ptr flo = fey;
+ flo.reset ();
+ if (!expect (ACE_TEXT ("fey"), fey, false, 7, 0))
+ ++errors;
+ if (!expect (ACE_TEXT ("flo"), flo, true, 0, 0))
+ ++errors;
+
+ return errors;
+}
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("Refcounted_Auto_Ptr_Test"));
+
+ int test_errors = 0;
+
+ // =========================================================================
+ // The following test uses the ACE_Refcounted_Auto_Ptr in a single
+ // thread of control, hence we use the ACE_Null_Mutex
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) performing synchronous tests...\n")));
+
+ test_errors += test_reset_release ();
+
+ Printer *printer1;
+ ACE_NEW_RETURN (printer1,
+ Printer ("I am printer 1"),
+ -1);
+ {
+ ACE_Refcounted_Auto_Ptr<Printer, ACE_Null_Mutex> r(printer1);
+ ACE_Refcounted_Auto_Ptr<Printer, ACE_Null_Mutex> r1(r);
+ ACE_Refcounted_Auto_Ptr<Printer, ACE_Null_Mutex> r2(r);
+ ACE_Refcounted_Auto_Ptr<Printer, ACE_Null_Mutex> r3(r);
+ ACE_Refcounted_Auto_Ptr<Printer, ACE_Null_Mutex> r4(r);
+ ACE_Refcounted_Auto_Ptr<Printer, ACE_Null_Mutex> r5 = r2;
+ ACE_Refcounted_Auto_Ptr<Printer, ACE_Null_Mutex> r6 = r1;
+ }
+ if (Printer::instance_count_ == 0)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Printer instance count is 0; correct\n")));
+ else
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%t) Printer instance count %d; expecting 0\n"),
+ Printer::instance_count_.value ()));
+ ++test_errors;
+ }
+
+#if defined (ACE_HAS_THREADS)
+
+ // =========================================================================
+ // The following test uses the ACE_Refcounted_Auto_Ptr in multiple
+ // threads of control.
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) performing asynchronous test...\n")));
+
+ Scheduler *scheduler_ptr;
+
+ // Create active objects..
+ ACE_NEW_RETURN (scheduler_ptr,
+ Scheduler (),
+ -1);
+
+ auto_ptr<Scheduler> scheduler(scheduler_ptr);
+
+ if (scheduler->open () == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("Error opening scheduler")),
+ 1);
+
+ {
+ ACE_NEW_RETURN (printer1,
+ Printer ("I am printer 2"),
+ -1);
+
+ Printer_var r (printer1);
+
+ for (int i = 0; i < n_loops; i++)
+ // Spawn off the methods, which run in a separate thread as
+ // active object invocations.
+ scheduler->print (r);
+ }
+
+ // Close things down.
+ scheduler->end ();
+
+ scheduler->wait ();
+
+ if (Printer::instance_count_ == 0)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Printer instance count is 0; correct\n")));
+ else
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%t) Printer instance count %d; expecting 0\n"),
+ Printer::instance_count_.value ()));
+ ++test_errors;
+ }
+
+#endif /* ACE_HAS_THREADS */
+ ACE_END_TEST;
+
+ return test_errors;
+}
diff --git a/ACE/tests/Refcounted_Auto_Ptr_Test.h b/ACE/tests/Refcounted_Auto_Ptr_Test.h
new file mode 100644
index 00000000000..745b7239c3d
--- /dev/null
+++ b/ACE/tests/Refcounted_Auto_Ptr_Test.h
@@ -0,0 +1,39 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Refcounted_Auto_Ptr_Test.h
+//
+// = DESCRIPTION
+// Define class needed for generating templates. IBM C++ requires this to
+// be in its own file for auto template instantiation.
+//
+// = AUTHOR
+// Steve Huston <shuston@riverace.com>
+//
+// ============================================================================
+
+#ifndef ACE_TESTS_REFCOUNTED_AUTO_PTR_TEST_H
+#define ACE_TESTS_REFCOUNTED_AUTO_PTR_TEST_H
+
+#include "ace/Atomic_Op.h"
+#include "ace/Synch.h"
+
+struct Printer
+{
+ Printer (const char *message);
+ ~Printer (void) ;
+
+ void print (void);
+
+ const char *message_;
+ unsigned int which_;
+ static ACE_Atomic_Op<ACE_SYNCH_MUTEX, unsigned int> current_instance_;
+ static ACE_Atomic_Op<ACE_SYNCH_MUTEX, long> instance_count_;
+};
+
+#endif /* ACE_TESTS_REFCOUNTED_AUTO_PTR_TEST_H */
diff --git a/ACE/tests/Reference_Counted_Event_Handler_Test.cpp b/ACE/tests/Reference_Counted_Event_Handler_Test.cpp
new file mode 100644
index 00000000000..1e947135d6d
--- /dev/null
+++ b/ACE/tests/Reference_Counted_Event_Handler_Test.cpp
@@ -0,0 +1,1015 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Reference_Counted_Event_Handler_Test.cpp
+//
+// = DESCRIPTION
+// This test is used to check reference counting of the Event
+// Handler when it interacts with the Reactor.
+//
+// = AUTHOR
+// Irfan Pyarali <irfan@oomworks.com>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/Reactor.h"
+#include "ace/Select_Reactor.h"
+#include "ace/TP_Reactor.h"
+#include "ace/WFMO_Reactor.h"
+#include "ace/Get_Opt.h"
+#include "ace/ACE.h"
+
+ACE_RCSID(tests, Reference_Counted_Event_Handler_Test, "$Id$")
+
+static const char message[] = "abcdefghijklmnopqrstuvwxyz";
+static const int message_size = 26;
+static int test_select_reactor = 1;
+static int test_tp_reactor = 1;
+static int test_wfmo_reactor = 1;
+static int test_io = 1;
+static int test_timers = 1;
+static int test_find = 1;
+static int test_simple_event_handler = 1;
+static int test_reference_counted_event_handler_1 = 1;
+static int test_reference_counted_event_handler_2 = 1;
+static int test_closed_in_upcall_event_handler = 1;
+static int debug = 1;
+static const char *one_second_timeout = "one second timeout";
+static const char *two_second_timeout = "two second timeout";
+
+class Reference_Counted_Event_Handler : public ACE_Event_Handler
+{
+public:
+
+ Reference_Counted_Event_Handler (int &events);
+
+ ~Reference_Counted_Event_Handler (void);
+
+ int handle_input (ACE_HANDLE);
+
+ int handle_output (ACE_HANDLE);
+
+ int handle_timeout (const ACE_Time_Value &,
+ const void *);
+
+ int handle_signal (int, siginfo_t *, ucontext_t *);
+
+ int handle_close (ACE_HANDLE,
+ ACE_Reactor_Mask);
+
+ ACE_Event_Handler::Reference_Count add_reference (void);
+
+ ACE_Event_Handler::Reference_Count remove_reference (void);
+
+ ACE_Pipe pipe_;
+
+ int &events_;
+
+};
+
+Reference_Counted_Event_Handler::Reference_Counted_Event_Handler (int &events)
+ : events_ (events)
+{
+ int result =
+ this->pipe_.open ();
+
+ ACE_ASSERT (result == 0);
+ ACE_UNUSED_ARG (result);
+
+ this->reference_counting_policy ().value
+ (ACE_Event_Handler::Reference_Counting_Policy::ENABLED);
+
+ ACE_DEBUG ((LM_DEBUG,
+ "Reference count in Reference_Counted_Event_Handler() is %d\n",
+ this->reference_count_.value ()));
+}
+
+Reference_Counted_Event_Handler::~Reference_Counted_Event_Handler (void)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ "Reference count in ~Reference_Counted_Event_Handler() is %d\n",
+ this->reference_count_.value ()));
+
+ this->pipe_.close ();
+}
+
+int
+Reference_Counted_Event_Handler::handle_input (ACE_HANDLE)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ "Reference count in Reference_Counted_Event_Handler::handle_input() is %d\n",
+ this->reference_count_.value ()));
+
+ --this->events_;
+
+ char buf[message_size + 1];
+
+ ssize_t result =
+ ACE::recv_n (this->pipe_.read_handle (),
+ buf,
+ sizeof buf - 1);
+
+ ACE_ASSERT (result == message_size);
+
+ buf[message_size] = '\0';
+
+ ACE_DEBUG ((LM_DEBUG,
+ "Message received: %s\n",
+ buf));
+
+ return 0;
+}
+
+int
+Reference_Counted_Event_Handler::handle_output (ACE_HANDLE)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ "Reference count in Reference_Counted_Event_Handler::handle_output() is %d\n",
+ this->reference_count_.value ()));
+
+ --this->events_;
+
+ ssize_t result =
+ ACE::send_n (this->pipe_.write_handle (),
+ message,
+ message_size);
+
+ ACE_ASSERT (result == message_size);
+
+ // No longer interested in output.
+ return -1;
+}
+
+int
+Reference_Counted_Event_Handler::handle_timeout (const ACE_Time_Value &,
+ const void *arg)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ "Reference count in Reference_Counted_Event_Handler::handle_timeout() for arg = %s is %d\n",
+ (const char *) arg,
+ this->reference_count_.value ()));
+
+ --this->events_;
+
+ return 0;
+}
+
+int
+Reference_Counted_Event_Handler::handle_signal (int,
+ siginfo_t *,
+ ucontext_t *)
+{
+ return 0;
+}
+
+int
+Reference_Counted_Event_Handler::handle_close (ACE_HANDLE handle,
+ ACE_Reactor_Mask masks)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ "Reference_Counted_Event_Handler::handle_close() called with handle = %d and masks = %d. "
+ "Reference count is %d\n",
+ handle,
+ masks,
+ this->reference_count_.value ()));
+
+ return 0;
+}
+
+ACE_Event_Handler::Reference_Count
+Reference_Counted_Event_Handler::add_reference (void)
+{
+ ACE_Event_Handler::Reference_Count reference_count =
+ this->ACE_Event_Handler::add_reference ();
+
+ ACE_DEBUG ((LM_DEBUG,
+ "Reference count after add_reference() is %d\n",
+ this->reference_count_.value ()));
+
+ return reference_count;
+}
+
+ACE_Event_Handler::Reference_Count
+Reference_Counted_Event_Handler::remove_reference (void)
+{
+ ACE_Event_Handler::Reference_Count reference_count =
+ this->ACE_Event_Handler::remove_reference ();
+
+ ACE_DEBUG ((LM_DEBUG,
+ "Reference count after remove_reference() is %d\n",
+ reference_count));
+
+ return reference_count;
+}
+
+void
+reference_counted_event_handler_test_1 (ACE_Reactor *reactor)
+{
+ int events = 0;
+ int result = 0;
+
+ Reference_Counted_Event_Handler *handler =
+ new Reference_Counted_Event_Handler (events);
+
+ ACE_Event_Handler_var safe_handler (handler);
+
+ if (test_io)
+ {
+ result =
+ reactor->register_handler (handler->pipe_.read_handle (),
+ handler,
+ ACE_Event_Handler::READ_MASK);
+ ACE_ASSERT (result == 0);
+
+ result =
+ reactor->register_handler (handler->pipe_.write_handle (),
+ handler,
+ ACE_Event_Handler::WRITE_MASK);
+ ACE_ASSERT (result == 0);
+
+ events += 2;
+ }
+
+ if (test_timers)
+ {
+ ACE_Time_Value const one_second (1);
+ long timer_id =
+ reactor->schedule_timer (handler,
+ one_second_timeout,
+ one_second,
+ one_second);
+ ACE_ASSERT (timer_id != -1);
+
+ result =
+ reactor->cancel_timer (timer_id,
+ 0,
+ 0);
+ ACE_ASSERT (result == 1);
+
+ timer_id =
+ reactor->schedule_timer (handler,
+ one_second_timeout,
+ one_second,
+ one_second);
+ ACE_ASSERT (timer_id != -1);
+
+ ACE_Time_Value const two_second (2);
+ timer_id =
+ reactor->schedule_timer (handler,
+ two_second_timeout,
+ two_second);
+ ACE_ASSERT (result != -1);
+
+ events += 3;
+ }
+
+ while (events > 0)
+ {
+ result =
+ reactor->handle_events ();
+ }
+}
+
+void
+reference_counted_event_handler_test_2 (ACE_Reactor *reactor)
+{
+ int events = 0;
+ int result = 0;
+ ACE_Time_Value const one_second (1);
+
+ if (test_find)
+ {
+ Reference_Counted_Event_Handler *handler =
+ new Reference_Counted_Event_Handler (events);
+
+ ACE_Event_Handler_var safe_handler (handler);
+
+ result =
+ reactor->register_handler (handler->pipe_.read_handle (),
+ handler,
+ ACE_Event_Handler::READ_MASK);
+ ACE_ASSERT (result == 0);
+
+ {
+ ACE_Event_Handler *result_handler = 0;
+
+ result =
+ reactor->handler (handler->pipe_.read_handle (),
+ ACE_Event_Handler::READ_MASK,
+ &result_handler);
+ ACE_Event_Handler_var safe_result_handler (result_handler);
+
+ ACE_ASSERT (result == 0);
+ ACE_ASSERT (result_handler == handler);
+ }
+
+ {
+ ACE_Event_Handler *result_handler = 0;
+
+ result =
+ reactor->handler (handler->pipe_.read_handle (),
+ ACE_Event_Handler::WRITE_MASK,
+ &result_handler);
+ ACE_Event_Handler_var safe_result_handler (result_handler);
+
+ ACE_ASSERT (result == -1);
+ }
+
+ {
+ ACE_Event_Handler_var result_handler =
+ reactor->find_handler (handler->pipe_.read_handle ());
+
+ ACE_ASSERT (result_handler.handler () == handler);
+ }
+ }
+
+ if (test_io)
+ {
+ Reference_Counted_Event_Handler *handler =
+ new Reference_Counted_Event_Handler (events);
+
+ ACE_Event_Handler_var safe_handler (handler);
+
+ result =
+ reactor->register_handler (handler->pipe_.read_handle (),
+ handler,
+ ACE_Event_Handler::READ_MASK);
+ ACE_ASSERT (result == 0);
+
+ result =
+ reactor->register_handler (handler->pipe_.write_handle (),
+ handler,
+ ACE_Event_Handler::WRITE_MASK);
+ ACE_ASSERT (result == 0);
+
+ events += 2;
+ }
+
+ if (test_timers)
+ {
+ Reference_Counted_Event_Handler *handler =
+ new Reference_Counted_Event_Handler (events);
+
+ ACE_Event_Handler_var safe_handler (handler);
+
+ long timer_id =
+ reactor->schedule_timer (handler,
+ one_second_timeout,
+ one_second,
+ one_second);
+ ACE_ASSERT (timer_id != -1);
+
+ result =
+ reactor->cancel_timer (timer_id,
+ 0,
+ 0);
+ ACE_ASSERT (result == 1);
+ }
+
+ if (test_timers)
+ {
+ Reference_Counted_Event_Handler *handler =
+ new Reference_Counted_Event_Handler (events);
+
+ ACE_Event_Handler_var safe_handler (handler);
+
+ long timer_id =
+ reactor->schedule_timer (handler,
+ one_second_timeout,
+ one_second,
+ one_second);
+ ACE_ASSERT (timer_id != -1);
+
+ ACE_Time_Value const two_second (2);
+ timer_id =
+ reactor->schedule_timer (handler,
+ two_second_timeout,
+ two_second);
+ ACE_ASSERT (result != -1);
+
+ events += 3;
+ }
+
+ while (events > 0)
+ {
+ result =
+ reactor->handle_events ();
+ }
+}
+
+void
+reference_count_1 (ACE_Reactor_Impl *impl)
+{
+ ACE_Reactor reactor (impl, 1);
+
+ ACE_DEBUG ((LM_DEBUG,
+ "\nTesting Reference Counted Event Handler Test 1....\n\n"));
+
+ reference_counted_event_handler_test_1 (&reactor);
+}
+
+void
+reference_count_2 (ACE_Reactor_Impl *impl)
+{
+ ACE_Reactor reactor (impl, 1);
+
+ ACE_DEBUG ((LM_DEBUG,
+ "\nTesting Reference Counted Event Handler Test 2....\n\n"));
+
+ reference_counted_event_handler_test_2 (&reactor);
+}
+
+class Simple_Event_Handler : public ACE_Event_Handler
+{
+public:
+
+ Simple_Event_Handler (int &events,
+ int close_count);
+
+ ~Simple_Event_Handler (void);
+
+ int handle_input (ACE_HANDLE);
+
+ int handle_output (ACE_HANDLE);
+
+ int handle_timeout (const ACE_Time_Value &,
+ const void *);
+
+ int handle_signal (int, siginfo_t *, ucontext_t *);
+
+ int handle_close (ACE_HANDLE,
+ ACE_Reactor_Mask);
+
+ ACE_Pipe pipe_;
+
+ int &events_;
+
+ int close_count_;
+
+};
+
+Simple_Event_Handler::Simple_Event_Handler (int &events,
+ int close_count)
+ : events_ (events),
+ close_count_ (close_count)
+{
+ int result =
+ this->pipe_.open ();
+
+ ACE_ASSERT (result == 0);
+ ACE_UNUSED_ARG (result);
+
+ ACE_DEBUG ((LM_DEBUG,
+ "Simple_Event_Handler()\n"));
+}
+
+Simple_Event_Handler::~Simple_Event_Handler (void)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ "~Simple_Event_Handler()\n"));
+
+ this->pipe_.close ();
+}
+
+int
+Simple_Event_Handler::handle_input (ACE_HANDLE)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ "Simple_Event_Handler::handle_input()\n"));
+
+ --this->events_;
+
+ char buf[message_size + 1];
+
+ ssize_t result =
+ ACE::recv_n (this->pipe_.read_handle (),
+ buf,
+ sizeof buf - 1);
+
+ ACE_ASSERT (result == message_size);
+
+ buf[message_size] = '\0';
+
+ ACE_DEBUG ((LM_DEBUG,
+ "Message received: %s\n",
+ buf));
+
+ return 0;
+}
+
+int
+Simple_Event_Handler::handle_output (ACE_HANDLE)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ "Simple_Event_Handler::handle_output()\n"));
+
+ --this->events_;
+
+ ssize_t result =
+ ACE::send_n (this->pipe_.write_handle (),
+ message,
+ message_size);
+
+ ACE_ASSERT (result == message_size);
+
+ // No longer interested in output.
+ return -1;
+}
+
+int
+Simple_Event_Handler::handle_timeout (const ACE_Time_Value &,
+ const void *arg)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ "Simple_Event_Handler::handle_timeout() for arg = %s\n",
+ (const char *) arg));
+
+ --this->events_;
+
+ return 0;
+}
+
+int
+Simple_Event_Handler::handle_signal (int,
+ siginfo_t *,
+ ucontext_t *)
+{
+ return 0;
+}
+
+int
+Simple_Event_Handler::handle_close (ACE_HANDLE handle,
+ ACE_Reactor_Mask masks)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ "Simple_Event_Handler::handle_close() called with handle = %d and masks = %d with close count = %d.\n",
+ handle,
+ masks,
+ --this->close_count_));
+
+ if (this->close_count_ == 0)
+ delete this;
+
+ return 0;
+}
+
+void
+simple_event_handler (ACE_Reactor *reactor)
+{
+ int events = 0;
+ int result = 0;
+ ACE_Time_Value const one_second (1);
+
+ if (test_find)
+ {
+ Simple_Event_Handler handler (events,
+ 0);
+
+ result =
+ reactor->register_handler (handler.pipe_.read_handle (),
+ &handler,
+ ACE_Event_Handler::READ_MASK);
+ ACE_ASSERT (result == 0);
+
+ {
+ ACE_Event_Handler *result_handler = 0;
+
+ result =
+ reactor->handler (handler.pipe_.read_handle (),
+ ACE_Event_Handler::READ_MASK,
+ &result_handler);
+ ACE_Event_Handler_var safe_result_handler (result_handler);
+
+ ACE_ASSERT (result == 0);
+ ACE_ASSERT (result_handler == &handler);
+ }
+
+ {
+ ACE_Event_Handler *result_handler = 0;
+
+ result =
+ reactor->handler (handler.pipe_.read_handle (),
+ ACE_Event_Handler::WRITE_MASK,
+ &result_handler);
+ ACE_Event_Handler_var safe_result_handler (result_handler);
+
+ ACE_ASSERT (result == -1);
+ }
+
+ {
+ ACE_Event_Handler_var result_handler =
+ reactor->find_handler (handler.pipe_.read_handle ());
+
+ ACE_ASSERT (result_handler.handler () == &handler);
+ }
+
+ result =
+ reactor->remove_handler (handler.pipe_.read_handle (),
+ ACE_Event_Handler::ALL_EVENTS_MASK | ACE_Event_Handler::DONT_CALL);
+
+ ACE_ASSERT (result == 0);
+ }
+
+ if (test_io)
+ {
+ Simple_Event_Handler *handler =
+ new Simple_Event_Handler (events,
+ 2);
+
+ result =
+ reactor->register_handler (handler->pipe_.read_handle (),
+ handler,
+ ACE_Event_Handler::READ_MASK);
+ ACE_ASSERT (result == 0);
+
+ result =
+ reactor->register_handler (handler->pipe_.write_handle (),
+ handler,
+ ACE_Event_Handler::WRITE_MASK);
+ ACE_ASSERT (result == 0);
+
+ events += 2;
+ }
+
+ if (test_timers)
+ {
+ Simple_Event_Handler *handler =
+ new Simple_Event_Handler (events,
+ 1);
+
+ long timer_id =
+ reactor->schedule_timer (handler,
+ one_second_timeout,
+ one_second,
+ one_second);
+ ACE_ASSERT (timer_id != -1);
+
+ result =
+ reactor->cancel_timer (timer_id,
+ 0,
+ 0);
+ ACE_ASSERT (result == 1);
+ }
+
+ if (test_timers)
+ {
+ Simple_Event_Handler *handler =
+ new Simple_Event_Handler (events,
+ 1);
+
+ long timer_id =
+ reactor->schedule_timer (handler,
+ one_second_timeout,
+ one_second,
+ one_second);
+ ACE_ASSERT (timer_id != -1);
+
+ ACE_Time_Value const two_second (2);
+ timer_id =
+ reactor->schedule_timer (handler,
+ two_second_timeout,
+ two_second);
+ ACE_ASSERT (result != -1);
+
+ events += 3;
+ }
+
+ while (events > 0)
+ {
+ result =
+ reactor->handle_events ();
+ }
+}
+
+void
+simple (ACE_Reactor_Impl *impl)
+{
+ ACE_Reactor reactor (impl, 1);
+
+ ACE_DEBUG ((LM_DEBUG,
+ "\nTesting Simple Event Handler....\n\n"));
+
+ simple_event_handler (&reactor);
+}
+
+class Closed_In_Upcall_Event_Handler : public ACE_Event_Handler
+{
+public:
+
+ Closed_In_Upcall_Event_Handler (int &events);
+
+ ~Closed_In_Upcall_Event_Handler (void);
+
+ int handle_input (ACE_HANDLE);
+
+ int handle_close (ACE_HANDLE,
+ ACE_Reactor_Mask);
+
+ ACE_Event_Handler::Reference_Count add_reference (void);
+
+ ACE_Event_Handler::Reference_Count remove_reference (void);
+
+ ACE_Pipe pipe_;
+
+ int &events_;
+
+};
+
+Closed_In_Upcall_Event_Handler::Closed_In_Upcall_Event_Handler (int &events)
+ : events_ (events)
+{
+ int result =
+ this->pipe_.open ();
+
+ ACE_ASSERT (result == 0);
+ ACE_UNUSED_ARG (result);
+
+ this->reference_counting_policy ().value
+ (ACE_Event_Handler::Reference_Counting_Policy::ENABLED);
+
+ ACE_DEBUG ((LM_DEBUG,
+ "Closed_In_Upcall_Event_Handler()\n"));
+}
+
+Closed_In_Upcall_Event_Handler::~Closed_In_Upcall_Event_Handler (void)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ "~Closed_In_Upcall_Event_Handler()\n"));
+
+ this->pipe_.close ();
+}
+
+int
+Closed_In_Upcall_Event_Handler::handle_input (ACE_HANDLE)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ "Closed_In_Upcall_Event_Handler::handle_input()\n"));
+
+ this->events_--;
+
+ int result =
+ this->reactor ()->remove_handler (this->pipe_.read_handle (),
+ ACE_Event_Handler::ALL_EVENTS_MASK);
+ ACE_ASSERT (result == 0);
+ ACE_UNUSED_ARG (result);
+
+ char buf[message_size + 1];
+
+ ssize_t recv_result =
+ ACE::recv_n (this->pipe_.read_handle (),
+ buf,
+ sizeof buf - 1);
+
+ ACE_ASSERT (recv_result == message_size);
+
+ buf[message_size] = '\0';
+
+ ACE_DEBUG ((LM_DEBUG,
+ "Message received: %s\n",
+ buf));
+
+ return 0;
+}
+
+int
+Closed_In_Upcall_Event_Handler::handle_close (ACE_HANDLE handle,
+ ACE_Reactor_Mask masks)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ "Closed_In_Upcall_Event_Handler::handle_close() called with handle = %d and masks = %d. "
+ "Reference count is %d\n",
+ handle,
+ masks,
+ this->reference_count_.value ()));
+
+ return 0;
+}
+
+ACE_Event_Handler::Reference_Count
+Closed_In_Upcall_Event_Handler::add_reference (void)
+{
+ ACE_Event_Handler::Reference_Count reference_count =
+ this->ACE_Event_Handler::add_reference ();
+
+ ACE_DEBUG ((LM_DEBUG,
+ "Reference count after add_reference() is %d\n",
+ this->reference_count_.value ()));
+
+ return reference_count;
+}
+
+ACE_Event_Handler::Reference_Count
+Closed_In_Upcall_Event_Handler::remove_reference (void)
+{
+ ACE_Event_Handler::Reference_Count reference_count =
+ this->ACE_Event_Handler::remove_reference ();
+
+ ACE_DEBUG ((LM_DEBUG,
+ "Reference count after remove_reference() is %d\n",
+ reference_count));
+
+ return reference_count;
+}
+
+void
+closed_in_upcall_event_handler (ACE_Reactor *reactor)
+{
+ int events = 0;
+ int handle_events_result = 0;
+
+ if (test_io)
+ {
+ Closed_In_Upcall_Event_Handler *handler = 0;
+ ACE_NEW (handler, Closed_In_Upcall_Event_Handler (events));
+
+ ACE_Event_Handler_var safe_handler (handler);
+
+ ssize_t send_n_result =
+ ACE::send_n (handler->pipe_.write_handle (),
+ message,
+ message_size);
+
+ ACE_ASSERT (send_n_result == message_size);
+
+ int register_handler_result =
+ reactor->register_handler (handler->pipe_.read_handle (),
+ handler,
+ ACE_Event_Handler::READ_MASK);
+ ACE_ASSERT (register_handler_result == 0);
+
+ events += 1;
+ }
+
+ while (events > 0)
+ {
+ handle_events_result =
+ reactor->handle_events ();
+ }
+}
+
+void
+closed_in_upcall (ACE_Reactor_Impl *impl)
+{
+ ACE_Reactor reactor (impl, 1);
+
+ ACE_DEBUG ((LM_DEBUG,
+ "\nTesting Closed in Upcall Event Handler....\n\n"));
+
+ closed_in_upcall_event_handler (&reactor);
+}
+
+template <class REACTOR_IMPLEMENTATION>
+class test
+{
+public:
+ test (void);
+};
+
+template <class REACTOR_IMPLEMENTATION>
+test<REACTOR_IMPLEMENTATION>::test (void)
+{
+ if (test_simple_event_handler)
+ simple (new REACTOR_IMPLEMENTATION);
+
+ if (test_reference_counted_event_handler_1)
+ reference_count_1 (new REACTOR_IMPLEMENTATION);
+
+ if (test_reference_counted_event_handler_2)
+ reference_count_2 (new REACTOR_IMPLEMENTATION);
+
+ if (test_closed_in_upcall_event_handler)
+ closed_in_upcall (new REACTOR_IMPLEMENTATION);
+}
+
+static int
+parse_args (int argc, ACE_TCHAR *argv[])
+{
+ ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("a:b:c:f:g:h:i:k:l:m:z:"));
+
+ int cc;
+ while ((cc = get_opt ()) != -1)
+ {
+ switch (cc)
+ {
+ case 'a':
+ test_select_reactor = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'b':
+ test_tp_reactor = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'c':
+ test_wfmo_reactor = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'f':
+ test_simple_event_handler = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'g':
+ test_reference_counted_event_handler_1 = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'h':
+ test_reference_counted_event_handler_2 = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'i':
+ test_closed_in_upcall_event_handler = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'k':
+ test_io = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'l':
+ test_timers = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'm':
+ test_find = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'z':
+ debug = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case '?':
+ case 'u':
+ default:
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("\nusage: %s \n\n")
+ ACE_TEXT ("\t[-a test Select Reactor] (defaults to %d)\n")
+ ACE_TEXT ("\t[-b test TP Reactor] (defaults to %d)\n")
+ ACE_TEXT ("\t[-c test WFMO Reactor] (defaults to %d)\n")
+ ACE_TEXT ("\t[-f test simple event handler] (defaults to %d)\n")
+ ACE_TEXT ("\t[-g test reference counted event handler (first test)] (defaults to %d)\n")
+ ACE_TEXT ("\t[-h test reference counted event handler (second test)] (defaults to %d)\n")
+ ACE_TEXT ("\t[-i test closed in upcall event handler] (defaults to %d)\n")
+ ACE_TEXT ("\t[-k test io] (defaults to %d)\n")
+ ACE_TEXT ("\t[-l test timers] (defaults to %d)\n")
+ ACE_TEXT ("\t[-m test find] (defaults to %d)\n")
+ ACE_TEXT ("\t[-z debug] (defaults to %d)\n")
+ ACE_TEXT ("\n"),
+ argv[0],
+ test_select_reactor,
+ test_tp_reactor,
+ test_wfmo_reactor,
+ test_simple_event_handler,
+ test_reference_counted_event_handler_1,
+ test_reference_counted_event_handler_2,
+ test_closed_in_upcall_event_handler,
+ test_io,
+ test_timers,
+ test_find,
+ debug));
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+int
+run_main (int argc, ACE_TCHAR *argv[])
+{
+ ACE_START_TEST (ACE_TEXT ("Reference_Counted_Event_Handler_Test"));
+
+ // Validate options.
+ int result =
+ parse_args (argc, argv);
+ if (result != 0)
+ return result;
+
+ if (test_select_reactor)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ "\n\nTesting Select Reactor....\n\n"));
+
+ test<ACE_Select_Reactor> test;
+ ACE_UNUSED_ARG (test);
+ }
+
+ if (test_tp_reactor)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ "\n\nTesting TP Reactor....\n\n"));
+
+ test<ACE_TP_Reactor> test;
+ ACE_UNUSED_ARG (test);
+ }
+
+#if defined (ACE_WIN32)
+
+ if (test_wfmo_reactor)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ "\n\nTesting WFMO Reactor....\n\n"));
+
+ test<ACE_WFMO_Reactor> test;
+ ACE_UNUSED_ARG (test);
+ }
+
+#endif /* ACE_WIN32 */
+
+ ACE_END_TEST;
+
+ return 0;
+}
+
diff --git a/ACE/tests/Reverse_Lock_Test.cpp b/ACE/tests/Reverse_Lock_Test.cpp
new file mode 100644
index 00000000000..5ee08dafbee
--- /dev/null
+++ b/ACE/tests/Reverse_Lock_Test.cpp
@@ -0,0 +1,48 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Reverse_Lock_Test.cpp
+//
+// = DESCRIPTION
+// This is a simple test to illustrate the functionality of
+// ACE_Reverse_Lock. The test acquires and releases mutexes. No
+// command line arguments are needed to run the test.
+//
+// = AUTHOR
+// Irfan Pyarali <irfan@cs.wustl.edu>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/Synch_Traits.h"
+#include "ace/Thread_Mutex.h"
+#include "ace/Guard_T.h"
+#include "ace/Reverse_Lock_T.h"
+
+ACE_RCSID(tests, Reverse_Lock_Test, "$Id$")
+
+typedef ACE_Reverse_Lock<ACE_SYNCH_MUTEX> REVERSE_MUTEX;
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("Reverse_Lock_Test"));
+
+ ACE_SYNCH_MUTEX mutex;
+ REVERSE_MUTEX reverse_mutex (mutex);
+
+ {
+ ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, monitor, mutex, -1);
+
+ ACE_GUARD_RETURN (REVERSE_MUTEX, reverse_monitor, reverse_mutex, -1);
+ }
+
+ ACE_END_TEST;
+ return 0;
+}
+
diff --git a/ACE/tests/SOCK_Connector_Test.cpp b/ACE/tests/SOCK_Connector_Test.cpp
new file mode 100644
index 00000000000..0eee2d171d3
--- /dev/null
+++ b/ACE/tests/SOCK_Connector_Test.cpp
@@ -0,0 +1,316 @@
+// $Id$
+
+// ==========================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// SOCK_Connector_Test.cpp
+//
+// = DESCRIPTION
+// This is a test of ACE_SOCK_Connector, focusing on failure cases more
+// than on success cases.
+//
+// = AUTHOR
+// Steve Huston <shuston@riverace.com>
+//
+// ==========================================================================
+
+#include "test_config.h"
+#include "ace/OS_NS_string.h"
+#include "ace/INET_Addr.h"
+#include "ace/SOCK_Connector.h"
+#include "ace/Time_Value.h"
+#include "ace/SOCK_Stream.h"
+#include "ace/OS_NS_sys_utsname.h"
+#include "ace/OS_NS_netdb.h"
+
+ACE_RCSID(tests, SOCK_Connector_Test, "$Id$")
+
+// Host candidate list
+struct Host_Candidate
+{
+ ACE_TCHAR host_name[MAXHOSTNAMELEN];
+};
+
+const int MAX_CANDIDATES = 50;
+Host_Candidate candidate[MAX_CANDIDATES];
+
+#if !defined (ACE_LACKS_GETHOSTENT)
+// Determine if a host exists, is reachable, and is up. Attempt a
+// blocking connection to it; if it succeeds, then the host exists, is
+// reachable, and is up.
+
+static u_int
+host_is_up (ACE_TCHAR hostname[])
+{
+ ACE_SOCK_Connector con;
+ ACE_SOCK_Stream sock;
+
+ // The ACE_INET_Addr construction causes gethostbyname_r to be
+ // called, so we need to copy the hostname.
+ ACE_TCHAR test_host[MAXHOSTNAMELEN];
+ ACE_OS::strcpy (test_host, hostname);
+
+ ACE_INET_Addr another_host ((u_short) 7, test_host);
+ ACE_Time_Value timeout_value (5);
+ const int status = con.connect (sock,
+ another_host,
+ &timeout_value);
+ sock.close ();
+ return status == 0 ? 1 : 0;
+}
+#endif /* ! ACE_LACKS_GETHOSTENT */
+
+// The original problem this program tested for was incorrectly saying
+// a non-blocking connect completed successfully when it didn't. The
+// test doesn't always work when done to localhost
+// (platform-dependant) so we look around for another host - any other
+// one will do.
+
+static void
+find_another_host (ACE_TCHAR other_host[])
+{
+ static ACE_TCHAR cached_other_host[MAXHOSTNAMELEN] = {'\0'};
+
+ if (cached_other_host[0] == '\0')
+ {
+
+ ACE_OS::strcpy (other_host,
+ ACE_DEFAULT_SERVER_HOST); // If all else fails
+
+#if !defined (ACE_LACKS_GETHOSTENT)
+ // These gethost-type things don't work everywhere.
+ struct hostent *h;
+ ACE_utsname un;
+
+ ACE_OS::uname (&un);
+
+ h = ACE_OS::gethostbyname (un.nodename);
+
+ if (h == 0)
+ ACE_OS::strcpy (other_host, ACE_LOCALHOST);
+ else
+ // Use me if can't find another
+ ACE_OS::strcpy (other_host, ACE_TEXT_CHAR_TO_TCHAR (h->h_name));
+
+ // @@ We really need to add wrappers for these hostent methods.
+
+ // AIX 4.3 has problems with DNS usage when sethostent(1) is
+ // called - further DNS lookups don't work at all.
+#if defined (ACE_AIX_MINOR_VERS) && (ACE_AIX_MINOR_VERS == 3)
+ sethostent (0);
+#else
+ sethostent (1);
+#endif /* (ACE_AIX_MINOR_VERS) && (ACE_AIX_MINOR_VERS == 3) */
+
+ int candidate_count = 0;
+
+ // Accumulate candidates first. There is some interaction on
+ // Linux systems between <gethostent> and <gethostbyname_r>
+ // (called by ACE_INET_Addr in host_is_up) This otherwise causes
+ // an infinite loop on Linux --mas 03-08-2001
+ while ((h = gethostent ()) != 0)
+ {
+ if (ACE_OS::strcmp (h->h_name,
+ ACE_TEXT_ALWAYS_CHAR (ACE_DEFAULT_SERVER_HOST)) == 0)
+ continue;
+ // AIX just _has_ to be different
+ if (ACE_OS::strcmp (h->h_name, "loopback") == 0)
+ continue;
+
+ // If not me.
+ if (ACE_OS::strcmp
+ (h->h_name, ACE_TEXT_ALWAYS_CHAR (other_host)) != 0
+ && ACE_OS::strcmp (h->h_name, un.nodename) != 0)
+ {
+ ACE_OS::strcpy (candidate[candidate_count].host_name,
+ ACE_TEXT_CHAR_TO_TCHAR (h->h_name));
+ if (++candidate_count >= MAX_CANDIDATES)
+ break;
+ }
+ }
+
+ // Now try to connect to candidates
+ for (int i = 0; i < candidate_count; i++)
+ if (host_is_up (candidate[i].host_name))
+ {
+ ACE_OS::strcpy (other_host, candidate[i].host_name);
+ break;
+ }
+
+ endhostent ();
+#endif /* ! ACE_LACKS_GETHOSTENT */
+
+ ACE_OS::strcpy (cached_other_host, other_host);
+ }
+ else
+ ACE_OS::strcpy (other_host, cached_other_host);
+}
+
+static int
+fail_no_listener_nonblocking (void)
+{
+ ACE_TCHAR test_host[MAXHOSTNAMELEN];
+ int status;
+ ACE_INET_Addr nobody_home;
+ ACE_SOCK_Connector con;
+ ACE_SOCK_Stream sock;
+ ACE_Time_Value nonblock (0, 0);
+
+ find_another_host (test_host);
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Testing to host \"%s\"\n"),
+ test_host));
+
+ if (nobody_home.set ((u_short) 42000, test_host) == -1)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Host lookup for %s %p\n"),
+ test_host,
+ ACE_TEXT ("failed")));
+ return -1;
+ }
+
+ status = con.connect (sock, nobody_home, &nonblock);
+
+ // Need a port that will fail.
+ ACE_ASSERT (status == -1);
+
+ // On some systems, a failed connect to localhost will return
+ // ECONNREFUSED or ENETUNREACH directly, instead of
+ // EWOULDBLOCK. That is also fine.
+
+ if (errno == EWOULDBLOCK || errno == ECONNREFUSED || errno == ENETUNREACH)
+ {
+ if (sock.get_handle () != ACE_INVALID_HANDLE)
+ status = con.complete (sock);
+
+ if (status != -1)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Connect which should fail didn't\n")));
+ status = -1;
+ }
+ else
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("Proper fail")));
+ status = 0;
+ }
+ }
+ else
+ {
+ ACE_DEBUG ((LM_WARNING,
+ ACE_TEXT ("Test not executed fully; ")
+ ACE_TEXT ("expected EWOULDBLOCK, %p (%d)\n"),
+ ACE_TEXT ("not"), errno));
+ status = -1;
+ }
+
+ // Just in case.
+ sock.close ();
+
+ return status;
+}
+
+
+// This test tries to hit a port that's listening. Echo (7) is pretty
+// popular. Just in case, though, it won't report a failure if it
+// gets "refused" (no listener) since the real fixed bug this is
+// testing is a returned error of EWOULDBLOCK when the connect really
+// did work. That was a side-affect of how
+// <ACE::handle_timed_complete> does checks on some systems.
+
+static int
+succeed_nonblocking (void)
+{
+ ACE_TCHAR test_host[MAXHOSTNAMELEN];
+ int status;
+ ACE_INET_Addr echo_server;
+ ACE_SOCK_Connector con;
+ ACE_SOCK_Stream sock;
+ ACE_Time_Value nonblock (0, 0);
+ u_short test_port = 7; // Echo
+
+ find_another_host (test_host);
+ if (ACE_OS::strcmp (ACE_TEXT ("localhost"), test_host) == 0)
+ {
+#if defined (ACE_WIN32)
+ test_port = 80; // Echo not available on Win32; try web server
+#endif /* ACE_WIN32 */
+ }
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Testing to host \"%s\", port %d\n"),
+ test_host, test_port));
+ if (echo_server.set (test_port, test_host) == -1)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Host lookup for %s %p\n"),
+ test_host,
+ ACE_TEXT ("failed")));
+ return -1;
+ }
+ status = con.connect (sock, echo_server, &nonblock);
+
+ // Need to test the call to 'complete' really.
+ if (status == 0 || (status == -1 && errno != EWOULDBLOCK))
+ {
+ ACE_DEBUG((LM_WARNING,
+ ACE_TEXT ("Immediate success/fail; test not completed\n")));
+ status = 0;
+ }
+ else
+ {
+ if (sock.get_handle () != ACE_INVALID_HANDLE)
+ status = con.complete (sock);
+
+ if (status == -1)
+ {
+ // Reset the status _before_ doing the printout, in case the
+ // printout overwrites errno.
+ if (errno == ECONNREFUSED)
+ {
+ status = 0;
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Should succeed, but refused: ok\n")));
+ }
+ else
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT("%p\n"),
+ ACE_TEXT("connect should succeed, but")));
+ }
+ }
+ else
+ ACE_DEBUG((LM_DEBUG,
+ ACE_TEXT("Connect which should succeed, did\n")));
+ }
+
+ // Just in case.
+ sock.close ();
+
+ return status;
+}
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("SOCK_Connector_Test"));
+
+ int status = 0;
+
+ if (fail_no_listener_nonblocking () == -1)
+ status = 1;
+
+ if (succeed_nonblocking () == -1)
+ status = 1;
+
+ ACE_END_TEST;
+ return status;
+}
+
+
+
diff --git a/ACE/tests/SOCK_Dgram_Bcast_Test.cpp b/ACE/tests/SOCK_Dgram_Bcast_Test.cpp
new file mode 100644
index 00000000000..d20cb0a0d07
--- /dev/null
+++ b/ACE/tests/SOCK_Dgram_Bcast_Test.cpp
@@ -0,0 +1,256 @@
+// $Id$
+// ===========================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// SOCK_Dgram_Bcast_Test.cpp
+//
+// = DESCRIPTION
+// This simple broadcast test is intended to check if ACE is capable
+// of sending and receiving broadcasts. In single host environment most
+// errors related to invalid broadcast initialization will not manifest
+// themself, because usually broadcast on localhost interface works
+// correctly. For this reason one should run also this test on two distinct
+// hosts in single LAN.
+// Tests that a call to open with an any address binds to the any address
+// for the protocol passed in.
+//
+// = AUTHOR
+// Marek Brudka (mbrudka@elka.pw.edu.pl)
+//
+// ==========================================================================
+
+#include "test_config.h"
+#include "ace/OS_NS_string.h"
+#include "ace/OS_NS_unistd.h"
+#include "ace/OS_NS_sys_time.h"
+#include "ace/Log_Msg.h"
+#include "ace/Get_Opt.h"
+#include "ace/SOCK_Dgram_Bcast.h"
+#include "ace/Thread_Manager.h"
+#include "ace/Process.h"
+#include "ace/Process_Manager.h"
+
+static int dgram_port = 14521;
+static int dgrams_no = 10;
+static ACE_Time_Value dgram_recv_timeout( 5, 0 );
+static ACE_exitcode receiver_exit_code = 0;
+
+/*\brief Create and send single datagram
+ \param socket broadcast over this socket
+ \param datagram_no datagram identifier
+ \return -1 if error, 0 if OK
+*/
+int send_datagram (ACE_SOCK_Dgram_Bcast &socket, int datagram_no)
+{
+ static char dgram_buffer[BUFSIZ];
+
+ ACE_OS::snprintf (dgram_buffer, sizeof(dgram_buffer) - 1,
+ "Datagram %d", datagram_no);
+ if (socket.send (dgram_buffer,
+ ACE_OS::strlen (dgram_buffer) + 1,
+ dgram_port) < 0 )
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"),
+ ACE_TEXT ("Cannot broadcast datagram")), -1);
+ else
+ ACE_DEBUG ((LM_INFO, ACE_TEXT ("%C sent\n"), dgram_buffer));
+ return 0;
+}
+
+/*\brief Send a sequence of datagrams with 1 second period
+ \note Th function employs dgram_port and dgrams_no global variables
+ \retval -1 if error
+ \retval 0 if sent
+*/
+int run_sender( )
+{
+ ACE_DEBUG ((LM_INFO,
+ ACE_TEXT ("Sending %d datagrams on port %d\n"),
+ dgrams_no,
+ dgram_port));
+ ACE_SOCK_Dgram_Bcast socket;
+
+ if (socket.open (ACE_Addr::sap_any) != -1)
+ {
+ while (dgrams_no-- != 0)
+ {
+ if (send_datagram (socket, dgrams_no) < 0)
+ break;
+ ACE_OS::sleep (1);
+ }
+ socket.close ();
+ return (0);
+ }
+
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"),
+ ACE_TEXT ("Cannot open broadcast socket")), -1);
+}
+
+/*\brief Receive single datagram
+ \note The function employes dgram_port and dgram_recv_timeout variables
+ \retval -1 if not received,
+ \retval 0 received a datagrams
+*/
+int run_receiver ()
+{
+ ACE_DEBUG
+ ((LM_INFO,
+ ACE_TEXT ("Receiving datagrams from port %d with timeout %d ms\n"),
+ dgram_port, dgram_recv_timeout.msec ()));
+
+ ACE_SOCK_Dgram socket;
+ ACE_INET_Addr remote ;
+ static char dgram_buffer[BUFSIZ];
+
+ if (socket.open (ACE_INET_Addr (dgram_port)) != -1)
+ if (socket.recv (dgram_buffer, sizeof (dgram_buffer),
+ remote, 0, &dgram_recv_timeout) > 0)
+ {
+ ACE_DEBUG ((LM_INFO, ACE_TEXT ("%C received\n"), dgram_buffer));
+ return 0;
+ }
+ else
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"),
+ ACE_TEXT ("Cannot receive datagrams")), -1);
+
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"),
+ ACE_TEXT ("Cannot open broadcast socket")), -1);
+}
+
+#if !defined (ACE_HAS_PROCESS_SPAWN) && defined (ACE_HAS_THREADS)
+/* \brief Thread main function to run run_receiver function
+ \note run_receiver return valu is stored in receiver_exit_code global variable
+*/
+static ACE_THR_FUNC_RETURN run_thread_receiver (void *)
+{
+ receiver_exit_code = run_receiver ();
+ return 0;
+}
+#endif /* !defined (ACE_HAS_PROCESS_SPAWN) && defined (ACE_HAS_THREADS) */
+
+/* \brief Just runs automatic tests
+
+Function sends a number of datagrams, spawns child thread or process and
+tries to receive at least one datagram.
+\retval 0 datagram was received
+\retval -1 datagram was not received
+*/
+int run_auto_test (const ACE_TCHAR *prog_name)
+{
+#if defined (ACE_HAS_PROCESS_SPAWN)
+ ACE_DEBUG ((LM_INFO, ACE_TEXT ("Running auto_tests in process mode\n")));
+
+ ACE_Process_Options opts;
+ pid_t child_pid;
+ opts.command_line (ACE_TEXT ("%s -p %d -t %d -a -r"),
+ prog_name, dgram_port, dgram_recv_timeout.msec ());
+ if ((child_pid = ACE_Process_Manager::instance ()->spawn (opts)) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("spawn_n()")), -1);
+
+#elif defined (ACE_HAS_THREADS)
+ ACE_UNUSED_ARG (prog_name);
+ ACE_DEBUG ((LM_INFO, ACE_TEXT ("Running auto_tests in thread mode\n")));
+ if (ACE_Thread_Manager::instance ()->spawn (run_thread_receiver) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("spawn_n ()")), -1);
+#else
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("Cannot run in auto_test mode without fork or threads.\n")),
+ -1);
+#endif /* defined (ACE_HAS_PROCESS_SPAWN) */
+
+ ACE_DEBUG ((LM_INFO,
+ ACE_TEXT ("Sending datagrams on port %d in auto_test mode\n"),
+ dgram_port));
+
+ ACE_SOCK_Dgram_Bcast socket;
+
+ if (socket.open (ACE_Addr::sap_any) != -1)
+ {
+ // send datagrams until child finishes
+ while (1)
+ {
+ send_datagram (socket, dgrams_no--);
+ ACE_Time_Value child_timeout (1);
+#if defined (ACE_HAS_PROCESS_SPAWN)
+
+ if (ACE_Process_Manager::instance ()->wait (child_pid,
+ child_timeout,
+ &receiver_exit_code) == child_pid)
+ break;
+#else /* ACE_HAS_THREADS */
+ // sleep 1 second or wait for child thread
+ child_timeout += ACE_OS::gettimeofday () ;
+ if (ACE_Thread_Manager::instance ()->wait (&child_timeout) == 0)
+ break;
+#endif
+ }
+ socket.close ();
+ ACE_DEBUG ((LM_INFO, ACE_TEXT ("Child finished with %d exit code\n"),
+ receiver_exit_code));
+ }
+ else
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"),
+ ACE_TEXT ("Cannot open broadcast socket")), -1);
+ return (receiver_exit_code);
+}
+
+void print_usage (void)
+{
+ printf("Usage:SOCK_Dgram_Bast_Test [-p port] [-n dgrams_no] [-t timeout_ms] [-s] [-r]\n"
+ "\tp broadcast port [14521]\n"
+ "\tn number of datagrams to broadcast [30] (<0 infinite)\n"
+ "\tt timeout in seconds for receive [5] (<=0 infinite)\n"
+ "\ts send datagrams and exit\n"
+ "\tr receive one datagram and exit\n\n"
+ "\t run auto-test when no r and s option is passed\n"
+ "\t test failures are minifested by -1 exit value, otherwise 0\n");
+}
+
+int run_main (int argc, ACE_TCHAR *argv[])
+{
+ // parse options and run in appropriate mode
+ int opt = 0;
+ int auto_test_recv = 0;
+ int result = 0;
+ ACE_Get_Opt opts (argc, argv, ACE_TEXT ("p:t:n:sra"));
+ while ((opt = opts ()) != -1)
+ switch (opt)
+ {
+ case 'a':
+ auto_test_recv = 1;
+ break;
+ case 's':
+ return (run_sender());
+ case 'r':
+ {
+ if (auto_test_recv)
+ {
+ ACE_START_TEST (ACE_TEXT ("SOCK_Dgram_Bcast_Test_Child"));
+ result = run_receiver ();
+ ACE_END_TEST;
+ return result;
+ }
+ return (run_receiver ());
+ }
+ case 'n':
+ dgrams_no = ACE_OS::atoi (opts.opt_arg ());
+ break;
+ case 't':
+ dgram_recv_timeout.msec (ACE_OS::atoi (opts.opt_arg ()));
+ break;
+ case 'p':
+ dgram_port = ACE_OS::atoi (opts.opt_arg ());
+ break;
+ default:
+ print_usage ();
+ return -1;
+ }
+ ACE_START_TEST (ACE_TEXT ("SOCK_Dgram_Bcast_Test"));
+ result = run_auto_test (ACE_TEXT ("SOCK_Dgram_Bcast_Test"));
+ ACE_END_TEST;
+ return result;
+}
diff --git a/ACE/tests/SOCK_Dgram_Test.cpp b/ACE/tests/SOCK_Dgram_Test.cpp
new file mode 100644
index 00000000000..54bbd705204
--- /dev/null
+++ b/ACE/tests/SOCK_Dgram_Test.cpp
@@ -0,0 +1,220 @@
+// $Id$
+// ===========================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// SOCK_Dgram.cpp
+//
+// = DESCRIPTION
+// Tests that a call to open with an any address binds to the any address
+// for the protocol passed in.
+//
+// This test uses the same test setup as SOCK_Test.
+//
+// = AUTHOR
+// Brian Buesker (bbuesker@qualcomm.com)
+//
+// ==========================================================================
+
+#include "test_config.h"
+#include "ace/OS_NS_sys_wait.h"
+#include "ace/Thread.h"
+#include "ace/Thread_Manager.h"
+#include "ace/SOCK_Dgram.h"
+#include "ace/Log_Msg.h"
+#include "ace/Time_Value.h"
+#include "ace/OS_NS_unistd.h"
+
+#define SERVER_PORT 20000
+#define TEST_DATA ACE_TEXT ("UDP Open Test")
+
+static void *
+client (void *arg)
+{
+ ACE_INET_Addr *remote_addr = (ACE_INET_Addr *) arg;
+ ACE_INET_Addr server_addr, peer_addr;
+ ACE_SOCK_Dgram cli_dgram;
+ ACE_Time_Value timeout (1);
+
+ char buf[20];
+
+ ACE_TCHAR hostname_string[100];
+
+ if (remote_addr->get_type () == AF_INET)
+ {
+ server_addr.set (remote_addr->get_port_number (),
+ ACE_LOCALHOST);
+ }
+#if defined (ACE_HAS_IPV6)
+ else
+ {
+ server_addr.set (remote_addr->get_port_number(),
+ ACE_IPV6_LOCALHOST);
+ }
+#endif /* ACE_HAS_IPV6 */
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) starting client UDP send\n")));
+
+ if (cli_dgram.open (ACE_Addr::sap_any, server_addr.get_type ()) == -1)
+ {
+ ACE_ERROR((LM_ERROR,
+ ACE_TEXT("%p\n"),
+ ACE_TEXT("open SOCK_Dgram failed for client for protocol")
+ ACE_TEXT(" = %d\n"),
+ server_addr.get_type ()));
+ }
+ else if (cli_dgram.send (TEST_DATA, sizeof (TEST_DATA), server_addr) == -1)
+ {
+ server_addr.addr_to_string (hostname_string, 100);
+ ACE_ERROR((LM_ERROR,
+ ACE_TEXT("%p\n"),
+ ACE_TEXT("UDP send to %s\n"),
+ hostname_string));
+ }
+ else if (cli_dgram.recv (buf, sizeof (buf), peer_addr, 0, &timeout) == -1)
+ {
+ if (errno == ETIME)
+ {
+ ACE_ERROR((LM_ERROR,
+ ACE_TEXT("%p\n"),
+ ACE_TEXT("recv for UDP over IPv4 timed out")));
+ }
+ else
+ {
+ ACE_ERROR((LM_ERROR,
+ ACE_TEXT("%p\n"),
+ ACE_TEXT("recv for UDP over IPv4 failed")));
+ }
+ }
+
+ cli_dgram.close();
+
+ return 0;
+}
+
+static void *
+server (void *arg)
+{
+ ACE_SOCK_Dgram *server_dgram = (ACE_SOCK_Dgram *) arg;
+
+ ACE_INET_Addr peer_addr;
+
+ char buf[20];
+ ACE_TCHAR hostname_string[100];
+
+ if (server_dgram->recv (buf, sizeof (buf), peer_addr, 0) == -1)
+ {
+ ACE_ERROR((LM_ERROR,
+ ACE_TEXT("%p\n"),
+ ACE_TEXT("recv for UDP over IPv6 failed")));
+ }
+ else if (server_dgram->send (TEST_DATA, sizeof (TEST_DATA),
+ peer_addr, 0) == -1)
+ {
+ peer_addr.addr_to_string (hostname_string, sizeof (hostname_string));
+ ACE_ERROR((LM_ERROR,
+ ACE_TEXT("%p\n"),
+ ACE_TEXT("Server UDP send to %s failed"),
+ hostname_string));
+ }
+ server_dgram->close ();
+
+ return 0;
+}
+
+static void
+spawn (int proto)
+{
+ ACE_SOCK_Dgram server_dgram;
+
+ ACE_INET_Addr server_addr;
+
+ if (proto == AF_INET)
+ {
+ server_addr.set (SERVER_PORT,
+ ACE_LOCALHOST);
+ }
+#if defined (ACE_HAS_IPV6)
+ else
+ {
+ server_addr.set (SERVER_PORT,
+ ACE_IPV6_LOCALHOST);
+ }
+#endif /* ACE_HAS_IPV6 */
+
+ // Bind UDP server to the appropriate port
+ if (server_dgram.open (server_addr, proto) == -1)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%P|%t) %p\n"), ACE_TEXT ("server open")));
+ else
+ {
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) started server at port %d\n"),
+ server_addr.get_port_number ()));
+#if !defined (ACE_LACKS_FORK)
+ switch (ACE_OS::fork (ACE_TEXT ("child")))
+ {
+ case -1:
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n%a"),
+ ACE_TEXT ("fork failed"),
+ 1));
+ /* NOTREACHED */
+ case 0:
+ client (&server_addr);
+ exit (0);
+ /* NOTREACHED */
+ default:
+ server ((void *) &server_dgram);
+ ACE_OS::wait ();
+ }
+#elif defined (ACE_HAS_THREADS)
+ if (ACE_Thread_Manager::instance ()->spawn
+ (ACE_THR_FUNC (server),
+ (void *) &server_dgram,
+ THR_NEW_LWP | THR_DETACHED) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n%a"),
+ ACE_TEXT ("thread create failed"),
+ 1));
+
+ if (ACE_Thread_Manager::instance ()->spawn
+ (ACE_THR_FUNC (client),
+ (void *) &server_addr,
+ THR_NEW_LWP | THR_DETACHED) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n%a"),
+ ACE_TEXT ("thread create failed"),
+ 1));
+
+ // Wait for the threads to exit.
+ ACE_Thread_Manager::instance ()->wait ();
+#else
+ ACE_ERROR ((LM_INFO,
+ ACE_TEXT ("(%P|%t) ")
+ ACE_TEXT ("only one thread may be run ")
+ ACE_TEXT ("in a process on this platform\n")));
+#endif /* ACE_HAS_THREADS */
+
+ server_dgram.close ();
+ }
+}
+
+int run_main (int argc, ACE_TCHAR *argv[])
+{
+ ACE_UNUSED_ARG (argc);
+ ACE_UNUSED_ARG (argv);
+
+ ACE_START_TEST (ACE_TEXT ("SOCK_Dgram_Test"));
+
+ spawn (AF_INET);
+
+#if defined (ACE_HAS_IPV6)
+
+ spawn (AF_INET6);
+
+#endif /* ACE_HAS_IPV6 */
+
+ ACE_END_TEST;
+ return 0;
+}
diff --git a/ACE/tests/SOCK_Netlink_Test.cpp b/ACE/tests/SOCK_Netlink_Test.cpp
new file mode 100644
index 00000000000..5d3ee4164ad
--- /dev/null
+++ b/ACE/tests/SOCK_Netlink_Test.cpp
@@ -0,0 +1,973 @@
+// $Id$
+
+// ====================================================================//
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// SOCK_Netlink_Test.cpp
+//
+// = DESCRIPTION
+// Tests adding of a secondary IP-address, using linux netlink
+// sockets.
+//
+// = AUTHOR
+//
+// Robert Iakobashvili, coroberti@gmail.com
+//
+// ====================================================================//
+
+#include "test_config.h"
+
+#ifdef ACE_HAS_NETLINK
+
+#include "ace/Event_Handler.h"
+#include "ace/Reactor.h"
+#include "ace/Log_Msg.h"
+#include "ace/Get_Opt.h"
+
+#include "ace/Netlink_Addr.h"
+#include "ace/SOCK_Netlink.h"
+
+#include "ace/OS_NS_sys_socket.h"
+
+#include <linux/rtnetlink.h>
+
+
+/**
+ * NETLINK SOCKET INTERFACE is a socket API communication
+ * between linux kernel and userland.
+ *
+ * Main usage of netlink communication is for communication between
+ * kernel/custom modules/drivers and userspace;
+ *
+ * In order not to force ACE-tests runners to install some driver for testing
+ * purposes, we are using here a build-in netlink interface used by linux for
+ * "routing" purposes (rtnetlink).
+ *
+ * This test is hopefully a useful example of how via netlink to add a new
+ * secondary IPv4 address to an interface and to delete it further. The
+ * example is integrated within reactive framework for IO demultiplexing.
+ *
+ * A one button test adds a new secondary IP-address to a loopback
+ * interface and deletes it. Even if the address added remains, this shall no
+ * cause any damage. In any case the lifetime of a secondary ip is limited
+ * till the next reboot. You may wish to run the test with -d option (not to
+ * make an address cleanup after addtion) and see it by 'ip addr' command.
+ * Further re-run of the test without -d option will cleanup the address.
+ *
+ * Please, note, that it is ok that the message "rtnetlink error message:
+ * Cannot assign requested address" will appear on your console, because first
+ * the test is trying to remove the secondary-ip and errors, if it was not before.
+ *
+ * The one-button test fails, of there is no a loopback device named "lo" on a
+ * host or the device is disabled.
+ *
+ * The same rtnetlink interface may be used to get/add/delete ip-addresses,
+ * get/add/delete routing rules, control ARP entires, control Qdisk disciplines,
+ * traffic classes and traffic filters, manage network interface configuration
+ *
+ * For more information, please, read man pages:
+ * netlink (3), netlink (7), rtnetlink (3), rtnetlink (3), rtnetlink (7) and ip (8).
+ *
+ * Some ideas for the test were borrowed from the code of iprouted2
+ * written by Alexey Kuznetsov.
+ *
+ * Command line options:
+ *
+ * -d do not cleanup the ip-address after addition (so that you can see it by the
+ * 'ip addr' command)
+ *
+ * -i the name of interface to add the address
+ *
+ * -a ipv4 slash netmask bits, like "192.168.1.1/24"
+ *
+
+ From Linux headers:
+
+ // Generic structure for encapsulation of optional route information.
+ // It is reminiscent of sockaddr, but with sa_family replaced with attribute type.
+ struct rtattr
+ {
+ unsigned short rta_len;
+ unsigned short rta_type;
+ };
+
+ //Interface address.
+ struct ifaddrmsg
+ {
+ unsigned char ifa_family;
+ unsigned char ifa_prefixlen; // The prefix length is the length of the address mask
+ unsigned char ifa_flags; // Flags: IFA_F_SECONDARY for secondary
+ // address (old alias interface), IFA_F_PERMANENT
+ // for a permanent address
+ unsigned char ifa_scope; // locality
+ int ifa_index; // Link index is the interface index in the table of interfaces.
+ };
+
+ struct nlmsghdr
+ {
+ __u32 nlmsg_len; // Length of message including header
+ __u16 nlmsg_type; // Message content
+ __u16 nlmsg_flags; // Additional flags
+ __u32 nlmsg_seq; // Sequence number
+ __u32 nlmsg_pid; // Sending process PID
+ };
+*/
+
+
+// The global config params
+//
+static int one_button_test = 0;
+static char ip_slash_mask[32];
+static char net_dev_name[16];
+static int dont_cleanup_added_ip = 0;
+
+// The function returns index of an interface by its name
+//
+int
+get_if_index (const char*const interface,
+ int &if_index)
+{
+ if_index = -1;
+
+ struct ifreq if_req;
+ ACE_OS::memset (&if_req, 0, sizeof (struct ifreq));
+
+ ACE_OS::strncpy (if_req.ifr_name,
+ static_cast<const char*> (interface),
+ sizeof (if_req.ifr_name));
+
+ ACE_HANDLE s = ACE_OS::socket (AF_INET,SOCK_DGRAM,0);
+
+ if (s == ACE_INVALID_HANDLE)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("get_if_index - failed on\n")
+ ACE_TEXT ("ACE_OS::socket")),
+ -1);
+
+ int result = ACE_OS::ioctl (s,
+ SIOCGIFINDEX,
+ reinterpret_cast<char*> (&if_req));
+
+ if (result == -1)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("get_if_index:")
+ ACE_TEXT ("ioctl (get interface index)")));
+ }
+ else
+ {
+ if_index = if_req.ifr_ifindex;
+ }
+ return result;
+}
+
+/**
+ An assisting structure for passing data via routing netlink socket.
+ The idea borrowed from a great iprouted2 utility,
+ written by Alexey Kuznetsov.
+*/
+struct Inet_Prefix
+{
+ u_char family;
+ u_char bytelen;
+ ACE_INT16 bitlen;
+ ACE_UINT32 data[4];
+};
+
+
+/**
+ * Contains header netlink message header of a type nlmsghdr with a
+ * following request type dependent controlling structure, which is for
+ * adding/deleting IP-addresses is of type ifaddrmsg with a following
+ * buffer, containing the data: ip-address, its length, number of netmask
+ * bits, etc.
+ */
+struct Netlink_Request
+{
+ struct nlmsghdr nhdr_; // message header
+ struct ifaddrmsg ifa_; // interface
+ char buf_[256];
+};
+
+
+
+/**
+ * The handler first is trying to delete an ip-address, further
+ * to add the ip and, if successful to cleanup the address.
+ */
+class Secondary_Ipaddr_Handler : public ACE_Event_Handler
+{
+public:
+
+ // Default constructor
+ Secondary_Ipaddr_Handler (void);
+
+ // Destructor
+ virtual ~Secondary_Ipaddr_Handler (void);
+
+ // Initialization. Schedules a timer to run start the business.
+ //
+ int open (ACE_Reactor *const reactor,
+ char* const ip_slash_mask,
+ const char *const if_name);
+
+ // Returns reference to netlink socket. Necessary for reactor.
+ virtual ACE_HANDLE get_handle (void) const;
+
+ /**
+ * Takes care of the input. Reads the incoming messages,
+ * makes their processing.
+ */
+ virtual int handle_input (ACE_HANDLE handle);
+
+ // Makes clean-up
+ virtual int handle_close (ACE_HANDLE handle,
+ ACE_Reactor_Mask close_mask);
+
+ // Runs a state machine. Controls adding/deleting of ip-address.
+ int handle_timeout (ACE_Time_Value const & tv,
+ void const * arg = 0);
+
+ // Sends to kernel a request to add secondary ip/mask to an
+ // interface.
+ int add_ip (char* const ip_slash_mask,
+ const char *const if_name);
+
+ // Sends to kernel a request to delete secondary ip/mask
+ // from an interface.
+ int delete_ip (char* const ip_slash_mask,
+ const char *const if_name);
+
+ /*
+ * 1. We are trying to delete the ip-address, if exists.
+ * Shall be either successful, or fail, when no-ip yet.
+ * 2. Adding the ip-address, shall be successful;
+ * 3. Cleaning up the ip-address. Shall be successful as well.
+ */
+ enum
+ {
+ START = 0,
+ IP_DELETED,
+ IP_ADDED,
+ IP_CLEANUPED,
+ SUCCESS,
+ FAILED
+ };
+
+ // Returns the currect state
+ int get_state () const { return this->state_;}
+
+protected:
+
+ // De-registers the handler from the reactor,
+ // other cleanup jobs
+ virtual int close ();
+
+ ACE_SOCK_Netlink& socket ();
+
+private:
+
+ // Schedule two sec timer.
+ int schedule_one_sec_timer ();
+
+ // A workhorse for add_ip () and delete_ip ()
+ int dispatch_ip_operation (char* const ip_slash_mask,
+ const char *const if_name,
+ bool action);
+
+ /**
+ * Initializes netlink request for adding (action = true) or
+ * deleting (action = false) of a secondary ip-address/mask.
+ */
+ int init_netlink_request (char* const ip_slash_mask,
+ const char *const if_name,
+ Netlink_Request& net_req,
+ bool action);
+
+ // Fills data part of Netlink_Request
+ int fill_inet_prefix (Inet_Prefix &inet_prefix,
+ const char*const ip_slash_netmask);
+
+ /**
+ * Fills routing request (operations with ip-addresses are
+ * a part of netlink routing interface).
+ */
+ void fill_rtnetlink_request (nlmsghdr &hdr,
+ int type,
+ void *data,
+ int data_length);
+
+ enum
+ {
+ COMMAND_TIMEOUT = -3,
+ COMMAND_RECV_ERROR = -2,
+ COMMAND_ERROR = -1,
+ COMMAND_SUCCESS = 0
+ };
+
+ // Mark command status in handle_input ().
+ void on_recv_error () { this->command_status_ = COMMAND_RECV_ERROR; }
+ void on_command_success () { this->command_status_ = COMMAND_SUCCESS; }
+ void on_command_error () { this->command_status_ = COMMAND_ERROR; }
+
+ // The socket.
+ ACE_SOCK_Netlink socket_ ;
+
+ // The address of the socket.
+ ACE_Netlink_Addr address_ ;
+
+ // Message sequence number.
+ ACE_UINT32 seq_ ;
+
+ // The request structure passed to kernel.
+ Netlink_Request netlink_request_;
+
+ // ip-addr-slash-mask
+ char ip_buff_[32];
+
+ // interface
+ char if_buff_[16];
+
+ // Buffer to receive messages. Not too large?
+ char recv_buff_[1024];
+
+ // The state of the handler.
+ int state_;
+
+ // The status of the command.
+ int command_status_;
+};
+
+Secondary_Ipaddr_Handler::Secondary_Ipaddr_Handler ()
+ :
+ socket_ (),
+ address_ (),
+ seq_ (0),
+ state_ (START),
+ command_status_ (COMMAND_SUCCESS)
+{
+}
+
+Secondary_Ipaddr_Handler::~Secondary_Ipaddr_Handler ()
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Secondary_Ipaddr_Handler::~Secondary_Ipaddr_Handler \n")));
+ this->close ();
+}
+int
+Secondary_Ipaddr_Handler::open (ACE_Reactor *const reactor,
+ char* const ip_slash_mask,
+ const char *const if_name)
+{
+ if (!reactor ||
+ !ip_slash_mask || !ACE_OS::strlen (ip_slash_mask) ||
+ !if_name || !ACE_OS::strlen (if_name))
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT("(%P) Secondary_Ipaddr_Handler::open: error ")
+ ACE_TEXT("zero pointers or zero length strings used as input. \n")),
+ -1);
+
+ this->reactor (reactor);
+
+ // Another option is to pass a zero pid to the address, to call open () on socket
+ // performing binding and after bind () to call getsockbyname to fill the address
+
+ this->address_.set (ACE_OS::getpid (), 0);
+
+ if (this->socket ().open (this->address_,
+ ACE_PROTOCOL_FAMILY_NETLINK,
+ NETLINK_ROUTE) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT("(%P|%t) Secondary_Ipaddr_Handler::open: - failed \n")
+ ACE_TEXT("to initialize netlink socket bu open (). \n")),
+ -1);
+
+ // register with the reactor for input
+ if (this->reactor ()->register_handler (this,
+ ACE_Event_Handler::READ_MASK) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT("(%P|%t) Secondary_Ipaddr_Handler::open - ")
+ ACE_TEXT("can't register with reactor for handling input.\n")),
+ -1);
+
+ if (this->reactor ()->schedule_timer (this,
+ 0,
+ ACE_Time_Value::zero) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT("(%P) Secondary_Ipaddr_Handler::open - ")
+ ACE_TEXT("can't schedule timer with reactor.\n")),
+ -1);
+
+ this->seq_ = time (NULL);
+
+ ACE_OS::strncpy (this->ip_buff_,
+ ip_slash_mask,
+ sizeof this->ip_buff_);
+
+ ACE_OS::strncpy (this->if_buff_,
+ if_name,
+ sizeof this->if_buff_);
+
+ return 0;
+}
+
+ACE_HANDLE
+Secondary_Ipaddr_Handler::get_handle (void) const
+{
+ return this->socket_.get_handle ();
+}
+
+int
+Secondary_Ipaddr_Handler::handle_input (ACE_HANDLE)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT("(%P) Secondary_Ipaddr_Handler::handle_input - entered \n")));
+
+ nlmsghdr *hdr = 0;
+ iovec iov;
+
+ iov.iov_base = this->recv_buff_;
+ iov.iov_len = sizeof (this->recv_buff_);
+
+ int rval_bytes = -1;
+ ACE_Netlink_Addr raddr;
+ raddr.set (0, 0);
+
+ rval_bytes = this->socket ().recv (&iov, 1, raddr);
+ switch (rval_bytes)
+ {
+ case -1: // Complain and leave
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT("(%P) Secondary_Ipaddr_Handler::handle_input - ")
+ ACE_TEXT("%p bad read\n"), ACE_TEXT("client")),
+ -1);
+
+ case 0: // Complain and leave
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT("(%P) Secondary_Ipaddr_Handler::handle_input - "),
+ ACE_TEXT("eof, closing daemon (fd = %d)\n"),
+ this->get_handle ()),
+ -1);
+
+ default:
+ if (raddr.get_size () != sizeof (sockaddr_nl))
+ {
+ this->on_recv_error ();
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT("(%n %P) Secondary_Ipaddr_Handler::handle_input - ")
+ ACE_TEXT("address length not equal sockaddr_nl\n")),
+ -1);
+ }
+
+ hdr = reinterpret_cast <nlmsghdr*> (this->recv_buff_);
+
+ if (static_cast <int> (hdr->nlmsg_len) != rval_bytes)
+ {
+ this->on_recv_error ();
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT("(%P) Secondary_Ipaddr_Handler::handle_input - ")
+ ACE_TEXT("size of nlmsg_len not equal received bytes\n")),
+ -1);
+ }
+
+ if (static_cast <int> (hdr->nlmsg_pid) != this->address_.get_pid () || hdr->nlmsg_seq != this->seq_)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT("(%P) Secondary_Ipaddr_Handler::handle_input - ")
+ ACE_TEXT("process id or message sequence is different \n")),
+ -1);
+
+ if (hdr->nlmsg_type == NLMSG_ERROR)
+ {
+ struct nlmsgerr *err = static_cast <struct nlmsgerr*> (NLMSG_DATA(hdr));
+
+ errno = -err->error;
+ if (errno == 0)
+ {
+ this->on_command_success ();
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT("(%P) Secondary_Ipaddr_Handler::handle_input - command success \n")));
+ return 0;
+ }
+
+ this->on_command_error ();
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT("(%P) Secondary_Ipaddr_Handler::handle_input - command informs about error \n")));
+
+ // some error message
+ perror("rtnetlink error message: ");
+
+ return 0;
+ }
+ }
+ return -1;
+}
+
+int
+Secondary_Ipaddr_Handler::handle_timeout (ACE_Time_Value const &,
+ void const *)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT("(%P) Secondary_Ipaddr_Handler::handle_timeout - entered \n")));
+
+ if (this->command_status_ != COMMAND_SUCCESS &&
+ (this->command_status_ != COMMAND_ERROR &&
+ this->state_ == IP_DELETED))
+ {
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT("(%P) Secondary_Ipaddr_Handler::handle_timeout - ")
+ ACE_TEXT("previous command failed\n")),
+ -1);
+ }
+ else
+ this->command_status_ = COMMAND_TIMEOUT; //invalidate command status
+
+ switch (this->state_)
+ {
+ case START: //delete the ip, if it presents
+ if (this->delete_ip (this->ip_buff_, this->if_buff_) == -1)
+ {
+ this->state_ = FAILED;
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT("(%P) Secondary_Ipaddr_Handler::handle_timeout - ")
+ ACE_TEXT("delete_ip failed\n")),
+ -1);
+ }
+ break;
+
+ case IP_DELETED: // add the ip
+ if (this->add_ip (this->ip_buff_, this->if_buff_) == -1)
+ {
+ this->state_ = FAILED;
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT("(%P) Secondary_Ipaddr_Handler::handle_timeout - ")
+ ACE_TEXT("add_ip failed\n")),
+ -1);
+ }
+ break;
+
+ case IP_ADDED: //delete added ip to make cleanup
+ if (dont_cleanup_added_ip)
+ {
+ this->state_ = SUCCESS;
+ return 0;
+ }
+ else
+ {
+ if (this->delete_ip (this->ip_buff_, this->if_buff_) == -1)
+ {
+ this->state_ = FAILED;
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT("(%P) Secondary_Ipaddr_Handler::handle_timeout - ")
+ ACE_TEXT("delete_ip failed\n")),
+ -1);
+ }
+ }
+ break;
+
+ case IP_CLEANUPED:
+ this->state_ = SUCCESS;
+ return 0;
+
+ default:
+ return -1;
+ }
+
+ this->schedule_one_sec_timer ();
+ this->state_++;
+ return 0;
+}
+
+int
+Secondary_Ipaddr_Handler::handle_close (ACE_HANDLE,
+ ACE_Reactor_Mask)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT("(%P|%t) Secondary_Ipaddr_Handler::handle_close \n")));
+ this->close ();
+ return 0;
+}
+
+int
+Secondary_Ipaddr_Handler::close ()
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT("(%P) Secondary_Ipaddr_Handler::close \n")));
+
+ if (this->reactor ())
+ {
+ this->reactor ()->remove_handler (this,
+ ACE_Event_Handler::ALL_EVENTS_MASK |
+ ACE_Event_Handler::DONT_CALL);
+
+ this->reactor ()->cancel_timer (this);
+
+ this->reactor (0);
+ }
+ return 0;
+}
+
+int
+Secondary_Ipaddr_Handler::schedule_one_sec_timer ()
+{
+ const ACE_Time_Value one_sec (1, 0);
+
+ if (this->reactor ()->schedule_timer (this,
+ 0,
+ one_sec) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT("(%P) Secondary_Ipaddr_Handler::schedule_one_sec_timer - ")
+ ACE_TEXT("can't schedule timer with reactor.\n")),
+ -1);
+ return 0;
+}
+
+ACE_SOCK_Netlink&
+Secondary_Ipaddr_Handler::socket ()
+{
+ return this->socket_;
+}
+
+int
+Secondary_Ipaddr_Handler::fill_inet_prefix (
+ Inet_Prefix &inet_prefix,
+ const char*const ip_slash_netmask)
+{
+ ACE_OS::memset (&inet_prefix, 0, sizeof inet_prefix);
+ char* slash = const_cast <char *> (ACE_OS::strchr (ip_slash_netmask, '/'));
+ if (slash)
+ *slash = '\0'; // The idea from Igor Potulnitsky
+
+ inet_prefix.family = AF_INET; // another option is AF_UNSPEC
+ inet_prefix.bytelen = 4;
+ inet_prefix.bitlen = -1;
+
+ char ip_buff[32];
+ ACE_OS::strncpy (ip_buff, ip_slash_netmask, sizeof (ip_buff));
+
+ char* to_search = ip_buff, *dot = 0;
+
+ for (int i = 0; i < 4; i++)
+ {
+ if (i < 3)
+ {
+ dot = ACE_OS::strchr (to_search, '.');
+ if (!dot || !ACE_OS::strlen (to_search))
+ return -1;
+ else
+ *dot = '\0';
+ }
+ int num = atoi (to_search);
+ if (num < 0 || num > 255)
+ return -1;
+ else
+ ((u_char *) &inet_prefix.data)[i] = (u_char)num;
+
+ if (i < 3)
+ to_search = dot + 1;
+ }
+
+ inet_prefix.bitlen = 32; // AF_INET: 32
+
+ if (slash)
+ {
+ int mask_len = 0;
+ mask_len = ACE_OS::atoi (slash + 1);
+ if (mask_len >= 0)
+ inet_prefix.bitlen = mask_len;
+ *slash = '/';
+ }
+ return 0;
+}
+
+void
+Secondary_Ipaddr_Handler::fill_rtnetlink_request (
+ nlmsghdr &hdr,
+ int type,
+ void *data,
+ int data_length)
+{
+ // points to the end of the aligned header
+ struct rtattr *rta = reinterpret_cast <struct rtattr*> (((reinterpret_cast <char*>(&hdr)) + NLMSG_ALIGN (hdr.nlmsg_len)));
+
+ rta->rta_type = type;
+ rta->rta_len = RTA_LENGTH (data_length);
+ ACE_OS::memcpy (RTA_DATA(rta), data, data_length);
+ hdr.nlmsg_len = NLMSG_ALIGN (hdr.nlmsg_len) + RTA_LENGTH (data_length);
+}
+
+int
+Secondary_Ipaddr_Handler::dispatch_ip_operation (
+ char* const ip_slash_mask,
+ const char *const if_name,
+ bool action)
+{
+ if (this->init_netlink_request (ip_slash_mask,
+ if_name,
+ this->netlink_request_,
+ action) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "Secondary_Ipaddr_Handler::ip_operation - "
+ "init_netlink_request () failed.\n"),
+ -1);
+
+ this->netlink_request_.nhdr_.nlmsg_seq = ++this->seq_;
+ this->netlink_request_.nhdr_.nlmsg_flags |= NLM_F_ACK;
+
+ iovec iov_send =
+ {
+ static_cast <void*> (&this->netlink_request_.nhdr_),
+ this->netlink_request_.nhdr_.nlmsg_len
+ };
+
+ ACE_Netlink_Addr addr_send;
+ addr_send.set (0, 0);
+
+ if (this->socket ().send (&iov_send,
+ 1,
+ addr_send) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT("Secondary_Ipaddr_Handler::ip_operation - ")
+ ACE_TEXT("send of request failed with errno %d.\n"),
+ errno),
+ -1);
+ return 0;
+}
+
+int
+Secondary_Ipaddr_Handler::delete_ip (
+ char* const ip_slash_mask,
+ const char *const if_name)
+{
+ if (this->dispatch_ip_operation (
+ ip_slash_mask,
+ if_name,
+ false) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT("(%P) Secondary_Ipaddr_Handler::delete_ip - ")
+ ACE_TEXT("dispatch_ip_operation() failed.\n")),
+ -1);
+ return 0;
+}
+
+int
+Secondary_Ipaddr_Handler::add_ip (
+ char* const ip_slash_mask,
+ const char *const if_name)
+{
+ if (this->dispatch_ip_operation (ip_slash_mask,
+ if_name,
+ true) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT("(%P) Secondary_Ipaddr_Handler::add_ip - ")
+ ACE_TEXT("dispatch_ip_operation() failed.\n")),
+ -1);
+ return 0;
+}
+
+int
+Secondary_Ipaddr_Handler::init_netlink_request (
+ char* const ip_slash_netmask,
+ const char *const if_name,
+ Netlink_Request& net_req,
+ bool action)
+{
+ ACE_OS::memset (&net_req, 0, sizeof(net_req));
+
+ // fill the request header
+ net_req.nhdr_.nlmsg_len =
+ NLMSG_LENGTH (sizeof(struct ifaddrmsg));
+ net_req.nhdr_.nlmsg_flags = NLM_F_REQUEST;
+ net_req.nhdr_.nlmsg_type = action ? RTM_NEWADDR : RTM_DELADDR;
+ net_req.ifa_.ifa_family = AF_INET;
+
+ int interface_index = -1;
+ if (get_if_index (if_name,
+ interface_index) == -1 || interface_index < 0)
+ {
+ fprintf (stderr, "get_if_index () - failed\n");
+ return -1;
+ }
+ net_req.ifa_.ifa_index = interface_index;
+
+ Inet_Prefix local_prefix;
+
+ if (fill_inet_prefix (local_prefix,
+ ip_slash_netmask) == -1)
+ {
+ fprintf (stderr, "fill_inet_prefix () - failed\n");
+ return -1;
+ }
+
+ fill_rtnetlink_request (net_req.nhdr_,
+ IFA_LOCAL,
+ &local_prefix.data,
+ local_prefix.bytelen);
+
+ net_req.ifa_.ifa_prefixlen = local_prefix.bitlen; // number of bits in netmask
+ net_req.ifa_.ifa_scope = 0;
+
+ return 0;
+}
+
+static int run_test (char*const ip_slash_netmask,
+ const char*const if_name)
+{
+ Secondary_Ipaddr_Handler sec_ip_handler;
+
+ if (sec_ip_handler.open (ACE_Reactor::instance (),
+ ip_slash_netmask,
+ if_name)
+ == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT("(%P) SOCK_Netlink_Test - run_test () failed ")
+ ACE_TEXT("due to sec_ip_handler.open () error.\n")),
+ -1);
+
+ ACE_Time_Value wait_time (4, 0);
+
+ ACE_Reactor::instance()->run_reactor_event_loop (wait_time);
+
+ if (sec_ip_handler.get_state () != Secondary_Ipaddr_Handler::SUCCESS)
+ return -1;
+
+ return 0;
+}
+
+static int
+parse_args (int argc, ACE_TCHAR *argv[])
+{
+ if (argc == 1) // one button test
+ {
+ one_button_test = 1;
+ return 0;
+ }
+
+ ACE_OS::memset (ip_slash_mask, 0, sizeof ip_slash_mask);
+ ACE_OS::memset (net_dev_name, 0, sizeof net_dev_name);
+
+ ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("a:di:"));
+ int c = 0, ip_len = 0, if_len = 0;
+ while ((c = get_opt ()) != EOF)
+ {
+ switch (c)
+ {
+ case 'a': // ip_slash_netmask_bits
+ ACE_OS::strcpy (ip_slash_mask,
+ reinterpret_cast <const char*> (get_opt.opt_arg ()));
+
+ if (! (ip_len = ACE_OS::strlen (ip_slash_mask)))
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT("%s, -a should be followed by a dotted ipv4 addr slash netmask bits.\n")
+ ACE_TEXT("Example: \"-a 192.168.1.1/24\" .\n"),
+ ACE_TEXT("SOCK_Netlink_Test")));
+ return -1;
+ }
+ break;
+
+ case 'd':
+ dont_cleanup_added_ip = 1;
+ break;
+
+ case 'i': // name of the interface
+ ACE_OS::strcpy (net_dev_name,
+ reinterpret_cast <const char*> (get_opt.opt_arg ()));
+ if (! (if_len = ACE_OS::strlen (net_dev_name)))
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT("%s, -i should be followed by a valid name of network interface.\n"),
+ ACE_TEXT("SOCK_Netlink_Test")));
+ return -1;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if ((ip_len == 0 && if_len) || (ip_len && if_len == 0))
+ {
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT("%s - error: both options -a and -i should be provided. \n"),
+ ACE_TEXT("SOCK_Netlink_Test")),
+ -1);
+ }
+ else if (ip_len == 0 && if_len == 0)
+ {
+ one_button_test = 1;
+ }
+
+ return 0;
+}
+
+#define DEFAULT_IP_SLASH_MASK "192.168.1.100/24"
+#define DEFAULT_NET_DEVICE_NAME "lo"
+
+int
+run_main (int argc, ACE_TCHAR *argv[])
+{
+ ACE_START_TEST (ACE_TEXT ("SOCK_Netlink_Test"));
+
+ if (::geteuid ())
+ {
+ ACE_DEBUG ((LM_INFO,
+ ACE_TEXT ("Process has no superuser priveleges. ")
+ ACE_TEXT ("Unable to run this test.\n")));
+ }
+ else
+ {
+ if (::parse_args (argc, argv) == -1)
+ {
+ return -1;
+ }
+
+ if (one_button_test)
+ {
+ ACE_OS::strcpy (ip_slash_mask,
+ DEFAULT_IP_SLASH_MASK);
+ ACE_OS::strcpy (net_dev_name,
+ DEFAULT_NET_DEVICE_NAME);
+ }
+
+ int rval = -1;
+ if ((rval = run_test (ip_slash_mask,
+ net_dev_name)) < 0)
+ {
+ ACE_DEBUG ((LM_ERROR,
+ ACE_TEXT ("run_test() failed with rval returned %d. "),
+ rval));
+ return -1;
+ }
+ }
+
+ ACE_END_TEST;
+
+ return 0;
+}
+
+#else /* ACE_HAS_NETLINK*/
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("SOCK_Netlink_Test"));
+
+ ACE_DEBUG ((LM_INFO,
+ ACE_TEXT("(%P|%t|%T) \"SOCK_Netlink_Test\" main() - ")
+ ACE_TEXT("Linux netlink socket support not configured.\n")
+ ACE_TEXT("#define ACE_HAS_NETLINK = 1 in your config.h ")
+ ACE_TEXT("file to enable and run the process as a superuser.\n")));
+
+ ACE_END_TEST;
+
+ return 0;
+}
+
+#endif /* ACE_HAS_NETLINK*/
+
diff --git a/ACE/tests/SOCK_SEQPACK_SCTP_Test.cpp b/ACE/tests/SOCK_SEQPACK_SCTP_Test.cpp
new file mode 100644
index 00000000000..374745d2c32
--- /dev/null
+++ b/ACE/tests/SOCK_SEQPACK_SCTP_Test.cpp
@@ -0,0 +1,394 @@
+// $Id$
+//
+// *WARRANTY DISCLAIMER: LIMITATION OF LIABILITY. THE SOFTWARE AND
+// CONTENT ARE PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED
+// REPRESENTATIONS, GUARANTEES, OR WARRANTIES, INCLUDING BUT NOT LIMITED
+// TO SUCH REPRESENTATION, GUARANTEES OR WARRANTIES REGARDING THE
+// USABILITY, SUITABILITY, CONDITION, OPERATION OR ACCURACY THEREOF. *
+//
+// *ALL OTHER WARRANTIES AND CONDITIONS (EXPRESS, IMPLIED OR STATUTORY)
+// ARE HEREBY DISCLAIMED, SUCH WARRANTIES AND CONDITIONS INCLUDING
+// WITHOUT LIMITATION, ALL WARRANTIES AND CONDITIONS OF MERCHANTABILITY,
+// TITLE, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT,
+// COMPATIBILITY, AND SECURITY OR ACCURACY.*
+//
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// SOCK_SEQPACK_SCTP_Test.cpp
+//
+// = DESCRIPTION
+// Performs several tests on the ACE_SOCK_SEQPACK_Connector,
+// ACE_SOCK_SEQPACK_Acceptor, and ACE_SOCK_SEQPACK_Association classes
+// specifically for SCTP using the loopback interface. Attempts to
+// replicate behavior of SOCK_Test.cpp, but integrating IPv6 tests
+// directly.
+//
+// = AUTHOR
+// Dave Craig <dwc@qualcomm.com>
+//
+
+#include "test_config.h"
+#include "ace/OS_NS_unistd.h"
+#include "ace/OS_NS_sys_select.h"
+#include "ace/OS_NS_sys_wait.h"
+#include "ace/SOCK_SEQPACK_Connector.h"
+#include "ace/SOCK_SEQPACK_Acceptor.h"
+#include "ace/Thread_Manager.h"
+#include "ace/Handle_Set.h"
+
+#define TTCPPORT 5001
+#define BYTE_MESG 0xcd
+
+struct tdesc {
+ ACE_Thread_Semaphore *tsemap;
+ bool ipv6_test;
+};
+
+typedef struct tdesc tdesc_t;
+
+#ifdef ACE_WIN64
+// This arg is ignored on Windows and causes pointer truncation
+// warnings on 64-bit compiled.
+#define SELECT_WIDTH(x) 0
+#else
+#define SELECT_WIDTH(x) (x)
+#endif
+
+ACE_THR_FUNC_RETURN
+Server (void *arg)
+{
+ ACE_SOCK_SEQPACK_Acceptor *AcceptorSocket =
+ reinterpret_cast<ACE_SOCK_SEQPACK_Acceptor *> (arg);
+
+ ACE_SOCK_SEQPACK_Association Stream;
+
+ ACE_Handle_Set handle_set;
+
+ const ACE_Time_Value def_timeout (ACE_DEFAULT_TIMEOUT);
+
+ ACE_Time_Value tv (def_timeout);
+
+ int select_width;
+
+ int result;
+
+ //
+ // Make sure AcceptorSocket is in nonblocking mode so as not to
+ // hang tests.
+ //
+ if (-1 == AcceptorSocket->enable (ACE_NONBLOCK))
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n"),
+ ACE_TEXT ("AcceptorSocket.enable (ACE_NONBLOCK)")));
+ }
+
+ //
+ // Set up select to wait for I/O events.
+ //
+ handle_set.reset ();
+ handle_set.set_bit (AcceptorSocket->get_handle ());
+
+ select_width = SELECT_WIDTH(int (AcceptorSocket->get_handle ()) + 1);
+
+ result = ACE_OS::select(select_width,
+ handle_set,
+ 0,
+ 0,
+ &tv);
+
+ ACE_ASSERT (tv == def_timeout);
+
+ if (-1 == result)
+ {
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n"),
+ ACE_TEXT ("select")),
+ 0);
+ }
+ else if (0 == result)
+ {
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT("(%P|%t) select timed out, shutting down\n")),
+ 0);
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) waiting for client to connect\n")));
+
+ while (-1 != AcceptorSocket->accept (Stream)) {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) client connected\n")));
+
+ //
+ // Enable non-blocking I/O.
+ //
+ if (Stream.enable (ACE_NONBLOCK))
+ {
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n"),
+ ACE_TEXT ("Stream.enable (ACE_NONBLOCK)")),
+ 0);
+ }
+
+ unsigned char byte = BYTE_MESG;
+
+ if (-1 == Stream.send_n (&byte, 1))
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n"),
+ ACE_TEXT ("Stream.send_n")));
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) byte sent\n")));
+
+ //
+ // Ubruptly terminate the association.
+ //
+ if (-1 == Stream.abort ())
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n"),
+ ACE_TEXT ("Association.abort")));
+ }
+
+ //
+ // Negative test: make sure that we cannot send on a closed association.
+ //
+ if (-1 != Stream.send_n (&byte, 1))
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Negative test fail: Association")
+ ACE_TEXT(".send_n succeeded after abort()\n")));
+ }
+
+ }
+
+ //
+ // Close server socket.
+ //
+ if (-1 == AcceptorSocket->close ())
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n"),
+ ACE_TEXT ("AcceptorSocket.close")));
+ }
+
+ return 0;
+}
+
+ACE_THR_FUNC_RETURN
+Client(void *arg)
+{
+ ACE_Multihomed_INET_Addr *ServerAddr =
+ reinterpret_cast<ACE_Multihomed_INET_Addr *> (arg);
+
+ ACE_SOCK_SEQPACK_Connector Connector;
+
+ ACE_SOCK_SEQPACK_Association Stream;
+
+ ACE_Time_Value tv (ACE_DEFAULT_TIMEOUT);
+
+ char b;
+ size_t bytes;
+
+ if (-1 == Connector.connect (Stream,
+ *ServerAddr,
+ &tv,
+ ACE_Addr::sap_any,
+ 1))
+ {
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p to %s:%d\n"),
+ ACE_TEXT ("Connector.connect"),
+ ServerAddr->get_host_name (),
+ ServerAddr->get_port_number ()),
+ 0);
+ }
+
+ if (-1 == Stream.disable (ACE_NONBLOCK))
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n"),
+ ACE_TEXT ("Association.disable (ACE_NONBLOCK)")));
+ }
+
+
+ if (-1 == Stream.recv_n (&b, 1, &tv, &bytes))
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n"),
+ ACE_TEXT ("Association.recv_n")));
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Client received %d bytes\n"),
+ bytes));
+ ACE_ASSERT(1 == bytes);
+
+ //
+ // Give server a little time to abort the association.
+ //
+ ACE_OS::sleep(1);
+
+ if (-1 != Stream.recv_n (&b, 1, &tv, &bytes))
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Negative test failed Association")
+ ACE_TEXT (".recv_n succeeded after abort()\n")));
+ }
+
+ return 0;
+}
+
+//
+// Spawn server and client threads and then wait until they complete the
+// test. There must be a timeout on the wait, so executable does not hang the
+// tests indefinitely.
+//
+int
+spawn_test(bool ipv6_test)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) spawn_test started ipv6 %d\n"),
+ ipv6_test));
+
+ ACE_SOCK_SEQPACK_Acceptor AcceptorSocket;
+
+ ACE_Multihomed_INET_Addr ServerAddr (TTCPPORT,
+#ifdef ACE_HAS_IPV6
+ (ipv6_test ?
+ ACE_IPV6_LOCALHOST :
+ ACE_LOCALHOST)
+#else /* ! ACE_HAS_IPV6 */
+ ACE_LOCALHOST
+#endif /* ! ACE_HAS_IPV6 */
+ );
+
+ if (-1 == AcceptorSocket.open (ServerAddr,
+ 1,
+#ifdef ACE_HAS_IPV6
+ (ipv6_test ? AF_INET6 : AF_INET),
+#else /* ! ACE_HAS_IPV6 */
+ AF_INET,
+#endif /* ! ACE_HAS_IPV6 */
+ ACE_DEFAULT_BACKLOG
+#if defined (IPPROTO_SCTP)
+ ,IPPROTO_SCTP
+#endif /* IPPROTO_SCTP */
+ ))
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n"),
+ ACE_TEXT ("AcceptorSocket.open")));
+ }
+
+ if (-1 == AcceptorSocket.get_local_addr (ServerAddr))
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n"),
+ ACE_TEXT ("AcceptorSocket.get_local_addr")));
+ }
+
+ struct sockaddr_in inaddr;
+
+ ServerAddr.get_addresses(&inaddr, 1);
+
+ ACE_ASSERT ((TTCPPORT == ServerAddr.get_port_number ()));
+ ACE_ASSERT ((ipv6_test || INADDR_LOOPBACK == ServerAddr.get_ip_address ()));
+ ACE_ASSERT ((!ipv6_test ||
+ ACE_Multihomed_INET_Addr(TTCPPORT, "::1") == ServerAddr));
+
+#ifndef ACE_LACKS_FORK
+ switch (ACE_OS::fork (ACE_TEXT ("child")))
+ {
+ case -1:
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p%a"),
+ ACE_TEXT ("fork failed")));
+ break;
+ case 0:
+ Client (&ServerAddr);
+ exit (0);
+ break;
+ default:
+ Server (reinterpret_cast<void *> (&AcceptorSocket));
+ ACE_OS::wait ();
+ break;
+ }
+#elif defined (ACE_HAS_THREADS)
+ if (-1 == ACE_Thread_Manager::instance ()->spawn
+ (Server,
+ reinterpret_cast<void *> (&AcceptorSocket),
+ THR_NEW_LWP | THR_DETACHED))
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p%a"),
+ ACE_TEXT ("thread create failed")));
+ }
+
+ if (-1 == ACE_Thread_Manager::instance ()->spawn
+ (Client,
+ reinterpret_cast<void *> (&ServerAddr),
+ THR_NEW_LWP | THR_DETACHED))
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p%a"),
+ ACE_TEXT ("thread create failed")));
+ }
+
+ ACE_Thread_Manager::instance ()->wait ();
+#else /* ACE_LACKS_FORK && ! ACE_HAS_THREADS */
+ ACE_ERROR ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) \n"),
+ ACE_TEXT ("only one thread may be run ")
+ ACE_TEXT ("in a process on this platform\n")));
+#endif /* ACE_LACKS_FORK && ! ACE_HAS_THREADS */
+
+ return 0;
+}
+
+int
+do_test(void)
+{
+ spawn_test(false);
+
+#ifdef ACE_HAS_IPV6
+ spawn_test(true);
+#endif
+
+ return 0;
+}
+
+int run_main (int argc, ACE_TCHAR *argv[])
+{
+ ACE_UNUSED_ARG (argc);
+ ACE_UNUSED_ARG (argv);
+
+ ACE_START_TEST (ACE_TEXT ("SOCK_SEQPACK_SCTP_Test"));
+
+ //
+ // Check whether host OS has SCTP support before starting this test.
+ // If not, just pass because there is not a hope of testing
+ // SOCK_SEQPACK.
+ //
+ int status = 0;
+
+#ifdef ACE_HAS_SCTP
+ status = do_test();
+#else /* ! ACE_HAS_SCTP */
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT("SCTP not supported by ACE.\n")
+ ACE_TEXT("This test will not do anything.\n")));
+#endif /* ! ACE_HAS_SCTP */
+
+ ACE_END_TEST;
+
+ return status;
+}
+
diff --git a/ACE/tests/SOCK_Send_Recv_Test.cpp b/ACE/tests/SOCK_Send_Recv_Test.cpp
new file mode 100644
index 00000000000..f971c98e65b
--- /dev/null
+++ b/ACE/tests/SOCK_Send_Recv_Test.cpp
@@ -0,0 +1,397 @@
+// $Id$
+
+// ===========================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// SOCK_Send_Recv_Test.cpp
+//
+// = DESCRIPTION
+// This is a test of the <ACE_SOCK>'s various send and receive
+// methods. The test forks two processes or spawns two threads
+// (depending upon the platform) and then executes client and
+// server allowing them to connect and exchange data in ways
+// designed to exercise the send and recv functions.
+//
+// Right now, it primarily tests the iov-like send and recv
+// functions, but others should be added to completely cover the
+// possible scenarios.
+//
+// = AUTHOR
+// Steve Huston <shuston@riverace.com>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/OS_NS_sys_wait.h"
+#include "ace/OS_NS_unistd.h"
+#include "ace/Thread.h"
+#include "ace/Thread_Manager.h"
+#include "ace/Time_Value.h"
+#include "ace/SOCK_Connector.h"
+#include "ace/SOCK_Acceptor.h"
+#include "ace/SOCK_Stream.h"
+
+ACE_RCSID(tests, SOCK_Send_Recv_Test, "$Id$")
+
+// Change to non-zero if test fails
+static int Test_Result = 0;
+
+#if !defined (ACE_LACKS_FORK) || defined (ACE_HAS_THREADS)
+
+// In test 3, a large amount of data is sent. The purpose is to overflow the
+// TCP send window, causing the sender to block (it's a send_n). This value
+// is the amount to send. The assumption is that no implementation has a
+// receive window larger than 128K bytes. If one is found, this is the place
+// to change it.
+// For some odd reason, NT will try to send a single large buffer, but not
+// multiple smaller ones that add up to the large size.
+const size_t Test3_Send_Size = 4*1024;
+const size_t Test3_Loops = 10;
+const size_t Test3_Total_Size = Test3_Send_Size * Test3_Loops;
+
+
+static void *
+client (void *arg)
+{
+ ACE_INET_Addr *remote_addr = reinterpret_cast<ACE_INET_Addr *> (arg);
+ ACE_INET_Addr server_addr (remote_addr->get_port_number (),
+ ACE_LOCALHOST);
+ ACE_SOCK_Stream cli_stream;
+ ACE_SOCK_Connector con;
+ ACE_Time_Value timeout (ACE_DEFAULT_TIMEOUT);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Connecting to port %d\n"),
+ server_addr.get_port_number()));
+
+ // Initiate connection with server; don't wait forever
+ if (con.connect (cli_stream,
+ server_addr,
+ &timeout) == -1)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n"),
+ ACE_TEXT ("connection failed")));
+ Test_Result = 1;
+ return 0;
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) connected to %s\n"),
+ ACE_TEXT_CHAR_TO_TCHAR(server_addr.get_host_name ())));
+
+ //******************* TEST 1 ******************************
+ //
+ // Do a iovec sendv - send the 255 byte buffer in 5 chunks. The
+ // server will verify that the correct data is sent, and that there
+ // is no more and no less.
+
+ u_char buffer[255];
+ size_t i;
+ ssize_t len;
+
+ // The server will verify that this data pattern gets there intact.
+
+ for (i = 0; i < sizeof buffer; ++i)
+ buffer[i] = static_cast<u_char> (i);
+
+ iovec iov[5];
+
+ iov[0].iov_base = reinterpret_cast<char *> (&buffer[0]);
+ iov[0].iov_len = 50;
+
+ iov[1].iov_base = reinterpret_cast<char *> (&buffer[50]);
+ iov[1].iov_len = 25;
+
+ iov[2].iov_base = reinterpret_cast<char *> (&buffer[75]);
+ iov[2].iov_len = 150;
+
+ iov[3].iov_base = reinterpret_cast<char *> (&buffer[225]);
+ iov[3].iov_len = 29;
+
+ iov[4].iov_base = reinterpret_cast<char *> (&buffer[254]);
+ iov[4].iov_len = 1;
+
+ len = cli_stream.sendv (iov, 5);
+ if (len == -1)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n"),
+ ACE_TEXT ("Test 1, sendv failed")));
+ Test_Result = 1;
+ }
+ else
+ ACE_ASSERT (len == 255);
+
+ //******************* TEST 2 ******************************
+ //
+ // The same data is coming back - receive it using recv (size_t n,
+ // ...) and compare it to the original data.
+
+ u_char buffer2[255];
+ // Give it a chance to get here
+ ACE_OS::sleep (2);
+ len = cli_stream.recv (4,
+ buffer2,
+ 150,
+ &buffer2[150],
+ 105);
+ if (len != 255)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p; len is %d, but should be 255!\n"),
+ len));
+ }
+ ACE_ASSERT (len == 255);
+
+ for (i = 0; i < 255; i++)
+ if (buffer2[i] != buffer[i])
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Test 2, rcvd byte %d is %d, not %d\n"),
+ i, buffer2[i], buffer[i]));
+ Test_Result = 1;
+ }
+
+ //******************* TEST 3 ******************************
+ //
+ // Do a send_n of a large size. The receive should sleep some to
+ // cause the data reception to be delayed, which will fill up the
+ // TCP window and cause send_n to block at some point. The particular
+ // case this tests only needs to be exercised if the socket is
+ // non-blocking, so set that first.
+
+ ssize_t sent;
+ char buff[Test3_Send_Size];
+ ACE_ASSERT (cli_stream.enable (ACE_NONBLOCK) != -1);
+ for (i = 0; i < Test3_Loops; ++i)
+ {
+ errno = 0;
+ sent = cli_stream.send_n (buff, sizeof (buff));
+ if (sent != sizeof (buff) && errno != 0)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Test 3, pass %d, sent %d, %p\n"),
+ i, sent, ACE_TEXT ("error")));
+ Test_Result = 1; // Fail
+ }
+ }
+
+ cli_stream.close ();
+
+ return 0;
+}
+
+static void *
+server (void *arg)
+{
+ ACE_SOCK_Acceptor *peer_acceptor = (ACE_SOCK_Acceptor *) arg;
+ ACE_SOCK_Stream sock_str;
+ ACE_INET_Addr cli_addr;
+ ACE_Time_Value timeout (ACE_DEFAULT_TIMEOUT);
+
+ // Accept the connection over which the stream tests will run.
+ // Don't lock up if client doesn't connect
+ if (peer_acceptor->accept (sock_str,
+ &cli_addr,
+ &timeout) == -1)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n"),
+ ACE_TEXT ("accept")));
+ Test_Result = 1;
+ return 0;
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) client %s connected from %d\n"),
+ ACE_TEXT_CHAR_TO_TCHAR(cli_addr.get_host_name ()),
+ cli_addr.get_port_number ()));
+
+ //******************* TEST 1 ******************************
+ //
+ // Do a iovec recvv - the client should send 255 bytes, which we
+ // will be detected and read into a ACE-allocated buffer. Use a 5
+ // second timeout to give the client a chance to send it all.
+
+ ACE_OS::sleep (5);
+
+ iovec iov[3];
+ u_char buffer[255];
+ ssize_t len;
+ int i;
+
+ iov[0].iov_base = reinterpret_cast<char *> (&buffer[0]);
+ iov[0].iov_len = 75;
+
+ iov[1].iov_base = reinterpret_cast<char *> (&buffer[75]);
+ iov[1].iov_len = 100;
+
+ iov[2].iov_base = reinterpret_cast<char *> (&buffer[175]);
+ iov[2].iov_len = 80;
+
+ len = sock_str.recvv_n (iov, 3);
+ if (len == -1)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n"),
+ ACE_TEXT ("Test 1, recvv failed")));
+ Test_Result = 1;
+ }
+
+ ACE_ASSERT (len == 255);
+ for (i = 0; i < 255; i++)
+ if (buffer[i] != i)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Test 1, rcvd byte %d is %d, not %d\n"),
+ i,
+ buffer[i],
+ i));
+ Test_Result = 1;
+ }
+
+ //******************* TEST 2 ******************************
+ //
+ // Send the buffer back, using send (size_t n, ...) in 3 pieces.
+
+ len = sock_str.send (6,
+ buffer,
+ 42,
+ &buffer[42],
+ 189,
+ &buffer[231],
+ 24);
+ ACE_ASSERT (len == 255);
+
+ //******************* TEST 3 ******************************
+ //
+ // The sender is testing send_n to make sure it blocks if the TCP
+ // window fills. So sleep here for a bit to avoid getting the data
+ // yet. Then just read and empty out the received data.
+ ACE_OS::sleep (8);
+ // Keep reading until the peer closes.
+ sock_str.disable (ACE_NONBLOCK);
+ ssize_t got = 1;
+ size_t total_recv = 0;
+ while (got != 0)
+ {
+ errno = 0;
+ got = sock_str.recv (buffer, sizeof (buffer));
+ if (got < 0)
+ break;
+ total_recv += got;
+ }
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) Test 3 received %d bytes\n"),
+ total_recv));
+
+ if (total_recv == Test3_Total_Size)
+ {
+ if (got != 0 || errno != 0)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Test 3 final recv status %d, expected 0\n"),
+ got));
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%P|%t) %p\n"),
+ ACE_TEXT ("expected errno == 0, instead")));
+ Test_Result = 1; // Fail
+ }
+ }
+ else
+ {
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%P|%t) Test 3 expected %d %p\n"),
+ Test3_Total_Size, ACE_TEXT ("bytes")));
+ Test_Result = 1;
+ }
+
+ sock_str.close();
+
+ return 0;
+}
+
+#endif /* !ACE_LACKS_FORK || ACE_HAS_THREADS */
+
+static void
+spawn (void)
+{
+ // Acceptor
+ ACE_SOCK_Acceptor peer_acceptor;
+
+ // Create a server address.
+ ACE_INET_Addr server_addr;
+
+ // Bind listener to any port and then find out what the port was.
+ if (peer_acceptor.open (ACE_Addr::sap_any) == -1
+ || peer_acceptor.get_local_addr (server_addr) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n"),
+ ACE_TEXT ("open")));
+ else
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) starting server at port %d\n"),
+ server_addr.get_port_number ()));
+
+#if !defined (ACE_LACKS_FORK)
+ switch (ACE_OS::fork (ACE_TEXT ("child")))
+ {
+ case -1:
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n%a"),
+ ACE_TEXT ("fork failed"),
+ 1));
+ /* NOTREACHED */
+ case 0:
+ client (&server_addr);
+ ACE_OS::exit (0);
+ /* NOTREACHED */
+ default:
+ server (reinterpret_cast<void *> (&peer_acceptor));
+ ACE_OS::wait ();
+ }
+#elif defined (ACE_HAS_THREADS)
+ if (ACE_Thread_Manager::instance ()->spawn
+ (ACE_THR_FUNC (server),
+ reinterpret_cast<void *> (&peer_acceptor),
+ THR_NEW_LWP | THR_DETACHED) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n%a"),
+ ACE_TEXT ("thread create failed"),
+ 1));
+
+ if (ACE_Thread_Manager::instance ()->spawn
+ (ACE_THR_FUNC (client),
+ reinterpret_cast<void *> (&server_addr),
+ THR_NEW_LWP | THR_DETACHED) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n%a"),
+ ACE_TEXT ("thread create failed"),
+ 1));
+
+ // Wait for the threads to exit.
+ ACE_Thread_Manager::instance ()->wait ();
+#else
+ ACE_ERROR ((LM_INFO,
+ ACE_TEXT ("(%P|%t) ")
+ ACE_TEXT ("only one thread may be run ")
+ ACE_TEXT ("in a process on this platform\n")));
+#endif /* ACE_HAS_THREADS */
+
+ peer_acceptor.close ();
+ }
+}
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("SOCK_Send_Recv_Test"));
+
+ spawn ();
+
+ ACE_END_TEST;
+ return Test_Result;
+}
diff --git a/ACE/tests/SOCK_Send_Recv_Test_IPV6.cpp b/ACE/tests/SOCK_Send_Recv_Test_IPV6.cpp
new file mode 100644
index 00000000000..b630ffb00ec
--- /dev/null
+++ b/ACE/tests/SOCK_Send_Recv_Test_IPV6.cpp
@@ -0,0 +1,399 @@
+// $Id$
+// ===========================================================================
+/**
+ * @file SOCK_Send_Recv_Test_IPV6.cpp
+ *
+ * @brief This is a test of the <ACE_SOCK>'s various send and receive
+ * methods.
+
+ * The test forks two processes or spawns two threads (depending upon
+ * the platform) and then executes client and server allowing them to
+ * connect and exchange data in ways designed to exercise the send
+ * and recv functions. Right now, it primarily tests the iov-like
+ * send and recv functions, but others should be added to completely
+ * cover the possible scenarios.
+ *
+ * @author Steve Huston <shuston@riverace.com>
+ * Brian Buesker <bbuesker@qualcomm.com>
+ */
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/OS_NS_sys_wait.h"
+#include "ace/OS_NS_unistd.h"
+#include "ace/Thread.h"
+#include "ace/Thread_Manager.h"
+#include "ace/Time_Value.h"
+#include "ace/SOCK_Connector.h"
+#include "ace/SOCK_Acceptor.h"
+#include "ace/SOCK_Stream.h"
+
+// Change to non-zero if test fails
+static int Test_Result = 0;
+
+#if !defined (ACE_LACKS_FORK) || defined (ACE_HAS_THREADS)
+
+// In test 3, a large amount of data is sent. The purpose is to overflow the
+// TCP send window, causing the sender to block (it's a send_n). This value
+// is the amount to send. The assumption is that no implementation has a
+// receive window larger than 128K bytes. If one is found, this is the place
+// to change it.
+// For some odd reason, NT will try to send a single large buffer, but not
+// multiple smaller ones that add up to the large size.
+const size_t Test3_Send_Size = 4*1024;
+const size_t Test3_Loops = 10;
+const size_t Test3_Total_Size = Test3_Send_Size * Test3_Loops;
+
+
+#if defined (ACE_HAS_IPV6)
+
+static void *
+client (void *arg)
+{
+ ACE_INET_Addr *remote_addr = reinterpret_cast<ACE_INET_Addr *> (arg);
+ ACE_INET_Addr server_addr (remote_addr->get_port_number (),
+ ACE_IPV6_LOCALHOST);
+
+ ACE_SOCK_Stream cli_stream;
+ ACE_SOCK_Connector con;
+ ACE_Time_Value timeout (ACE_DEFAULT_TIMEOUT);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Connecting to port %d\n"),
+ server_addr.get_port_number()));
+
+ // Initiate connection with server; don't wait forever
+ if (con.connect (cli_stream,
+ server_addr,
+ &timeout) == -1)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n"),
+ ACE_TEXT ("connection failed")));
+ Test_Result = 1;
+ return 0;
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) connected to %s\n"),
+ ACE_TEXT_CHAR_TO_TCHAR(server_addr.get_host_name ())));
+
+ //******************* TEST 1 ******************************
+ //
+ // Do a iovec sendv - send the 255 byte buffer in 5 chunks. The
+ // server will verify that the correct data is sent, and that there
+ // is no more and no less.
+
+ u_char buffer[255];
+ size_t i;
+ ssize_t len;
+
+ // The server will verify that this data pattern gets there intact.
+
+ for (i = 0; i < sizeof buffer; ++i)
+ buffer[i] = static_cast<u_char> (i);
+
+ iovec iov[5];
+
+ iov[0].iov_base = reinterpret_cast<char *> (&buffer[0]);
+ iov[0].iov_len = 50;
+
+ iov[1].iov_base = reinterpret_cast<char *> (&buffer[50]);
+ iov[1].iov_len = 25;
+
+ iov[2].iov_base = reinterpret_cast<char *> (&buffer[75]);
+ iov[2].iov_len = 150;
+
+ iov[3].iov_base = reinterpret_cast<char *> (&buffer[225]);
+ iov[3].iov_len = 29;
+
+ iov[4].iov_base = reinterpret_cast<char *> (&buffer[254]);
+ iov[4].iov_len = 1;
+
+ len = cli_stream.sendv (iov, 5);
+ if (len == -1)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n"),
+ ACE_TEXT ("Test 1, sendv failed")));
+ Test_Result = 1;
+ }
+ else
+ ACE_ASSERT (len == 255);
+
+ //******************* TEST 2 ******************************
+ //
+ // The same data is coming back - receive it using recv (size_t n,
+ // ...) and compare it to the original data.
+
+ u_char buffer2[255];
+ // Give it a chance to get here
+ ACE_OS::sleep (2);
+ len = cli_stream.recv (4,
+ buffer2,
+ 150,
+ &buffer2[150],
+ 105);
+ if (len != 255)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p; len is %d, but should be 255!\n"),
+ len));
+ }
+ ACE_ASSERT (len == 255);
+
+ for (i = 0; i < 255; i++)
+ if (buffer2[i] != buffer[i])
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Test 2, rcvd byte %d is %d, not %d\n"),
+ i, buffer2[i], buffer[i]));
+ Test_Result = 1;
+ }
+
+ //******************* TEST 3 ******************************
+ //
+ // Do a send_n of a large size. The receive should sleep some to
+ // cause the data reception to be delayed, which will fill up the
+ // TCP window and cause send_n to block at some point. The particular
+ // case this tests only needs to be exercised if the socket is
+ // non-blocking, so set that first.
+
+ ssize_t sent;
+ char buff[Test3_Send_Size];
+ ACE_ASSERT (cli_stream.enable (ACE_NONBLOCK) != -1);
+ for (i = 0; i < Test3_Loops; ++i)
+ {
+ errno = 0;
+ sent = cli_stream.send_n (buff, sizeof (buff));
+ if (sent != sizeof (buff) && errno != 0)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Test 3, pass %d, sent %d, %p\n"),
+ i, sent, ACE_TEXT ("error")));
+ Test_Result = 1; // Fail
+ }
+ }
+
+ cli_stream.close ();
+
+ return 0;
+}
+
+static void *
+server (void *arg)
+{
+ ACE_SOCK_Acceptor *peer_acceptor = (ACE_SOCK_Acceptor *) arg;
+ ACE_SOCK_Stream sock_str;
+ ACE_INET_Addr cli_addr;
+ ACE_Time_Value timeout (ACE_DEFAULT_TIMEOUT);
+
+ // Accept the connection over which the stream tests will run.
+ // Don't lock up if client doesn't connect
+ if (peer_acceptor->accept (sock_str,
+ &cli_addr,
+ &timeout) == -1)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n"),
+ ACE_TEXT ("accept")));
+ Test_Result = 1;
+ return 0;
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) client %s connected from %d\n"),
+ ACE_TEXT_CHAR_TO_TCHAR(cli_addr.get_host_name ()),
+ cli_addr.get_port_number ()));
+
+ //******************* TEST 1 ******************************
+ //
+ // Do a iovec recvv - the client should send 255 bytes, which we
+ // will be detected and read into a ACE-allocated buffer. Use a 5
+ // second timeout to give the client a chance to send it all.
+
+ ACE_OS::sleep (5);
+
+ iovec iov[3];
+ u_char buffer[255];
+ ssize_t len;
+ int i;
+
+ iov[0].iov_base = reinterpret_cast<char *> (&buffer[0]);
+ iov[0].iov_len = 75;
+
+ iov[1].iov_base = reinterpret_cast<char *> (&buffer[75]);
+ iov[1].iov_len = 100;
+
+ iov[2].iov_base = reinterpret_cast<char *> (&buffer[175]);
+ iov[2].iov_len = 80;
+
+ len = sock_str.recvv_n (iov, 3);
+ if (len == -1)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n"),
+ ACE_TEXT ("Test 1, recvv failed")));
+ Test_Result = 1;
+ }
+
+ ACE_ASSERT (len == 255);
+ for (i = 0; i < 255; i++)
+ if (buffer[i] != i)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Test 1, rcvd byte %d is %d, not %d\n"),
+ i,
+ buffer[i],
+ i));
+ Test_Result = 1;
+ }
+
+ //******************* TEST 2 ******************************
+ //
+ // Send the buffer back, using send (size_t n, ...) in 3 pieces.
+
+ len = sock_str.send (6,
+ buffer,
+ 42,
+ &buffer[42],
+ 189,
+ &buffer[231],
+ 24);
+ ACE_ASSERT (len == 255);
+
+ //******************* TEST 3 ******************************
+ //
+ // The sender is testing send_n to make sure it blocks if the TCP
+ // window fills. So sleep here for a bit to avoid getting the data
+ // yet. Then just read and empty out the received data.
+ ACE_OS::sleep (8);
+ // Keep reading until the peer closes.
+ sock_str.disable (ACE_NONBLOCK);
+ ssize_t got = 1;
+ size_t total_recv = 0;
+ while (got != 0)
+ {
+ errno = 0;
+ got = sock_str.recv (buffer, sizeof (buffer));
+ if (got < 0)
+ break;
+ total_recv += got;
+ }
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) Test 3 received %d bytes\n"),
+ total_recv));
+
+ if (total_recv == Test3_Total_Size)
+ {
+ if (got != 0 || errno != 0)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Test 3 final recv status %d, expected 0\n"),
+ got));
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%P|%t) %p\n"),
+ ACE_TEXT ("expected errno == 0, instead")));
+ Test_Result = 1; // Fail
+ }
+ }
+ else
+ {
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%P|%t) Test 3 expected %d %p\n"),
+ Test3_Total_Size, ACE_TEXT ("bytes")));
+ Test_Result = 1;
+ }
+
+ sock_str.close();
+
+ return 0;
+}
+
+#endif /*ACE_HAS_IPV6*/
+
+#endif /* !ACE_LACKS_FORK || ACE_HAS_THREADS */
+
+#if defined (ACE_HAS_IPV6)
+static void
+spawn (void)
+{
+ // Acceptor
+ ACE_SOCK_Acceptor peer_acceptor;
+
+ // Create a server address.
+ ACE_INET_Addr server_addr;
+
+ // Bind listener to any port and then find out what the port was.
+ if (peer_acceptor.open (ACE_Addr::sap_any, 0, AF_INET6) == -1
+ || peer_acceptor.get_local_addr (server_addr) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n"),
+ ACE_TEXT ("open")));
+ else
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) starting server at port %d\n"),
+ server_addr.get_port_number ()));
+
+#if !defined (ACE_LACKS_FORK)
+ switch (ACE_OS::fork (ACE_TEXT("child")))
+ {
+ case -1:
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n%a"),
+ ACE_TEXT ("fork failed"),
+ 1));
+ /* NOTREACHED */
+ case 0:
+ client (&server_addr);
+ ACE_OS::exit (0);
+ /* NOTREACHED */
+ default:
+ server (reinterpret_cast<void *> (&peer_acceptor));
+ ACE_OS::wait ();
+ }
+#elif defined (ACE_HAS_THREADS)
+ if (ACE_Thread_Manager::instance ()->spawn
+ (ACE_THR_FUNC (server),
+ reinterpret_cast<void *> (&peer_acceptor),
+ THR_NEW_LWP | THR_DETACHED) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n%a"),
+ ACE_TEXT ("thread create failed"),
+ 1));
+
+ if (ACE_Thread_Manager::instance ()->spawn
+ (ACE_THR_FUNC (client),
+ reinterpret_cast<void *> (&server_addr),
+ THR_NEW_LWP | THR_DETACHED) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n%a"),
+ ACE_TEXT ("thread create failed"),
+ 1));
+
+ // Wait for the threads to exit.
+ ACE_Thread_Manager::instance ()->wait ();
+#else
+ ACE_ERROR ((LM_INFO,
+ ACE_TEXT ("(%P|%t) ")
+ ACE_TEXT ("only one thread may be run ")
+ ACE_TEXT ("in a process on this platform\n")));
+#endif /* ACE_HAS_THREADS */
+
+ peer_acceptor.close ();
+ }
+}
+
+#endif /*ACE_HAS_IPV6*/
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("SOCK_Send_Recv_Test_IPV6"));
+
+#if defined (ACE_HAS_IPV6)
+ spawn ();
+#endif /* ACE_HAS_IPV6 */
+
+ ACE_END_TEST;
+ return Test_Result;
+}
diff --git a/ACE/tests/SOCK_Test.cpp b/ACE/tests/SOCK_Test.cpp
new file mode 100644
index 00000000000..6472711a857
--- /dev/null
+++ b/ACE/tests/SOCK_Test.cpp
@@ -0,0 +1,286 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// SOCK_Test.cpp
+//
+// = DESCRIPTION
+// This is a test of the <ACE_SOCK_Acceptor> and
+// <ACE_SOCK_Connector> classes. The test forks two processes or
+// spawns two threads (depending upon the platform) and then
+// executes client and server allowing them to connect and
+// exchange data.
+//
+// = AUTHOR
+// Prashant Jain <pjain@cs.wustl.edu> and Doug Schmidt <schmidt@cs.wustl.edu>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/OS_NS_unistd.h"
+#include "ace/OS_NS_sys_select.h"
+#include "ace/OS_NS_sys_wait.h"
+#include "ace/Thread.h"
+#include "ace/Time_Value.h"
+#include "ace/Thread_Manager.h"
+#include "ace/SOCK_Connector.h"
+#include "ace/SOCK_Acceptor.h"
+#include "ace/Handle_Set.h"
+
+ACE_RCSID(tests, SOCK_Test, "$Id$")
+
+static const char ACE_ALPHABET[] = "abcdefghijklmnopqrstuvwxyz";
+
+static void *
+client (void *arg)
+{
+ ACE_INET_Addr *remote_addr = (ACE_INET_Addr *) arg;
+ ACE_INET_Addr server_addr (remote_addr->get_port_number (), ACE_LOCALHOST);
+ ACE_SOCK_Stream cli_stream;
+ ACE_SOCK_Connector con;
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) starting non-blocking connect\n")));
+ // Initiate timed, non-blocking connection with server.
+
+ // Attempt a non-blocking connect to the server.
+ if (con.connect (cli_stream, server_addr,
+ (ACE_Time_Value *) &ACE_Time_Value::zero) == -1)
+ {
+ if (errno != EWOULDBLOCK)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%P|%t) %p\n"), ACE_TEXT ("connection failed")));
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) starting timed connect\n")));
+
+ // Check if non-blocking connection is in progress,
+ // and wait up to ACE_DEFAULT_TIMEOUT seconds for it to complete.
+ ACE_Time_Value tv (ACE_DEFAULT_TIMEOUT);
+
+ if (con.complete (cli_stream, &server_addr, &tv) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("(%P|%t) %p\n"), ACE_TEXT ("connection failed")), 0);
+ else
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) connected to %s\n"),
+ ACE_TEXT_CHAR_TO_TCHAR(server_addr.get_host_name ())));
+ }
+
+ if (cli_stream.disable (ACE_NONBLOCK) == -1)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%P|%t) %p\n"), ACE_TEXT ("disable")));
+
+ // Send data to server (correctly handles "incomplete writes").
+
+ for (const char *c = ACE_ALPHABET; *c != '\0'; c++)
+ if (cli_stream.send_n (c, 1) == -1)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%P|%t) %p\n"), ACE_TEXT ("send_n")));
+
+ // Explicitly close the writer-side of the connection.
+ if (cli_stream.close_writer () == -1)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%P|%t) %p\n"), ACE_TEXT ("close_writer")));
+
+ char buf[1];
+
+ // Wait for handshake with server.
+ if (cli_stream.recv_n (buf, 1) != 1)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%P|%t) %p\n"), ACE_TEXT ("recv_n")));
+
+ // Close the connection completely.
+ if (cli_stream.close () == -1)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%P|%t) %p\n"), ACE_TEXT ("close")));
+
+ return 0;
+}
+
+static void *
+server (void *arg)
+{
+ ACE_SOCK_Acceptor *peer_acceptor = (ACE_SOCK_Acceptor *) arg;
+
+ if (peer_acceptor->enable (ACE_NONBLOCK) == -1)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%P|%t) %p\n"), ACE_TEXT ("enable")));
+
+ // Keep these objects out here to prevent excessive constructor
+ // calls...
+ ACE_SOCK_Stream new_stream;
+ ACE_INET_Addr cli_addr;
+ ACE_Handle_Set handle_set;
+ const ACE_Time_Value def_timeout (ACE_DEFAULT_TIMEOUT);
+ ACE_Time_Value tv (def_timeout);
+
+ char buf[BUFSIZ];
+ const char *t = ACE_ALPHABET;
+
+ handle_set.reset ();
+ handle_set.set_bit (peer_acceptor->get_handle ());
+
+ int select_width;
+# if defined (ACE_WIN64)
+ // This arg is ignored on Windows and causes pointer truncation
+ // warnings on 64-bit compiles.
+ select_width = 0;
+# else
+ select_width = int (peer_acceptor->get_handle ()) + 1;
+# endif /* ACE_WIN64 */
+ int result = ACE_OS::select (select_width,
+ handle_set,
+ 0, 0, &tv);
+ ACE_ASSERT (tv == def_timeout);
+
+ if (result == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("(%P|%t) %p\n"), ACE_TEXT ("select")), 0);
+ else if (result == 0)
+ {
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) select timed out, shutting down\n")));
+ return 0;
+ }
+
+ // Create a new ACE_SOCK_Stream endpoint (note automatic restart
+ // if errno == EINTR).
+
+ while ((result = peer_acceptor->accept (new_stream, &cli_addr)) != -1)
+ {
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) client %s connected from %d\n"),
+ ACE_TEXT_CHAR_TO_TCHAR(cli_addr.get_host_name ()), cli_addr.get_port_number ()));
+
+ // Enable non-blocking I/O.
+ if (new_stream.enable (ACE_NONBLOCK) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("(%P|%t) %p\n"), ACE_TEXT ("enable")), 0);
+
+ handle_set.reset ();
+ handle_set.set_bit (new_stream.get_handle ());
+
+ // Read data from client (terminate on error).
+ int select_width;
+ for (ssize_t r_bytes; ;)
+ {
+# if defined (ACE_WIN64)
+ // This arg is ignored on Windows and causes pointer truncation
+ // warnings on 64-bit compiles.
+ select_width = 0;
+# else
+ select_width = int (new_stream.get_handle ()) + 1;
+# endif /* ACE_WIN64 */
+ if (ACE_OS::select (select_width,
+ handle_set,
+ 0, 0, 0) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("(%P|%t) %p\n"), ACE_TEXT ("select")), 0);
+
+ while ((r_bytes = new_stream.recv (buf, 1)) > 0)
+ {
+ ACE_ASSERT (*t == buf[0]);
+ t++;
+ }
+
+ if (r_bytes == 0)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) reached end of input, connection closed by client\n")));
+
+ // Handshake back with client.
+ if (new_stream.send_n ("", 1) != 1)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%P|%t) %p\n"), ACE_TEXT ("send_n")));
+
+ // Close endpoint.
+ if (new_stream.close () == -1)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%P|%t) %p\n"), ACE_TEXT ("close")));
+ return 0;
+ }
+ else if (r_bytes == -1)
+ {
+ if (errno == EAGAIN || errno == EWOULDBLOCK)
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) no input available, going back to reading\n")));
+ else
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("(%P|%t) %p\n"), ACE_TEXT ("recv_n")), 0);
+ }
+ }
+ }
+
+ if (result == -1)
+ {
+ if (errno == EWOULDBLOCK)
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) no connections available, shutting down\n")));
+ else
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%P|%t) %p\n"), ACE_TEXT ("accept")));
+ }
+
+ return 0;
+}
+
+static void
+spawn (void)
+{
+ // Acceptor
+ ACE_SOCK_Acceptor peer_acceptor;
+
+ // Create a server address.
+ ACE_INET_Addr server_addr;
+
+ // Bind listener to any port and then find out what the port was.
+ if (peer_acceptor.open (ACE_Addr::sap_any) == -1
+ || peer_acceptor.get_local_addr (server_addr) == -1)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%P|%t) %p\n"), ACE_TEXT ("open")));
+ else
+ {
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) starting server at port %d\n"),
+ server_addr.get_port_number ()));
+
+#if !defined (ACE_LACKS_FORK)
+ switch (ACE_OS::fork (ACE_TEXT ("child")))
+ {
+ case -1:
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n%a"),
+ ACE_TEXT ("fork failed"),
+ 1));
+ /* NOTREACHED */
+ case 0:
+ client (&server_addr);
+ exit (0);
+ /* NOTREACHED */
+ default:
+ server ((void *) &peer_acceptor);
+ ACE_OS::wait ();
+ }
+#elif defined (ACE_HAS_THREADS)
+ if (ACE_Thread_Manager::instance ()->spawn
+ (ACE_THR_FUNC (server),
+ (void *) &peer_acceptor,
+ THR_NEW_LWP | THR_DETACHED) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n%a"),
+ ACE_TEXT ("thread create failed"),
+ 1));
+
+ if (ACE_Thread_Manager::instance ()->spawn
+ (ACE_THR_FUNC (client),
+ (void *) &server_addr,
+ THR_NEW_LWP | THR_DETACHED) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n%a"),
+ ACE_TEXT ("thread create failed"),
+ 1));
+
+ // Wait for the threads to exit.
+ ACE_Thread_Manager::instance ()->wait ();
+#else
+ ACE_ERROR ((LM_INFO,
+ ACE_TEXT ("(%P|%t) ")
+ ACE_TEXT ("only one thread may be run ")
+ ACE_TEXT ("in a process on this platform\n")));
+#endif /* ACE_HAS_THREADS */
+
+ peer_acceptor.close ();
+ }
+}
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("SOCK_Test"));
+
+ spawn ();
+
+ ACE_END_TEST;
+ return 0;
+}
diff --git a/ACE/tests/SOCK_Test_IPv6.cpp b/ACE/tests/SOCK_Test_IPv6.cpp
new file mode 100644
index 00000000000..08950687fcf
--- /dev/null
+++ b/ACE/tests/SOCK_Test_IPv6.cpp
@@ -0,0 +1,290 @@
+// $Id$
+// ============================================================================
+/**
+ * @file SOCK_Test_IPv6.cpp
+ *
+ * @brief This is a test of the <ACE_SOCK_Acceptor> and
+ * <ACE_SOCK_Connector> classes.
+ *
+ * The test forks two processes or spawns two threads (depending upon
+ * the platform) and then executes client and server allowing them to
+ * connect and exchange data.
+ *
+ * @author Prashant Jain <pjain@cs.wustl.edu>
+ * Doug Schmidt <schmidt@cs.wustl.edu>
+ * Brian Buesker <bbuesker@qualcomm.com>
+ */
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/OS_NS_sys_select.h"
+#include "ace/OS_NS_sys_wait.h"
+#include "ace/Thread.h"
+#include "ace/Thread_Manager.h"
+#include "ace/Time_Value.h"
+#include "ace/SOCK_Connector.h"
+#include "ace/SOCK_Acceptor.h"
+#include "ace/Handle_Set.h"
+
+#if !defined (ACE_LACKS_FORK)
+# include "ace/OS_NS_unistd.h"
+#endif
+
+#if defined (ACE_HAS_IPV6)
+
+static const char ACE_ALPHABET[] = "abcdefghijklmnopqrstuvwxyz";
+
+static void *
+client (void *arg)
+{
+ ACE_INET_Addr *remote_addr = (ACE_INET_Addr *) arg;
+ ACE_INET_Addr server_addr (remote_addr->get_port_number (),
+ ACE_IPV6_LOCALHOST);
+
+ ACE_SOCK_Stream cli_stream;
+ ACE_SOCK_Connector con;
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) starting non-blocking connect\n")));
+ // Initiate timed, non-blocking connection with server.
+
+ // Attempt a non-blocking connect to the server.
+ if (con.connect (cli_stream, server_addr,
+ (ACE_Time_Value *) &ACE_Time_Value::zero) == -1)
+ {
+ if (errno != EWOULDBLOCK)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%P|%t) %p\n"), ACE_TEXT ("connection failed")));
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) starting timed connect\n")));
+
+ // Check if non-blocking connection is in progress,
+ // and wait up to ACE_DEFAULT_TIMEOUT seconds for it to complete.
+ ACE_Time_Value tv (ACE_DEFAULT_TIMEOUT);
+
+ if (con.complete (cli_stream, &server_addr, &tv) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("(%P|%t) %p\n"), ACE_TEXT ("connection failed")), 0);
+ else
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) connected to %s\n"),
+ ACE_TEXT_CHAR_TO_TCHAR(server_addr.get_host_name ())));
+ }
+
+ if (cli_stream.disable (ACE_NONBLOCK) == -1)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%P|%t) %p\n"), ACE_TEXT ("disable")));
+
+ // Send data to server (correctly handles "incomplete writes").
+
+ for (const char *c = ACE_ALPHABET; *c != '\0'; c++)
+ if (cli_stream.send_n (c, 1) == -1)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%P|%t) %p\n"), ACE_TEXT ("send_n")));
+
+ // Explicitly close the writer-side of the connection.
+ if (cli_stream.close_writer () == -1)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%P|%t) %p\n"), ACE_TEXT ("close_writer")));
+
+ char buf[1];
+
+ // Wait for handshake with server.
+ if (cli_stream.recv_n (buf, 1) != 1)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%P|%t) %p\n"), ACE_TEXT ("recv_n")));
+
+ // Close the connection completely.
+ if (cli_stream.close () == -1)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%P|%t) %p\n"), ACE_TEXT ("close")));
+
+ return 0;
+}
+
+static void *
+server (void *arg)
+{
+ ACE_SOCK_Acceptor *peer_acceptor = (ACE_SOCK_Acceptor *) arg;
+
+ if (peer_acceptor->enable (ACE_NONBLOCK) == -1)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%P|%t) %p\n"), ACE_TEXT ("enable")));
+
+ // Keep these objects out here to prevent excessive constructor
+ // calls...
+ ACE_SOCK_Stream new_stream;
+ ACE_INET_Addr cli_addr;
+ ACE_Handle_Set handle_set;
+ const ACE_Time_Value def_timeout (ACE_DEFAULT_TIMEOUT);
+ ACE_Time_Value tv (def_timeout);
+
+ char buf[BUFSIZ];
+ const char *t = ACE_ALPHABET;
+
+ handle_set.reset ();
+ handle_set.set_bit (peer_acceptor->get_handle ());
+
+ int select_width;
+# if defined (ACE_WIN64)
+ // This arg is ignored on Windows and causes pointer truncation
+ // warnings on 64-bit compiles.
+ select_width = 0;
+# else
+ select_width = int (peer_acceptor->get_handle ()) + 1;
+# endif /* ACE_WIN64 */
+ int result = ACE_OS::select (select_width,
+ handle_set,
+ 0, 0, &tv);
+ ACE_ASSERT (tv == def_timeout);
+
+ if (result == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("(%P|%t) %p\n"), ACE_TEXT ("select")), 0);
+ else if (result == 0)
+ {
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) select timed out, shutting down\n")));
+ return 0;
+ }
+
+ // Create a new ACE_SOCK_Stream endpoint (note automatic restart
+ // if errno == EINTR).
+
+ while ((result = peer_acceptor->accept (new_stream, &cli_addr)) != -1)
+ {
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) client %s connected from %d\n"),
+ ACE_TEXT_CHAR_TO_TCHAR(cli_addr.get_host_name ()), cli_addr.get_port_number ()));
+
+ // Enable non-blocking I/O.
+ if (new_stream.enable (ACE_NONBLOCK) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("(%P|%t) %p\n"), ACE_TEXT ("enable")), 0);
+
+ handle_set.reset ();
+ handle_set.set_bit (new_stream.get_handle ());
+
+ // Read data from client (terminate on error).
+ int select_width;
+ for (ssize_t r_bytes; ;)
+ {
+# if defined (ACE_WIN64)
+ // This arg is ignored on Windows and causes pointer truncation
+ // warnings on 64-bit compiles.
+ select_width = 0;
+# else
+ select_width = int (new_stream.get_handle ()) + 1;
+# endif /* ACE_WIN64 */
+ if (ACE_OS::select (select_width,
+ handle_set,
+ 0, 0, 0) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("(%P|%t) %p\n"), ACE_TEXT ("select")), 0);
+
+ while ((r_bytes = new_stream.recv (buf, 1)) > 0)
+ {
+ ACE_ASSERT (*t == buf[0]);
+ t++;
+ }
+
+ if (r_bytes == 0)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) reached end of input, connection closed by client\n")));
+
+ // Handshake back with client.
+ if (new_stream.send_n ("", 1) != 1)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%P|%t) %p\n"), ACE_TEXT ("send_n")));
+
+ // Close endpoint.
+ if (new_stream.close () == -1)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%P|%t) %p\n"), ACE_TEXT ("close")));
+ return 0;
+ }
+ else if (r_bytes == -1)
+ {
+ if (errno == EAGAIN || errno == EWOULDBLOCK)
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) no input available, going back to reading\n")));
+ else
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("(%P|%t) %p\n"), ACE_TEXT ("recv_n")), 0);
+ }
+ }
+ }
+
+ if (result == -1)
+ {
+ if (errno == EWOULDBLOCK)
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) no connections available, shutting down\n")));
+ else
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%P|%t) %p\n"), ACE_TEXT ("accept")));
+ }
+
+ return 0;
+}
+
+static void
+spawn (void)
+{
+ // Acceptor
+ ACE_SOCK_Acceptor peer_acceptor;
+
+ // Create a server address.
+ ACE_INET_Addr server_addr;
+
+ // Bind listener to any port and then find out what the port was.
+ if (peer_acceptor.open (ACE_Addr::sap_any, 0, AF_INET6) == -1
+ || peer_acceptor.get_local_addr (server_addr) == -1)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%P|%t) %p\n"), ACE_TEXT ("open")));
+ else
+ {
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) starting server at port %d\n"),
+ server_addr.get_port_number ()));
+
+#if !defined (ACE_LACKS_FORK)
+ switch (ACE_OS::fork (ACE_TEXT("child")))
+ {
+ case -1:
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n%a"),
+ ACE_TEXT ("fork failed"),
+ 1));
+ /* NOTREACHED */
+ case 0:
+ client (&server_addr);
+ exit (0);
+ /* NOTREACHED */
+ default:
+ server ((void *) &peer_acceptor);
+ ACE_OS::wait ();
+ }
+#elif defined (ACE_HAS_THREADS)
+ if (ACE_Thread_Manager::instance ()->spawn
+ (ACE_THR_FUNC (server),
+ (void *) &peer_acceptor,
+ THR_NEW_LWP | THR_DETACHED) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n%a"),
+ ACE_TEXT ("thread create failed"),
+ 1));
+
+ if (ACE_Thread_Manager::instance ()->spawn
+ (ACE_THR_FUNC (client),
+ (void *) &server_addr,
+ THR_NEW_LWP | THR_DETACHED) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n%a"),
+ ACE_TEXT ("thread create failed"),
+ 1));
+
+ // Wait for the threads to exit.
+ ACE_Thread_Manager::instance ()->wait ();
+#else
+ ACE_ERROR ((LM_INFO,
+ ACE_TEXT ("(%P|%t) ")
+ ACE_TEXT ("only one thread may be run ")
+ ACE_TEXT ("in a process on this platform\n")));
+#endif /* ACE_HAS_THREADS */
+
+ peer_acceptor.close ();
+ }
+}
+#endif /*ACE_HAS_IPV6*/
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("SOCK_Test_IPv6"));
+
+#if defined (ACE_HAS_IPV6)
+ spawn ();
+#endif /* ACE_HAS_IPV6 */
+
+ ACE_END_TEST;
+ return 0;
+}
diff --git a/ACE/tests/SPIPE_Test.cpp b/ACE/tests/SPIPE_Test.cpp
new file mode 100644
index 00000000000..a9b17ab672c
--- /dev/null
+++ b/ACE/tests/SPIPE_Test.cpp
@@ -0,0 +1,222 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// SPIPE_Test.cpp
+//
+// = DESCRIPTION
+// This is a simple test of Named Pipes that uses
+// ACE_SPIPE_Acceptor and ACE_SPIPE_Connector classes. The test
+// forks two processes or spawns two threads (depending upon the
+// platform) and then executes the client and server allowing
+// them to use the named pipe to exchange data. No user input is
+// required as far as command line arguments are concerned.
+//
+// = AUTHOR
+// Prashant Jain <pjain@cs.wustl.edu>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/Thread.h"
+#include "ace/Thread_Manager.h"
+#include "ace/SPIPE_Addr.h"
+#include "ace/SPIPE_Connector.h"
+#include "ace/SPIPE_Acceptor.h"
+#include "ace/OS_NS_string.h"
+#include "ace/OS_NS_unistd.h"
+
+ACE_RCSID(tests, SPIPE_Test, "SPIPE_Test.cpp,v 4.36 2002/03/06 21:48:03 nanbor Exp")
+
+#if defined (ACE_HAS_STREAM_PIPES) \
+ || (defined (ACE_WIN32) && defined(ACE_HAS_WINNT4) \
+ && (ACE_HAS_WINNT4 !=0))
+# define TEST_HAS_STREAM_PIPES
+#endif
+
+#if defined (TEST_HAS_STREAM_PIPES)
+
+static const char ACE_ALPHABET[] = "abcdefghijklmnopqrstuvwxyz";
+
+// pipe name to use
+static const ACE_TCHAR *PIPE_NAME = ACE_TEXT ("ace_pipe_name");
+
+static void *
+client (void *)
+{
+ const ACE_TCHAR *rendezvous = PIPE_NAME;
+ ACE_SPIPE_Stream cli_stream;
+ ACE_SPIPE_Connector con;
+
+ ACE_OS::sleep (5);
+
+ if (con.connect (cli_stream, ACE_SPIPE_Addr (rendezvous)) == -1)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n%a"), rendezvous, 1));
+
+ for (const char *c = ACE_ALPHABET; *c != '\0'; c++)
+ if (cli_stream.send (c, 1) == -1)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("send")));
+
+ if (cli_stream.close () == -1)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("close")));
+
+#if (defined (ACE_WIN32) && defined (ACE_HAS_WINNT4) && (ACE_HAS_WINNT4 != 0))
+
+ // Wait for server to get ready...
+ ACE_OS::sleep (1);
+
+ // Connect in bytestream-oriented mode.
+ if (con.connect (cli_stream,
+ ACE_SPIPE_Addr (rendezvous),
+ 0,
+ ACE_Addr::sap_any,
+ 0,
+ O_RDWR,
+ 0,
+ 0,
+ PIPE_READMODE_BYTE) == -1)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n%a"), rendezvous, 1));
+
+
+ // Write out the alphabet all at once.
+ if (cli_stream.send_n (ACE_ALPHABET,
+ ACE_OS::strlen (ACE_ALPHABET)) != (ssize_t) ACE_OS::strlen (ACE_ALPHABET))
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("send_n")));
+
+ // Write out the alphabet one byte at a time
+ for (const char *d = ACE_ALPHABET; *d != '\0'; d++)
+ if (cli_stream.send (d, 1) == -1)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("send")));
+
+ if (cli_stream.close () == -1)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("close")));
+#endif
+
+#if !defined (ACE_WIN32)
+ ACE_OS::exit (0);
+#endif
+ return 0;
+}
+
+static void *
+server (void *)
+{
+ ACE_SPIPE_Acceptor acceptor;
+ ACE_SPIPE_Stream new_stream;
+ char buf[BUFSIZ];
+ const char *t = ACE_ALPHABET;
+
+ const ACE_TCHAR *rendezvous = PIPE_NAME;
+
+ // Initialize named pipe listener.
+
+ if (acceptor.open (ACE_SPIPE_Addr (rendezvous)) == -1)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n%a"), ACE_TEXT ("open"), 1));
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("waiting for connection\n")));
+
+ // Accept a client connection
+ if (acceptor.accept (new_stream, 0) == -1)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n%a"), ACE_TEXT ("accept"), 1));
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Accepted connection\n")));
+
+ while (new_stream.recv (buf, 1) > 0)
+ {
+ ACE_ASSERT (*t == buf[0]);
+ t++;
+ }
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("End of connection. Closing handle\n")));
+ new_stream.close ();
+ acceptor.close ();
+
+#if (defined (ACE_WIN32) && defined (ACE_HAS_WINNT4) && (ACE_HAS_WINNT4 != 0))
+ // Initialize an NT bytestream named pipe listener.
+ if (acceptor.open (ACE_SPIPE_Addr (rendezvous),
+ 1,
+ 0,
+ 0,
+ PIPE_TYPE_BYTE | PIPE_READMODE_BYTE) == -1)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n%a"), ACE_TEXT ("open"), 1));
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("waiting for connection\n")));
+
+ // Accept a client connection
+ if (acceptor.accept (new_stream, 0) == -1)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n%a"), ACE_TEXT ("accept"), 1));
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Accepted connection\n")));
+
+ // The client will write the entire buffer at once, verify that we
+ // can stream it in one byte at a time.
+ for (t = ACE_ALPHABET; *t; t++)
+ {
+ if (new_stream.recv (buf, 1) <= 0)
+ {
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n%a"), ACE_TEXT ("recv"), 1));
+ break;
+ }
+ ACE_ASSERT (*t == buf[0]);
+ }
+
+ // Wait for the client to stream in the buffer one byte at a time.
+
+ ACE_OS::sleep (1);
+
+ // Verify that we can read the stream of individual bytes all at
+ // once.
+ if (new_stream.recv (buf, sizeof(buf)) != (ssize_t) ACE_OS::strlen (ACE_ALPHABET))
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n%a"), ACE_TEXT ("recv"), 1));
+ else
+ ACE_ASSERT(memcmp(ACE_ALPHABET, buf, ACE_OS::strlen (ACE_ALPHABET)) == 0);
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("End of connection. Closing handle\n")));
+ new_stream.close ();
+ acceptor.close ();
+#endif /* (defined (ACE_WIN32) && defined (ACE_HAS_WINNT4) && (ACE_HAS_WINNT4 != 0)) */
+
+ return 0;
+}
+#endif /* TEST_HAS_STREAM_PIPES */
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("SPIPE_Test"));
+
+#if defined (TEST_HAS_STREAM_PIPES)
+#if !defined (ACE_LACKS_FORK)
+ switch (ACE_OS::fork ())
+ {
+ case -1:
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n%a"), ACE_TEXT ("fork failed")));
+ exit (-1);
+ case 0:
+ client (0);
+ default:
+ server (0);
+ }
+#elif defined (ACE_HAS_THREADS)
+ if (ACE_Thread_Manager::instance ()->spawn (ACE_THR_FUNC (client),
+ (void *) 0,
+ THR_NEW_LWP | THR_DETACHED) == -1)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n%a"), ACE_TEXT ("thread create failed")));
+
+ if (ACE_Thread_Manager::instance ()->spawn (ACE_THR_FUNC (server),
+ (void *) 0,
+ THR_NEW_LWP | THR_DETACHED) == -1)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n%a"), ACE_TEXT ("thread create failed")));
+
+ ACE_Thread_Manager::instance ()->wait ();
+#endif /* !ACE_LACKS_EXEC */
+#else
+ ACE_DEBUG ((LM_INFO,
+ ACE_TEXT ("SPIPE is not supported on this platform\n")));
+#endif /* TEST_HAS_STREAM_PIPES */
+ ACE_END_TEST;
+ return 0;
+}
diff --git a/ACE/tests/SSL/Main.cpp b/ACE/tests/SSL/Main.cpp
new file mode 100644
index 00000000000..44b92128394
--- /dev/null
+++ b/ACE/tests/SSL/Main.cpp
@@ -0,0 +1,30 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Main.cpp
+//
+// = DESCRIPTION
+// This is a wrapper for the test programs. It obviates the test cpp's
+// from having to always include OS.h.
+//
+// = AUTHOR
+// Don Hinton <dhinton@dresystems.com>
+//
+// ============================================================================
+
+#include "ace/OS_main.h"
+#if defined (ACE_HAS_WINCE)
+# include "ace/ACE.h"
+#endif /* ACE_HAS_WINCE */
+int run_main (int argc, ACE_TCHAR *argv[]);
+
+int
+ACE_TMAIN (int argc, ACE_TCHAR *argv[])
+{
+ return run_main (argc, argv);
+}
diff --git a/ACE/tests/SSL/Makefile.am b/ACE/tests/SSL/Makefile.am
new file mode 100644
index 00000000000..c3ae6261b1b
--- /dev/null
+++ b/ACE/tests/SSL/Makefile.am
@@ -0,0 +1,81 @@
+## Process this file with automake to create Makefile.in
+##
+## $Id$
+##
+## This file was generated by MPC. Any changes made directly to
+## this file will be lost the next time it is generated.
+##
+## MPC Command:
+## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu
+
+ACE_BUILDDIR = $(top_builddir)
+ACE_ROOT = $(top_srcdir)
+
+noinst_PROGRAMS =
+
+## Makefile.SSL_Asynch_Stream_Test.am
+
+if BUILD_SSL
+if !BUILD_ACE_FOR_TAO
+
+noinst_PROGRAMS += SSL_Asynch_Stream_Test
+
+SSL_Asynch_Stream_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR) \
+ -DACE_HAS_SSL=1 \
+ @ACE_TLS_CPPFLAGS@
+
+SSL_Asynch_Stream_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ SSL_Asynch_Stream_Test.cpp
+
+SSL_Asynch_Stream_Test_LDFLAGS = \
+ @ACE_TLS_LDFLAGS@
+
+SSL_Asynch_Stream_Test_LDADD = \
+ $(ACE_BUILDDIR)/ace/SSL/libACE_SSL.la \
+ $(top_builddir)/tests/libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la \
+ @ACE_TLS_LIBS@
+
+endif !BUILD_ACE_FOR_TAO
+endif BUILD_SSL
+
+## Makefile.Thread_Pool_Reactor_SSL_Test.am
+
+if BUILD_SSL
+if !BUILD_ACE_FOR_TAO
+
+noinst_PROGRAMS += Thread_Pool_Reactor_SSL_Test
+
+Thread_Pool_Reactor_SSL_Test_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR) \
+ -DACE_HAS_SSL=1 \
+ @ACE_TLS_CPPFLAGS@
+
+Thread_Pool_Reactor_SSL_Test_SOURCES = \
+ $(ACE_ROOT)/tests/Main.cpp \
+ Thread_Pool_Reactor_SSL_Test.cpp \
+ Thread_Pool_Reactor_SSL_Test.h
+
+Thread_Pool_Reactor_SSL_Test_LDFLAGS = \
+ @ACE_TLS_LDFLAGS@
+
+Thread_Pool_Reactor_SSL_Test_LDADD = \
+ $(ACE_BUILDDIR)/ace/SSL/libACE_SSL.la \
+ $(top_builddir)/tests/libTest_Output.la \
+ $(ACE_BUILDDIR)/ace/libACE.la \
+ @ACE_TLS_LIBS@
+
+endif !BUILD_ACE_FOR_TAO
+endif BUILD_SSL
+
+## Clean up template repositories, etc.
+clean-local:
+ -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.*
+ -rm -f gcctemp.c gcctemp so_locations *.ics
+ -rm -rf cxx_repository ptrepository ti_files
+ -rm -rf templateregistry ir.out
+ -rm -rf ptrepository SunWS_cache Templates.DB
diff --git a/ACE/tests/SSL/SSL_Asynch_Stream_Test.cpp b/ACE/tests/SSL/SSL_Asynch_Stream_Test.cpp
new file mode 100644
index 00000000000..58556a44f0b
--- /dev/null
+++ b/ACE/tests/SSL/SSL_Asynch_Stream_Test.cpp
@@ -0,0 +1,478 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests/SSL
+//
+// = FILENAME
+// SSL_Asynch_Stream_Test.cpp
+//
+// = DESCRIPTION
+// This program is a functionality test of ACE_SSL_Asynch_Stream.
+// It demonstrates one proper use case of ACE_SSL_Asynch_Stream in the
+// Proactor framework and validates its basic functionality.
+//
+// Usage: SSL_Asynch_Stream_Test [-r <hostname:port#>]
+// [-t <num threads>] [-d <delay>]
+// [-i <client conn attempt#>] [-n <client request# per conn>]
+//
+// Default value:
+// <hostname:port#>: ACE_DEFAULT_SERVER_HOST:ACE_DEFAULT_PORT
+// <num threads>: ACE_MAX_THREADS
+// <client conn attempt#>: ACE_MAX_ITERATIONS
+// <client req# per conn>: 20
+// <delay>: 0 usec
+//
+// = AUTHOR
+// Steve Huston <shuston@riverace.com>
+//
+// ============================================================================
+
+#include "tests/test_config.h"
+#include "ace/Default_Constants.h"
+#include "ace/OS_NS_string.h"
+#include "ace/Event_Handler.h"
+#include "ace/Get_Opt.h"
+#include "ace/Proactor.h"
+#include "ace/Reactor.h"
+#include "ace/Thread_Manager.h"
+#include "ace/INET_Addr.h"
+#include "ace/SSL/SSL_Asynch_Stream.h"
+#include "ace/SSL/SSL_SOCK_Connector.h"
+#include "ace/SSL/SSL_SOCK_Acceptor.h"
+#include "ace/SSL/SSL_SOCK_Stream.h"
+
+ACE_RCSID(tests, SSL_Asynch_Stream_Test, "$Id$")
+
+#if defined (ACE_HAS_THREADS) && ((defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)) || (defined (ACE_HAS_AIO_CALLS)))
+ // This only works on Win32 platforms and on Unix platforms
+ // supporting POSIX aio calls.
+
+class Client_Handler : public ACE_Handler
+{
+public:
+ Client_Handler ()
+ : msgs_sent_ (0),
+ stream_ (ACE_SSL_Asynch_Stream::ST_CLIENT),
+ block_ (1024) {}
+ ~Client_Handler ();
+
+ int open (ACE_HANDLE);
+
+private:
+ virtual void handle_write_stream (const ACE_SSL_Asynch_Write_Stream_Result &result);
+
+private:
+ size_t msgs_sent_;
+ ACE_SSL_Asynch_Stream stream_;
+ ACE_Message_Block block_;
+};
+
+class Server_Handler : public ACE_Handler
+{
+public:
+ Server_Handler ()
+ : msgs_rcvd_ (0),
+ stream_ (ACE_SSL_Asynch_Stream::ST_SERVER),
+ block_ (1024) {}
+ ~Server_Handler ();
+
+ int open (ACE_HANDLE);
+
+private:
+ virtual void handle_read_stream (const ACE_SSL_Asynch_Read_Stream_Result &result);
+
+private:
+ size_t msgs_rcvd_;
+ ACE_SSL_Asynch_Stream stream_;
+ ACE_Message_Block block_;
+};
+
+class Server_Acceptor : public ACE_Event_Handler
+{
+public:
+ int open (const ACE_INET_Addr &listen_addr);
+
+ // Called when a new connection is ready to accept.
+ virtual int handle_input (ACE_HANDLE fd = ACE_INVALID_HANDLE);
+
+ virtual int handle_close (ACE_HANDLE handle,
+ ACE_Reactor_Mask close_mask);
+
+private:
+ ACE_SSL_SOCK_Acceptor acceptor_;
+};
+
+// Accepting end point. This is actually "localhost:10010", but some
+// platform couldn't resolve the name so we use the IP address
+// directly here.
+static const ACE_TCHAR *rendezvous = \
+ ACE_DEFAULT_SERVER_HOST ACE_TEXT (":") ACE_DEFAULT_SERVER_PORT_STR;
+
+// Total number of proactor threads.
+static size_t num_threads = ACE_MAX_THREADS;
+
+#if defined (CHORUS) // Add platforms that can't handle too many
+ // connection simultaneously here.
+#define ACE_LOAD_FACTOR /2
+#else
+#define ACE_LOAD_FACTOR
+#endif
+
+// Number of client connections to attempt.
+static size_t cli_conn_no = ACE_MAX_ITERATIONS ACE_LOAD_FACTOR;
+
+// Number of requests each client connection sends.
+static size_t cli_req_no = ACE_MAX_THREADS ACE_LOAD_FACTOR;
+
+// Delay before a thread sending the next request (in msec.)
+static int req_delay = 0;
+
+// This is the string sent from client to server.
+static const char *test_string = "SSL_Asynch_Stream_Test!";
+
+static void
+parse_args (int argc, ACE_TCHAR *argv[])
+{
+ ACE_Get_Opt getopt (argc, argv, ACE_TEXT ("r:t:d:i:n:"));
+
+ int c;
+
+ while ((c = getopt ()) != -1)
+ {
+ switch (c)
+ {
+ case 'r': // hostname:port
+ rendezvous = getopt.opt_arg ();
+ break;
+ case 't':
+ num_threads = ACE_OS::atoi (getopt.opt_arg ());
+ break;
+ case 'd':
+ req_delay = ACE_OS::atoi (getopt.opt_arg ());
+ break;
+ case 'i':
+ cli_conn_no = ACE_OS::atoi (getopt.opt_arg ());
+ break;
+ case 'n':
+ cli_req_no = ACE_OS::atoi (getopt.opt_arg ());
+ break;
+ default:
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Usage: %s [-r <hostname:port#>]")
+ ACE_TEXT ("\t[-t <nr threads>] [-d <delay>]")
+ ACE_TEXT ("\t[-i <client conn attempt#>]")
+ ACE_TEXT ("\t[-n <client request# per conn>]\n"),
+ argv[0]));
+ break;
+ }
+ }
+}
+
+Client_Handler::~Client_Handler ()
+{
+ if (this->stream_.handle () != ACE_INVALID_HANDLE)
+ {
+ if (this->msgs_sent_ != cli_req_no)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%t) Client handle %d sent %d messages; ")
+ ACE_TEXT ("expected %d\n"),
+ this->stream_.handle (),
+ this->msgs_sent_,
+ cli_req_no));
+ else
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Client handle %d sent %d messages; ")
+ ACE_TEXT ("closing connection\n"),
+ this->stream_.handle (),
+ cli_req_no));
+ }
+ this->stream_.close ();
+}
+
+int
+Client_Handler::open (ACE_HANDLE handle)
+{
+ if (this->stream_.open (*this, handle) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%t) Client_Handler: %p\n"),
+ ACE_TEXT ("open")),
+ -1);
+ this->block_.copy (test_string);
+ if (this->stream_.write (this->block_, this->block_.length ()) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%t) Client_Handler: %p\n"),
+ ACE_TEXT ("initiate write")),
+ -1);
+ return 0;
+}
+
+void
+Client_Handler::handle_write_stream
+ (const ACE_SSL_Asynch_Write_Stream_Result &result)
+{
+ if (!result.success ())
+ {
+ errno = result.error ();
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%t) Client handle %d: %p\n"),
+ this->stream_.handle (),
+ ACE_TEXT ("write")));
+ delete this;
+ return;
+ }
+ ACE_Message_Block &b = result.message_block ();
+ bool send_again = true;
+ if (b.length () == 0)
+ {
+ // All block's data sent; rewind the read pointer and send it again
+ // until we've sent the configured number of times.
+ ++this->msgs_sent_;
+ if (this->msgs_sent_ == cli_req_no)
+ send_again = false; // All done
+ else
+ b.rd_ptr (b.base ());
+ }
+
+ if (send_again)
+ {
+ if (this->stream_.write (this->block_, this->block_.length ()) == -1)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%t) Client_Handler: %p\n"),
+ ACE_TEXT ("initiate write")));
+ delete this;
+ }
+ }
+ else
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Client handle %d done sending\n"),
+ this->stream_.handle ()));
+ delete this;
+ }
+ return;
+}
+
+Server_Handler::~Server_Handler ()
+{
+ if (this->stream_.handle () != ACE_INVALID_HANDLE)
+ {
+ if (this->msgs_rcvd_ != cli_req_no)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%t) Server handle %d received %d messages; ")
+ ACE_TEXT ("expected %d\n"),
+ this->stream_.handle (),
+ this->msgs_rcvd_,
+ cli_req_no));
+ else
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Server handle %d received %d messages; ")
+ ACE_TEXT ("closing connection\n"),
+ this->stream_.handle (),
+ cli_req_no));
+ }
+ this->stream_.close ();
+}
+
+int
+Server_Handler::open (ACE_HANDLE handle)
+{
+ if (this->stream_.open (*this, handle) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%t) Server_Handler: %p\n"),
+ ACE_TEXT ("open")),
+ -1);
+ if (this->stream_.read (this->block_, this->block_.space () - 1) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%t) Server_Handler: %p\n"),
+ ACE_TEXT ("read")),
+ -1);
+ return 0;
+}
+
+void
+Server_Handler::handle_read_stream
+ (const ACE_SSL_Asynch_Read_Stream_Result &result)
+{
+ if (!result.success ())
+ {
+ errno = result.error ();
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%t) Server handle %d: %p\n"),
+ this->stream_.handle (),
+ ACE_TEXT ("read")));
+ delete this;
+ return;
+ }
+ if (result.bytes_transferred () == 0)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Server handle %d closed by peer\n"),
+ this->stream_.handle ()));
+ delete this;
+ return;
+ }
+
+ // Scan through the received data for the expected string. There may be
+ // multiples and/or partials. Count up how many arrive before the connection
+ // is closed.
+ // The read operation left one byte space at the end so we can insert a
+ // nul terminator to ease scanning.
+ ACE_Message_Block &b = result.message_block ();
+ *(b.wr_ptr ()) = '\0';
+ size_t test_string_len = ACE_OS::strlen (test_string);
+ while (b.length () >= test_string_len)
+ {
+ if (0 != ACE_OS::strncmp (b.rd_ptr (), test_string, test_string_len))
+ ACE_ERROR_BREAK ((LM_ERROR,
+ ACE_TEXT ("(%t) Read string: %C; expected: %C\n"),
+ b.rd_ptr (),
+ test_string));
+ b.rd_ptr (test_string_len);
+ }
+ b.crunch ();
+ if (this->stream_.read (b, b.space () - 1) == -1)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%t) Server_Handler: %p\n"),
+ ACE_TEXT ("read")));
+ delete this;
+ }
+ return;
+}
+
+
+int
+Server_Acceptor::open (const ACE_INET_Addr &listen_addr)
+{
+ if (this->acceptor_.open (listen_addr) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("listen")),
+ -1);
+ return 0;
+}
+
+int
+Server_Acceptor::handle_input (ACE_HANDLE)
+{
+ ACE_SSL_SOCK_Stream new_stream;
+ if (this->acceptor_.accept (new_stream) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%t) %p\n"),
+ ACE_TEXT ("accept")),
+ -1);
+ Server_Handler *new_handler = 0;
+ ACE_NEW_RETURN (new_handler, Server_Handler, -1);
+ if (new_handler->open (new_stream.get_handle ()) != 0)
+ delete new_handler;
+
+ return 0;
+}
+
+int
+Server_Acceptor::handle_close (ACE_HANDLE, ACE_Reactor_Mask)
+{
+ this->acceptor_.close ();
+ return 0;
+}
+
+
+static ACE_THR_FUNC_RETURN
+proactor_loop (void *)
+{
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) Start handling events.\n")));
+
+ int result =
+ ACE_Proactor::instance ()->proactor_run_event_loop ();
+ if (result == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%t) %p\n"),
+ ACE_TEXT ("Error handling events")),
+ 0);
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) Done handling events.\n")));
+
+ return 0;
+}
+
+static ACE_THR_FUNC_RETURN
+start_clients (void *)
+{
+ // Client thread function.
+ ACE_INET_Addr addr (rendezvous);
+ ACE_SSL_SOCK_Stream stream;
+ ACE_SSL_SOCK_Connector connect;
+
+ for (size_t i = 0 ; i < cli_conn_no; i++)
+ {
+ if (connect.connect (stream, addr) < 0)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%t) %p\n"),
+ ACE_TEXT ("connect")));
+ continue;
+ }
+
+ Client_Handler *new_handler = 0;
+ ACE_NEW_RETURN (new_handler, Client_Handler, (ACE_THR_FUNC_RETURN)-1);
+ if (new_handler->open (stream.get_handle ()) != 0)
+ delete new_handler;
+ stream.set_handle (ACE_INVALID_HANDLE);
+ }
+
+ return 0;
+}
+
+int
+run_main (int argc, ACE_TCHAR *argv[])
+{
+ ACE_START_TEST (ACE_TEXT ("SSL_Asynch_Stream_Test"));
+
+ ACE_SSL_Context *context = ACE_SSL_Context::instance ();
+ // Note - the next two strings are naked on purpose... the arguments to
+ // the ACE_SSL_Context methods are const char *, not ACE_TCHAR *.
+ context->certificate ("dummy.pem", SSL_FILETYPE_PEM);
+ context->private_key ("key.pem", SSL_FILETYPE_PEM);
+
+ parse_args (argc, argv);
+
+ Server_Acceptor acceptor;
+ ACE_INET_Addr accept_addr (rendezvous);
+
+ if (acceptor.open (accept_addr) == -1)
+ return 1;
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) Listening at %s\n"), rendezvous));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) Spawning %d proactor threads\n"),
+ num_threads));
+ ACE_Thread_Manager::instance ()->spawn_n (num_threads, proactor_loop);
+ ACE_Thread_Manager::instance ()->spawn (start_clients);
+
+ ACE_Time_Value loop_limit (20);
+ ACE_Reactor::instance ()->run_reactor_event_loop (loop_limit);
+ ACE_Thread_Manager::instance ()->wait ();
+
+ // Check for num connections up/down.
+
+ ACE_END_TEST;
+ return 0;
+}
+
+#else
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("SSL_Asynch_Stream_Test"));
+
+ ACE_ERROR ((LM_INFO,
+ ACE_TEXT ("This test requires threads and AIO which are not ")
+ ACE_TEXT ("supported on this platform\n")));
+
+ ACE_END_TEST;
+ return 0;
+}
+#endif /* ACE_HAS_THREADS && (WIN32 || AIO) */
diff --git a/ACE/tests/SSL/Thread_Pool_Reactor_SSL_Test.cpp b/ACE/tests/SSL/Thread_Pool_Reactor_SSL_Test.cpp
new file mode 100644
index 00000000000..290bf83592f
--- /dev/null
+++ b/ACE/tests/SSL/Thread_Pool_Reactor_SSL_Test.cpp
@@ -0,0 +1,352 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests/SSL
+//
+// = FILENAME
+// Thread_Pool_Reactor_Test.cpp
+//
+// = DESCRIPTION
+// This program is a torture test of threaded SSL usage. It
+// is based on the tests/Thread_Pool_Reactor_Test and adds
+// SSL stuff submitted by Robert Handl <robert.handl@ehpt.com>.
+// It starts by spawning several server threads waiting to handle
+// events. Several other client threads are spawned right after
+// to initiate connections to server threads. Each connection
+// adds a new Svc_Handler into the TP_Reactor and sends out
+// several "requests" to the server thread. After the connection
+// is closed, the Svc_Handler is removed from the TP_Reactor.
+// Each message is treated as a separate request by the server so
+// two consecutive requests might be serviced by two different
+// threads.
+//
+// Usage: Thread_Pool_Reactor_Test_SSL [-r <hostname:port#>]
+// [-s <server thr#>] [-c <client thr#>] [-d <delay>]
+// [-i <client conn attempt#>] [-n <client request# per conn>]
+//
+// Default value:
+// <hostname:port#>: ACE_DEFAULT_RENDEZVOUS
+// <server thr#>: ACE_MAX_THREADS
+// <client thr#>: ACE_MAX_ITERATIONS
+// <client conn attempt#>: ACE_MAX_ITERATIONS
+// <client req# per conn>: ACE_MAX_THREADS
+// <delay>: 50 usec
+//
+// = AUTHOR
+// Irfan Pyarali <irfan@cs.wustl.edu> and
+// Nanbor Wang <nanbor@cs.wustl.edu>
+//
+// ============================================================================
+
+#include "tests/test_config.h"
+#include "ace/OS_NS_string.h"
+#include "ace/OS_NS_unistd.h"
+#include "ace/Get_Opt.h"
+#include "ace/Acceptor.h"
+#include "ace/Thread_Manager.h"
+#include "ace/TP_Reactor.h"
+#include "ace/SSL/SSL_SOCK_Connector.h"
+#include "ace/SSL/SSL_SOCK_Acceptor.h"
+
+ACE_RCSID(tests, Atomic_Op_Test, "$Id$")
+
+#if defined (ACE_HAS_THREADS)
+
+#include "Thread_Pool_Reactor_SSL_Test.h"
+typedef ACE_Strategy_Acceptor <Request_Handler, ACE_SSL_SOCK_ACCEPTOR>
+ ACCEPTOR;
+
+// Accepting end point. This is actually "localhost:10010", but some
+// platform couldn't resolve the name so we use the IP address
+// directly here.
+static const ACE_TCHAR *rendezvous = ACE_TEXT ("127.0.0.1:10010");
+
+// Total number of server threads.
+static size_t svr_thrno = ACE_MAX_THREADS;
+
+#if defined (CHORUS) // Add platforms that can't handle too many
+ // connection simultaneously here.
+#define ACE_LOAD_FACTOR /2
+#else
+#define ACE_LOAD_FACTOR
+#endif
+
+// Total number of client threads.
+static size_t cli_thrno = ACE_MAX_THREADS ACE_LOAD_FACTOR;
+
+// Total connection attemps of a client thread.
+static size_t cli_conn_no = ACE_MAX_ITERATIONS ACE_LOAD_FACTOR;
+
+// Total requests a client thread sends.
+static size_t cli_req_no = ACE_MAX_THREADS ACE_LOAD_FACTOR;
+
+// Delay before a thread sending the next request (in msec.)
+static int req_delay = 50;
+
+static void
+parse_arg (int argc, ACE_TCHAR *argv[])
+{
+ ACE_Get_Opt getopt (argc, argv, ACE_TEXT ("r:s:c:d:i:n:"));
+
+ int c;
+
+ while ((c = getopt ()) != -1)
+ {
+ switch (c)
+ {
+ case 'r': // hostname:port
+ rendezvous = getopt.opt_arg ();
+ break;
+ case 's':
+ svr_thrno = ACE_OS::atoi (getopt.opt_arg ());
+ break;
+ case 'c':
+ cli_thrno = ACE_OS::atoi (getopt.opt_arg ());
+ break;
+ case 'd':
+ req_delay = ACE_OS::atoi (getopt.opt_arg ());
+ break;
+ case 'i':
+ cli_conn_no = ACE_OS::atoi (getopt.opt_arg ());
+ break;
+ case 'n':
+ cli_req_no = ACE_OS::atoi (getopt.opt_arg ());
+ break;
+ default:
+ ACE_ERROR ((LM_ERROR,
+ "Usage: Thread_Pool_Reactor_Test [-r <hostname:port#>]"
+ "\t[-s <server thr#>] [-c <client thr#>] [-d <delay>]"
+ "\t[-i <client conn attempt#>]"
+ "[-n <client request# per conn>]\n"));
+ break;
+ }
+ }
+}
+
+Request_Handler::Request_Handler (ACE_Thread_Manager *thr_mgr)
+ : ACE_Svc_Handler<ACE_SSL_SOCK_STREAM, ACE_MT_SYNCH> (thr_mgr),
+ nr_msgs_rcvd_(0)
+{
+ // Make sure we use TP_Reactor with this class (that's the whole
+ // point, right?)
+ this->reactor (ACE_Reactor::instance ());
+}
+
+int
+Request_Handler::handle_input (ACE_HANDLE fd)
+{
+ ACE_TCHAR buffer[BUFSIZ];
+ ACE_TCHAR len = 0;
+ ssize_t result = this->peer ().recv (&len, sizeof (ACE_TCHAR));
+
+ if (result > 0
+ && this->peer ().recv_n (buffer, len * sizeof (ACE_TCHAR))
+ == static_cast<ssize_t> (len * sizeof (ACE_TCHAR)))
+ {
+ ++this->nr_msgs_rcvd_;
+
+ ACE_DEBUG ((LM_DEBUG,
+ "(%t) svr input; fd: 0x%x; input: %s\n",
+ fd,
+ buffer));
+ if (ACE_OS::strcmp (buffer, ACE_TEXT ("shutdown")) == 0)
+ ACE_Reactor::end_event_loop ();
+ return 0;
+ }
+ else
+ ACE_DEBUG ((LM_DEBUG,
+ "(%t) Request_Handler: 0x%x peer closed (0x%x)\n",
+ this, fd));
+ return -1;
+}
+
+int
+Request_Handler::handle_close (ACE_HANDLE fd, ACE_Reactor_Mask)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ "(%t) svr close; fd: 0x%x, rcvd %d msgs\n",
+ fd,
+ this->nr_msgs_rcvd_));
+ if (this->nr_msgs_rcvd_ != cli_req_no)
+ ACE_ERROR((LM_ERROR,
+ "(%t) Handler 0x%x: Expected %d messages; got %d\n",
+ this,
+ cli_req_no,
+ this->nr_msgs_rcvd_));
+ this->destroy ();
+ return 0;
+}
+
+static int
+reactor_event_hook (ACE_Reactor *)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ "(%t) handling events ....\n"));
+
+ return 0;
+}
+
+static ACE_THR_FUNC_RETURN
+svr_worker (void *)
+{
+ // Server thread function.
+ int result =
+ ACE_Reactor::instance ()->run_reactor_event_loop (&reactor_event_hook);
+
+ if (result == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "(%t) %p\n",
+ "Error handling events"),
+ 0);
+
+ ACE_DEBUG ((LM_DEBUG,
+ "(%t) I am done handling events. Bye, bye\n"));
+
+ return 0;
+}
+
+static ACE_THR_FUNC_RETURN
+cli_worker (void *arg)
+{
+ // Client thread function.
+ ACE_INET_Addr addr (rendezvous);
+ ACE_SSL_SOCK_Stream stream;
+ ACE_SSL_SOCK_Connector connect;
+ ACE_Time_Value delay (0, req_delay);
+ size_t len = * reinterpret_cast<ACE_TCHAR *> (arg);
+
+ for (size_t i = 0 ; i < cli_conn_no; i++)
+ {
+ if (connect.connect (stream, addr) < 0)
+ {
+ ACE_ERROR ((LM_ERROR,
+ "(%t) %p\n",
+ "connect"));
+ continue;
+ }
+
+ for (size_t j = 0; j < cli_req_no; j++)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ "(%t) conn_worker handle 0x%x, req %d\n",
+ stream.get_handle (),
+ j+1));
+ if (stream.send_n (arg,
+ (len + 1) * sizeof (ACE_TCHAR)) == -1)
+ {
+ ACE_ERROR ((LM_ERROR,
+ "(%t) %p\n",
+ "send_n"));
+ continue;
+ }
+ ACE_OS::sleep (delay);
+ }
+
+ stream.close ();
+ }
+
+ return 0;
+}
+
+static ACE_THR_FUNC_RETURN
+worker (void *)
+{
+ ACE_OS::sleep (3);
+ const ACE_TCHAR *msg = ACE_TEXT ("Message from Connection worker");
+ ACE_TCHAR buf [BUFSIZ];
+ buf[0] = ACE_OS::strlen (msg) + 1;
+ ACE_OS::strcpy (&buf[1], msg);
+
+ ACE_INET_Addr addr (rendezvous);
+
+ ACE_DEBUG((LM_DEBUG,
+ "(%t) Spawning %d client threads...\n",
+ cli_thrno));
+ int grp = ACE_Thread_Manager::instance ()->spawn_n (cli_thrno,
+ &cli_worker,
+ buf);
+ ACE_ASSERT (grp != -1);
+
+ ACE_Thread_Manager::instance ()->wait_grp (grp);
+
+ ACE_DEBUG ((LM_DEBUG,
+ "(%t) Client threads done; shutting down...\n"));
+ ACE_SSL_SOCK_Stream stream;
+ ACE_SSL_SOCK_Connector connect;
+
+ if (connect.connect (stream, addr) == -1)
+ ACE_ERROR ((LM_ERROR,
+ "(%t) %p Error while connecting\n",
+ "connect"));
+
+ const ACE_TCHAR *sbuf = ACE_TEXT ("\011shutdown");
+
+ ACE_DEBUG ((LM_DEBUG,
+ "shutdown stream handle = %x\n",
+ stream.get_handle ()));
+
+ if (stream.send_n (sbuf, (ACE_OS::strlen (sbuf) + 1) * sizeof (ACE_TCHAR)) == -1)
+ ACE_ERROR ((LM_ERROR,
+ "(%t) %p\n",
+ "send_n"));
+
+ stream.close ();
+
+ return 0;
+}
+
+int
+run_main (int argc, ACE_TCHAR *argv[])
+{
+ ACE_START_TEST (ACE_TEXT ("Thread_Pool_Reactor_SSL_Test"));
+
+ ACE_SSL_Context *context = ACE_SSL_Context::instance ();
+ // Note - the next two strings are naked on purpose... the arguments to
+ // the ACE_SSL_Context methods are const char *, not ACE_TCHAR *.
+ context->certificate ("dummy.pem", SSL_FILETYPE_PEM);
+ context->private_key ("key.pem", SSL_FILETYPE_PEM);
+
+ parse_arg (argc, argv);
+
+ // Changed the default
+ ACE_TP_Reactor sr;
+ ACE_Reactor new_reactor (&sr);
+ ACE_Reactor::instance (&new_reactor);
+
+ ACCEPTOR acceptor;
+ ACE_INET_Addr accept_addr (rendezvous);
+
+ if (acceptor.open (accept_addr) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("open")),
+ 1);
+
+ ACE_DEBUG((LM_DEBUG,
+ ACE_TEXT ("(%t) Spawning %d server threads...\n"),
+ svr_thrno));
+ ACE_Thread_Manager::instance ()->spawn_n (svr_thrno,
+ svr_worker);
+ ACE_Thread_Manager::instance ()->spawn (worker);
+
+ ACE_Thread_Manager::instance ()->wait ();
+
+ ACE_END_TEST;
+ return 0;
+}
+
+#else
+int
+ACE_TMAIN (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("Thread_Pool_Reactor_SSL_Test"));
+
+ ACE_ERROR ((LM_INFO,
+ "threads not supported on this platform\n"));
+
+ ACE_END_TEST;
+ return 0;
+}
+#endif /* ACE_HAS_THREADS */
diff --git a/ACE/tests/SSL/Thread_Pool_Reactor_SSL_Test.h b/ACE/tests/SSL/Thread_Pool_Reactor_SSL_Test.h
new file mode 100644
index 00000000000..fca5a7f8432
--- /dev/null
+++ b/ACE/tests/SSL/Thread_Pool_Reactor_SSL_Test.h
@@ -0,0 +1,50 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests/SSL
+//
+// = FILENAME
+// Thread_Pool_Reactor_Test_SSL.h
+//
+// = DESCRIPTION
+// This class gets its own header file to work around AIX C++
+// compiler "features" related to template instantiation... It is
+// only used by Thread_Pool_Reactor_Test_SSL.cpp.
+//
+// = AUTHOR
+// Irfan Pyarali <irfan@cs.wustl.edu>
+// Nanbor Wang <nanbor@cs.wustl.edu>
+//
+// ============================================================================
+
+#ifndef ACE_TESTS_THREAD_POOL_REACTOR_TEST_SSL_H
+#define ACE_TESTS_THREAD_POOL_REACTOR_TEST_SSL_H
+
+#include "ace/SSL/SSL_SOCK_Stream.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "ace/Svc_Handler.h"
+
+class Request_Handler : public ACE_Svc_Handler<ACE_SSL_SOCK_STREAM,
+ ACE_MT_SYNCH>
+{
+ // = TITLE
+ // This class is the Svc_Handler used by <Acceptor>.
+public:
+ Request_Handler (ACE_Thread_Manager *tm = 0);
+ // The default constructor makes sure the right reactor is used.
+
+protected:
+ virtual int handle_input (ACE_HANDLE fd = ACE_INVALID_HANDLE);
+ virtual int handle_close (ACE_HANDLE fd, ACE_Reactor_Mask = 0);
+
+private:
+ size_t nr_msgs_rcvd_;
+};
+
+#endif /* ACE_TESTS_THREAD_POOL_REACTOR_TEST_SSL_H */
diff --git a/ACE/tests/SSL/acetest.mpb b/ACE/tests/SSL/acetest.mpb
new file mode 100644
index 00000000000..3321d43a7fe
--- /dev/null
+++ b/ACE/tests/SSL/acetest.mpb
@@ -0,0 +1,20 @@
+// -*- MPC -*-
+// $Id$
+
+project : aceexe {
+
+ after += Test_Output
+ libs += Test_Output
+
+ Source_Files {
+ $(ACE_ROOT)/tests/Main.cpp
+ }
+ Header_Files {
+ }
+ Resource_Files {
+ }
+ Documentation_Files {
+ }
+ Inline_Files {
+ }
+}
diff --git a/ACE/tests/SSL/dummy.pem b/ACE/tests/SSL/dummy.pem
new file mode 100644
index 00000000000..d631a33b956
--- /dev/null
+++ b/ACE/tests/SSL/dummy.pem
@@ -0,0 +1,15 @@
+-----BEGIN CERTIFICATE-----
+MIICaTCCAdICAQAwDQYJKoZIhvcNAQEEBQAwcjELMAkGA1UEBhMCVVMxCzAJBgNV
+BAgTAkNBMQ8wDQYDVQQHEwZJcnZpbmUxDDAKBgNVBAoTA09DSTEMMAoGA1UECxMD
+VEFPMREwDwYDVQQDEwhwcml5YW5rYTEWMBQGCSqGSIb3DQEJARYHcGdvbnRsYTAe
+Fw0wMTAzMjkwNDM4NDZaFw0wMTA0MjgwNDM4NDZaMIGHMQswCQYDVQQGEwJVUzEL
+MAkGA1UECBMCQ0ExDzANBgNVBAcTBklydmluZTEdMBsGA1UEChMUT2JqZWN0IENv
+bXB1dGluZyBJbmMxEDAOBgNVBAsTB09DSStUQU8xETAPBgNVBAMTCHByaXlhbmth
+MRYwFAYJKoZIhvcNAQkBFgdwZ29udGxhMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB
+iQKBgQClC6z/bX1JHF1Hg06NCnBmsikEjViEdJFuqLOH3rXSGbm+2Eo+IO4dHlFS
+u6+Ntk4olBZTuf0DqzyEgrOiN7cnKXpxJzb1cwCmVkvDQISMygf4o66+CHtF8o8Z
+Sbi9F5u9W+MILaoCexEIVZqfHffcGxvm5O2MorBSQNka3NcC3wIDAQABMA0GCSqG
+SIb3DQEBBAUAA4GBADuKX6kllE2sNdQYMbSzt5C/lcpgcsK0BR6L01cQA95b5TvL
+HsKMeeeRj2npR4EPXY2gqgWTrKHZvf01aoKE5LuyzSQ+qfFMuEfo7+p9SYIuIrLD
+5+J0wOwN0R0YZAEY5gCAqRGw26dwWDai+PASPsx0YXV1y9jBB1FFtUFgrpR8
+-----END CERTIFICATE-----
diff --git a/ACE/tests/SSL/key.pem b/ACE/tests/SSL/key.pem
new file mode 100644
index 00000000000..54ff8f0f488
--- /dev/null
+++ b/ACE/tests/SSL/key.pem
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXAIBAAKBgQClC6z/bX1JHF1Hg06NCnBmsikEjViEdJFuqLOH3rXSGbm+2Eo+
+IO4dHlFSu6+Ntk4olBZTuf0DqzyEgrOiN7cnKXpxJzb1cwCmVkvDQISMygf4o66+
+CHtF8o8ZSbi9F5u9W+MILaoCexEIVZqfHffcGxvm5O2MorBSQNka3NcC3wIDAQAB
+AoGALYq/PexUeewdwTH2ZuzOf0gCEYN/PW19A/ABOii2OzdmDcdZFTO5AMfw4Mdx
+dcUsY/4Y+xmDO5Pwqw/1yXleTDqvEKCgIEHN4NWnYYSiZOy3LBzQ8XaMZ7/2PCqc
+s4EtesuRB2kZ7PH2R1vJfyGIxZPaO5MOFbs3QFnpBUjqOmECQQDQCYgnBcshCEro
+gsrTjxtZiVHjmXEo0Uo2m4CBQW1PLJmmUXBzivGkVFfhjKULjwvso3BePfmzy9wP
+7YFjVXN9AkEAyxjBXi2kYCcXfGQiNuIrLkyVXeGR2YWnhzS2nL1TjNngmCBbnj48
+qvoqOUQgFK0AeTe/x7lb4Cf24ejWF5vmiwJALensorAkpKWv4qD7IrXy00/7QsAa
+uWd3eZXYRq6p8U9mmc5fgyCnNB1pR95CjsqDVza7FhGXipbzepBwffveAQJBAMKc
+mxYyqDMW4nNoxDxRJs17xxkpwAdvAiQWB/JTnQ737DX5s7EDtECl7PXo6NDHIhAF
+srigToCR6wl4gkYnNpcCQHmlfa9Duf3VJI/XeHE9ZU8vS4qgx0Ikfh01xCqWlsaq
+nPRmtfktt4P8gxlryZCEPpRs9l/XwQY6tnpHr5EmV2Y=
+-----END RSA PRIVATE KEY-----
diff --git a/ACE/tests/SSL/tests.mpc b/ACE/tests/SSL/tests.mpc
new file mode 100644
index 00000000000..c49e4d746a5
--- /dev/null
+++ b/ACE/tests/SSL/tests.mpc
@@ -0,0 +1,17 @@
+// -*- MPC -*-
+// $Id$
+
+project(SSL Asynch_Stream Test) : acetest, ssl {
+ exename = SSL_Asynch_Stream_Test
+ Source_Files {
+ SSL_Asynch_Stream_Test.cpp
+ }
+}
+
+project(Thread Pool Reactor SSL Test) : acetest, ssl {
+ exename = Thread_Pool_Reactor_SSL_Test
+ Source_Files {
+ Thread_Pool_Reactor_SSL_Test.cpp
+ }
+}
+
diff --git a/ACE/tests/SString_Test.cpp b/ACE/tests/SString_Test.cpp
new file mode 100644
index 00000000000..896b54e4e1e
--- /dev/null
+++ b/ACE/tests/SString_Test.cpp
@@ -0,0 +1,336 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// SString_Test.cpp
+//
+// = DESCRIPTION
+// This is a simple test that illustrates the use of ACE_CString
+// and ACE_WString. No command line arguments are needed to run
+// the test.
+//
+// = AUTHOR
+// Prashant Jain <pjain@cs.wustl.edu>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/OS_NS_string.h"
+#include "ace/Auto_Ptr.h"
+#include "ace/SString.h"
+
+ACE_RCSID(tests, SString_Test, "$Id$")
+
+static int testConcatenation() {
+#ifdef ACE_HAS_WCHAR
+ ACE_WString s1;
+ s1 += L'H';
+ if (s1 != ACE_WString(L"H")) {
+ ACE_ERROR((LM_ERROR, "Concat wchar_t\n"));
+ return 1;
+ }
+ s1 = ACE_WString(L"Hello");
+ s1 += L" World";
+ if (s1 != ACE_WString(L"Hello World")) {
+ ACE_ERROR((LM_ERROR, "Concat wchar_t*\n"));
+ return 1;
+ }
+ s1 = L"Hello";
+ s1 += ACE_WString(L" World");
+ if (s1 != ACE_WString(L"Hello World")) {
+ ACE_ERROR((LM_ERROR, "Concat wstring\n"));
+ return 1;
+ }
+ s1 = L"Hello";
+ s1.append(L" World", 6);
+ if (s1 != ACE_WString(L"Hello World")) {
+ ACE_ERROR((LM_ERROR, "Concat wchar_t* 2\n"));
+ return 1;
+ }
+ s1 += L'.';
+ if (s1 != ACE_WString(L"Hello World.")) {
+ ACE_ERROR((LM_ERROR, "Concat wchar_t\n"));
+ return 1;
+ }
+ ACE_WString s2(L"Hello World");
+ s2 += L'.';
+ if (s2 != ACE_WString(L"Hello World.")) {
+ ACE_ERROR((LM_ERROR, "Concat wchar_t 2\n"));
+ return 1;
+ }
+#endif /* ACE_HAS_WCHAR */
+ return 0;
+}
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("SString_Test"));
+
+ {
+
+ /* Set #1 */
+ ACE_CString s0 ("hello");
+ ACE_CString s1 ("hello");
+ ACE_CString s2 ("world");
+ ACE_CString s3 ("ll");
+ ACE_CString s4 ("ello");
+ ACE_CString s5 = s1 + " " + s2;
+
+ char single_character = 'z';
+ ACE_CString single_character_string (single_character);
+
+ ACE_CString empty_string;
+ ACE_CString zero_size_string (s1.c_str (), 0, 0, 1);
+
+ // Not equal comparisons. Error if they are equal
+ if (s1 == s2){ACE_ERROR((LM_ERROR,"Set #1:\n"));return 1;}
+ if (s1 == s5){ACE_ERROR((LM_ERROR,"Set #1: \n"));return 1;}
+
+ // Equal comparisons. Error if they are not equal
+ if (s1 != s1){ACE_ERROR((LM_ERROR,"Set #1: \n"));return 1;}
+ if (s1 != s0){ACE_ERROR((LM_ERROR,"Set #1: \n"));return 1;}
+
+ // Substring match. Error if they are not equal
+ if (s1.strstr (s2) != ACE_CString::npos){ACE_ERROR((LM_ERROR,"Set #1: \n"));return 1;}
+ if (s1.strstr (s3) != 2){ACE_ERROR((LM_ERROR,"Set #1: \n"));return 1;}
+ if (s3.strstr (s1) != ACE_CString::npos){ACE_ERROR((LM_ERROR,"Set #1: \n"));return 1;}
+ if (s1.strstr (s4) != 1){ACE_ERROR((LM_ERROR,"Set #1: \n"));return 1;}
+
+ // Substring creation. Error if they are not equal
+ if (s1.substring (0) != s1){ACE_ERROR((LM_ERROR,"Set #1: \n"));return 1;}
+ if (s1.substring (1) != s4){ACE_ERROR((LM_ERROR,"Set #1: \n"));return 1;}
+ if (s1.substring (2, 2) != s3){ACE_ERROR((LM_ERROR,"Set #1: \n"));return 1;}
+ if (s1.substring (0, 0) != empty_string){ACE_ERROR((LM_ERROR,"Set #1: \n"));return 1;}
+ if (s1.substring (4, 10).length () != 1){ACE_ERROR((LM_ERROR,"Set #1: \n"));return 1;}
+
+ // Forward search. Error if they are not equal
+ if (s1.find (s3) != 2){ACE_ERROR((LM_ERROR,"Set #1: \n"));return 1;}
+ if (s3.find (s1) != ACE_CString::npos){ACE_ERROR((LM_ERROR,"Set #1: \n"));return 1;}
+ if (s1.find (s3, 2) != 2){ACE_ERROR((LM_ERROR,"Set #1: \n"));return 1;}
+ if (s3.find (s1, 1) != ACE_CString::npos){ACE_ERROR((LM_ERROR,"Set #1: \n"));return 1;}
+ if (s1.find (s2) != ACE_CString::npos){ACE_ERROR((LM_ERROR,"Set #1: \n"));return 1;}
+ if (s1.find ('o') != 4){ACE_ERROR((LM_ERROR,"Set #1: \n"));return 1;}
+
+ // Reverse search. Error if they are not equal
+ if (s1.rfind ('l') != 3){ACE_ERROR((LM_ERROR,"Set #1: \n"));return 1;}
+ if (s1.rfind ('l', 3) != 2){ACE_ERROR((LM_ERROR,"Set #1: \n"));return 1;}
+
+ // Assignment. Error if they are not equal
+ ACE_CString s6;
+ s6 = s0;
+ if (s6 != s0){ACE_ERROR((LM_ERROR,"Set #1: \n"));return 1;}
+ s6 = s4;
+ if (s4 != s6){ACE_ERROR((LM_ERROR,"Set #1: \n"));return 1;}
+ s6 = s5;
+ if (s6 != s5){ACE_ERROR((LM_ERROR,"Set #1: \n"));return 1;}
+ }
+
+ {
+ /* Set #2 */
+ ACE_CString s0 = "hello";
+ ACE_CString s1 ("hello", 0, 0);
+ ACE_CString s2 ("world", 0, 0);
+ ACE_CString s3 ("ll", 0, 0);
+ ACE_CString s4 ("ello", 0, 0);
+ ACE_CString s5 = s1 + " " + s2;
+
+ char single_character = 'z';
+ ACE_CString single_character_string (single_character);
+
+ ACE_CString empty_string (0, 0, 0);
+ ACE_CString zero_size_string (s1.c_str (), 0, 0, 0);
+
+ // Not equal comparisons. Error if they are equal
+ if (s1 == s2){ACE_ERROR((LM_ERROR,"Set #2: \n"));return 1;}
+ if (s1 == s5){ACE_ERROR((LM_ERROR,"Set #2: \n"));return 1;}
+
+ // Equal comparisons. Error if they are not equal
+ if (s1 != s1){ACE_ERROR((LM_ERROR,"Set #2: \n"));return 1;}
+ if (s1 != s0){ACE_ERROR((LM_ERROR,"Set #2: \n"));return 1;}
+
+ // Substring match. Error if they are not equal
+ if (s1.strstr (s2) != ACE_CString::npos){ACE_ERROR((LM_ERROR,"Set #2: \n"));return 1;}
+ if (s1.strstr (s3) != 2){ACE_ERROR((LM_ERROR,"Set #2: \n"));return 1;}
+ if (s3.strstr (s1) != ACE_CString::npos){ACE_ERROR((LM_ERROR,"Set #2: \n"));return 1;}
+ if (s1.strstr (s4) != 1){ACE_ERROR((LM_ERROR,"Set #2: \n"));return 1;}
+
+ // Substring creation. Error if they are not equal
+ if (s1.substring (0) != s1){ACE_ERROR((LM_ERROR,"Set #2: \n"));return 1;}
+ if (s1.substring (1) != s4){ACE_ERROR((LM_ERROR,"Set #2: \n"));return 1;}
+ if (s1.substring (2, 2) != s3){ACE_ERROR((LM_ERROR,"Set #2: \n"));return 1;}
+ if (s1.substring (0, 0) != empty_string){ACE_ERROR((LM_ERROR,"Set #2: \n"));return 1;}
+
+ // Forward search. Error if they are not equal
+ if (s1.find (s3) != 2){ACE_ERROR((LM_ERROR,"Set #2: \n"));return 1;}
+ if (s3.find (s1) != ACE_CString::npos){ACE_ERROR((LM_ERROR,"Set #2: \n"));return 1;}
+ if (s1.find (s3, 2) != 2){ACE_ERROR((LM_ERROR,"Set #2: \n"));return 1;}
+ if (s3.find (s1, 1) != ACE_CString::npos){ACE_ERROR((LM_ERROR,"Set #2: \n"));return 1;}
+ if (s1.find (s2) != ACE_CString::npos){ACE_ERROR((LM_ERROR,"Set #2: \n"));return 1;}
+ if (s1.find ('o') != 4){ACE_ERROR((LM_ERROR,"Set #2: \n"));return 1;}
+
+ // Reverse search. Error if they are not equal
+ if (s1.rfind ('l') != 3){ACE_ERROR((LM_ERROR,"Set #2: \n"));return 1;}
+ if (s1.rfind ('l', 3) != 2){ACE_ERROR((LM_ERROR,"Set #2: \n"));return 1;}
+
+ // Assignment. Error if they are not equal
+ ACE_CString s6;
+ s6 = s0;
+ if (s6 != s0){ACE_ERROR((LM_ERROR,"Set #2: \n"));return 1;}
+ s6 = s4;
+ if (s4 != s6){ACE_ERROR((LM_ERROR,"Set #2: \n"));return 1;}
+ s6 = s5;
+ if (s6 != s5){ACE_ERROR((LM_ERROR,"Set #2: \n"));return 1;}
+
+ // Clear. Error if they are not equal
+ s0.clear();
+ if (s0.length() != 0){ACE_ERROR((LM_ERROR,"Set #2: \n"));return 1;}
+
+ // Rep. Error if they are not equal
+ ACE_Auto_Basic_Array_Ptr<char> s (s1.rep ());
+ if (ACE_OS::strlen (s.get ()) != s1.length ())
+ {
+ ACE_ERROR((LM_ERROR,"Auto_ptr s: \n"));
+ };
+
+ ACE_CString s7 (s.get ());
+ if (s1 != s7){ACE_ERROR((LM_ERROR,"Set #2: \n"));return 1;}
+ }
+
+ {
+ /* Set #3 */
+ ACE_NS_WString s0 ("hello");
+ ACE_NS_WString s1 ("hello");
+ ACE_NS_WString s2 ("world");
+ ACE_NS_WString s3 ("ll");
+ ACE_NS_WString s4 ("ello");
+ ACE_NS_WString s5 = s1 + " " + s2;
+ ACE_NS_WString s6 = ("hella"); // Same length as s1, off by one char.
+
+ ACE_WCHAR_T single_character = 'z';
+ ACE_NS_WString single_character_string (single_character);
+
+ ACE_NS_WString empty_string;
+ ACE_NS_WString zero_size_string (s1.c_str (), 0, 0);
+
+ // Not equal comparisons. Error if they are equal
+ if (s1 == s2){ACE_ERROR((LM_ERROR,"Set #3: \n"));return 1;}
+ if (s1 == s5){ACE_ERROR((LM_ERROR,"Set #3: \n"));return 1;}
+ if (s1 == s6){ACE_ERROR((LM_ERROR,"Set #3: off-by-one failed\n"));return 1;}
+
+ // Equal comparisons. Error if they are not equal
+ if (s1 != s1){ACE_ERROR((LM_ERROR,"Set #3: \n"));return 1;}
+ if (s1 != s0){ACE_ERROR((LM_ERROR,"Set #3: \n"));return 1;}
+
+ // Substring match. Error if they are not equal
+ if (s1.strstr (s2) != ACE_NS_WString::npos){ACE_ERROR((LM_ERROR,"Set #3: \n"));return 1;}
+ if (s1.strstr (s3) != 2){ACE_ERROR((LM_ERROR,"Set #3: \n"));return 1;}
+ if (s3.strstr (s1) != ACE_NS_WString::npos){ACE_ERROR((LM_ERROR,"Set #3: \n"));return 1;}
+ if (s1.strstr (s4) != 1){ACE_ERROR((LM_ERROR,"Set #3: \n"));return 1;}
+
+ // Substring creation. Error if they are not equal
+ if (s1.substring (0) != s1){ACE_ERROR((LM_ERROR,"Set #3: \n"));return 1;}
+ if (s1.substring (1) != s4){ACE_ERROR((LM_ERROR,"Set #3: \n"));return 1;}
+ if (s1.substring (2, 2) != s3){ACE_ERROR((LM_ERROR,"Set #3: \n"));return 1;}
+ if (s1.substring (0, 0) != empty_string){ACE_ERROR((LM_ERROR,"Set #3: \n"));return 1;}
+
+ // Forward search. Error if they are not equal
+ if (s1.find (s3) != 2){ACE_ERROR((LM_ERROR,"Set #3: \n"));return 1;}
+ if (s3.find (s1) != ACE_NS_WString::npos){ACE_ERROR((LM_ERROR,"Set #3: \n"));return 1;}
+ if (s1.find (s3, 2) != 2){ACE_ERROR((LM_ERROR,"Set #3: \n"));return 1;}
+ if (s3.find (s1, 1) != ACE_NS_WString::npos){ACE_ERROR((LM_ERROR,"Set #3: \n"));return 1;}
+ if (s1.find (s2) != ACE_NS_WString::npos){ACE_ERROR((LM_ERROR,"Set #3: \n"));return 1;}
+ if (s1.find ('o') != 4){ACE_ERROR((LM_ERROR,"Set #3: \n"));return 1;}
+
+ // Reverse search. Error if they are not equal
+ if (s1.rfind ('l') != 3){ACE_ERROR((LM_ERROR,"Set #3: \n"));return 1;}
+ if (s1.rfind ('l', 3) != 2){ACE_ERROR((LM_ERROR,"Set #3: \n"));return 1;}
+
+ // Assignment. Error if they are not equal
+ ACE_NS_WString s7;
+ s7 = s0;
+ if (s7 != s0){ACE_ERROR((LM_ERROR,"Set #3: \n"));return 1;}
+ s7 = s4;
+ if (s4 != s7){ACE_ERROR((LM_ERROR,"Set #3: \n"));return 1;}
+ s7 = s5;
+ if (s7 != s5){ACE_ERROR((LM_ERROR,"Set #3: \n"));return 1;}
+
+ // Clear. Error if they are not equal
+ s0.clear();
+ if (s0.length() != 0){ACE_ERROR((LM_ERROR,"Set #3: \n"));return 1;}
+ }
+
+ {
+ /* Set #4 */
+ ACE_CString s1("dog");
+ ACE_CString s2("d");
+
+ if (s1 == s2){ACE_ERROR((LM_ERROR,"Set #4: \n"));return 1;}
+ if (!(s1 > s2)){ACE_ERROR((LM_ERROR,"Set #4: \n"));return 1;}
+ if (s1 < s2){ACE_ERROR((LM_ERROR,"Set #4: \n"));return 1;}
+
+ ACE_CString s3 ("dog");
+ ACE_CString s4 ("dogbert");
+
+ if (s3 == s4){ACE_ERROR((LM_ERROR,"Set #4: \n"));return 1;}
+ if (!(s3 < s4)){ACE_ERROR((LM_ERROR,"Set #4: \n"));return 1;}
+ if (s3 > s4){ACE_ERROR((LM_ERROR,"Set #4: \n"));return 1;}
+
+ ACE_CString s5 ("dogbert",3);
+ ACE_CString s6 ("dogbert",5);
+
+ if(s5 == s6){ACE_ERROR((LM_ERROR,"Set #4: \n"));return 1;}
+ if(!(s5 < s6)){ACE_ERROR((LM_ERROR,"Set #4: \n"));return 1;}
+ if(s5 > s6){ACE_ERROR((LM_ERROR,"Set #4: \n"));return 1;}
+
+ ACE_CString s7 ("dogbert",4);
+ ACE_CString s8 ("dogbert",2);
+
+ if(s7 == s8){ACE_ERROR((LM_ERROR,"Set #4: \n"));return 1;}
+ if(!(s7 > s8)){ACE_ERROR((LM_ERROR,"Set #4: \n"));return 1;}
+ if(s7 < s8){ACE_ERROR((LM_ERROR,"Set #4: \n"));return 1;}
+
+ ACE_CString s9 ("dogbert",3);
+ ACE_CString s10 ("dogbert");
+
+ if(s9 == s10){ACE_ERROR((LM_ERROR,"Set #4: \n"));return 1;}
+ if(!(s9 < s10)){ACE_ERROR((LM_ERROR,"Set #4: \n"));return 1;}
+ if(s9 > s10){ACE_ERROR((LM_ERROR,"Set #4: \n"));return 1;}
+
+ ACE_CString s11 ("dogbert",5);
+ ACE_CString s12 ("dog");
+
+ if(s11 == s12){ACE_ERROR((LM_ERROR,"Set #4: \n"));return 1;}
+ if(!(s11 > s12)){ACE_ERROR((LM_ERROR,"Set #4: \n"));return 1;}
+ if(s11 < s12){ACE_ERROR((LM_ERROR,"Set #4: \n"));return 1;}
+
+ s11.fast_clear ();
+ if (s11.length () != 0)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("fast_clear didn't yield 0 length\n")));
+ }
+
+ {
+ // Set 1 for ACE_SString, which is not tested
+ ACE_SString sstr;
+
+ const char *str = "What_a_day_it_has_been";
+
+ sstr.rep (const_cast<char *>(str));
+
+ ACE_SString tmp =
+ sstr.substring (2, 300);
+
+ if (tmp.length () == 300)
+ ACE_ERROR ((LM_ERROR, "SString substring \n"));
+
+ }
+
+ int err = testConcatenation();
+
+ ACE_END_TEST;
+ return err;
+}
diff --git a/ACE/tests/SV_Shared_Memory_Test.cpp b/ACE/tests/SV_Shared_Memory_Test.cpp
new file mode 100644
index 00000000000..f8351395346
--- /dev/null
+++ b/ACE/tests/SV_Shared_Memory_Test.cpp
@@ -0,0 +1,192 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// SV_Shared_Memory_Test.cpp
+//
+// = DESCRIPTION
+// This is a simple test of <ACE_SV_Shared_Memory> and
+// <ACE_Malloc> using the <ACE_Shared_Memory_Pool>. The test
+// forks two processes and then executes client and server
+// allowing them to exchange data using shared memory. No user
+// input is required as far as command line arguments are
+// concerned.
+//
+// = AUTHOR
+// Prashant Jain <pjain@cs.wustl.edu>
+// and Douglas C. Schmidt <schmidt@cs.wustl.edu>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/Malloc_T.h"
+#include "ace/Shared_Memory_Pool.h"
+#include "ace/SV_Semaphore_Simple.h"
+#include "ace/SV_Semaphore_Complex.h"
+#include "ace/OS_NS_unistd.h"
+
+
+ACE_RCSID(tests, SV_Shared_Memory_Test, "$Id$")
+
+#if defined (ACE_HAS_SYSV_IPC) && !defined(ACE_LACKS_SYSV_SHMEM)
+
+// The shared memory allocator, which uses up the ACE_DEFAULT_SEM_KEY.
+// We hide the allocator inside this function so that it doesn't get
+// constructed until after the ACE_Object_Manager gets constructed,
+// even with ACE_HAS_NONSTATIC_OBJECT_MANAGER.
+
+static
+ACE_Malloc<ACE_SHARED_MEMORY_POOL, ACE_SV_Semaphore_Simple> &
+myallocator (void)
+{
+ static ACE_Malloc<ACE_SHARED_MEMORY_POOL,
+ ACE_SV_Semaphore_Simple> myallocator;
+ return myallocator;
+}
+
+// Create some more keys that are different from the
+// ACE_DEFAULT_SEM_KEY used by the allocator.
+static const int SEM_KEY_1 = ACE_DEFAULT_SEM_KEY + 1;
+static const int SEM_KEY_2 = ACE_DEFAULT_SEM_KEY + 2;
+
+static const int SHMSZ = 27;
+static const char SHMDATA[SHMSZ] = "abcdefghijklmnopqrstuvwxyz";
+
+static ACE_SV_Semaphore_Complex *parent_mutex = 0;
+static ACE_SV_Semaphore_Complex *parent_synch = 0;
+
+static int
+parent (char *shm)
+{
+ // This for loop executes in a critical section proteced by
+ // <parent_mutex>.
+ for (int i = 0; i < SHMSZ; i++)
+ shm[i] = SHMDATA[i];
+
+ int result;
+ result = parent_mutex->release ();
+ ACE_ASSERT (result != -1);
+
+ result = parent_synch->acquire ();
+ ACE_ASSERT (result != -1);
+
+ result = myallocator ().remove ();
+ ACE_ASSERT (result != -1);
+
+ result = parent_mutex->remove ();
+ ACE_ASSERT (result != -1);
+
+ result = parent_synch->remove ();
+ ACE_ASSERT (result != -1);
+
+ return 0;
+}
+
+static int
+child (char *shm)
+{
+ int result;
+
+ ACE_SV_Semaphore_Complex mutex;
+
+ // This semaphore is initially created with a count of 0, i.e., it
+ // is "locked."
+ result = mutex.open (SEM_KEY_1,
+ ACE_SV_Semaphore_Complex::ACE_CREATE,
+ 0);
+ ACE_ASSERT (result != -1);
+
+ ACE_SV_Semaphore_Complex synch;
+ // This semaphore is initially created with a count of 0, i.e., it
+ // is "locked."
+ result = synch.open (SEM_KEY_2,
+ ACE_SV_Semaphore_Complex::ACE_CREATE,
+ 0);
+ ACE_ASSERT (result != -1);
+
+ // Perform "busy waiting" here until we acquire the semaphore. This
+ // isn't really a good design -- it's just to illustrate that you
+ // can do non-blocking acquire() calls with the ACE System V
+ // semaphore wrappers.
+ while ((result = mutex.tryacquire ()) == -1)
+ if (errno == EAGAIN)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P) spinning in child!\n")));
+ else
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P) child mutex.tryacquire")));
+ ACE_ASSERT (result != -1);
+ }
+
+ for (int i = 0; i < SHMSZ; i++)
+ ACE_ASSERT (SHMDATA[i] == shm[i]);
+
+ result = synch.release ();
+ ACE_ASSERT (result != -1);
+
+ return 0;
+}
+
+#endif /* ACE_HAS_SYSV_IPC */
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("SV_Shared_Memory_Test"));
+
+#if defined (ACE_HAS_SYSV_IPC) && !defined (ACE_LACKS_FORK) && \
+ !defined(ACE_LACKS_SYSV_SHMEM)
+ char *shm = reinterpret_cast<char *> (myallocator ().malloc (SHMSZ));
+
+ // Create the mutex and synch before spawning the child process, to
+ // avoid race condition between their creation in the parent and use
+ // in the child.
+ ACE_NEW_RETURN (parent_mutex,
+ ACE_SV_Semaphore_Complex,
+ -1);
+ ACE_NEW_RETURN (parent_synch,
+ ACE_SV_Semaphore_Complex,
+ -1);
+
+ // This semaphore is initially created with a count of 0, i.e., it
+ // is "locked."
+ int result = parent_mutex->open (SEM_KEY_1,
+ ACE_SV_Semaphore_Complex::ACE_CREATE,
+ 0);
+ ACE_ASSERT (result != -1);
+
+ // This semaphore is initially created with a count of 0, i.e., it
+ // is "locked."
+ result = parent_synch->open (SEM_KEY_2,
+ ACE_SV_Semaphore_Complex::ACE_CREATE,
+ 0);
+ ACE_ASSERT (result != -1);
+
+ switch (ACE_OS::fork (ACE_TEXT ("SV_Shared_Memory_Test.cpp")))
+ {
+ case -1:
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%P) fork failed\n")),
+ -1);
+ /* NOTREACHED */
+ case 0:
+ child (shm);
+ break;
+ default:
+ parent (shm);
+ delete parent_mutex;
+ delete parent_synch;
+ break;
+ }
+#else
+ ACE_ERROR ((LM_INFO,
+ ACE_TEXT ("SYSV IPC, SYSV SHMEM, or fork ")
+ ACE_TEXT ("are not supported on this platform\n")));
+#endif /* ACE_HAS_SYSV_IPC */
+ ACE_END_TEST;
+ return 0;
+}
diff --git a/ACE/tests/Semaphore_Test.cpp b/ACE/tests/Semaphore_Test.cpp
new file mode 100644
index 00000000000..e2b82042559
--- /dev/null
+++ b/ACE/tests/Semaphore_Test.cpp
@@ -0,0 +1,245 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Semaphore Test
+//
+// = DESCRIPTION
+// This test verifies the functionality of the <ACE_Thread_Semaphore>
+// implementation.
+//
+// = AUTHOR
+// Darrell Brunsch <brunsch@cs.wustl.edu>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/Thread_Semaphore.h"
+#include "ace/Thread.h"
+#include "ace/Thread_Manager.h"
+#include "ace/Get_Opt.h"
+#include "ace/OS_NS_sys_time.h"
+#include "ace/OS_NS_time.h"
+#include "ace/OS_NS_unistd.h"
+
+ACE_RCSID(tests, Semaphore_Test, "$Id$")
+
+// msec that times are allowed to differ before test fails.
+#if defined (ACE_HAS_HI_RES_TIMER) || defined (ACE_HAS_AIX_HI_RES_TIMER) || \
+ defined (ACE_HAS_PENTIUM) || defined (ACE_HAS_ALPHA_TIMER) || \
+ defined (ACE_HAS_POWERPC_TIMER)
+# define ACE_ALLOWED_SLACK 100
+#else /* don't have a high-res timer */
+# define ACE_ALLOWED_SLACK 1100
+#endif /* don't have a high-res timer */
+
+// Test results, 'success' is 0
+static int test_result = 0;
+
+#if defined (ACE_HAS_THREADS)
+
+// Semaphore used in the tests. Start it "locked" (i.e., its initial
+// count is 0).
+static ACE_Thread_Semaphore s ((unsigned int) 0);
+
+// Default number of iterations.
+static int n_iterations = 10;
+
+// Number of worker threads.
+static size_t n_workers = 10;
+
+// Amount to release the semaphore.
+static u_int n_release_count = 3;
+
+#if !defined (ACE_HAS_STHREADS) && (!defined (ACE_HAS_POSIX_SEM) || defined (ACE_HAS_POSIX_SEM_TIMEOUT))
+// Number of timeouts.
+static size_t timeouts = 0;
+
+// Number of times to call test_timeout ().
+static size_t test_timeout_count = 3;
+
+// Tests the amount of time spent in a timed wait.
+static int
+test_timeout (void)
+{
+ int status = 0;
+
+ // milliseconds...
+ long msecs_expected;
+ long msecs_waited;
+ long msecs_diff;
+
+ // Wait a little longer each time
+ static long wait_secs = 3;
+
+ ACE_Time_Value wait = ACE_OS::gettimeofday ();
+
+ ACE_Time_Value begin = wait;
+
+ wait.sec (wait.sec () + wait_secs);
+
+ if (s.acquire (wait) == -1)
+ ACE_ASSERT (errno == ETIME);
+
+ ACE_Time_Value wait_diff = ACE_OS::gettimeofday () - begin;
+
+ msecs_waited = wait_diff.msec ();
+ msecs_expected = wait_secs * 1000;
+ msecs_diff = labs (msecs_expected - msecs_waited);
+
+ if (msecs_diff > ACE_ALLOWED_SLACK)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Timed wait fails length test\n")));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Value: %d ms, actual %d ms\n"),
+ msecs_expected,
+ msecs_waited));
+ status = -1;
+ }
+
+ ++wait_secs;
+ return status;
+}
+#endif /* ACE_HAS_STHREADS && ACE_HAS_POSIX_SEM */
+
+// Explain usage and exit.
+static void
+print_usage_and_die (void)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("usage: %n [-s n_release_count] [-w n_workers] [-n iteration_count]\n")));
+ ACE_OS::exit (1);
+}
+
+static void
+parse_args (int argc, ACE_TCHAR *argv[])
+{
+ ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("s:w:n:"));
+
+ int c;
+
+ while ((c = get_opt ()) != -1)
+ switch (c)
+ {
+ case 's':
+ n_release_count = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'w':
+ n_workers = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'n':
+ n_iterations = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ default:
+ print_usage_and_die ();
+ break;
+ }
+}
+
+// Worker tries to acquire the semaphore, hold it for a while, and
+// then releases it.
+
+static void *
+worker (void *)
+{
+ for (int iterations = 1;
+ iterations <= n_iterations;
+ iterations++)
+ {
+#if !defined (ACE_HAS_STHREADS) && (!defined (ACE_HAS_POSIX_SEM) || defined (ACE_HAS_POSIX_SEM_TIMEOUT))
+ ACE_Time_Value wait (0,
+ iterations * 1000 * 100); // Wait 'iter' msec
+ ACE_Time_Value tv = ACE_OS::gettimeofday () + wait;
+ if (s.acquire (tv) == -1)
+ {
+ // verify that we have ETIME
+ ACE_ASSERT(ACE_OS::last_error() == ETIME);
+ ++timeouts;
+ ACE_Time_Value diff = ACE_OS::gettimeofday ();
+ diff = diff - tv; // tv should have been reset to time acquired
+ long diff_msec = diff.msec ();
+
+ if (diff_msec > ACE_ALLOWED_SLACK)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Acquire fails time reset test\n")));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Diff btw now and returned time: %d ms\n"),
+ diff.msec ()));
+ test_result = 1;
+ }
+ // Hold the lock for a while.
+ ACE_OS::sleep (ACE_Time_Value (0,
+ (ACE_OS::rand () % 1000) * 1000));
+ s.release ();
+ }
+#else
+ s.acquire ();
+ // Hold the lock for a while.
+ ACE_OS::sleep (ACE_Time_Value (0,
+ (ACE_OS::rand () % 1000) * 1000));
+ s.release ();
+#endif /* ACE_HAS_STHREADS && ACE_HAS_POSIX_SEM */
+ ACE_Thread::yield ();
+ }
+
+ return 0;
+}
+
+#endif /* ACE_HAS_THREADS */
+
+// Test semaphore functionality.
+
+int run_main (int argc, ACE_TCHAR *argv[])
+{
+ ACE_START_TEST (ACE_TEXT ("Semaphore_Test"));
+
+#if defined (ACE_HAS_THREADS)
+ parse_args (argc, argv);
+ ACE_OS::srand (ACE_OS::time (0L));
+
+# if !defined (ACE_HAS_STHREADS) && (!defined (ACE_HAS_POSIX_SEM) || defined (ACE_HAS_POSIX_SEM_TIMEOUT))
+ //Test timed waits.
+ for (size_t i = 0; i < test_timeout_count; i++)
+ if (test_timeout () != 0)
+ test_result = 1;
+# endif /* ACE_HAS_STHREADS && ACE_HAS_POSIX_SEM */
+
+ // Release the semaphore a certain number of times.
+ s.release (n_release_count);
+
+ if (ACE_Thread_Manager::instance ()->spawn_n
+ (static_cast<size_t> (n_workers),
+ ACE_THR_FUNC (worker),
+ 0,
+ THR_NEW_LWP) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("spawn_n")),
+ 1);
+
+ ACE_Thread_Manager::instance ()->wait ();
+
+# if !defined (ACE_HAS_STHREADS) && (!defined (ACE_HAS_POSIX_SEM) || defined (ACE_HAS_POSIX_SEM_TIMEOUT))
+ size_t percent = (timeouts * 100) / (n_workers * n_iterations);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Worker threads timed out %d percent of the time\n"),
+ percent));
+# endif /* ACE_HAS_STHREADS && ACE_HAS_POSIX_SEM */
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Semaphore Test successful\n")));
+#else
+ ACE_UNUSED_ARG (argc);
+ ACE_UNUSED_ARG (argv);
+ ACE_ERROR ((LM_INFO,
+ ACE_TEXT ("Threads not supported on this platform\n")));
+#endif /* ACE_HAS_THREADS */
+ ACE_END_TEST;
+ return test_result;
+}
diff --git a/ACE/tests/Sendfile_Test.cpp b/ACE/tests/Sendfile_Test.cpp
new file mode 100644
index 00000000000..887be6d1b59
--- /dev/null
+++ b/ACE/tests/Sendfile_Test.cpp
@@ -0,0 +1,317 @@
+// $Id$
+
+/**
+ * @file Sendfile_Test.cpp
+ *
+ * This is a test of the @c ACE_OS::sendfile() wrapper function. It
+ * is primarily meant to test the case when ACE_HAS_SENDFILE is not
+ * defined, i.e. when sendfile() support is emulated.
+ *
+ * @author
+ * Steve Huston <shuston@riverace.com>
+ * Ossama Othman <ossama@dre.vanderbilt.edu>
+ */
+
+#include "test_config.h"
+#include "ace/OS_NS_sys_wait.h"
+#include "ace/OS_NS_unistd.h"
+#include "ace/OS_NS_fcntl.h"
+#include "ace/Thread.h"
+#include "ace/Thread_Manager.h"
+#include "ace/Time_Value.h"
+#include "ace/SOCK_Connector.h"
+#include "ace/SOCK_Acceptor.h"
+#include "ace/SOCK_Stream.h"
+#include "ace/OS_NS_sys_sendfile.h"
+
+// Change to non-zero if test fails
+static int Test_Result = 0;
+
+#if !defined (ACE_LACKS_FORK) || defined (ACE_HAS_THREADS)
+
+// This test sends a large amount of data. The purpose is to overflow the
+// TCP send window, causing the sender to block (it's a send_n). This value
+// is the amount to send. The assumption is that no implementation has a
+// receive window larger than 128K bytes. If one is found, this is the place
+// to change it.
+// For some odd reason, NT will try to send a single large buffer, but not
+// multiple smaller ones that add up to the large size.
+const size_t Test3_Send_Size = 4*1024;
+const size_t Test3_Loops = 10;
+const size_t Test3_Total_Size = Test3_Send_Size * Test3_Loops;
+
+
+static void *
+client (void *arg)
+{
+ ACE_INET_Addr *remote_addr = reinterpret_cast<ACE_INET_Addr *> (arg);
+ ACE_INET_Addr server_addr (remote_addr->get_port_number (),
+ ACE_LOCALHOST);
+ ACE_SOCK_Stream cli_stream;
+ ACE_SOCK_Connector con;
+ ACE_Time_Value timeout (ACE_DEFAULT_TIMEOUT);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Connecting to port %d\n"),
+ server_addr.get_port_number()));
+
+ // Initiate connection with server; don't wait forever
+ if (con.connect (cli_stream,
+ server_addr,
+ &timeout) == -1)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n"),
+ ACE_TEXT ("connection failed")));
+ Test_Result = 1;
+ return 0;
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) connected to %s\n"),
+ ACE_TEXT_CHAR_TO_TCHAR(server_addr.get_host_name ())));
+
+ //******************* TEST 1 ******************************
+ //
+ // Send the 255 byte buffer in 5 chunks. The
+ // server will verify that the correct data is sent, and that there
+ // is no more and no less.
+
+ u_char buffer[255];
+ size_t i;
+
+ // The server will verify that this data pattern gets there intact.
+
+ for (i = 0; i < sizeof buffer; ++i)
+ buffer[i] = static_cast<u_char> (i);
+
+ ACE_TCHAR const test_file[] = ACE_TEXT ("Sendfile_Test_File");
+ ACE_HANDLE in_fd =
+ ACE_OS::open (test_file,
+ O_CREAT | O_RDWR | O_TRUNC,
+ ACE_DEFAULT_FILE_PERMS);
+
+ ACE_ASSERT (in_fd != ACE_INVALID_HANDLE);
+
+ ACE_OS::unlink (test_file);
+
+ ssize_t const byte_count =
+ ACE_OS::write (in_fd, buffer, sizeof (buffer));
+
+ ACE_ASSERT (byte_count == static_cast<ssize_t> (sizeof (buffer)));
+
+ off_t offset = 0;
+
+ ssize_t len =
+ ACE_OS::sendfile (cli_stream.get_handle (),
+ in_fd,
+ &offset,
+ byte_count);
+
+ if (len == -1)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n"),
+ ACE_TEXT ("Test 1, sendfile failed")));
+ Test_Result = 1;
+ }
+ else
+ ACE_ASSERT (len == 255);
+
+ //******************* TEST 2 ******************************
+ //
+ // The same data is coming back - receive it using recv (size_t n,
+ // ...) and compare it to the original data.
+
+ u_char buffer2[255];
+ // Give it a chance to get here
+ ACE_OS::sleep (2);
+ len = cli_stream.recv (4,
+ buffer2,
+ 150,
+ &buffer2[150],
+ 105);
+ if (len != 255)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p; len is %d, but should be 255!\n"),
+ len));
+ }
+ ACE_ASSERT (len == 255);
+
+ for (i = 0; i < 255; i++)
+ if (buffer2[i] != buffer[i])
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Test 2, rcvd byte %d is %d, not %d\n"),
+ i, buffer2[i], buffer[i]));
+ Test_Result = 1;
+ }
+
+
+ cli_stream.close ();
+ (void) ACE_OS::close (in_fd);
+
+ return 0;
+}
+
+static void *
+server (void *arg)
+{
+ ACE_SOCK_Acceptor *peer_acceptor = (ACE_SOCK_Acceptor *) arg;
+ ACE_SOCK_Stream sock_str;
+ ACE_INET_Addr cli_addr;
+ ACE_Time_Value timeout (ACE_DEFAULT_TIMEOUT);
+
+ // Accept the connection over which the stream tests will run.
+ // Don't lock up if client doesn't connect
+ if (peer_acceptor->accept (sock_str,
+ &cli_addr,
+ &timeout) == -1)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n"),
+ ACE_TEXT ("accept")));
+ Test_Result = 1;
+ return 0;
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) client %s connected from %d\n"),
+ ACE_TEXT_CHAR_TO_TCHAR(cli_addr.get_host_name ()),
+ cli_addr.get_port_number ()));
+
+ //******************* TEST 1 ******************************
+ //
+ // Do a iovec recvv - the client should send 255 bytes, which we
+ // will be detected and read into a ACE-allocated buffer. Use a 5
+ // second timeout to give the client a chance to send it all.
+
+ ACE_OS::sleep (5);
+
+ u_char buffer[255];
+ ssize_t len;
+ int i;
+
+ len = sock_str.recv (buffer, 255);
+ if (len == -1)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n"),
+ ACE_TEXT ("Test 1, recvv failed")));
+ Test_Result = 1;
+ }
+
+ ACE_ASSERT (len == 255);
+ for (i = 0; i < 255; i++)
+ if (buffer[i] != i)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Test 1, rcvd byte %d is %d, not %d\n"),
+ i,
+ buffer[i],
+ i));
+ Test_Result = 1;
+ }
+
+ //******************* TEST 2 ******************************
+ //
+ // Send the buffer back, using send (size_t n, ...) in 3 pieces.
+
+ len = sock_str.send (6,
+ buffer,
+ 42,
+ &buffer[42],
+ 189,
+ &buffer[231],
+ 24);
+ ACE_ASSERT (len == 255);
+
+
+ sock_str.close();
+
+ return 0;
+}
+
+#endif /* !ACE_LACKS_FORK || ACE_HAS_THREADS */
+
+static void
+spawn (void)
+{
+ // Acceptor
+ ACE_SOCK_Acceptor peer_acceptor;
+
+ // Create a server address.
+ ACE_INET_Addr server_addr;
+
+ // Bind listener to any port and then find out what the port was.
+ if (peer_acceptor.open (ACE_Addr::sap_any) == -1
+ || peer_acceptor.get_local_addr (server_addr) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n"),
+ ACE_TEXT ("open")));
+ else
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) starting server at port %d\n"),
+ server_addr.get_port_number ()));
+
+#if !defined (ACE_LACKS_FORK)
+ switch (ACE_OS::fork (ACE_TEXT ("child")))
+ {
+ case -1:
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n%a"),
+ ACE_TEXT ("fork failed"),
+ 1));
+ /* NOTREACHED */
+ case 0:
+ client (&server_addr);
+ ACE_OS::exit (0);
+ /* NOTREACHED */
+ default:
+ server (reinterpret_cast<void *> (&peer_acceptor));
+ ACE_OS::wait ();
+ }
+#elif defined (ACE_HAS_THREADS)
+ if (ACE_Thread_Manager::instance ()->spawn
+ (ACE_THR_FUNC (server),
+ reinterpret_cast<void *> (&peer_acceptor),
+ THR_NEW_LWP | THR_DETACHED) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n%a"),
+ ACE_TEXT ("thread create failed"),
+ 1));
+
+ if (ACE_Thread_Manager::instance ()->spawn
+ (ACE_THR_FUNC (client),
+ reinterpret_cast<void *> (&server_addr),
+ THR_NEW_LWP | THR_DETACHED) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n%a"),
+ ACE_TEXT ("thread create failed"),
+ 1));
+
+ // Wait for the threads to exit.
+ ACE_Thread_Manager::instance ()->wait ();
+#else
+ ACE_ERROR ((LM_INFO,
+ ACE_TEXT ("(%P|%t) ")
+ ACE_TEXT ("only one thread may be run ")
+ ACE_TEXT ("in a process on this platform\n")));
+#endif /* ACE_HAS_THREADS */
+
+ peer_acceptor.close ();
+ }
+}
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("Sendfile_Test"));
+
+ spawn ();
+
+ ACE_END_TEST;
+ return Test_Result;
+}
diff --git a/ACE/tests/Service_Config_DLL.cpp b/ACE/tests/Service_Config_DLL.cpp
new file mode 100644
index 00000000000..abe2f5aab7f
--- /dev/null
+++ b/ACE/tests/Service_Config_DLL.cpp
@@ -0,0 +1,231 @@
+// -*- C++ -*-
+//=============================================================================
+/**
+ * @file Service_Config_DLL.cpp
+ *
+ * $Id$
+ *
+ * This file is related to, and used with, Service_Config_Test. It's
+ * used when testing the reentrance/thread-safety of the
+ * Service Configurator, in addition to testing the Service
+ * Configurator's ability to handle nested processing of Service
+ * Configurator directives.
+ *
+ * @author Ossama Othman <ossama@uci.edu>
+ */
+//=============================================================================
+
+#include "Service_Config_DLL.h"
+#include "ace/Service_Config.h"
+#include "ace/OS_NS_stdio.h"
+#include "ace/OS_NS_string.h"
+
+ACE_RCSID (tests,
+ Service_Config_DLL,
+ "$Id$")
+
+static ACE_THR_FUNC_RETURN
+invoke_service_config (void *arg)
+{
+ const ACE_TCHAR *directive = reinterpret_cast<const ACE_TCHAR *> (arg);
+
+
+ // Process a Service Configurator directive in the current thread.
+ if (ACE_Service_Config::process_directive (directive) != 0)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Service_Config_DLL::svc() - ")
+ ACE_TEXT ("process_directive() failed for:\n")
+ ACE_TEXT ("\"%s\"\n"),
+ directive));
+
+ return 0;
+}
+
+Service_Config_DLL::Service_Config_DLL (void)
+{
+ ACE_OS::memset (this->directive_[0], 0, BUFSIZ * sizeof (ACE_TCHAR));
+ ACE_OS::memset (this->directive_[1], 0, BUFSIZ * sizeof (ACE_TCHAR));
+}
+
+int
+Service_Config_DLL::init (int argc, ACE_TCHAR *argv[])
+{
+ if (argc == 2)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Loading Test_Object_%s and Test_Object_%s\n"),
+ argv[0],
+ argv[1]));
+
+ ACE_OS::sprintf (this->directive_[0],
+#if (ACE_USES_CLASSIC_SVC_CONF == 1)
+ ACE_TEXT ("dynamic Test_Object_%s Service_Object * Service_Config_DLL:_make_Service_Config_DLL() \"Test_Object_%s\""),
+#else
+ ACE_TEXT ("<?xml version='1.0'?> <dynamic id='Test_Object_%s' type='service_object'> <initializer init='_make_Service_Config_DLL' path='Service_Config_DLL' params='Test_Object_%s'/> </dynamic>"),
+#endif
+ argv[0],
+ argv[0]);
+
+ ACE_OS::sprintf (this->directive_[1],
+#if (ACE_USES_CLASSIC_SVC_CONF == 1)
+ ACE_TEXT ("dynamic Test_Object_%s Service_Object * Service_Config_DLL:_make_Service_Config_DLL() \"Test_Object_%s\""),
+#else
+ ACE_TEXT ("<?xml version='1.0'?> <dynamic id='Test_Object_%s' type='service_object'> <initializer init='_make_Service_Config_DLL' path='Service_Config_DLL' params='Test_Object_%s'/> </dynamic>"),
+#endif
+
+ argv[1],
+ argv[1]);
+
+ if (ACE_Service_Config::process_directive (this->directive_[0]) != 0)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Service_Config_DLL::init() - ")
+ ACE_TEXT ("process_directive() failed for:\n")
+ ACE_TEXT ("\"%s\": %m\n"),
+ this->directive_[0]));
+
+#if defined (ACE_HAS_THREADS)
+
+ // Become an Active Object if more than one argument passed.
+ // Two arguments indicate two "test objects" to be dynamically
+ // loaded.
+ return this->activate ();
+
+#endif /* ACE_HAS_THREADS */
+
+ }
+ else if (argc == 1)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Service_Config_DLL::init () %@ - %s\n"),
+ this,
+ argv[0]));
+ }
+ else
+ {
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Incorrect number of arguments ")
+ ACE_TEXT ("(%d) passed to Service_Config_DLL::init ()"),
+ argc),
+ -1);
+ }
+
+ return 0;
+}
+
+int
+Service_Config_DLL::fini (void)
+{
+ return 0;
+}
+
+int
+Service_Config_DLL::svc (void)
+{
+ if (ACE_Thread_Manager::instance ()->spawn (invoke_service_config,
+ this->directive_[1]) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Unable to spawn thread to ")
+ ACE_TEXT ("invoke Service Configurator.\n")),
+ -1);
+
+ return 0;
+}
+
+// The same class (Service_Config_DLL) is used to implement each of the
+// Service Objects whose service descriptors are defined below.
+
+// -----------------------------------------------------------------
+
+ACE_STATIC_SVC_DEFINE (Test_Object_1,
+ ACE_TEXT ("Test_Object_1"),
+ ACE_SVC_OBJ_T,
+ &ACE_SVC_NAME (Service_Config_DLL),
+ ACE_Service_Type::DELETE_THIS
+ | ACE_Service_Type::DELETE_OBJ,
+ 0)
+
+// -----------------------------------------------------------------
+
+ACE_STATIC_SVC_DEFINE (Test_Object_2,
+ ACE_TEXT ("Test_Object_2"),
+ ACE_SVC_OBJ_T,
+ &ACE_SVC_NAME (Service_Config_DLL),
+ ACE_Service_Type::DELETE_THIS
+ | ACE_Service_Type::DELETE_OBJ,
+ 0)
+
+// -----------------------------------------------------------------
+
+ACE_STATIC_SVC_DEFINE (Test_Object_3,
+ ACE_TEXT ("Test_Object_3"),
+ ACE_SVC_OBJ_T,
+ &ACE_SVC_NAME (Service_Config_DLL),
+ ACE_Service_Type::DELETE_THIS
+ | ACE_Service_Type::DELETE_OBJ,
+ 0)
+
+// -----------------------------------------------------------------
+
+ACE_STATIC_SVC_DEFINE (Test_Object_4,
+ ACE_TEXT ("Test_Object_4"),
+ ACE_SVC_OBJ_T,
+ &ACE_SVC_NAME (Service_Config_DLL),
+ ACE_Service_Type::DELETE_THIS
+ | ACE_Service_Type::DELETE_OBJ,
+ 0)
+
+// -----------------------------------------------------------------
+
+ACE_STATIC_SVC_DEFINE (Test_Object_5,
+ ACE_TEXT ("Test_Object_5"),
+ ACE_SVC_OBJ_T,
+ &ACE_SVC_NAME (Service_Config_DLL),
+ ACE_Service_Type::DELETE_THIS
+ | ACE_Service_Type::DELETE_OBJ,
+ 0)
+
+// -----------------------------------------------------------------
+
+ACE_STATIC_SVC_DEFINE (Test_Object_6,
+ ACE_TEXT ("Test_Object_6"),
+ ACE_SVC_OBJ_T,
+ &ACE_SVC_NAME (Service_Config_DLL),
+ ACE_Service_Type::DELETE_THIS
+ | ACE_Service_Type::DELETE_OBJ,
+ 0)
+
+// -----------------------------------------------------------------
+
+ACE_STATIC_SVC_DEFINE (Final_Object,
+ ACE_TEXT ("Final_Object"),
+ ACE_SVC_OBJ_T,
+ &ACE_SVC_NAME (Service_Config_DLL),
+ ACE_Service_Type::DELETE_THIS
+ | ACE_Service_Type::DELETE_OBJ,
+ 0)
+
+// -----------------------------------------------------------------
+
+ACE_STATIC_SVC_DEFINE (Test_Object_1_More,
+ ACE_TEXT ("Test_Object_1_More"),
+ ACE_SVC_OBJ_T,
+ &ACE_SVC_NAME (Service_Config_DLL),
+ ACE_Service_Type::DELETE_THIS
+ | ACE_Service_Type::DELETE_OBJ,
+ 0)
+
+// -----------------------------------------------------------------
+
+ACE_STATIC_SVC_DEFINE (Test_Object_2_More,
+ ACE_TEXT ("Test_Object_2_More"),
+ ACE_SVC_OBJ_T,
+ &ACE_SVC_NAME (Service_Config_DLL),
+ ACE_Service_Type::DELETE_THIS
+ | ACE_Service_Type::DELETE_OBJ,
+ 0)
+
+
+// -----------------------------------------------------------------
+
+// Same factory is used for all service descriptors defined above.
+ACE_FACTORY_DEFINE (Service_Config_DLL, Service_Config_DLL)
diff --git a/ACE/tests/Service_Config_DLL.h b/ACE/tests/Service_Config_DLL.h
new file mode 100644
index 00000000000..1d0c194d2fa
--- /dev/null
+++ b/ACE/tests/Service_Config_DLL.h
@@ -0,0 +1,68 @@
+// -*- C++ -*-
+
+//=============================================================================
+/**
+ * @file Service_Config_DLL.h
+ *
+ * $Id$
+ *
+ * @author Ossama Othman <ossama@uci.edu>
+ */
+//=============================================================================
+
+#ifndef SERVICE_CONFIG_DLL_H
+#define SERVICE_CONFIG_DLL_H
+
+#include /**/ "ace/pre.h"
+
+#include "Service_Config_DLL_Export.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "ace/Task.h"
+
+/**
+ * @class Service_Config_DLL
+ *
+ * @brief The Service_Config_DLL that is instantiated when the
+ * client-side test module/library is dynamically loaded.
+ *
+ * This class is the implementation used for all service instances
+ * (i.e. those declared using the ACE_FACTORY_* macros).
+ */
+class Service_Config_DLL_Export Service_Config_DLL : public ACE_Task_Base
+{
+public:
+
+ /// Constructor.
+ Service_Config_DLL (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);
+
+ /// Run by a daemon thread.
+ /**
+ * Each thread will invoke the Service Configurator via this
+ * method unless the object is the "FINAL" object.
+ */
+ virtual int svc (void);
+
+private:
+
+ /// Directives to be passed to be processed by the Service
+ /// Configurator in seperate threads.
+ ACE_TCHAR directive_[2][BUFSIZ];
+
+};
+
+
+ACE_FACTORY_DECLARE (Service_Config_DLL, Service_Config_DLL)
+
+#include /**/ "ace/post.h"
+
+#endif /* SERVICE_CONFIG_DLL_H */
diff --git a/ACE/tests/Service_Config_DLL_Export.h b/ACE/tests/Service_Config_DLL_Export.h
new file mode 100644
index 00000000000..1688a745350
--- /dev/null
+++ b/ACE/tests/Service_Config_DLL_Export.h
@@ -0,0 +1,38 @@
+
+// -*- C++ -*-
+// $Id$
+// Definition for Win32 Export directives.
+// This file is generated automatically by generate_export_file.pl
+// ------------------------------
+#ifndef SERVICE_CONFIG_DLL_EXPORT_H
+#define SERVICE_CONFIG_DLL_EXPORT_H
+
+#include "ace/config-all.h"
+
+#if defined (ACE_AS_STATIC_LIBS) && !defined (SERVICE_CONFIG_DLL_HAS_DLL)
+# define SERVICE_CONFIG_DLL_HAS_DLL 0
+#endif /* ACE_AS_STATIC_LIBS && ! SERVICE_CONFIG_DLL_HAS_DLL */
+
+#if !defined (SERVICE_CONFIG_DLL_HAS_DLL)
+# define SERVICE_CONFIG_DLL_HAS_DLL 1
+#endif /* ! TEST_HAS_DLL */
+
+#if defined (SERVICE_CONFIG_DLL_HAS_DLL) && (SERVICE_CONFIG_DLL_HAS_DLL == 1)
+# if defined (SERVICE_CONFIG_DLL_BUILD_DLL)
+# define Service_Config_DLL_Export ACE_Proper_Export_Flag
+# define TEST_SINGLETON_DECLARATION(T) ACE_EXPORT_SINGLETON_DECLARATION (T)
+# define TEST_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) ACE_EXPORT_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK)
+# else /* SERVICE_CONFIG_DLL_BUILD_DLL */
+# define Service_Config_DLL_Export ACE_Proper_Import_Flag
+# define TEST_SINGLETON_DECLARATION(T) ACE_IMPORT_SINGLETON_DECLARATION (T)
+# define TEST_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) ACE_IMPORT_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK)
+# endif /* SERVICE_CONFIG_DLL_BUILD_DLL */
+#else /* SERVICE_CONFIG_DLL_HAS_DLL == 1 */
+# define Service_Config_DLL_Export
+# define TEST_SINGLETON_DECLARATION(T)
+# define TEST_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK)
+#endif /* SERVICE_CONFIG_DLL_HAS_DLL == 1 */
+
+#endif /* SERVICE_CONFIG_DLL_EXPORT_H */
+
+// End of auto generated file.
diff --git a/ACE/tests/Service_Config_Test.UTF-16.conf b/ACE/tests/Service_Config_Test.UTF-16.conf
new file mode 100644
index 00000000000..fee216c95f9
--- /dev/null
+++ b/ACE/tests/Service_Config_Test.UTF-16.conf
Binary files differ
diff --git a/ACE/tests/Service_Config_Test.UTF-16.conf.xml b/ACE/tests/Service_Config_Test.UTF-16.conf.xml
new file mode 100644
index 00000000000..1d75d2763c0
--- /dev/null
+++ b/ACE/tests/Service_Config_Test.UTF-16.conf.xml
Binary files differ
diff --git a/ACE/tests/Service_Config_Test.WCHAR_T.conf b/ACE/tests/Service_Config_Test.WCHAR_T.conf
new file mode 100644
index 00000000000..81f6e1fe4d6
--- /dev/null
+++ b/ACE/tests/Service_Config_Test.WCHAR_T.conf
Binary files differ
diff --git a/ACE/tests/Service_Config_Test.WCHAR_T.conf.xml b/ACE/tests/Service_Config_Test.WCHAR_T.conf.xml
new file mode 100644
index 00000000000..88e7c26e8eb
--- /dev/null
+++ b/ACE/tests/Service_Config_Test.WCHAR_T.conf.xml
Binary files differ
diff --git a/ACE/tests/Service_Config_Test.conf b/ACE/tests/Service_Config_Test.conf
new file mode 100644
index 00000000000..34d51068365
--- /dev/null
+++ b/ACE/tests/Service_Config_Test.conf
@@ -0,0 +1,19 @@
+# Dynamically loading each of the Service Objects below causes a
+# number of threads to be spawned, each one invoking the Service
+# Configurator (e.g. ACE_Service_Config::process_directive(). If the
+# Service Configurator is thread safe and reentrant, then parsing of
+# this `Service_Config_Test.conf' file should run to completion
+# without error.
+#
+# Test_Object_1 will cause Test_Object_2 and Test_Object_3 to be
+# dynamically loaded. Dynamic loading of each of object will occur in
+# a separate thread.
+dynamic Test_Object_1 Service_Object * Service_Config_DLL:_make_Service_Config_DLL() "2 3"
+
+# Test_Object_4 will cause Test_Object_5 and Test_Object_6 to be
+# dynamically loaded. Dynamic loading of each of object will occur in
+# a separate thread.
+dynamic Test_Object_4 Service_Object * Service_Config_DLL:_make_Service_Config_DLL() "5 6"
+
+# Final_Object does nothing but print a completion message.
+dynamic Final_Object Service_Object * Service_Config_DLL:_make_Service_Config_DLL() "FINAL"
diff --git a/ACE/tests/Service_Config_Test.conf.xml b/ACE/tests/Service_Config_Test.conf.xml
new file mode 100644
index 00000000000..f3273f0cb93
--- /dev/null
+++ b/ACE/tests/Service_Config_Test.conf.xml
@@ -0,0 +1,27 @@
+<?xml version='1.0'?>
+<!-- Converted from Service_Config_Test.conf by svcconf-convert.pl -->
+<ACE_Svc_Conf>
+ <!-- Dynamically loading each of the Service Objects below causes a -->
+ <!-- number of threads to be spawned, each one invoking the Service -->
+ <!-- Configurator (e.g. ACE_Service_Config::process_directive(). If the -->
+ <!-- Service Configurator is thread safe and reentrant, then parsing of -->
+ <!-- this `Service_Config_Test.conf' file should run to completion -->
+ <!-- without error. -->
+ <!-- -->
+ <!-- Test_Object_1 will cause Test_Object_2 and Test_Object_3 to be -->
+ <!-- dynamically loaded. Dynamic loading of each of object will occur in -->
+ <!-- a separate thread. -->
+ <dynamic id="Test_Object_1" type="Service_Object">
+ <initializer init="_make_Service_Config_DLL" path="Service_Config_DLL" params="2 3"/>
+ </dynamic>
+ <!-- Test_Object_4 will cause Test_Object_5 and Test_Object_6 to be -->
+ <!-- dynamically loaded. Dynamic loading of each of object will occur in -->
+ <!-- a separate thread. -->
+ <dynamic id="Test_Object_4" type="Service_Object">
+ <initializer init="_make_Service_Config_DLL" path="Service_Config_DLL" params="5 6"/>
+ </dynamic>
+ <!-- Final_Object does nothing but print a completion message. -->
+ <dynamic id="Final_Object" type="Service_Object">
+ <initializer init="_make_Service_Config_DLL" path="Service_Config_DLL" params="FINAL"/>
+ </dynamic>
+</ACE_Svc_Conf>
diff --git a/ACE/tests/Service_Config_Test.cpp b/ACE/tests/Service_Config_Test.cpp
new file mode 100644
index 00000000000..dde86668b3c
--- /dev/null
+++ b/ACE/tests/Service_Config_Test.cpp
@@ -0,0 +1,259 @@
+// -*- C++ -*-
+
+//=============================================================================
+/**
+ * @file Service_Config_Test.cpp
+ *
+ * $Id$
+ *
+ * This is a simple test to make sure the ACE Service Configurator
+ * framework is working correctly.
+ *
+ * @author David Levine <levine@cs.wustl.edu>
+ * @author Ossama Othman <ossama@uci.edu>
+ */
+//=============================================================================
+
+#include "test_config.h"
+#include "ace/OS_NS_stdio.h"
+#include "ace/OS_NS_errno.h"
+#include "ace/Log_Msg.h"
+#include "ace/Object_Manager.h"
+#include "ace/Service_Config.h"
+#include "ace/Reactor.h"
+#include "ace/Thread_Manager.h"
+#include "ace/ARGV.h"
+
+ACE_RCSID (tests,
+ Service_Config_Test,
+ "$Id$")
+
+static const u_int VARIETIES = 3;
+
+static u_int error = 0;
+
+/**
+ * @class Test_Singleton
+ *
+ * @brief Test the Singleton
+ *
+ * This should be a template class, with singleton instantiations.
+ * But to avoid having to deal with compilers that want template
+ * declarations in separate files, it's just a plain class. The
+ * instance argument differentiates the "singleton" instances. It
+ * also demonstrates the use of the param arg to the cleanup ()
+ * function.
+ */
+class Test_Singleton
+{
+public:
+ static Test_Singleton *instance (u_short variety);
+ ~Test_Singleton (void);
+
+private:
+ u_short variety_;
+ static u_short current_;
+
+ Test_Singleton (u_short variety);
+
+ friend class misspelled_verbase_friend_declaration_to_avoid_compiler_warning_with_private_ctor;
+};
+
+u_short Test_Singleton::current_ = 0;
+
+extern "C" void
+test_singleton_cleanup (void *object, void *param)
+{
+ // We can't reliably use ACE_Log_Msg in a cleanup hook. Yet.
+ ACE_UNUSED_ARG (param);
+ /* ACE_DEBUG ((LM_DEBUG, "cleanup %d\n", (u_short) param)); */
+
+ delete (Test_Singleton *) object;
+}
+
+Test_Singleton *
+Test_Singleton::instance (u_short variety)
+{
+ static Test_Singleton *instances[VARIETIES] = { 0 };
+
+ if (instances[variety] == 0)
+ ACE_NEW_RETURN (instances[variety],
+ Test_Singleton (variety),
+ 0);
+
+ ACE_Object_Manager::at_exit (instances[variety],
+ test_singleton_cleanup,
+ reinterpret_cast<void *> (static_cast<size_t> (variety)));
+ return instances[variety];
+}
+
+Test_Singleton::Test_Singleton (u_short variety)
+ : variety_ (variety)
+{
+ if (variety_ != current_++)
+ {
+ ACE_DEBUG ((LM_ERROR,
+ ACE_TEXT ("ERROR: instance %u created out of order!\n"),
+ variety_));
+ ++error;
+ }
+}
+
+// We can't reliably use ACE_Log_Msg in a destructor that is called by
+// ACE_Object_Manager. Yet.
+
+Test_Singleton::~Test_Singleton (void)
+{
+ /* ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Test_Singleton %u dtor\n"), variety_)); */
+
+ if (variety_ != --current_)
+ {
+ ACE_OS::fprintf (stderr,
+ ACE_TEXT ("ERROR: instance %u destroyed out of order!\n"),
+ variety_);
+ /* ACE_DEBUG ((LM_ERROR, ACE_TEXT ("ERROR: instance %u destroyed out of order!\n"),
+ variety_)); */
+ ++error;
+ }
+}
+
+void
+testLoadingServiceConfFile (int argc, ACE_TCHAR *argv[])
+{
+ ACE_ARGV new_argv;
+
+#if defined (ACE_USES_WCHAR)
+ // When using full Unicode support, use the version of the Service
+ // Configurator file appropriate to the platform.
+ // For example, Windows Unicode uses UTF-16.
+ //
+ // iconv(1) found on Linux and Solaris, for example, can
+ // be used to convert between encodings.
+ //
+ // Byte ordering is also an issue, so we should be
+ // generating this file on-the-fly from the UTF-8 encoded
+ // file by using functions like iconv(1) or iconv(3).
+# if defined (ACE_WIN32)
+ const ACE_TCHAR svc_conf[] =
+ ACE_TEXT ("Service_Config_Test.UTF-16")
+ ACE_TEXT (ACE_DEFAULT_SVC_CONF_EXT);
+# else
+ const ACE_TCHAR svc_conf[] =
+ ACE_TEXT ("Service_Config_Test.WCHAR_T")
+ ACE_TEXT (ACE_DEFAULT_SVC_CONF_EXT);
+# endif /* ACE_WIN32 */
+#else
+ // ASCII (UTF-8) encoded Service Configurator file.
+ const ACE_TCHAR svc_conf[] =
+ ACE_TEXT ("Service_Config_Test")
+ ACE_TEXT (ACE_DEFAULT_SVC_CONF_EXT);
+#endif /* ACE_USES_WCHAR */
+
+ // Process the Service Configurator directives in this test's
+ ACE_ASSERT (new_argv.add (argv) != -1
+ && new_argv.add (ACE_TEXT ("-f")) != -1
+ && new_argv.add (svc_conf) != -1);
+
+ // We need this scope to make sure that the destructor for the
+ // <ACE_Service_Config> gets called.
+ ACE_Service_Config daemon;
+
+ ACE_ASSERT (daemon.open (new_argv.argc (),
+ new_argv.argv ()) != -1 || errno == ENOENT);
+
+ ACE_Time_Value tv (argc > 1 ? ACE_OS::atoi (argv[1]) : 2);
+
+ ACE_ASSERT (ACE_Reactor::instance()->run_reactor_event_loop (tv) == 0);
+
+ // Wait for all threads to complete.
+ ACE_Thread_Manager::instance ()->wait ();
+}
+
+
+// @brief The size of a repository is pre-determined and can not be exceeded
+void
+testLimits (int , ACE_TCHAR *[])
+{
+ static const ACE_TCHAR *svc_desc1 =
+#if (ACE_USES_CLASSIC_SVC_CONF == 1)
+ ACE_TEXT ("dynamic Test_Object_1_More Service_Object * ")
+ ACE_TEXT (" Service_Config_DLL:_make_Service_Config_DLL() \"Test_Object_1_More\"")
+#else
+ ACE_TEXT ("<dynamic id=\"Test_Object_1_More\" type=\"Service_Object\">")
+ ACE_TEXT (" <initializer init=\"_make_Service_Config_DLL\" path=\"Service_Config_DLL\" params=\"Test_Object_1_More\"/>")
+ ACE_TEXT ("</dynamic>")
+#endif /* (ACE_USES_CLASSIC_SVC_CONF == 1) */
+ ;
+
+ static const ACE_TCHAR *svc_desc2 =
+#if (ACE_USES_CLASSIC_SVC_CONF == 1)
+ ACE_TEXT ("dynamic Test_Object_2_More Service_Object * ")
+ ACE_TEXT (" Service_Config_DLL:_make_Service_Config_DLL() \"Test_Object_2_More\"")
+#else
+ ACE_TEXT ("<dynamic id=\"Test_Object_2_More\" type=\"Service_Object\">")
+ ACE_TEXT (" <initializer init=\"_make_Service_Config_DLL\" path=\"Service_Config_DLL\" params=\"Test_Object_2_More\"/>")
+ ACE_TEXT ("</dynamic>")
+#endif /* (ACE_USES_CLASSIC_SVC_CONF == 1) */
+ ;
+
+
+ u_int error0 = error;
+
+ // Ensure enough room for one
+ ACE_Service_Gestalt one (1, true);
+
+ // Add two.
+ // We cant simply rely on the fact that insertion fails, because it
+ // is typical to have no easy way of getting detailed error
+ // information from a parser.
+ one.process_directive (svc_desc1);
+ one.process_directive (svc_desc2);
+
+ if (-1 == one.find (ACE_TEXT ("Test_Object_1_More"), 0, 0))
+ {
+ ++error;
+ ACE_ERROR ((LM_ERROR, ACE_TEXT("Expected to have registered the first service\n")));
+ }
+
+ if (-1 != one.find (ACE_TEXT ("Test_Object_2_More"), 0, 0))
+ {
+ ++error;
+ ACE_ERROR ((LM_ERROR, ACE_TEXT("Being able to add more than 1 service was not expected\n")));
+ }
+
+ if (error == error0)
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT("Limits test completed successfully\n")));
+ else
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT("Limits test failed\n")));
+}
+
+
+// @brief ??
+void
+testOrderlyInstantialtion (int , ACE_TCHAR *[])
+{
+ for (u_int i = 0; i < VARIETIES; ++i)
+ {
+ Test_Singleton *s = Test_Singleton::instance (i);
+
+ if (s == 0)
+ {
+ ++error;
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("instance () allocate failed!\n")));
+ }
+ }
+}
+
+int
+run_main (int argc, ACE_TCHAR *argv[])
+{
+ ACE_START_TEST (ACE_TEXT ("Service_Config_Test"));
+
+ testOrderlyInstantialtion (argc, argv);
+ testLoadingServiceConfFile (argc, argv);
+ testLimits (argc, argv);
+
+ ACE_END_TEST;
+ return error == 0 ? 0 : 1;
+}
diff --git a/ACE/tests/Signal_Test.cpp b/ACE/tests/Signal_Test.cpp
new file mode 100644
index 00000000000..49d05835568
--- /dev/null
+++ b/ACE/tests/Signal_Test.cpp
@@ -0,0 +1,499 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Signal_Test.cpp
+//
+// = DESCRIPTION
+// This program tests the signal handling capabilities of ACE on
+// various OS platforms that support sending signals between
+// processes.
+//
+// = AUTHOR
+// Douglas C. Schmidt <schmidt@cs.wustl.edu>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/Thread_Manager.h"
+#include "ace/Process.h"
+#include "ace/Signal.h"
+#include "ace/Get_Opt.h"
+#include "ace/ARGV.h"
+#include "ace/ACE.h"
+#include "ace/OS_NS_signal.h"
+#include "ace/OS_NS_stdio.h"
+#include "ace/OS_NS_unistd.h"
+
+ACE_RCSID(tests, Signal_Test, "$Id$")
+
+#if !defined (ACE_LACKS_UNIX_SIGNALS)
+
+// Global options.
+static size_t n_iterations = 100000;
+
+// Keeps track of whether we're the child or not.
+static int child = 0;
+
+// Keep track of the child pid.
+static pid_t child_pid = 0;
+
+// Keep track of the (original) parent pid.
+static pid_t parent_pid = 0;
+
+// Keep track of which test we're running.
+static int test_number = 0;
+
+// Coordinate the shutdown between threads.
+static sig_atomic_t shut_down = 0;
+
+static int
+handle_signal (int signum)
+{
+ // ACE_DEBUG / ACE_ERROR invocations have been #if'd out because
+ // they are "unsafe" when handler is invoked asynchronously. On
+ // NetBSD 3.X, calls to change the thread's signal mask block as
+ // a lock seems to be held by the signal trampoline code.
+
+#if 0
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) received signal %S\n"),
+ signum));
+#endif
+
+ switch (signum)
+ {
+ case SIGCHLD:
+ // Signal to the main thread to shut down.
+ shut_down = 1;
+
+ // This should only occur for the asynchronous case, so we don't
+ // need to return -1!
+ return 0;
+ case SIGINT:
+ /* FALLTHRU */
+ case SIGTERM:
+ // Shut down our thread using <ACE_Thread_Manager::exit>.
+#if 0
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) shutting down due to %S\n"),
+ signum));
+#endif
+
+ // Signal to the worker thread to shut down.
+ shut_down = 1;
+
+ // Bail out and close down.
+ return -1;
+ /* NOTREACHED */
+
+ case SIGHUP:
+ {
+ // Shutdown the child.
+
+#if 0
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) killing child pid %d \n"),
+ child_pid));
+#endif
+ int const result = ACE_OS::kill (child_pid,
+ SIGTERM);
+ ACE_ASSERT (result != -1);
+
+ return -1;
+ }
+ /* NOTREACHED */
+ case -1:
+#if 0
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n"),
+ "sigwait"));
+#endif
+ return -1;
+ /* NOTREACHED */
+ default:
+#if 0
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) signal %S unexpected\n"),
+ signum));
+#endif
+ return -1;
+ /* NOTREACHED */
+ }
+}
+
+// This function handles signals synchronously.
+
+static ACE_THR_FUNC_RETURN
+synchronous_signal_handler (void *)
+{
+ ACE_Sig_Set sigset;
+
+ // Register signal handlers.
+ if (child)
+ {
+ sigset.sig_add (SIGINT);
+ sigset.sig_add (SIGTERM);
+ }
+ else
+ sigset.sig_add (SIGHUP);
+
+ for (;;)
+ {
+ // Block waiting for SIGINT, SIGTERM, or SIGHUP, depending on
+ // whether we're the parent or child process.
+ if (handle_signal (ACE_OS::sigwait (sigset)) == -1)
+ break;
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) handled signal\n")));
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) synchronous signal handler done\n")));
+
+ return 0;
+}
+
+// This function arranges to handle signals asynchronously, which is
+// necessary if an OS platform lacks threads.
+
+static ACE_THR_FUNC_RETURN
+asynchronous_signal_handler (void *)
+{
+ ACE_Sig_Set sigset;
+
+ // Register signal handlers.
+ if (child)
+ {
+ sigset.sig_add (SIGINT);
+ sigset.sig_add (SIGTERM);
+ }
+ else
+ {
+ sigset.sig_add (SIGCHLD);
+ sigset.sig_add (SIGHUP);
+ }
+
+ // Register the <handle_signal> method to process all the signals in
+ // <sigset>.
+ ACE_Sig_Action sa (sigset,
+ (ACE_SignalHandler) handle_signal);
+ ACE_UNUSED_ARG (sa);
+
+ return 0;
+}
+
+// Function that runs in the child process in its own worker thread.
+
+static ACE_THR_FUNC_RETURN
+worker_child (void *arg)
+{
+ long handle_signals_synchronously =
+ reinterpret_cast <long> (arg);
+
+ for (size_t i = 0; i < n_iterations; i++)
+ {
+ if (shut_down > 0)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) we've been shutdown!\n")));
+ break;
+ }
+
+ // Every 100 iterations sleep for 2 seconds.
+ if ((i % 100) == 0)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) sleeping for 2 seconds\n")));
+ ACE_OS::sleep (2);
+ }
+
+ // After 1000 iterations sent a SIGHUP to our parent.
+ if ((i % 1000) == 0)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) sending SIGHUP to parent process %d\n"),
+ parent_pid));
+ int const result = ACE_OS::kill (parent_pid,
+ SIGHUP);
+ if (result == -1)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n"),
+ ACE_TEXT ("kill")));
+ ACE_ASSERT (result != -1);
+ }
+ }
+ }
+
+ if (handle_signals_synchronously)
+ {
+ if (!shut_down)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) sending SIGINT to ourselves\n")));
+ // We need to do this to dislodge the signal handling thread if
+ // it hasn't shut down on its own accord yet.
+ int const result = ACE_OS::kill (ACE_OS::getpid (), SIGINT);
+ ACE_ASSERT (result != -1);
+ }
+ }
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) finished running child\n")));
+ return 0;
+}
+
+// This function runs the parent process in a separate worker thread.
+static ACE_THR_FUNC_RETURN
+worker_parent (void *arg)
+{
+ long handle_signals_synchronously =
+ reinterpret_cast <long> (arg);
+ ACE_Process_Options options;
+
+ ACE_TCHAR *l_argv[3];
+ ACE_TCHAR pid_str[100];
+ // Store the parent's process id so we can pass it to the child
+ // portably. Also, pass the test number, as well.
+ ACE_OS::sprintf (pid_str,
+ ACE_TEXT ("-p %ld -t %d"),
+ static_cast <long> (parent_pid),
+ test_number);
+
+ // We're going to create a new process that runs this program again,
+ // so we need to indicate that it's the child.
+ const ACE_TCHAR *t = ACE_TEXT (".")
+ ACE_DIRECTORY_SEPARATOR_STR
+ ACE_TEXT ("Signal_Test")
+ ACE_PLATFORM_EXE_SUFFIX
+ ACE_TEXT (" -c");
+ l_argv[0] = const_cast <ACE_TCHAR *> (t);
+ l_argv[1] = pid_str;
+ l_argv[2] = 0;
+
+ ACE_ARGV argv (l_argv);
+
+ // Generate a command-line!
+ options.command_line (argv.buf ());
+ ACE_Process pm;
+
+ child_pid = pm.spawn (options);
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) spawning child process %d\n"),
+ child_pid));
+
+ ACE_ASSERT (child_pid != -1);
+
+ // Perform a <wait> until our child process has exited.
+
+ if (handle_signals_synchronously)
+ {
+ int status;
+ // Wait for the child process to exit.
+ pm.wait (&status);
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) reaped child with status %d\n"),
+ status));
+ }
+ else
+ while (shut_down == 0)
+ {
+ // Wait for a signal to arrive.
+ if (ACE_OS::sigsuspend (0) == -1 && errno != EINTR)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n"),
+ ACE_TEXT ("sigsuspend")));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) got signal!\n")));
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) parent worker done\n")));
+ return 0;
+}
+
+// This is the driver function that spawns threads to run the test for
+// the parent and the child process.
+
+static void
+run_test (ACE_THR_FUNC worker,
+ long handle_signals_in_separate_thread,
+ long handle_signals_synchronously)
+{
+#if defined (ACE_HAS_THREADS)
+ if (handle_signals_synchronously)
+ {
+ // For the synchronous signal tests, block signals to prevent
+ // asynchronous delivery to default handler (at least necessary
+ // on linux and solaris; POSIX spec also states that signal(s)
+ // should be blocked before call to sigwait())
+ ACE_Sig_Guard guard;
+
+ int result;
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) spawning worker thread\n")));
+ result = ACE_Thread_Manager::instance ()->spawn
+ (worker,
+ reinterpret_cast <void *> (handle_signals_synchronously),
+ THR_DETACHED);
+ ACE_ASSERT (result != -1);
+
+ if (handle_signals_in_separate_thread)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) spawning signal handler thread\n")));
+
+ result = ACE_Thread_Manager::instance ()->spawn
+ (synchronous_signal_handler,
+ 0,
+ THR_DETACHED);
+ ACE_ASSERT (result != -1);
+ }
+ else
+ {
+ synchronous_signal_handler (0);
+ }
+
+ // Wait for the thread(s) to finish.
+ result = ACE_Thread_Manager::instance ()->wait ();
+ ACE_ASSERT (result != -1);
+ }
+ else
+#else
+ // Don't remove this since otherwise some compilers give warnings
+ // when ACE_HAS_THREADS is disabled!
+ ACE_UNUSED_ARG (synchronous_signal_handler);
+#endif /* ACE_HAS_THREADS */
+ {
+ ACE_UNUSED_ARG (handle_signals_in_separate_thread);
+ // Arrange to handle signals asynchronously.
+ asynchronous_signal_handler (0);
+ (*worker) (reinterpret_cast <void *> (handle_signals_synchronously));
+ }
+}
+
+// Parse the command-line arguments and set options.
+
+static void
+parse_args (int argc, ACE_TCHAR *argv[])
+{
+ ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("i:chp:t:"));
+
+ int c;
+
+ while ((c = get_opt ()) != -1)
+ switch (c)
+ {
+ case 'i':
+ n_iterations = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'c':
+ child = 1;
+ break;
+ case 'p':
+ parent_pid = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 't':
+ test_number = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'h':
+ default:
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) usage:\n")
+ ACE_TEXT ("-i <iterations>\n")
+ ACE_TEXT ("-c\n")
+ ACE_TEXT ("-p <parent_pid>\n")
+ ACE_TEXT ("-t <test_number>\n")));
+ break;
+ }
+}
+
+int
+run_main (int argc, ACE_TCHAR *argv[])
+{
+ ACE_OS::signal(SIGHUP, SIG_DFL);
+
+ if (argc > 1)
+ {
+ ACE_APPEND_LOG (ACE_TEXT ("Signal_Test-child"));
+ parse_args (argc, argv);
+
+ if (test_number == 1)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) **** test 1: handle signals synchronously in separate thread\n")));
+
+ // First, handle signals synchronously in separate thread.
+ run_test (worker_child, 1, 1);
+ }
+ else if (test_number == 2)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) **** test 2: handle signals synchronously in this thread\n")));
+
+ // Next, handle signals synchronously in this thread.
+ run_test (worker_child, 0, 1);
+ }
+ else if (test_number == 3)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) **** test 3: handle signals asynchronously in this thread\n")));
+
+ // Finally, handle signals asynchronously in this thread.
+ run_test (worker_child, 0, 0);
+ }
+
+ ACE_END_LOG;
+ }
+ else
+ {
+ ACE_START_TEST (ACE_TEXT ("Signal_Test"));
+ ACE_INIT_LOG (ACE_TEXT ("Signal_Test-child"));
+
+ // We need to get the process id here to work around "features"
+ // of Linux threads...
+ parent_pid = ACE_OS::getpid ();
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) **** test 1: handle signals synchronously in a separate thread\n")));
+
+ ++test_number;
+ // Run the parent logic for the signal test, first by handling
+ // signals synchronously in a separate thread.
+ run_test (worker_parent, 1L, 1L);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) **** test 2: handle signals synchronously in this thread\n")));
+
+ ++test_number;
+ // And next by handling synchronously signals in this thread.
+ run_test (worker_parent, 0L, 1L);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) **** test 3: handle signals asynchronously in this thread\n")));
+
+ ++test_number;
+ // And finally by handling asynchronously signals in this thread.
+ run_test (worker_parent, 0L, 0L);
+
+ ACE_END_TEST;
+ }
+ return 0;
+}
+
+#else
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("Signal_Test"));
+ ACE_ERROR ((LM_INFO,
+ ACE_TEXT ("The Unix Signals capability is not supported on this platform\n")));
+ ACE_END_TEST;
+ return 0;
+}
+#endif /* !defined (ACE_LACKS_UNIX_SIGNALS) */
diff --git a/ACE/tests/Sigset_Ops_Test.cpp b/ACE/tests/Sigset_Ops_Test.cpp
new file mode 100644
index 00000000000..076e64ce2d3
--- /dev/null
+++ b/ACE/tests/Sigset_Ops_Test.cpp
@@ -0,0 +1,148 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Sigset_Ops_Test.cpp
+//
+// = DESCRIPTION
+// This program tests the correctness of following functions.
+// sigfillset(), sigemptyset(), sigaddset(), sigdelset(),
+// sigismember().
+//
+// = AUTHOR
+// Nanbor Wang <nanbor@cs.wustl.edu>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/OS_NS_signal.h"
+#include "ace/OS_NS_errno.h"
+
+ACE_RCSID(tests, Sigset_Ops_Test, "$Id$")
+
+void
+siglistset (sigset_t x, int *sigset, int can_miss = 0)
+{
+ int empty = 1 ;
+ int result = 0 ;
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Signal (s) in the set = %08x:\n"), x)) ;
+
+ for (int i = 1; i < ACE_NSIG; i++)
+ {
+ result = ACE_OS::sigismember (&x, i);
+
+ if (result > 0)
+ {
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT (" %d\n"), i)) ;
+ empty = 0 ;
+ }
+ else if (can_miss)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Be careful... Signal %d is not valid\n"),
+ i));
+ result = 1;
+ }
+ ACE_ASSERT ((sigset [i] ? result > 0 : result <= 0)) ;
+ }
+
+ if (empty)
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Empty!!\n\n"))) ;
+ else
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\n\n"))) ;
+}
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("Sigset_Ops_Test"));
+
+#if defined (ACE_LACKS_SIGSET)
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("%n uses ACE implementation of sigset* () functions.\n\n"))) ;
+#else
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("%n uses platform's native sigset* () functions.\n\n"))) ;
+#endif
+
+ sigset_t x ; // examined sigset
+ int sigset [ACE_NSIG] ; // a comparison sigset
+ int i ;
+ int status = 0; // 0 is success, else fail code
+
+ // Two test signal numbers. I choose these low value signals to
+ // avoid exceeding the ACE_NSIG range.
+ const int tsig1 = 5 ;
+ const int tsig2 = 8 ;
+
+ // Testing sigfillset
+ ACE_OS::sigfillset (&x) ;
+
+ // fill the comparison set
+ for (i = 0 ; i < ACE_NSIG ; i++)
+ sigset [i] = 1 ;
+
+ // There's no guarantee that the valid signals are sequential without
+ // missed spots. For example, Red Hat Enterprise Linux 3 (any version
+ // with NPTL) does not include signal 32 in sigfillset() since it's
+ // reserved for kernel/nptl use. So, allow a miss in this check, but
+ // be prepared to check the log file for misses if signal capability seems
+ // odd if the test passes.
+ siglistset (x, sigset, 1) ;
+
+ // testing sigemptyset
+ ACE_OS::sigemptyset (&x) ;
+
+ // empty the comparison set
+ for (i = 0 ; i < ACE_NSIG ; i++)
+ sigset [i] = 0 ;
+
+ siglistset (x, sigset) ;
+
+ // add the first signal into set
+ ACE_OS::sigaddset (&x, tsig1) ;
+ sigset [tsig1] = 1 ;
+ siglistset (x, sigset) ;
+
+ // add the second signal into set
+ ACE_OS::sigaddset (&x, tsig2) ;
+ sigset [tsig2] = 1 ;
+ siglistset (x, sigset) ;
+
+ // then remove it
+ ACE_OS::sigdelset (&x, tsig1) ;
+ sigset [tsig1] = 0 ;
+ siglistset (x, sigset) ;
+
+ // remove the second one
+ ACE_OS::sigdelset (&x, tsig2) ;
+ sigset [tsig2] = 0 ;
+ siglistset (x, sigset) ;
+
+ // Now testing out of bound signal
+ if (ACE_OS::sigismember (&x, ACE_NSIG) >= 0)
+ {
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("Platform doesn't check for valid signal number.\n")));
+ status = 1;
+ }
+ else if (ACE_OS::last_error () != EINVAL)
+ {
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p.\n"), ACE_TEXT ("Expected status EINVAL; got")));
+ status = 1;
+ }
+
+ /* Skip this test at this moment
+ // Test if platform can catch invalid sigset error Currently, I can
+ // only think of passing a NULL ptr If you know other situations
+ // that fall into this catagory, please let me know. Thanks.
+ ACE_DEBUG ((LM_ERROR, ACE_TEXT ("Now testing invalid sigset. If your platform gets a \nsegmentation fault, then it doesn't check the error properly.\n"))) ;
+
+ ACE_ASSERT (ACE_OS::sigfillset (NULL) < 0 && ACE_OS::last_error () == EFAULT) ;
+ */
+
+ ACE_END_TEST;
+ return status;
+}
diff --git a/ACE/tests/Simple_Message_Block_Test.cpp b/ACE/tests/Simple_Message_Block_Test.cpp
new file mode 100644
index 00000000000..6a7eb841240
--- /dev/null
+++ b/ACE/tests/Simple_Message_Block_Test.cpp
@@ -0,0 +1,215 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Simple_Message_Block_Test.cpp
+//
+// = DESCRIPTION
+// This test program is a torture test that illustrates how
+// ACE_Message_Block reference counting works, how and when locks
+// are used, how memory is managed, and how continuation chains
+// of message blocks are made. Ideally used with purify :-)
+//
+// = AUTHOR
+// Irfan Pyarali <irfan@cs.wustl.edu>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/Message_Block.h"
+#include "ace/Synch_Traits.h"
+#include "ace/Lock_Adapter_T.h"
+#include "ace/OS_NS_string.h"
+#include "ace/Thread_Mutex.h"
+
+ACE_RCSID(tests, Simple_Message_Block_Test, "$Id$")
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("Simple_Message_Block_Test"));
+
+ {
+ // Checks normal stack deletes.
+ ACE_Message_Block mb;
+ }
+
+ {
+ // Checks normal heap deletes.
+ ACE_Message_Block *mb;
+
+ ACE_NEW_RETURN (mb, ACE_Message_Block, -1);
+ mb->release ();
+ }
+
+ {
+ // Checks continuation of message blocks on the stack.
+ ACE_Message_Block mb1 (1024);
+ ACE_Message_Block mb2 (1024);
+
+ mb1.cont (&mb2);
+ }
+
+ {
+ // Checks continuation of message blocks on the heap.
+ ACE_Message_Block *mb1;
+ ACE_Message_Block *mb2;
+
+ ACE_NEW_RETURN (mb1, ACE_Message_Block (1024), -1);
+ ACE_NEW_RETURN (mb2, ACE_Message_Block (1024), -1);
+
+ mb1->cont (mb2);
+ mb1->release ();
+ }
+
+ // Same set of tests but with locking_strategy set.
+ {
+ ACE_Lock_Adapter <ACE_SYNCH_MUTEX> mutex;
+ ACE_Lock *lock = &mutex;
+
+ {
+ // Checks normal stack deletes.
+ ACE_Message_Block mb;
+ mb.locking_strategy (lock);
+ }
+
+ {
+ // Checks normal heap deletes.
+ ACE_Message_Block *mb;
+ ACE_NEW_RETURN (mb, ACE_Message_Block, -1);
+ mb->locking_strategy (lock);
+ mb->release ();
+ }
+
+ {
+ // Checks continuation of message blocks on the stack with one
+ // lock strategy.
+ ACE_Message_Block mb1 (1024);
+ ACE_Message_Block mb2 (1024);
+
+ mb1.locking_strategy (lock);
+
+ mb1.cont (&mb2);
+ }
+
+ {
+ // Checks continuation of message blocks on the heap with one
+ // lock strategy.
+ ACE_Message_Block *mb1;
+ ACE_Message_Block *mb2;
+
+ ACE_NEW_RETURN (mb1, ACE_Message_Block (1024), -1);
+ ACE_NEW_RETURN (mb2, ACE_Message_Block (1024), -1);
+
+ mb1->locking_strategy (lock);
+
+ mb1->cont (mb2);
+ mb1->release ();
+ }
+
+ {
+ // Checks continuation of message blocks on the stack with two
+ // lock strategy.
+ ACE_Message_Block mb1 (1024);
+ ACE_Message_Block mb2 (1024);
+
+ mb1.locking_strategy (lock);
+ mb2.locking_strategy (lock);
+
+ mb1.cont (&mb2);
+ }
+
+ {
+ // Checks continuation of message blocks on the heap with two
+ // lock strategy
+ ACE_Message_Block *mb1;
+ ACE_Message_Block *mb2;
+
+ ACE_NEW_RETURN (mb1, ACE_Message_Block (1024), -1);
+ ACE_NEW_RETURN (mb2, ACE_Message_Block (1024), -1);
+
+ mb1->locking_strategy (lock);
+ mb2->locking_strategy (lock);
+
+ mb1->cont (mb2);
+ mb1->release ();
+ }
+
+ {
+ // Checks continuation of message blocks on the heap with two
+ // lock strategy where the second one is a duplicate of the
+ // first
+ ACE_Message_Block *mb1;
+ ACE_NEW_RETURN (mb1, ACE_Message_Block (1024), -1);
+ mb1->locking_strategy (lock);
+
+ ACE_Message_Block *mb2 = mb1->duplicate ();
+
+ mb1->cont (mb2);
+ mb1->release ();
+ }
+ }
+
+ {
+ // Checks continuation of message blocks on the heap with two
+ // different lock strategies
+
+ ACE_Lock_Adapter <ACE_SYNCH_MUTEX> lock1;
+ ACE_Lock_Adapter <ACE_SYNCH_MUTEX> lock2;
+
+ ACE_Message_Block *mb1;
+ ACE_Message_Block *mb2;
+
+ ACE_NEW_RETURN (mb1, ACE_Message_Block (1024), -1);
+ ACE_NEW_RETURN (mb2, ACE_Message_Block (1024), -1);
+
+ mb1->locking_strategy (&lock1);
+ mb2->locking_strategy (&lock2);
+
+ mb1->cont (mb2);
+ mb1->release ();
+ }
+
+ {
+ // Checks failure of copy when "virtual" allocation (using mark)
+ // is too small
+ char message[]="abcdefghijklmnop";
+ ACE_Message_Block mb1 (ACE_OS::strlen (message) + 1);
+ ACE_Message_Block mb2 (ACE_OS::strlen (message) + 1);
+
+ // Resize mb2 so that we mark for use less than the allocated buffer
+ if (mb2.size (ACE_OS::strlen (message) + 1 - 10) == -1)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Resize test failed ..\n")));
+ }
+
+ // We expect this to succeed
+ if (mb1.copy (message, ACE_OS::strlen (message) + 1) == -1)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Copy test failed ..\n")));
+ }
+
+ // We expect this to fail
+ if (mb2.copy (message, ACE_OS::strlen (message) + 1) != -1)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Copy test succeeded when it should have failed ..\n")));
+ }
+
+ // We also expect this to fail
+ if (mb2.copy (message) != -1)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) Copy test succeeded when it should have failed ..\n")));
+ }
+ }
+ ACE_END_TEST;
+ return 0;
+}
+
diff --git a/ACE/tests/Svc_Handler_Test.cpp b/ACE/tests/Svc_Handler_Test.cpp
new file mode 100644
index 00000000000..c36d8483e08
--- /dev/null
+++ b/ACE/tests/Svc_Handler_Test.cpp
@@ -0,0 +1,157 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Svc_Handler_Test.cpp
+//
+// = DESCRIPTION
+// This tests illustrates the "buffering" strategy of the
+// <ACE_Buffered_Svc_Handler>. This test also illustrates how the
+// <ACE_FILE_IO> classes work.
+//
+// = AUTHORS
+// Douglas C. Schmidt <schmidt@cs.wustl.edu>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/OS_NS_string.h"
+#include "ace/FILE_Connector.h"
+#include "ace/Null_Condition.h"
+#include "ace/Null_Mutex.h"
+#include "ace/Svc_Handler.h"
+#include "ace/Synch_Traits.h"
+
+ACE_RCSID(tests, Svc_Handler_Test, "$Id$")
+
+typedef ACE_Buffered_Svc_Handler <ACE_FILE_STREAM, ACE_NULL_SYNCH> SVC_HANDLER;
+
+static void
+run_test (SVC_HANDLER &svc_handler,
+ size_t iterations)
+{
+ // Create a whole slew of message blocks and pass them to the
+ // <svc_handler>.
+ for (size_t i = 0; i < iterations; i++)
+ {
+ ACE_Message_Block *mb;
+ ACE_NEW (mb,
+ ACE_Message_Block (sizeof (ACE_LIB_TEXT("hello "))));
+
+ ACE_Message_Block *cb1;
+ ACE_NEW (cb1,
+ ACE_Message_Block (sizeof (ACE_LIB_TEXT("there\n"))));
+
+ ACE_Message_Block *cb2;
+ ACE_NEW (cb2,
+ ACE_Message_Block (sizeof (ACE_LIB_TEXT("there\n"))));
+
+ mb->copy ("hello ",
+ ACE_OS::strlen (ACE_LIB_TEXT("hello ")));
+ cb1->copy ("there ",
+ ACE_OS::strlen (ACE_LIB_TEXT("there ")));
+ mb->cont (cb1);
+ cb2->copy ("doug\n",
+ ACE_OS::strlen (ACE_LIB_TEXT("doug\n")));
+ cb1->cont (cb2);
+
+ // Note that this is a buffered call!
+ if (svc_handler.put (mb) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("put")));
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("final flush\n")));
+
+ // Make sure to flush everything out before we exit.
+ if (svc_handler.flush () == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("flush")));
+}
+
+int
+run_main (int argc, ACE_TCHAR *argv[])
+{
+ ACE_START_TEST (ACE_TEXT ("Svc_Handler_Test"));
+ {
+ size_t max_buffer_size = BUFSIZ;
+ size_t iterations = 10;
+
+ if (argc > 1)
+ max_buffer_size = ACE_OS::atoi (argv[1]);
+ if (argc > 2)
+ iterations = ACE_OS::atoi (argv[2]);
+
+ ACE_FILE_Connector connector;
+ ACE_FILE_IO file_io;
+ // Create a temporary filename.
+ ACE_FILE_Addr file (ACE_sap_any_cast (ACE_FILE_Addr &));
+
+ // Open up the temp file.
+ if (connector.connect (file_io, file) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("connect failed for %p\n"),
+ file.get_path_name ()),
+ 1);
+
+#if (!defined (ACE_WIN32) \
+ || (defined (ACE_HAS_WINNT4) && ACE_HAS_WINNT4 == 1)) && \
+ !defined (VXWORKS)
+# define TEST_CAN_UNLINK_IN_ADVANCE
+#endif
+
+ // Create the service handler and assign it <file_io> as its data
+ // sink.
+ SVC_HANDLER svc_handler (0,
+ 0,
+ 0,
+ max_buffer_size,
+ 0);
+ svc_handler.peer () = file_io;
+
+ // Run the test.
+ run_test (svc_handler, iterations);
+
+ file_io.close ();
+
+ // Open up the temp file.
+ if (connector.connect (file_io, file) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("connect failed for %p\n"),
+ file.get_path_name ()),
+ 1);
+ char buf[ACE_MAXLOGMSGLEN + 1];
+ ACE_LOG_MSG->clr_flags (ACE_Log_Msg::VERBOSE_LITE);
+
+ ACE_FILE_Info info;
+ file_io.get_info (info);
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT("file size = %d\n"), info.size_));
+
+ for (ssize_t n_bytes; (n_bytes = file_io.recv (buf, ACE_MAXLOGMSGLEN)) > 0; )
+ {
+ buf[n_bytes] = '\0';
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT("%s"), ACE_TEXT_CHAR_TO_TCHAR(buf)));
+ }
+
+ ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT("\n")));
+
+ file_io.close ();
+
+ if (file_io.unlink () == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("unlink failed for %p\n"),
+ file.get_path_name ()),
+ 1);
+ }
+
+ ACE_END_TEST;
+ return 0;
+}
+
diff --git a/ACE/tests/TP_Reactor_Test.cpp b/ACE/tests/TP_Reactor_Test.cpp
new file mode 100644
index 00000000000..91d2b43812f
--- /dev/null
+++ b/ACE/tests/TP_Reactor_Test.cpp
@@ -0,0 +1,1241 @@
+// $Id$
+
+//============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// TPReactor_test.cpp
+//
+// = DESCRIPTION
+// This program illustrates how the <ACE_TP_Reactor> can be used to
+// implement an application that does various operations.
+// usage: TP_Reactor_Test
+// -n number threads in the TP_Reactor thread pool
+// -d duplex mode 1 (full-duplex) vs. 0 (half-duplex)
+// -p port to listen(Server)/connect(Client)
+// -h host to connect (Client mode)
+// -s number of sender's instances ( Client mode)
+// -b run client and server (both modes ) at the same time
+// -v log level
+// 0 - log all messages
+// 1 - log only errors and unusual cases
+// -i time to run in seconds
+// -u show this message
+//
+// The main differences between Thread_Pool_Reactor_Test.cpp and
+// this test are:
+//
+// 1. Thread_Pool_Reactor_Test.cpp tests only handle_input()
+// events on the server, whereas this one tests both handle_input() and
+// handle_output() on both server and client, i.e., the receiver
+// and sender are completely event-driven.
+//
+// 2. The receiver and sender in this test can work in full duplex
+// mode, i.e., input and ouput events are processed independently.
+// Half-duplex mode (request-reply) is also supported.
+//
+// This test is therefore a bit more stressful than the
+// Thread_Pool_Reactor.cpp for the ACE_TP_Reactor since same
+// thread pool is shared between client and server.
+//
+// This test is a "twin" of the Proactor_Test.cpp, so it can help for
+// developers to provide independent of Reactor/Proactor solutions.
+//
+// = AUTHOR
+// Alexander Libman <alibman@ihug.com.au>,<alexl@rumblgroup.com>
+//
+//============================================================================
+
+#include "test_config.h"
+
+#if defined(ACE_HAS_THREADS)
+
+#include "TP_Reactor_Test.h"
+
+#include "ace/Signal.h"
+#include "ace/Service_Config.h"
+#include "ace/Get_Opt.h"
+
+#include "ace/Reactor.h"
+#include "ace/TP_Reactor.h"
+#include "ace/OS_NS_signal.h"
+#include "ace/OS_NS_stdio.h"
+#include "ace/OS_NS_string.h"
+#include "ace/OS_NS_unistd.h"
+#include "ace/Synch_Traits.h"
+#include "ace/Thread_Semaphore.h"
+
+ACE_RCSID(TPReactor, TPReactor_Test, "TPReactor_Test.cpp,v 1.27 2000/03/07 17:15:56 schmidt Exp")
+
+// Some debug helper functions
+static int disable_signal (int sigmin, int sigmax);
+
+// both: 0 run client or server / depends on host
+// != 0 run client and server
+static int both = 0;
+
+// Host that we're connecting to.
+static const ACE_TCHAR *host = 0;
+
+// number of Senders instances
+static int senders = 1;
+
+// duplex mode: == 0 half-duplex
+// != 0 full duplex
+static int duplex = 0;
+
+// number threads in the TP_Reactor thread pool
+static int threads = 1;
+
+// Port that we're receiving connections on.
+static u_short port = ACE_DEFAULT_SERVER_PORT;
+
+// Log options
+static int loglevel = 1; // 0 full , 1 only errors
+
+static const size_t MIN_TIME = 1; // min 1 sec
+static const size_t MAX_TIME = 3600; // max 1 hour
+static u_int seconds = 2; // default time to run - 2 seconds
+
+static char data[] =
+ "GET / HTTP/1.1\r\n"
+ "Accept: */*\r\n"
+ "Accept-Language: C++\r\n"
+ "Accept-Encoding: gzip, deflate\r\n"
+ "User-Agent: TPReactor_Test/1.0 (non-compatible)\r\n"
+ "Connection: Keep-Alive\r\n"
+ "\r\n" ;
+
+// *************************************************************
+
+class LogLocker
+{
+public:
+
+ LogLocker () { ACE_LOG_MSG->acquire (); }
+ virtual ~LogLocker () { ACE_LOG_MSG->release (); }
+};
+// *************************************************************
+
+/**
+ * @class MyTask
+ *
+ * MyTask plays role for TP_Reactor threads pool
+ *
+ * MyTask is ACE_Task resposible for:
+ * 1. Creation and deletion of TP_Reactor and TP_Reactor thread pool
+ * 2. Running TP_Reactor event loop
+ */
+class MyTask : public ACE_Task<ACE_MT_SYNCH>
+{
+public:
+ MyTask (void): sem_ ((unsigned int) 0),
+ my_reactor_ (0) {}
+
+ virtual ~MyTask () { stop (); }
+
+ virtual int svc (void);
+
+ int start (int num_threads);
+ int stop (void);
+
+private:
+ int create_reactor (void);
+ int delete_reactor (void);
+
+ ACE_SYNCH_RECURSIVE_MUTEX lock_;
+ ACE_Thread_Semaphore sem_;
+ ACE_Reactor *my_reactor_;
+};
+
+int
+MyTask::create_reactor (void)
+{
+ ACE_GUARD_RETURN (ACE_SYNCH_RECURSIVE_MUTEX,
+ monitor,
+ this->lock_,
+ -1);
+
+ ACE_ASSERT (this->my_reactor_ == 0);
+
+ ACE_TP_Reactor * pImpl = 0;
+
+ ACE_NEW_RETURN (pImpl,ACE_TP_Reactor, -1);
+
+ ACE_NEW_RETURN (my_reactor_,
+ ACE_Reactor (pImpl ,1),
+ -1);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT (" (%t) Create TP_Reactor\n")));
+
+ ACE_Reactor::instance (this->my_reactor_);
+
+ this->reactor (my_reactor_);
+
+ return 0;
+}
+
+int
+MyTask::delete_reactor (void)
+{
+ ACE_GUARD_RETURN (ACE_SYNCH_RECURSIVE_MUTEX,
+ monitor,
+ this->lock_,
+ -1);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT (" (%t) Delete TP_Reactor\n")));
+
+ delete this->my_reactor_;
+ ACE_Reactor::instance ((ACE_Reactor *) 0);
+ this->my_reactor_ = 0;
+ this->reactor (0);
+
+ return 0;
+}
+
+int
+MyTask::start (int num_threads)
+{
+ if (this->create_reactor () == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p.\n"),
+ ACE_TEXT ("unable to create reactor")),
+ -1);
+
+ if (this->activate (THR_NEW_LWP, num_threads) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p.\n"),
+ ACE_TEXT ("unable to activate thread pool")),
+ -1);
+
+ for (; num_threads > 0 ; num_threads--)
+ sem_.acquire ();
+
+ return 0;
+}
+
+
+int
+MyTask::stop (void)
+{
+ if (this->my_reactor_ != 0)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("End TP_Reactor event loop\n")));
+
+ ACE_Reactor::instance()->end_reactor_event_loop ();
+ }
+
+ if (this->wait () == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("%p.\n"),
+ ACE_TEXT ("unable to stop thread pool")));
+
+ if (this->delete_reactor () == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("%p.\n"),
+ ACE_TEXT ("unable to delete reactor")));
+
+ return 0;
+}
+
+int
+MyTask::svc (void)
+{
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT (" (%t) MyTask started\n")));
+
+ // signal that we are ready
+ sem_.release (1);
+
+ while (ACE_Reactor::instance()->reactor_event_loop_done () == 0)
+ ACE_Reactor::instance()->run_reactor_event_loop ();
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT (" (%t) MyTask finished\n")));
+ return 0;
+}
+
+// *************************************************************
+
+Acceptor::Acceptor (void)
+ : ACE_Acceptor<Receiver,ACE_SOCK_ACCEPTOR> ((ACE_Reactor *) 0),
+ sessions_ (0),
+ total_snd_(0),
+ total_rcv_(0),
+ total_w_ (0),
+ total_r_ (0)
+{
+ ACE_Guard<ACE_Recursive_Thread_Mutex> locker (this->mutex_);
+
+ for (size_t i = 0; i < MAX_RECEIVERS; ++i)
+ this->list_receivers_[i] =0;
+}
+
+Acceptor::~Acceptor (void)
+{
+ this->reactor (0);
+ stop ();
+}
+
+void
+Acceptor::stop (void)
+{
+ // this method can be called only after reactor event loop id done
+ // in all threads
+
+ ACE_Guard<ACE_Recursive_Thread_Mutex> locker (this->mutex_);
+
+ for (size_t i = 0; i < MAX_RECEIVERS; ++i)
+ {
+ delete this->list_receivers_[i];
+ this->list_receivers_[i] =0;
+ }
+}
+
+void
+Acceptor::on_new_receiver (Receiver &rcvr)
+{
+ ACE_Guard<ACE_Recursive_Thread_Mutex> locker (this->mutex_);
+ this->sessions_++;
+ this->list_receivers_[rcvr.index_] = & rcvr;
+ ACE_DEBUG ((LM_DEBUG,
+ "Receiver::CTOR sessions_=%d\n",
+ this->sessions_));
+}
+
+void
+Acceptor::on_delete_receiver (Receiver &rcvr)
+{
+ ACE_Guard<ACE_Recursive_Thread_Mutex> locker (this->mutex_);
+
+ this->sessions_--;
+
+ this->total_snd_ += rcvr.get_total_snd ();
+ this->total_rcv_ += rcvr.get_total_rcv ();
+ this->total_w_ += rcvr.get_total_w ();
+ this->total_r_ += rcvr.get_total_r ();
+
+ if (rcvr.index_ < MAX_RECEIVERS
+ && this->list_receivers_[rcvr.index_] == &rcvr)
+ this->list_receivers_[rcvr.index_] = 0;
+
+ ACE_TCHAR bufs [256];
+ ACE_TCHAR bufr [256];
+
+ ACE_OS::sprintf ( bufs , ACE_TEXT ("%ld(%ld)"),
+ rcvr.get_total_snd (),
+ rcvr.get_total_w () );
+
+ ACE_OS::sprintf ( bufr , ACE_TEXT ("%ld(%ld)"),
+ rcvr.get_total_rcv (),
+ rcvr.get_total_r ());
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Receiver::~DTOR index=%d snd=%s rcv=%s sessions_=%d\n"),
+ rcvr.index_,
+ bufs,
+ bufr,
+ this->sessions_));
+}
+
+int
+Acceptor::start (const ACE_INET_Addr &addr)
+{
+ if (ACE_Acceptor<Receiver,ACE_SOCK_ACCEPTOR>
+ ::open (addr,
+ ACE_Reactor::instance (),
+ ACE_NONBLOCK) < 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "%p\n",
+ "Acceptor::start () - open failed"),
+ 0);
+ return 1;
+}
+
+int
+Acceptor::make_svc_handler (Receiver *&sh)
+{
+ ACE_Guard<ACE_Recursive_Thread_Mutex> locker (this->mutex_);
+
+ if (sessions_ >= MAX_RECEIVERS)
+ return -1;
+
+ for (size_t i = 0; i < MAX_RECEIVERS; ++i)
+ if (this->list_receivers_ [i] == 0)
+ {
+ ACE_NEW_RETURN (sh,
+ Receiver (this , i),
+ -1);
+ return 0;
+ }
+ return -1;
+}
+
+// *************************************************************
+
+Receiver::Receiver (Acceptor * acceptor, size_t index)
+ : acceptor_ (acceptor),
+ index_ (index),
+ flg_mask_ (ACE_Event_Handler::NULL_MASK),
+ total_snd_(0),
+ total_rcv_(0),
+ total_w_ (0),
+ total_r_ (0)
+{
+ if (acceptor_ != 0)
+ acceptor_->on_new_receiver (*this);
+}
+
+
+Receiver::~Receiver (void)
+{
+ this->reactor (0);
+ if (acceptor_ != 0)
+ acceptor_->on_delete_receiver (*this);
+
+ this->index_ = 0;
+
+ for (; ;)
+ {
+ ACE_Time_Value tv = ACE_Time_Value::zero;
+ ACE_Message_Block *mb = 0;
+
+ if (this->getq (mb, &tv) < 0)
+ break;
+
+ ACE_Message_Block::release (mb);
+ }
+}
+
+int
+Receiver::check_destroy (void)
+{
+ if (flg_mask_ == ACE_Event_Handler::NULL_MASK)
+ return -1;
+
+ return 0;
+}
+
+int
+Receiver::open (void *)
+{
+ ACE_Guard<ACE_Recursive_Thread_Mutex> locker (mutex_);
+
+ ACE_Reactor *TPReactor = ACE_Reactor::instance ();
+
+ this->reactor (TPReactor);
+
+ flg_mask_ = ACE_Event_Handler::NULL_MASK ;
+
+ if (TPReactor->register_handler (this, flg_mask_) == -1)
+ return -1;
+
+ initiate_io (ACE_Event_Handler::READ_MASK);
+
+ return check_destroy ();
+}
+
+int
+Receiver::initiate_io (ACE_Reactor_Mask mask)
+{
+ if (ACE_BIT_ENABLED (flg_mask_, mask))
+ return 0;
+
+ if (ACE_Reactor::instance ()->schedule_wakeup (this, mask) == -1)
+ return -1;
+
+ ACE_SET_BITS (flg_mask_, mask);
+ return 0;
+}
+
+int
+Receiver::terminate_io (ACE_Reactor_Mask mask)
+{
+ if (ACE_BIT_DISABLED (flg_mask_, mask))
+ return 0;
+
+ if (ACE_Reactor::instance ()->cancel_wakeup (this, mask) == -1)
+ return -1;
+
+ ACE_CLR_BITS (flg_mask_, mask);
+ return 0;
+}
+
+int
+Receiver::handle_close (ACE_HANDLE, ACE_Reactor_Mask)
+{
+ ACE_Reactor *TPReactor = ACE_Reactor::instance ();
+
+ TPReactor->remove_handler (this,
+ ACE_Event_Handler::ALL_EVENTS_MASK |
+ ACE_Event_Handler::DONT_CALL); // Don't call handle_close
+ this->reactor (0);
+ this->destroy ();
+ return 0;
+}
+
+int
+Receiver::handle_input (ACE_HANDLE h)
+{
+ ACE_Guard<ACE_Recursive_Thread_Mutex> locker (mutex_);
+
+ ACE_Message_Block *mb = 0;
+ ACE_NEW_RETURN (mb,
+ ACE_Message_Block (BUFSIZ),
+ -1);
+
+ int err = 0;
+ ssize_t res = this->peer ().recv (mb->rd_ptr (), BUFSIZ-1);
+
+ this->total_r_++;
+
+ if (res >= 0)
+ {
+ mb->wr_ptr (res);
+ this->total_rcv_ += res;
+ }
+ else
+ err = errno ;
+
+ mb->wr_ptr ()[0] = '\0';
+
+ if (loglevel == 0 || res <= 0 || err!= 0)
+ {
+ LogLocker log_lock;
+
+ ACE_DEBUG ((LM_DEBUG, "**** Receiver::handle_input () SessionId=%d****\n", index_));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "bytes_to_read", BUFSIZ));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "handle", h));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "bytes_transferred", res));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "error", err));
+ ACE_DEBUG ((LM_DEBUG, "%s = %s\n", "message_block", mb->rd_ptr ()));
+ ACE_DEBUG ((LM_DEBUG, "**** end of message ****************\n"));
+ }
+
+ if (err == EWOULDBLOCK)
+ {
+ err=0;
+ res=0;
+ return check_destroy ();
+ }
+
+ if (err !=0 || res <= 0)
+ {
+ ACE_Message_Block::release (mb);
+ return -1;
+ }
+
+ ACE_Time_Value tv = ACE_Time_Value::zero;
+
+ int qcount = this->putq (mb, & tv);
+
+ if (qcount <= 0) // failed to putq
+ {
+ ACE_Message_Block::release (mb);
+ return -1 ;
+ }
+
+ int rc = 0;
+
+ if (duplex == 0) // half-duplex , stop read
+ rc = this->terminate_io (ACE_Event_Handler::READ_MASK);
+ else // full duplex
+ {
+ if (qcount >= 20 ) // flow control, stop read
+ rc = this->terminate_io (ACE_Event_Handler::READ_MASK);
+ else
+ rc = this->initiate_io (ACE_Event_Handler::READ_MASK);
+ }
+
+ if (rc == -1)
+ return -1;
+
+ //initiate write
+ if (this->initiate_io (ACE_Event_Handler::WRITE_MASK) != 0)
+ return -1;
+
+ return check_destroy ();
+}
+
+int
+Receiver::handle_output (ACE_HANDLE h)
+{
+ ACE_Guard<ACE_Recursive_Thread_Mutex> locker (mutex_);
+
+ ACE_Time_Value tv = ACE_Time_Value::zero;
+ ACE_Message_Block *mb = 0;
+
+ int err = 0;
+ ssize_t res = 0;
+ size_t bytes = 0;
+
+ int qcount = this->getq (mb, &tv);
+
+ if (mb != 0) // qcount >= 0)
+ {
+ bytes = mb->length ();
+ res = this->peer ().send (mb->rd_ptr (), bytes);
+
+ this->total_w_++;
+
+ if (res < 0)
+ err = errno ;
+ else
+ this->total_snd_ += res;
+
+
+ if (loglevel == 0 || res <= 0 || err!= 0)
+ {
+ LogLocker log_lock;
+
+ ACE_DEBUG ((LM_DEBUG, "**** Receiver::handle_output () SessionId=%d****\n", index_));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "bytes_to_write", bytes));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "handle", h));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "bytes_transferred", res));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "error", err));
+ ACE_DEBUG ((LM_DEBUG, "%s = %s\n", "message_block", mb->rd_ptr ()));
+ ACE_DEBUG ((LM_DEBUG, "**** end of message ****************\n"));
+ }
+ }
+
+ ACE_Message_Block::release (mb);
+
+ if (err != 0 || res < 0)
+ return -1;
+
+ if (qcount <= 0) // no more message blocks in queue
+ {
+ if (this->terminate_io (ACE_Event_Handler::WRITE_MASK) != 0)
+ return -1;
+
+ if (this->initiate_io (ACE_Event_Handler::READ_MASK) != 0)
+ return -1;
+ }
+
+ return check_destroy ();
+}
+
+// *************************************************************
+
+Connector::Connector (void)
+ : ACE_Connector<Sender,ACE_SOCK_CONNECTOR> ((ACE_Reactor *) 0),
+ sessions_ (0),
+ total_snd_(0),
+ total_rcv_(0),
+ total_w_ (0),
+ total_r_ (0)
+{
+ ACE_Guard<ACE_Recursive_Thread_Mutex> locker (this->mutex_);
+
+ for (size_t i = 0; i < MAX_SENDERS; ++i)
+ this->list_senders_[i] = 0;
+}
+
+Connector::~Connector (void)
+{
+ this->reactor (0);
+ stop ();
+}
+
+void
+Connector::stop ()
+{
+ // this method can be called only
+ // after reactor event loop id done
+ // in all threads
+
+ ACE_Guard<ACE_Recursive_Thread_Mutex> locker (this->mutex_);
+
+ for (size_t i = 0; i < MAX_SENDERS; ++i)
+ {
+ delete this->list_senders_[i];
+ this->list_senders_[i] =0;
+ }
+}
+
+void
+Connector::on_new_sender (Sender & sndr)
+{
+ ACE_Guard<ACE_Recursive_Thread_Mutex> locker (this->mutex_);
+ this->sessions_++;
+ this->list_senders_[sndr.index_] = &sndr;
+ ACE_DEBUG ((LM_DEBUG,
+ "Sender::CTOR sessions_=%d\n",
+ this->sessions_));
+}
+
+void
+Connector::on_delete_sender (Sender & sndr)
+{
+ ACE_Guard<ACE_Recursive_Thread_Mutex> locker (this->mutex_);
+
+ this->sessions_--;
+ this->total_snd_ += sndr.get_total_snd();
+ this->total_rcv_ += sndr.get_total_rcv();
+ this->total_w_ += sndr.get_total_w();
+ this->total_r_ += sndr.get_total_r();
+
+ if (sndr.index_ < MAX_SENDERS
+ && this->list_senders_[sndr.index_] == &sndr)
+ this->list_senders_[sndr.index_] = 0;
+
+ ACE_TCHAR bufs [256];
+ ACE_TCHAR bufr [256];
+
+ ACE_OS::sprintf ( bufs , ACE_TEXT ("%ld(%ld)"),
+ sndr.get_total_snd(),
+ sndr.get_total_w() );
+
+ ACE_OS::sprintf ( bufr , ACE_TEXT ("%ld(%ld)"),
+ sndr.get_total_rcv(),
+ sndr.get_total_r() );
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Sender::~DTOR index=%d snd=%s rcv=%s sessions_=%d\n"),
+ sndr.index_,
+ bufs,
+ bufr,
+ this->sessions_));
+
+}
+
+int
+Connector::start (const ACE_INET_Addr & addr, int num)
+{
+
+ if (ACE_Connector<Sender,ACE_SOCK_CONNECTOR>
+ ::open (ACE_Reactor::instance (),
+ ACE_NONBLOCK) < 0)
+ ACE_ERROR_RETURN
+ ((LM_ERROR,
+ "%p\n",
+ "Connector::start () - open failed"),
+ 0);
+
+ int rc = 0;
+
+ for (int i = 0 ; i < num ; i++)
+ {
+ Sender * sender = 0;
+
+ if (ACE_Connector<Sender,ACE_SOCK_CONNECTOR>
+ ::connect (sender, addr) < 0)
+ ACE_ERROR_RETURN
+ ((LM_ERROR,
+ "%p\n",
+ "Connector::start () - connect failed"),
+ rc);
+ }
+
+ return rc;
+}
+
+int
+Connector::make_svc_handler (Sender * & sh)
+{
+ ACE_Guard<ACE_Recursive_Thread_Mutex> locker (this->mutex_);
+
+ if (sessions_ >= MAX_SENDERS)
+ return -1;
+
+ for (size_t i = 0; i < MAX_SENDERS; ++i)
+ if (this->list_senders_ [i] == 0)
+ {
+ ACE_NEW_RETURN (sh,
+ Sender (this , i),
+ -1);
+ return 0;
+ }
+
+ return -1;
+}
+
+// *************************************************************
+
+Sender::Sender (Connector* connector, size_t index)
+ : connector_ (connector),
+ index_ (index),
+ flg_mask_ (ACE_Event_Handler::NULL_MASK),
+ total_snd_(0),
+ total_rcv_(0),
+ total_w_ (0),
+ total_r_ (0)
+{
+ if (connector_ != 0)
+ connector_->on_new_sender (*this);
+
+ ACE_OS::sprintf (send_buf_ ,data);
+}
+
+
+Sender::~Sender (void)
+{
+ this->reactor (0);
+ if (connector_ != 0)
+ connector_->on_delete_sender (*this);
+
+ this->index_ = 0;
+
+ for (; ;)
+ {
+ ACE_Time_Value tv = ACE_Time_Value::zero;
+ ACE_Message_Block *mb = 0;
+
+ if (this->getq (mb, &tv) < 0)
+ break;
+
+ ACE_Message_Block::release (mb);
+ }
+}
+
+int
+Sender::check_destroy (void)
+{
+ if (flg_mask_ == ACE_Event_Handler::NULL_MASK)
+ return -1;
+
+ return 0;
+}
+
+int Sender::open (void *)
+{
+ ACE_Guard<ACE_Recursive_Thread_Mutex> locker (mutex_);
+
+ ACE_Reactor * TPReactor = ACE_Reactor::instance ();
+
+ this->reactor (TPReactor);
+
+ flg_mask_ = ACE_Event_Handler::NULL_MASK ;
+
+ if (TPReactor->register_handler (this,flg_mask_) == -1)
+ return -1;
+
+ if (this->initiate_write () == -1)
+ return -1;
+
+ if (duplex != 0)
+ initiate_io (ACE_Event_Handler::READ_MASK);
+
+ return check_destroy ();
+}
+
+int
+Sender::initiate_write (void)
+{
+ if ( this->msg_queue ()->message_count () < 20) // flow control
+ {
+ size_t nbytes = ACE_OS::strlen (send_buf_);
+
+ ACE_Message_Block *mb = 0;
+ ACE_NEW_RETURN (mb,
+ ACE_Message_Block (nbytes+8),
+ -1);
+
+ mb->init (send_buf_, nbytes);
+ mb->rd_ptr (mb->base ());
+ mb->wr_ptr (mb->base ());
+ mb->wr_ptr (nbytes);
+
+ ACE_Time_Value tv = ACE_Time_Value::zero;
+
+ int qcount =this->putq (mb, & tv);
+
+ if (qcount <= 0)
+ {
+ ACE_Message_Block::release (mb);
+ return -1;
+ }
+ }
+
+ return initiate_io (ACE_Event_Handler::WRITE_MASK);
+}
+
+int
+Sender::initiate_io (ACE_Reactor_Mask mask)
+{
+ if (ACE_BIT_ENABLED (flg_mask_, mask))
+ return 0;
+
+ if (ACE_Reactor::instance ()->schedule_wakeup (this, mask) == -1)
+ return -1;
+
+ ACE_SET_BITS (flg_mask_, mask);
+ return 0;
+}
+
+int
+Sender::terminate_io (ACE_Reactor_Mask mask)
+{
+ if (ACE_BIT_DISABLED (flg_mask_, mask))
+ return 0;
+
+ if (ACE_Reactor::instance ()->cancel_wakeup (this, mask) == -1)
+ return -1;
+
+ ACE_CLR_BITS (flg_mask_, mask);
+ return 0;
+}
+
+int
+Sender::handle_close (ACE_HANDLE, ACE_Reactor_Mask)
+{
+ ACE_Reactor * TPReactor = ACE_Reactor::instance ();
+
+ TPReactor->remove_handler (this,
+ ACE_Event_Handler::ALL_EVENTS_MASK |
+ ACE_Event_Handler::DONT_CALL); // Don't call handle_close
+ this->reactor (0);
+ this->destroy ();
+ return 0;
+}
+
+int
+Sender::handle_input (ACE_HANDLE h)
+{
+ ACE_Guard<ACE_Recursive_Thread_Mutex> locker (mutex_);
+
+ ACE_Message_Block *mb = 0;
+ ACE_NEW_RETURN (mb,
+ ACE_Message_Block (BUFSIZ),
+ -1);
+
+ int err = 0;
+ ssize_t res = this->peer ().recv (mb->rd_ptr (),
+ BUFSIZ-1);
+ this->total_r_++;
+
+ if (res >= 0)
+ {
+ mb->wr_ptr (res);
+ this->total_rcv_ += res;
+ }
+ else
+ err = errno ;
+
+ mb->wr_ptr ()[0] = '\0';
+
+ if (loglevel == 0 || res <= 0 || err!= 0)
+ {
+ LogLocker log_lock;
+
+ ACE_DEBUG ((LM_DEBUG, "**** Sender::handle_input () SessionId=%d****\n", index_));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "bytes_to_read", BUFSIZ));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "handle", h));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "bytes_transferred", res));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "error", err));
+ ACE_DEBUG ((LM_DEBUG, "%s = %s\n", "message_block", mb->rd_ptr ()));
+ ACE_DEBUG ((LM_DEBUG, "**** end of message ****************\n"));
+ }
+
+ ACE_Message_Block::release (mb);
+
+ if (err == EWOULDBLOCK)
+ {
+ err=0;
+ res=0;
+ return check_destroy ();
+ }
+
+ if (err !=0 || res <= 0)
+ return -1;
+
+ int rc = 0;
+
+ if (duplex != 0) // full duplex, continue read
+ rc = initiate_io (ACE_Event_Handler::READ_MASK);
+ else
+ rc = terminate_io (ACE_Event_Handler::READ_MASK);
+
+ if (rc != 0)
+ return -1 ;
+
+ rc = initiate_write ();
+ if (rc != 0)
+ return -1;
+
+ return check_destroy ();
+}
+
+int
+Sender::handle_output (ACE_HANDLE h)
+{
+ ACE_Guard<ACE_Recursive_Thread_Mutex> locker (mutex_);
+
+ ACE_Time_Value tv = ACE_Time_Value::zero;
+ ACE_Message_Block *mb = 0;
+
+ int err=0;
+ ssize_t res=0;
+ size_t bytes=0;
+
+ int qcount = this->getq (mb , & tv);
+
+ if (mb != 0) // qcount >= 0
+ {
+ bytes = mb->length ();
+ res = this->peer ().send (mb->rd_ptr (), bytes);
+
+ this->total_w_++;
+
+ if (res < 0)
+ err = errno ;
+ else
+ this->total_snd_ += res;
+
+ if (loglevel == 0 || res <= 0 || err!= 0)
+ {
+ LogLocker log_lock;
+
+ ACE_DEBUG ((LM_DEBUG, "**** Sender::handle_output () SessionId=%d****\n", index_));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "bytes_to_write", bytes));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "handle", h));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "bytes_transferred", res));
+ ACE_DEBUG ((LM_DEBUG, "%s = %d\n", "error", err));
+ ACE_DEBUG ((LM_DEBUG, "%s = %s\n", "message_block", mb->rd_ptr ()));
+ ACE_DEBUG ((LM_DEBUG, "**** end of message ****************\n"));
+ }
+ }
+
+ ACE_Message_Block::release (mb);
+
+ if (err != 0 || res < 0)
+ return -1;
+
+ int rc = 0;
+
+ if (qcount <= 0) // no more message blocks in queue
+ {
+ if (duplex != 0 && // full duplex, continue write
+ (this->total_snd_ - this->total_rcv_ ) < 1024*32 ) // flow control
+ rc = initiate_write ();
+ else
+ rc = terminate_io (ACE_Event_Handler::WRITE_MASK);
+
+ if (rc == -1)
+ return -1;
+ }
+
+ rc = initiate_io (ACE_Event_Handler::READ_MASK);
+ if (rc == -1)
+ return -1;
+
+ return check_destroy ();
+}
+
+
+// *************************************************************
+// Configuration helpers
+// *************************************************************
+int
+print_usage (int /* argc */, ACE_TCHAR *argv[])
+{
+ ACE_ERROR
+ ((LM_ERROR,
+ ACE_TEXT ("\nusage: %s")
+ ACE_TEXT ("\n-n <number threads in the thread pool>")
+ ACE_TEXT ("\n-d <duplex mode 1-on/0-off>")
+ ACE_TEXT ("\n-p <port to listen/connect>")
+ ACE_TEXT ("\n-h <host> for Sender mode")
+ ACE_TEXT ("\n-s <number of sender's instances>")
+ ACE_TEXT ("\n-b run client and server at the same time")
+ ACE_TEXT ("\n-v log level")
+ ACE_TEXT ("\n 0 - log all messages")
+ ACE_TEXT ("\n 1 - log only errors and unusual cases")
+ ACE_TEXT ("\n-i time to run in seconds")
+ ACE_TEXT ("\n-u show this message")
+ ACE_TEXT ("\n"),
+ argv[0]
+ ));
+ return -1;
+}
+
+static int
+parse_args (int argc, ACE_TCHAR *argv[])
+{
+ if (argc == 1) // no arguments , so one button test
+ {
+ both = 1; // client and server simultaneosly
+ duplex = 1; // full duplex is on
+ host = ACE_TEXT ("localhost"); // server to connect
+ port = ACE_DEFAULT_SERVER_PORT; // port to connect/listen
+ threads = 3; // size of Proactor thread pool
+ senders = 20; // number of senders
+ loglevel = 1; // log level : 0 full/ 1 only errors
+ seconds = 20; // time to run in seconds
+#if defined(SOMAXCONN) // The test is invalid if senders > SOMAXCONN
+ if(SOMAXCONN < senders)
+ senders = SOMAXCONN;
+#endif
+ return 0;
+ }
+
+ ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("i:n:p:d:h:s:v:ub"));
+ int c;
+
+ while ((c = get_opt ()) != EOF)
+ {
+ switch (c)
+ {
+ case 'i': // time to run
+ seconds = ACE_OS::atoi (get_opt.opt_arg());
+ if (seconds < MIN_TIME)
+ seconds = MIN_TIME;
+ if (seconds > MAX_TIME)
+ seconds = MAX_TIME;
+ break;
+ case 'b': // both client and server
+ both = 1;
+ break;
+ case 'v': // log level
+ loglevel = ACE_OS::atoi (get_opt.opt_arg());
+ break;
+ case 'd': // duplex
+ duplex = ACE_OS::atoi (get_opt.opt_arg());
+ break;
+ case 'h': // host for sender
+ host = get_opt.opt_arg();
+ break;
+ case 'p': // port number
+ port = ACE_OS::atoi (get_opt.opt_arg());
+ break;
+ case 'n': // thread pool size
+ threads = ACE_OS::atoi (get_opt.opt_arg());
+ break;
+ case 's': // number of senders
+ senders = ACE_OS::atoi (get_opt.opt_arg());
+ if (size_t (senders) > MAX_SENDERS)
+ senders = MAX_SENDERS;
+ break;
+ case 'u':
+ default:
+ return print_usage (argc,argv);
+ } // switch
+ } // while
+
+ return 0;
+}
+
+static int
+disable_signal (int sigmin, int sigmax)
+{
+#if defined (ACE_HAS_PTHREADS_STD) && !defined (ACE_LACKS_PTHREAD_SIGMASK)
+ sigset_t signal_set;
+ if (sigemptyset (&signal_set) == - 1)
+ ACE_ERROR ((LM_ERROR,
+ "Error: (%P | %t):%p\n",
+ "sigemptyset failed"));
+
+ for (int i = sigmin; i <= sigmax; i++)
+ sigaddset (&signal_set, i);
+
+ // Put the <signal_set>.
+ if (ACE_OS::pthread_sigmask (SIG_BLOCK, &signal_set, 0) != 0)
+ ACE_ERROR ((LM_ERROR,
+ "Error: (%P | %t):%p\n",
+ "pthread_sigmask failed"));
+#else
+ ACE_UNUSED_ARG(sigmin);
+ ACE_UNUSED_ARG(sigmax);
+#endif /* ACE_HAS_PTHREADS_STD && !ACE_LACKS_PTHREAD_SIGMASK */
+
+ return 1;
+}
+
+#endif /* ACE_HAS_THREADS */
+
+int
+run_main (int argc, ACE_TCHAR *argv[])
+{
+ ACE_START_TEST (ACE_TEXT ("TP_Reactor_Test"));
+
+#if defined(ACE_HAS_THREADS)
+ if (::parse_args (argc, argv) == -1)
+ return -1;
+
+ ::disable_signal (SIGPIPE, SIGPIPE);
+
+ MyTask task1;
+ Acceptor acceptor;
+ Connector connector;
+
+ if (task1.start (threads) == 0)
+ {
+ int rc = 0;
+
+ ACE_INET_Addr addr (port);
+ if (both != 0 || host == 0) // Acceptor
+ rc += acceptor.start (addr);
+
+ if (both != 0 || host != 0)
+ {
+ if (host == 0)
+ host = ACE_LOCALHOST;
+
+ if (addr.set (port, host, 1, addr.get_type ()) == -1)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), host));
+ rc += connector.start (addr, senders);
+
+ }
+
+ if (rc > 0)
+ ACE_OS::sleep (seconds);
+ }
+
+ task1.stop ();
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\nNumber of Receivers objects = %d\n")
+ ACE_TEXT ("\nNumber of Sender objects = %d\n"),
+ acceptor.get_number_sessions (),
+ connector.get_number_sessions ()));
+
+ // As Reactor event loop now is inactive it is safe to destroy all
+ // senders
+
+ connector.stop ();
+ acceptor.stop ();
+
+ //Print statistic
+ ACE_TCHAR bufs [256];
+ ACE_TCHAR bufr [256];
+
+ ACE_OS::sprintf ( bufs , ACE_TEXT ("%ld(%ld)"),
+ connector.get_total_snd(),
+ connector.get_total_w() );
+
+ ACE_OS::sprintf ( bufr , ACE_TEXT ("%ld(%ld)"),
+ connector.get_total_rcv(),
+ connector.get_total_r() );
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Connector/Senders total bytes: snd=%s rcv=%s\n"),
+ bufs,
+ bufr
+ ));
+
+ ACE_OS::sprintf ( bufs , ACE_TEXT ("%ld(%ld)"),
+ acceptor.get_total_snd(),
+ acceptor.get_total_w() );
+
+ ACE_OS::sprintf ( bufr , ACE_TEXT ("%ld(%ld)"),
+ acceptor.get_total_rcv(),
+ acceptor.get_total_r() );
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Acceptor/Receivers total bytes: snd=%s rcv=%s\n"),
+ bufs,
+ bufr
+ ));
+
+#else /* ACE_HAS_THREADS */
+ ACE_UNUSED_ARG( argc );
+ ACE_UNUSED_ARG( argv );
+#endif /* ACE_HAS_THREADS */
+
+ ACE_END_TEST;
+
+ return 0;
+}
diff --git a/ACE/tests/TP_Reactor_Test.h b/ACE/tests/TP_Reactor_Test.h
new file mode 100644
index 00000000000..6ebfe56cece
--- /dev/null
+++ b/ACE/tests/TP_Reactor_Test.h
@@ -0,0 +1,200 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// TP_Reactor_Test.h
+//
+// = DESCRIPTION
+// Define class needed for generating templates. IBM C++ requires this to
+// be in its own file for auto template instantiation.
+//
+// = AUTHOR
+// Alexander Libman <alibman@ihug.com.au>,<alexl@rumblgroup.com>
+//
+// ============================================================================
+
+#ifndef ACE_TESTS_TP_REACTOR_TEST_H
+#define ACE_TESTS_TP_REACTOR_TEST_H
+
+#include "ace/INET_Addr.h"
+#include "ace/SOCK_Acceptor.h"
+#include "ace/SOCK_Connector.h"
+#include "ace/SOCK_Stream.h"
+#include "ace/Acceptor.h"
+#include "ace/Connector.h"
+#include "ace/Svc_Handler.h"
+#include "ace/Recursive_Thread_Mutex.h"
+
+const size_t MAX_SENDERS = 1000;
+const size_t MAX_RECEIVERS = 1000;
+
+
+// *************************************************************
+// Receiver and Acceptor
+// *************************************************************
+// forward declaration
+class Acceptor;
+
+class Receiver : public ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_MT_SYNCH>
+{
+ friend class Acceptor;
+public:
+
+ Receiver (Acceptor * acceptor=0, size_t index=MAX_RECEIVERS+1);
+
+ ~Receiver (void);
+
+ long get_total_snd (void) { return this->total_snd_; }
+ long get_total_rcv (void) { return this->total_rcv_; }
+ long get_total_w (void) { return this->total_w_; }
+ long get_total_r (void) { return this->total_r_; }
+
+ // virtual from ACE_Svc_Handler<>
+ virtual int open (void * pVoid);
+
+ // virtual from ACE_Event_Handler
+ virtual int handle_input (ACE_HANDLE h);
+ virtual int handle_output (ACE_HANDLE h);
+ virtual int handle_close (ACE_HANDLE h , ACE_Reactor_Mask mask);
+
+private:
+ int terminate_io (ACE_Reactor_Mask mask);
+ int initiate_io (ACE_Reactor_Mask mask);
+ int check_destroy (void);
+
+ Acceptor * acceptor_;
+ size_t index_;
+ int flg_mask_;
+
+ ACE_Recursive_Thread_Mutex mutex_;
+ long total_snd_;
+ long total_rcv_;
+ long total_w_;
+ long total_r_;
+};
+
+// *************************************************************
+
+class Acceptor : public ACE_Acceptor<Receiver,ACE_SOCK_ACCEPTOR>
+{
+ friend class Receiver;
+public:
+ size_t get_number_sessions (void) { return sessions_; }
+ long get_total_snd (void) { return this->total_snd_; }
+ long get_total_rcv (void) { return this->total_rcv_; }
+ long get_total_w (void) { return this->total_w_; }
+ long get_total_r (void) { return this->total_r_; }
+
+ Acceptor (void);
+ virtual ~Acceptor (void);
+
+ void stop (void);
+ int start (const ACE_INET_Addr & addr);
+
+ // virtual from ACE_Acceptor<Receiver,ACE_SOCK_ACCEPTOR>
+ virtual int make_svc_handler (Receiver * & sh);
+
+private:
+
+ ACE_Recursive_Thread_Mutex mutex_;
+ size_t sessions_;
+ Receiver *list_receivers_[MAX_RECEIVERS];
+ long total_snd_;
+ long total_rcv_;
+ long total_w_;
+ long total_r_;
+
+ void on_new_receiver (Receiver & rcvr);
+ void on_delete_receiver (Receiver & rcvr);
+};
+
+
+// *******************************************
+// Sender
+// *******************************************
+
+class Connector;
+
+class Sender : public ACE_Svc_Handler<ACE_SOCK_STREAM,ACE_MT_SYNCH>
+{
+ friend class Connector;
+
+public:
+ Sender (Connector * connector=0, size_t index=MAX_SENDERS+1);
+
+ ~Sender (void);
+
+ long get_total_snd (void) { return this->total_snd_; }
+ long get_total_rcv (void) { return this->total_rcv_; }
+ long get_total_w (void) { return this->total_w_; }
+ long get_total_r (void) { return this->total_r_; }
+
+ // virtual from ACE_Svc_Handler<>
+ virtual int open (void * pVoid);
+
+ // virtual from ACE_Event_Handler
+ virtual int handle_input (ACE_HANDLE h);
+ virtual int handle_output (ACE_HANDLE h);
+ virtual int handle_close (ACE_HANDLE h , ACE_Reactor_Mask mask);
+
+private:
+ int terminate_io (ACE_Reactor_Mask mask);
+ int initiate_io (ACE_Reactor_Mask mask);
+ int initiate_write ();
+ int check_destroy (void);
+
+ Connector * connector_;
+ size_t index_;
+ int flg_mask_;
+
+ ACE_Recursive_Thread_Mutex mutex_;
+
+ char send_buf_ [1024];
+ long total_snd_;
+ long total_rcv_;
+ long total_w_;
+ long total_r_;
+};
+
+// *************************************************************
+
+class Connector: public ACE_Connector<Sender,ACE_SOCK_CONNECTOR>
+{
+ friend class Sender;
+public:
+ size_t get_number_sessions (void) { return sessions_; }
+ long get_total_snd (void) { return this->total_snd_; }
+ long get_total_rcv (void) { return this->total_rcv_; }
+ long get_total_w (void) { return this->total_w_; }
+ long get_total_r (void) { return this->total_r_; }
+
+
+ Connector ();
+ virtual ~Connector ();
+
+ void stop ();
+ int start (const ACE_INET_Addr & addr , int num);
+
+ // virtual from ACE_Connector<>
+ virtual int make_svc_handler (Sender * & sh);
+
+private:
+
+ ACE_Recursive_Thread_Mutex mutex_;
+ size_t sessions_;
+ Sender * list_senders_ [MAX_SENDERS];
+ long total_snd_;
+ long total_rcv_;
+ long total_w_;
+ long total_r_;
+
+ void on_new_sender (Sender & sndr);
+ void on_delete_sender (Sender & sndr);
+};
+
+
+#endif /* ACE_TESTS_TP_REACTOR_TEST_H */
diff --git a/ACE/tests/TSS_Static_Test.cpp b/ACE/tests/TSS_Static_Test.cpp
new file mode 100644
index 00000000000..40e0b6d9e57
--- /dev/null
+++ b/ACE/tests/TSS_Static_Test.cpp
@@ -0,0 +1,113 @@
+// $Id$
+
+// ============================================================================
+//
+// = FILENAME
+// TSS_Static_Test.cpp
+//
+// = DESCRIPTION
+// This program tests the interaction between TSS and thread keys
+// created during static construction. VxWorks static construction
+// is quite broken. This test is designed to test changes to work
+// around a bug in the VxWorks loader that constructs static objects
+// multiple times. It sounds hard to believe, but I've seen it!
+//
+// = AUTHOR
+// Chad Elliott <elliott_c@ociweb.com>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/ACE.h"
+#include "ace/Thread.h"
+
+ACE_RCSID(tests, TSS_Static_Test, "$Id$")
+
+#if defined (ACE_HAS_TSS_EMULATION)
+
+class Some_Object
+{
+public:
+ Some_Object (void);
+ ~Some_Object (void);
+};
+
+Some_Object::Some_Object (void)
+{
+ ACE::init ();
+
+ // Cause the ACE_Log_Msg to be constructed during static construction
+ ACE_DEBUG ((LM_DEBUG, ""));
+
+ // Assign something to TSS during static construction
+ ACE_thread_key_t key;
+ if (ACE_Thread::keycreate (&key, 0) == 0)
+ {
+ ACE_Thread::setspecific (key, this);
+ }
+}
+
+
+Some_Object::~Some_Object (void)
+{
+ ACE::fini ();
+}
+
+
+static Some_Object sobject;
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("TSS_Static_Test"));
+
+ int status = 0;
+ ACE_thread_key_t key;
+ if (ACE_Thread::keycreate (&key, 0) == 0)
+ {
+ void* specific = 0;
+ if (ACE_Thread::getspecific (key, &specific) == 0)
+ {
+ if (specific == 0)
+ {
+ ACE_DEBUG ((LM_DEBUG, "Got back pointer: %x from key: %d. "
+ "Good!\n",
+ (size_t)specific, key));
+ }
+ else
+ {
+ ++status;
+ ACE_ERROR ((LM_ERROR, "Something (%x) was found in tss "
+ "slot %d.\n"
+ "Nothing should be stored in our "
+ "TSS slot!\n",
+ (size_t)specific, key));
+ }
+ }
+ else
+ {
+ ++status;
+ ACE_ERROR ((LM_ERROR, "Unable to get the thread specific "
+ "storage.\n"));
+ }
+ }
+ else
+ {
+ ++status;
+ ACE_ERROR ((LM_ERROR, "Unable to create the thread specific "
+ "storage key.\n"));
+ }
+ ACE_END_TEST;
+ return status;
+}
+#else
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("TSS_Static_Test"));
+ ACE_DEBUG ((LM_INFO, ACE_TEXT ("This test requires TSS Emulation.\n")));
+ ACE_END_TEST;
+ return 0;
+}
+#endif /* ACE_HAS_TSS_EMULATION */
+
diff --git a/ACE/tests/TSS_Test.cpp b/ACE/tests/TSS_Test.cpp
new file mode 100644
index 00000000000..b805f5bcf0a
--- /dev/null
+++ b/ACE/tests/TSS_Test.cpp
@@ -0,0 +1,309 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// TSS_Test.cpp
+//
+// = DESCRIPTION
+// This program tests thread specific storage of data. The ACE_TSS
+// wrapper transparently ensures that the objects of this class
+// will be placed in thread-specific storage. All calls on
+// ACE_TSS::operator->() are delegated to the appropriate method
+// in the Errno class.
+//
+// = AUTHOR
+// Prashant Jain <pjain@cs.wustl.edu> and Doug Schmidt <schmidt@cs.wustl.edu>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/OS_NS_unistd.h"
+#include "ace/Guard_T.h"
+#include "ace/Thread_Manager.h"
+#include "ace/Thread_Mutex.h"
+#include "ace/Signal.h"
+#include "TSS_Test_Errno.h"
+
+ACE_RCSID(tests, TSS_Test, "$Id$")
+
+static u_int errors = 0;
+
+#if defined (ACE_HAS_THREADS)
+
+#if defined (ACE_DEFAULT_THREAD_KEYS)
+ // If ACE_DEFAULT_THREAD_KEYS is defined, it is probably
+ // set to a small value. So that the test doesn't run out
+ // of keys quickly in the first thread, set the number of
+ // ITERATIONS to be small as well.
+ static const int ITERATIONS =
+ (ACE_DEFAULT_THREAD_KEYS - ACE_MAX_THREADS) / (2 * ACE_MAX_THREADS) < 2
+ ? 1
+ : (ACE_DEFAULT_THREAD_KEYS - ACE_MAX_THREADS) / (2 * ACE_MAX_THREADS);
+#else
+ // POSIX requires at least _POSIX_THREAD_KEYS_MAX (128) keys. 25
+ // iterations with 4 worker threads should be sufficient to check
+ // the TSS wrappers without exceeding the minimum requirements.
+
+ static const int ITERATIONS = 25;
+#endif /* ACE_DEFAULT_THREAD_KEYS */
+
+// Static variables.
+int Errno::flags_;
+int Errno::created_;
+int Errno::deleted_;
+
+ACE_Thread_Mutex *Errno::lock_ = 0;
+
+// This is our thread-specific error handler . . .
+// See comment below about why it's dynamically allocated.
+static ACE_TSS<Errno> *tss_error;
+
+// This is for testing/demonstrating ACE_TSS_Type_Adapter. It's
+// dynamically allocated to avoid static objects, also.
+static ACE_TSS<ACE_TSS_Type_Adapter<u_int> > *u;
+
+// Serializes output.
+static ACE_Thread_Mutex output_lock;
+
+extern "C" void
+cleanup (void *ptr)
+{
+#if defined (ACE_HAS_PTHREADS_DRAFT4)
+ // The intended use of this function doesn't apply with
+ // Draft 4 threads. With Draft 4 threads, this function
+ // is called implicitly by pthread_setspecific whenever an
+ // old value is replaced. This function is intended to be
+ // used with Draft 6 and later threads, where it is called
+ // on thread termination with the thread-specific value.
+ ACE_UNUSED_ARG (ptr);
+#else /* ! ACE_HAS_PTHREADS_DRAFT4 */
+ // Don't do this: ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) in cleanup, ptr = %x\n"), ptr));
+ // The Log_Msg buffer is a TSS object, too, and it may be gone!
+ // if you must say something here try:
+ // ACE_OS::fprintf (stderr, ACE_TEXT("(%d) in cleanup, ptr = %x\n"), ACE_Thread::self(), ptr);
+ // and this:
+ // operator delete (ptr);
+ // is nonsense when applied to a void *! (even tho the compilers accept it????
+ delete static_cast <int *> (ptr);
+#endif /* ! ACE_HAS_PTHREADS_DRAFT4 */
+}
+
+// This worker function is the entry point for each thread.
+
+static void *
+worker (void *c)
+{
+ int count = *(static_cast<int*> (c));
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) worker, iterations = %d\n"), count));
+
+ ACE_thread_key_t key = ACE_OS::NULL_key;
+ int *ip = 0;
+
+ // Make one key that will be available when the thread exits so that
+ // we'll have something to cleanup!
+
+ if (ACE_Thread::keycreate (&key, cleanup) == -1)
+ {
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%t) %p (no keys available)\n"),
+ ACE_TEXT ("ACE_Thread::keycreate")));
+ return (void *) -1;
+ }
+
+ ACE_NEW_RETURN (ip, int, 0);
+
+ if (ACE_Thread::setspecific (key, (void *) ip) == -1)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%t) %p\n"),
+ ACE_TEXT ("ACE_Thread::setspecific")));
+
+ for (int i = 0; i < count; i++)
+ {
+ if (ACE_Thread::keycreate (&key, cleanup) == -1)
+ {
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%t) %p (no more keys)\n"),
+ ACE_TEXT ("ACE_Thread::keycreate")));
+ break;
+ }
+
+ ACE_NEW_RETURN (ip, int, 0);
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) in worker at location 1, ")
+ ACE_TEXT ("key = %d, ip = %x\n"),
+ key, ip));
+
+ if (ACE_Thread::setspecific (key, (void *) ip) == -1)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%t) %p\n"),
+ ACE_TEXT ("ACE_Thread::setspecific")));
+
+ if (ACE_Thread::getspecific (key, (void **) &ip) == -1)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%t) %p\n"),
+ ACE_TEXT ("ACE_Thread::getspecific")));
+
+ if (ACE_Thread::setspecific (key, (void *) 0) == -1)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%t) %p\n"),
+ ACE_TEXT ("ACE_Thread::setspecific")));
+
+#if ! defined (ACE_HAS_PTHREADS_DRAFT4)
+ // See comment in cleanup () above.
+ delete ip;
+#endif /* ! ACE_HAS_PTHREADS_DRAFT4 */
+
+ // We don't do keyfree for ACE_HAS_PTHREADS_DRAFT4 (or 6) since it
+ // is not supported there, and will generate an error anyway. Unless
+ // ACE_HAS_TSS_EMULATION is turned on, then it should work.
+#if !(defined (ACE_HAS_PTHREADS_DRAFT4) || defined (ACE_HAS_PTHREADS_DRAFT6)) \
+ || defined (ACE_HAS_TSS_EMULATION)
+ if (ACE_Thread::keyfree (key) == -1)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%t) %p\n"),
+ ACE_TEXT ("ACE_Thread::keyfree")));
+#endif /* !(PTHREADS_DRAFT4 or 6) || defined (ACE_HAS_TSS_EMULATION) */
+
+ // Cause an error.
+ ACE_OS::read (ACE_INVALID_HANDLE, 0, 0);
+
+ // The following two lines set the thread-specific state.
+ (*tss_error)->error (errno);
+ (*tss_error)->line (__LINE__);
+
+ // This sets the static state (note how C++ makes it easy to do
+ // both).
+ (*tss_error)->flags (count);
+
+ {
+ // Use the guard to serialize access
+ ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, output_lock, 0));
+ ACE_ASSERT ((*tss_error)->flags () == ITERATIONS);
+ }
+
+ // Demonstrate use of ACE_TSS_Type_Adapter to wrap built-in
+ // types when used with ACE_TSS. See DESCRIPTION of template
+ // class ACE_TSS_Type_Adapter in ace/Synch_T.h for what this
+ // should look like. Unfortunately, some compilers have trouble
+ // with the implicit type conversions. Others have problems with
+ // the *explicit* type conversions.
+#if !defined (ACE_HAS_BROKEN_EXPLICIT_TYPECAST_OPERATOR_INVOCATION)
+ (*u)->operator u_int & () = 37;
+ if ((*u)->operator u_int () != 37)
+ {
+ // Use the guard to serialize access to errors.
+ ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, output_lock,
+ 0));
+ ACE_DEBUG ((LM_ERROR,
+ ACE_TEXT ("use of ACE_TSS_Type_Adapter failed, value ")
+ ACE_TEXT ("is %u, it should be 37!\n"),
+ (*u)->operator u_int ()));
+ ++errors;
+ }
+#endif /* !defined (ACE_HAS_BROKEN_EXPLICIT_TYPECAST_OPERATOR_INVOCATION) */
+
+#if defined (ACE_HAS_TSS_EMULATION)
+ key = ACE_OS::NULL_key;
+
+ if (ACE_Thread::keycreate (&key, cleanup) == -1)
+ {
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%t) %p (no more keys)\n"),
+ ACE_TEXT ("ACE_Thread::keycreate")));
+ break;
+ }
+
+ ACE_NEW_RETURN (ip, int, 0);
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) in worker at location 2, ")
+ ACE_TEXT ("key = %d, ip = %x\n"),
+ key, ip));
+
+ if (ACE_Thread::setspecific (key, (void *) ip) == -1)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%t) %p\n"),
+ ACE_TEXT ("ACE_Thread::setspecific")));
+
+ if (ACE_Thread::getspecific (key, (void **) &ip) == -1)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%t) %p\n"),
+ ACE_TEXT ("ACE_Thread::getspecific")));
+
+ if (ACE_Thread::setspecific (key, (void *) 0) == -1)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%t) %p\n"),
+ ACE_TEXT ("ACE_Thread::setspecific")));
+
+# if !defined (ACE_HAS_PTHREADS_DRAFT4)
+ // See comment in cleanup () above.
+ delete ip;
+# endif /* ! ACE_HAS_PTHREADS_DRAFT4 */
+
+ // We don't do keyfree for ACE_HAS_PTHREADS_DRAFT4 (or 6) since it
+ // is not supported there, and will generate an error anyway. Unless
+ // ACE_HAS_TSS_EMULATION is turned on, then it should work.
+# if !(defined (ACE_HAS_PTHREADS_DRAFT4) || \
+ defined (ACE_HAS_PTHREADS_DRAFT6) ) \
+ || defined (ACE_HAS_TSS_EMULATION)
+ if (ACE_Thread::keyfree (key) == -1)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%t) %p\n"),
+ ACE_TEXT ("ACE_Thread::keyfree")));
+# endif /* !(PTHREADS_DRAFT4 or 6) || defined (ACE_HAS_TSS_EMULATION) */
+#endif /* ACE_HAS_TSS_EMULATION */
+ }
+ return 0;
+}
+
+#endif /* ACE_HAS_THREADS */
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("TSS_Test"));
+
+#if defined (ACE_HAS_THREADS)
+ Errno::allocate_lock ();
+
+ const u_int threads = ACE_MAX_THREADS;
+
+ // Dynamically allocate TSS_Error so that we can control when it
+ // gets deleted. Specifically, we need to delete it before the
+ // ACE_Object_Manager destroys the ACE_Allocator. That's because
+ // deletion of TSS_Error causes the internal structures of
+ // ACE_TSS_Cleanup to be modified, and which in turn uses
+ // ACE_Allocator.
+ ACE_NEW_RETURN (tss_error, ACE_TSS<Errno>, 1);
+
+ // Similarly, dynamically allocate u.
+ ACE_NEW_RETURN (u, ACE_TSS<ACE_TSS_Type_Adapter<u_int> >, 1);
+
+ int iterations = ITERATIONS;
+ if (ACE_Thread_Manager::instance ()->spawn_n
+ (threads,
+ ACE_THR_FUNC (worker),
+ &iterations,
+ THR_BOUND) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"), ACE_TEXT ("spawn_n")), 1);
+
+ ACE_Thread_Manager::instance ()->wait ();
+
+ delete u;
+ delete tss_error;
+
+ Errno::deallocate_lock ();
+
+
+ if (Errno::created () != Errno::deleted ())
+ {
+ //@@TODO: this should probably be promoted to an error rather than just a
+ // warning.
+ ACE_ERROR ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) Warning: Number created (%d) != number deleted (%d)\n"),
+ Errno::created (),
+ Errno::deleted ()
+ ));
+ }
+
+#else /* ACE_HAS_THREADS */
+ ACE_ERROR ((LM_INFO,
+ ACE_TEXT ("threads are not supported on this platform\n")));
+#endif /* ACE_HAS_THREADS */
+
+ ACE_END_TEST;
+ return errors ? -1 : 0;
+}
diff --git a/ACE/tests/TSS_Test_Errno.h b/ACE/tests/TSS_Test_Errno.h
new file mode 100644
index 00000000000..7d822a7099b
--- /dev/null
+++ b/ACE/tests/TSS_Test_Errno.h
@@ -0,0 +1,102 @@
+/* -*- C++ -*- */
+// $Id$
+
+// ============================================================================
+//
+// = FILENAME
+// TSS_Test_Errno.h
+//
+// = DESCRIPTION
+// This file contains the definition of Errno. Some compilers need
+// it in a .h file for template instantiation (such as AIX C Set
+// ++).
+//
+// = AUTHOR
+// Douglas C. Schmidt <schmidt@cs.wustl.edu>
+//
+// ============================================================================
+
+#include "ace/Guard_T.h"
+#include "ace/Thread_Mutex.h"
+
+class Errno
+{
+ // = TITLE
+ // Define a simple Errno abstraction
+ //
+ // = DESCRIPTION
+ // This class gets its own header file to work around AIX C++
+ // compiler "features" related to template instantiation... It is
+ // only used by TSS_Test.cpp.
+public:
+ Errno()
+ {
+ ACE_MT (ACE_GUARD (ACE_Thread_Mutex, ace_Mon, *Errno::lock_));
+ created_ += 1;
+ }
+ ~Errno()
+ {
+ ACE_MT (ACE_GUARD (ACE_Thread_Mutex, ace_Mon, *Errno::lock_));
+ deleted_ += 1;
+ }
+
+ int error (void) { return this->errno_; }
+ void error (int i) { this->errno_ = i; }
+
+ int line (void) { return this->lineno_; }
+ void line (int l) { this->lineno_ = l; }
+
+ // Errno::flags_ is a static variable, so we've got to protect it
+ // with a mutex since it isn't kept in thread-specific storage.
+ int flags (void)
+ {
+ ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_Mon, *Errno::lock_, -1));
+
+ return Errno::flags_;
+ }
+ int flags (int f)
+ {
+ ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, *Errno::lock_, -1));
+
+ Errno::flags_ = f;
+ return 0;
+ }
+
+ static int created (void)
+ {
+ return created_;
+ }
+
+ static int deleted (void)
+ {
+ return deleted_;
+ }
+
+#if defined (ACE_HAS_THREADS)
+ static
+ ACE_Thread_Mutex *
+ allocate_lock (void)
+ {
+ ACE_NEW_RETURN (Errno::lock_, ACE_Thread_Mutex, 0);
+ return Errno::lock_;
+ }
+
+ static
+ void
+ deallocate_lock () { delete lock_; lock_ = 0; }
+#endif /* ACE_HAS_THREADS */
+
+private:
+ // = errno_ and lineno_ will be thread-specific data so they don't
+ // need a lock.
+ int errno_;
+ int lineno_;
+
+ static int flags_;
+ static int created_;
+ static int deleted_;
+#if defined (ACE_HAS_THREADS)
+ // flags_ needs a lock.
+ static ACE_Thread_Mutex *lock_;
+#endif /* ACE_HAS_THREADS */
+};
diff --git a/ACE/tests/Task_Ex_Test.cpp b/ACE/tests/Task_Ex_Test.cpp
new file mode 100644
index 00000000000..98cc6926cf7
--- /dev/null
+++ b/ACE/tests/Task_Ex_Test.cpp
@@ -0,0 +1,163 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Task_Ex_Test.cpp
+//
+// = DESCRIPTION
+// This test program illustrates the ACE_Task_Ex class which has the ACE_Message_Queue_Ex
+// that has the capability to hold user-defined messages instead of ACE_Message_Block
+//
+//
+// = AUTHOR
+// Kobi Cohen-Arazi <kobi-co@barak-online.net>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "Task_Ex_Test.h"
+#include "ace/Task_Ex_T.h"
+#include "ace/Log_Msg.h"
+#include "ace/Auto_Ptr.h"
+
+ACE_RCSID(tests, Task_Test_Ex, "$Id$")
+
+#if defined (ACE_HAS_THREADS)
+
+/// default params
+#if defined (ACE_VXWORKS)
+// this is a very expensive test on VxWorks so limit it otherwise it will never finish in time:-)
+const ACE_INT32 PRODUCER_THREADS_NO=10;
+const ACE_INT32 CONSUMER_THREADS_NO=10;
+const ACE_INT32 NUMBER_OF_MSGS=200;
+#else
+const ACE_INT32 PRODUCER_THREADS_NO=20;
+const ACE_INT32 CONSUMER_THREADS_NO=20;
+const ACE_INT32 NUMBER_OF_MSGS=2000;
+#endif
+
+/// @class Consumer consumes user defined Msgs
+class Consumer : public ACE_Task_Ex<ACE_MT_SYNCH, User_Defined_Msg>
+{
+public:
+ /// activate/spawn the threads.
+ int open (void*);
+
+ /// svc thread entry point
+ virtual int svc (void);
+private:
+
+};
+
+int Consumer::open (void*)
+{
+ if(this->activate (THR_NEW_LWP | THR_JOINABLE,
+ CONSUMER_THREADS_NO)==-1)
+ {
+ ACE_ERROR_RETURN((LM_ERROR,
+ ACE_TEXT("Consumer::open Error spanwing thread %p\n"),
+ "err="),
+ -1);
+ }
+ return 0;
+}
+
+int Consumer::svc ()
+{
+ User_Defined_Msg* pMsg=0;
+ while(this->getq (pMsg)!=-1)
+ {
+ ACE_ASSERT (pMsg!=0);
+ auto_ptr<User_Defined_Msg> pAuto(pMsg);
+ ACE_DEBUG((LM_DEBUG,
+ ACE_TEXT("Consumer::svc got msg id=%d\n"),
+ pMsg->msg_id ()));
+ if(pMsg->msg_id ()==NUMBER_OF_MSGS-1)
+ break;
+ }
+
+ ACE_DEBUG((LM_INFO,
+ ACE_TEXT("Consumer::svc ended thread %t\n")));
+
+ return 0;
+}
+
+
+/// producer function produces user defined messages.
+ACE_THR_FUNC_RETURN producer (void *arg)
+{
+ Consumer* c = static_cast<Consumer*> (arg);
+ ACE_ASSERT(c!=0);
+ if (c==0)
+ {
+ ACE_ERROR((LM_ERROR,
+ ACE_TEXT("producer Error casting to consumer\n")));
+ return (ACE_THR_FUNC_RETURN)-1;
+ }
+ for (int i=0;i!=NUMBER_OF_MSGS;++i)
+ {
+ User_Defined_Msg* pMsg=0;
+ ACE_NEW_NORETURN(pMsg, User_Defined_Msg(i));
+ if (pMsg==0)
+ {
+ ACE_ERROR((LM_ERROR,
+ ACE_TEXT("producer Error allocating data %p\n"),
+ "err="));
+ return (ACE_THR_FUNC_RETURN)-1;
+ }
+ if(c->putq (pMsg)==-1)
+ {
+ ACE_ERROR((LM_ERROR,
+ ACE_TEXT("producer Error putq data %p\n"),
+ "err="));
+ return (ACE_THR_FUNC_RETURN)-1;
+ }
+ }
+ return 0;
+}
+
+#endif /* ACE_HAS_THREADS */
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("Task_Ex_Test"));
+
+#if defined (ACE_HAS_THREADS)
+
+ Consumer c;
+ if(c.open (0)==-1)
+ ACE_ERROR_RETURN((LM_ERROR,
+ ACE_TEXT ("main Error opening consumer\n")),-1);
+
+
+ int result=ACE_Thread_Manager::instance()->spawn_n (PRODUCER_THREADS_NO,
+ ACE_THR_FUNC(producer),
+ static_cast<void*> (&c));
+ if (result==-1)
+ {
+ ACE_ERROR_RETURN((LM_ERROR,
+ ACE_TEXT ("main Error spawning threads %p\n"),
+ "err="),-1);
+ }
+
+ // wait all threads
+ int wait_result=ACE_Thread_Manager::instance()->wait();
+ if (wait_result==-1)
+ {
+ ACE_ERROR((LM_ERROR,
+ ACE_TEXT("main Error Thread_Manager->wait %p\n"),
+ "err="));
+ return -1;
+ }
+#else
+ ACE_ERROR ((LM_INFO,
+ ACE_TEXT ("threads not supported on this platform\n")));
+#endif /* ACE_HAS_THREADS */
+ ACE_END_TEST;
+ return 0;
+}
diff --git a/ACE/tests/Task_Ex_Test.h b/ACE/tests/Task_Ex_Test.h
new file mode 100644
index 00000000000..c7092a5e808
--- /dev/null
+++ b/ACE/tests/Task_Ex_Test.h
@@ -0,0 +1,34 @@
+// -*- C++ -*-
+
+//=============================================================================
+/**
+ * @file Task_Ex_Test.h
+ *
+ * $Id$
+ *
+ * Define class needed for generating templates. IBM C++ requires this
+ * to be in its own file for auto template instantiation.
+ *
+ * @author Kobi Cohen-Arazi <kobi-co@barak-online.net>
+ */
+//=============================================================================
+
+#ifndef ACE_TESTS_TASK_EX_TEST_H
+#define ACE_TESTS_TASK_EX_TEST_H
+
+#include "ace/Basic_Types.h"
+
+class User_Defined_Msg
+{
+public:
+ /// c'tor sets the msg id
+ User_Defined_Msg (ACE_INT32 id) : msg_id_ (id)
+ {}
+ /// accessors to msg_id_
+ ACE_INT32 msg_id () const {return msg_id_;}
+private:
+ /// keep the msg id here
+ ACE_INT32 msg_id_;
+};
+
+#endif /* ACE_TESTS_TASK_EX_TEST_H */
diff --git a/ACE/tests/Task_Test.cpp b/ACE/tests/Task_Test.cpp
new file mode 100644
index 00000000000..7359861fd9f
--- /dev/null
+++ b/ACE/tests/Task_Test.cpp
@@ -0,0 +1,157 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Task_Test.cpp
+//
+// = DESCRIPTION
+// This test program illustrates how the ACE barrier
+// synchronization mechanisms work in conjunction with the
+// <ACE_Task> and the <ACE_Thread_Manager>. This also illustrates
+// how the <ACE_Thread_Hook> mechanism works.
+//
+// = AUTHOR
+// Prashant Jain <pjain@cs.wustl.edu> and
+// Douglas C. Schmidt <schmidt@cs.wustl.edu>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/Task.h"
+#include "ace/Thread_Hook.h"
+
+ACE_RCSID(tests, Task_Test, "$Id$")
+
+#if defined (ACE_HAS_THREADS)
+#include "ace/Atomic_Op.h"
+#include "ace/Barrier.h"
+
+// Make sure that only one thread sees the "time to clean up" condition
+// in Barrier_Task::close()
+static ACE_Atomic_Op<ACE_Thread_Mutex, int> close_cleanups (0);
+
+class My_Thread_Hook : public ACE_Thread_Hook
+{
+public:
+ virtual ACE_THR_FUNC_RETURN start (ACE_THR_FUNC func,
+ void *arg);
+};
+
+class Barrier_Task : public ACE_Task<ACE_MT_SYNCH>
+{
+public:
+ Barrier_Task (ACE_Thread_Manager *thr_mgr,
+ int n_threads,
+ int n_iterations);
+
+ virtual int close (u_long flags = 0);
+
+ virtual int svc (void);
+ // Iterate <n_iterations> time printing off a message and "waiting"
+ // for all other threads to complete this iteration.
+
+private:
+ ACE_Barrier barrier_;
+ // Reference to the tester barrier. This controls each iteration of
+ // the tester function running in every thread.
+
+ int n_iterations_;
+ // Number of iterations to run.
+};
+
+ACE_THR_FUNC_RETURN
+My_Thread_Hook::start (ACE_THR_FUNC func,
+ void *arg)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) starting the thread!\n")));
+ return (func) (arg);
+}
+
+Barrier_Task::Barrier_Task (ACE_Thread_Manager *thr_mgr,
+ int n_threads,
+ int n_iterations)
+ : ACE_Task<ACE_MT_SYNCH> (thr_mgr),
+ barrier_ (n_threads),
+ n_iterations_ (n_iterations)
+{
+ // Create worker threads.
+ if (this->activate (THR_NEW_LWP, n_threads) == -1)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("activate failed")));
+}
+
+// Check to see if it's time to clean up by examining last_thread().
+int
+Barrier_Task::close (u_long)
+{
+ if (ACE_OS::thr_equal (ACE_Thread::self (),
+ this->last_thread ()))
+ {
+ ++close_cleanups;
+ }
+ return 0;
+}
+
+// Iterate <n_iterations> time printing off a message and "waiting"
+// for all other threads to complete this iteration.
+int
+Barrier_Task::svc (void)
+{
+ for (int iterations = 1;
+ iterations <= this->n_iterations_;
+ iterations++)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) in iteration %d\n"),
+ iterations));
+
+ // Block until all other threads have waited, then continue.
+ this->barrier_.wait ();
+ }
+
+ // Note that the <ACE_Task::svc_run> method automatically removes us
+ // from the Thread_Manager when the thread exits.
+
+ return 0;
+}
+
+#endif /* ACE_HAS_THREADS */
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("Task_Test"));
+
+#if defined (ACE_HAS_THREADS)
+ // Set the thread hook!
+ ACE_Thread_Hook::thread_hook (new My_Thread_Hook);
+
+ int n_threads = ACE_MAX_THREADS;
+ int n_iterations = ACE_MAX_ITERATIONS;
+
+ Barrier_Task barrier_task (ACE_Thread_Manager::instance (),
+ n_threads,
+ n_iterations);
+
+ ACE_Thread_Manager::instance ()->wait ();
+
+ // Only one of the threads should see a cleanup...
+ if (close_cleanups != 1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("%d threads saw cleanup indication; ")
+ ACE_TEXT ("should be 1\n"),
+ close_cleanups.value ()));
+
+ // Cleanup the thread hook so it doesn't leak.
+ delete ACE_Thread_Hook::thread_hook ();
+#else
+ ACE_ERROR ((LM_INFO,
+ ACE_TEXT ("threads not supported on this platform\n")));
+#endif /* ACE_HAS_THREADS */
+ ACE_END_TEST;
+ return 0;
+}
diff --git a/ACE/tests/Test_Output.cpp b/ACE/tests/Test_Output.cpp
new file mode 100644
index 00000000000..3502fea9e3b
--- /dev/null
+++ b/ACE/tests/Test_Output.cpp
@@ -0,0 +1,252 @@
+// -*- C++ -*-
+
+// ============================================================================
+/**
+ * @file Test_Output.cpp
+ *
+ * $Id$
+ *
+ * This file factors out common macros and other utilities used by the
+ * ACE automated regression tests.
+ *
+ * @author Prashant Jain <pjain@cs.wustl.edu>
+ * @author Tim Harrison <harrison@cs.wustl.edu>
+ * @author David Levine <levine@cs.wustl.edu>
+ * @author Don Hinton <dhinton@dresystems.com>
+ */
+// ============================================================================
+
+#include "tests/test_config.h"
+#include "ace/OS_NS_stdio.h"
+#include "ace/OS_NS_string.h"
+#include "ace/OS_NS_sys_stat.h"
+#include "ace/Guard_T.h"
+#include "ace/Object_Manager.h"
+
+// FUZZ: disable check_for_streams_include
+#include "ace/streams.h"
+
+#include "ace/Framework_Component.h"
+#include "ace/Log_Msg.h"
+#include "ace/ACE.h"
+
+#if defined (VXWORKS)
+# include "ace/OS_NS_unistd.h"
+# include "ace/OS_NS_fcntl.h"
+#endif /* VXWORKS */
+
+ACE_Test_Output *ACE_Test_Output::instance_ = 0;
+
+ACE_Test_Output::ACE_Test_Output (void)
+ : output_file_ (0)
+{
+#if !defined (ACE_LACKS_IOSTREAM_TOTALLY)
+ this->output_file_ = new OFSTREAM;
+#endif /* ACE_LACKS_IOSTREAM_TOTALLY */
+}
+
+ACE_Test_Output::~ACE_Test_Output (void)
+{
+#if !defined (ACE_LACKS_IOSTREAM_TOTALLY) && !defined (ACE_PSOS)
+ ACE_OSTREAM_TYPE *log_msg_stream = ACE_LOG_MSG->msg_ostream ();
+
+ ACE_LOG_MSG->msg_ostream (&cerr, 0);
+#endif /* ! ACE_LACKS_IOSTREAM_TOTALLY && ! ACE_PSOS */
+
+ ACE_LOG_MSG->clr_flags (ACE_Log_Msg::OSTREAM);
+ ACE_LOG_MSG->set_flags (ACE_Log_Msg::STDERR);
+
+#if !defined (ACE_LACKS_IOSTREAM_TOTALLY) && !defined (ACE_HAS_PHARLAP)
+ if (this->output_file_ == log_msg_stream)
+ delete this->output_file_;
+ // else something else changed the stream and hence should
+ // have closed and deleted the output_file_
+#endif /* ! ACE_LACKS_IOSTREAM_TOTALLY */
+}
+
+OFSTREAM *
+ACE_Test_Output::output_file (void)
+{
+ // the output_file_ is given to ACE_LOG_MSG
+ // and something else might destroy and/or change the stream
+ // so return what ACE_LOG_MSG is using.
+#if defined (ACE_LACKS_IOSTREAM_TOTALLY)
+ return reinterpret_cast<OFSTREAM*>(ACE_LOG_MSG->msg_ostream ());
+#else
+ return dynamic_cast<OFSTREAM*>(ACE_LOG_MSG->msg_ostream ());
+#endif /* ACE_LACKS_IOSTREAM_TOTALLY */
+}
+
+int
+ACE_Test_Output::set_output (const ACE_TCHAR *filename, int append)
+{
+#if defined (ACE_HAS_PHARLAP)
+ // For PharLap, just send it all to the host console for now - redirect
+ // to a file there for saving/analysis.
+ EtsSelectConsole(ETS_CO_HOST);
+ ACE_LOG_MSG->msg_ostream (&cout);
+
+#else
+ ACE_TCHAR temp[MAXPATHLEN];
+ // Ignore the error value since the directory may already exist.
+ const ACE_TCHAR *test_dir;
+
+#if !defined (ACE_HAS_WINCE)
+# if defined (ACE_WIN32) || !defined (ACE_USES_WCHAR)
+ test_dir = ACE_OS::getenv (ACE_TEXT ("ACE_TEST_DIR"));
+# else
+ ACE_TCHAR tempenv[MAXPATHLEN];
+ char *test_dir_n = ACE_OS::getenv ("ACE_TEST_DIR");
+ if (test_dir_n == 0)
+ test_dir = 0;
+ else
+ {
+ ACE_OS::strcpy (tempenv, ACE_TEXT_CHAR_TO_TCHAR (test_dir_n));
+ test_dir = tempenv;
+ }
+# endif /* ACE_WIN32 || !ACE_USES_WCHAR */
+
+ if (test_dir == 0)
+#endif /* ACE_HAS_WINCE */
+ test_dir = ACE_TEXT ("");
+
+ // This could be done with ACE_OS::sprintf() but it requires different
+ // format strings for wide-char POSIX vs. narrow-char POSIX and Windows.
+ // Easier to keep straight like this.
+ ACE_OS_String::strcpy (temp, test_dir);
+ ACE_OS_String::strcat (temp, ACE_LOG_DIRECTORY);
+ ACE_OS_String::strcat
+ (temp, ACE::basename (filename, ACE_DIRECTORY_SEPARATOR_CHAR));
+ ACE_OS_String::strcat (temp, ACE_LOG_FILE_EXT_NAME);
+
+#if defined (VXWORKS)
+ // This is the only way I could figure out to avoid a console
+ // warning about opening an existing file (w/o O_CREAT), or
+ // attempting to unlink a non-existant one.
+ ACE_HANDLE fd = ACE_OS::open (temp,
+ O_WRONLY|O_CREAT,
+ S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
+ if (fd != ERROR)
+ {
+ ACE_OS::close (fd);
+ ACE_OS::unlink (temp);
+ }
+# else /* ! VXWORKS */
+ // This doesn't seem to work on VxWorks if the directory doesn't
+ // exist: it creates a plain file instead of a directory. If the
+ // directory does exist, it causes a wierd console error message
+ // about "cat: input error on standard input: Is a directory". So,
+ // VxWorks users must create the directory manually.
+# if defined (ACE_HAS_WINCE)
+ ACE_OS::mkdir (ACE_LOG_DIRECTORY_FOR_MKDIR);
+# else
+ ACE_OS::mkdir (ACE_LOG_DIRECTORY);
+# endif // ACE_HAS_WINCE
+# endif /* ! VXWORKS */
+
+# if !defined (ACE_LACKS_IOSTREAM_TOTALLY)
+ this->output_file_->open (ACE_TEXT_ALWAYS_CHAR (temp),
+ ios::out | (append ? ios::app : ios::trunc));
+ if (this->output_file_->bad ())
+ return -1;
+#else /* when ACE_LACKS_IOSTREAM_TOTALLY */
+ ACE_TCHAR *fmode = 0;
+ if (append)
+ fmode = ACE_TEXT ("a");
+ else
+ fmode = ACE_TEXT ("w");
+ this->output_file_ = ACE_OS::fopen (temp, fmode);
+# endif /* ACE_LACKS_IOSTREAM_TOTALLY */
+
+ ACE_LOG_MSG->msg_ostream (this->output_file_);
+#endif /* ACE_HAS_PHARLAP */
+
+ ACE_LOG_MSG->clr_flags (ACE_Log_Msg::STDERR | ACE_Log_Msg::LOGGER );
+ ACE_LOG_MSG->set_flags (ACE_Log_Msg::OSTREAM);
+
+ return 0;
+}
+
+void
+ACE_Test_Output::close (void)
+{
+ if (this->output_file_ &&
+ (this->output_file_ == ACE_LOG_MSG->msg_ostream ()))
+ {
+#if !defined (ACE_LACKS_IOSTREAM_TOTALLY)
+ this->output_file_->flush ();
+ this->output_file_->close ();
+ delete this->output_file_;
+#else
+ ACE_OS::fflush (this->output_file_);
+ ACE_OS::fclose (this->output_file_);
+#endif /* !ACE_LACKS_IOSTREAM_TOTALLY */
+ this->output_file_=0;
+ ACE_LOG_MSG->msg_ostream (this->output_file_, 0);
+ }
+ // else something else changed the stream and hence should
+ // have closed and deleted the output_file_
+}
+
+ACE_Test_Output*
+ACE_Test_Output::instance ()
+{
+ if (ACE_Test_Output::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_Test_Output::instance_ == 0)
+ {
+ ACE_NEW_RETURN (ACE_Test_Output::instance_,
+ ACE_Test_Output,
+ 0);
+ ACE_REGISTER_FRAMEWORK_COMPONENT(ACE_Test_Output, ACE_Test_Output::instance_)
+ }
+ }
+ return ACE_Test_Output::instance_;
+}
+
+const ACE_TCHAR *
+ACE_Test_Output::dll_name (void)
+{
+ return ACE_TEXT ("Test_Output");
+}
+
+const ACE_TCHAR *
+ACE_Test_Output::name (void)
+{
+ return ACE_TEXT ("ACE_Test_Output");
+}
+
+void
+ACE_Test_Output::close_singleton (void)
+{
+ delete ACE_Test_Output::instance_;
+ ACE_Test_Output::instance_ = 0;
+}
+
+void
+randomize (int array[], size_t size)
+{
+ size_t i;
+
+ for (i = 0; i < size; i++)
+ array [i] = static_cast <int> (i);
+
+ // See with a fixed number so that we can produce "repeatable"
+ // random numbers.
+ ACE_OS::srand (0);
+
+ // Generate an array of random numbers from 0 .. size - 1.
+
+ for (i = 0; i < size; i++)
+ {
+ size_t index = ACE_OS::rand() % size--;
+ int temp = array [index];
+ array [index] = array [size];
+ array [size] = temp;
+ }
+}
+
diff --git a/ACE/tests/Test_Output_Export.h b/ACE/tests/Test_Output_Export.h
new file mode 100644
index 00000000000..4f6ec2f7cb5
--- /dev/null
+++ b/ACE/tests/Test_Output_Export.h
@@ -0,0 +1,54 @@
+
+// -*- C++ -*-
+// $Id$
+// Definition for Win32 Export directives.
+// This file is generated automatically by generate_export_file.pl Test_Output
+// ------------------------------
+#ifndef TEST_OUTPUT_EXPORT_H
+#define TEST_OUTPUT_EXPORT_H
+
+#include "ace/config-all.h"
+
+#if defined (ACE_AS_STATIC_LIBS) && !defined (TEST_OUTPUT_HAS_DLL)
+# define TEST_OUTPUT_HAS_DLL 0
+#endif /* ACE_AS_STATIC_LIBS && TEST_OUTPUT_HAS_DLL */
+
+#if !defined (TEST_OUTPUT_HAS_DLL)
+# define TEST_OUTPUT_HAS_DLL 1
+#endif /* ! TEST_OUTPUT_HAS_DLL */
+
+#if defined (TEST_OUTPUT_HAS_DLL) && (TEST_OUTPUT_HAS_DLL == 1)
+# if defined (TEST_OUTPUT_BUILD_DLL)
+# define Test_Output_Export ACE_Proper_Export_Flag
+# define TEST_OUTPUT_SINGLETON_DECLARATION(T) ACE_EXPORT_SINGLETON_DECLARATION (T)
+# define TEST_OUTPUT_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) ACE_EXPORT_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK)
+# else /* TEST_OUTPUT_BUILD_DLL */
+# define Test_Output_Export ACE_Proper_Import_Flag
+# define TEST_OUTPUT_SINGLETON_DECLARATION(T) ACE_IMPORT_SINGLETON_DECLARATION (T)
+# define TEST_OUTPUT_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) ACE_IMPORT_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK)
+# endif /* TEST_OUTPUT_BUILD_DLL */
+#else /* TEST_OUTPUT_HAS_DLL == 1 */
+# define Test_Output_Export
+# define TEST_OUTPUT_SINGLETON_DECLARATION(T)
+# define TEST_OUTPUT_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK)
+#endif /* TEST_OUTPUT_HAS_DLL == 1 */
+
+// Set TEST_OUTPUT_NTRACE = 0 to turn on library specific tracing even if
+// tracing is turned off for ACE.
+#if !defined (TEST_OUTPUT_NTRACE)
+# if (ACE_NTRACE == 1)
+# define TEST_OUTPUT_NTRACE 1
+# else /* (ACE_NTRACE == 1) */
+# define TEST_OUTPUT_NTRACE 0
+# endif /* (ACE_NTRACE == 1) */
+#endif /* !TEST_OUTPUT_NTRACE */
+
+#if (TEST_OUTPUT_NTRACE == 1)
+# define TEST_OUTPUT_TRACE(X)
+#else /* (TEST_OUTPUT_NTRACE == 1) */
+# define TEST_OUTPUT_TRACE(X) ACE_TRACE_IMPL(X)
+#endif /* (TEST_OUTPUT_NTRACE == 1) */
+
+#endif /* TEST_OUTPUT_EXPORT_H */
+
+// End of auto generated file.
diff --git a/ACE/tests/Thread_Manager_Test.cpp b/ACE/tests/Thread_Manager_Test.cpp
new file mode 100644
index 00000000000..2d9467b5124
--- /dev/null
+++ b/ACE/tests/Thread_Manager_Test.cpp
@@ -0,0 +1,444 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Thread_Manager_Test.cpp
+//
+// = DESCRIPTION
+// This program tests the group management mechanisms provided by
+// the <ACE_Thread_Manager>, including the group signal handling,
+// group suspension and resumption, and cooperative thread
+// cancellation mechanisms.
+//
+// = AUTHOR
+// Prashant Jain <pjain@cs.wustl.edu> and Douglas C. Schmidt
+// <schmidt@cs.wustl.edu>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/Thread_Manager.h"
+#include "ace/Signal.h"
+#include "ace/Task.h"
+#include "ace/OS_NS_unistd.h"
+#include "ace/OS_NS_sys_time.h"
+
+ACE_RCSID(tests, Thread_Manager_Test, "$Id$")
+
+#if defined (ACE_HAS_THREADS)
+#include "ace/Barrier.h"
+
+// Each thread keeps track of whether it has been signalled by using a
+// global array. It must be dynamically allocated to allow sizing at
+// runtime, based on the number of threads.
+static ACE_thread_t *signalled = 0;
+static u_int n_threads = ACE_MAX_THREADS;
+
+// Helper function that looks for an existing entry in the signalled
+// array. Also finds the position of the first unused entry in the
+// array, and updates if requested with the t_id.
+extern "C" int
+been_signalled (const ACE_thread_t t_id,
+ const u_int update = 0)
+{
+ u_int unused_slot = n_threads;
+
+ for (u_int i = 0; i < n_threads; ++i)
+ {
+ if (ACE_OS::thr_equal (signalled[i], t_id))
+ // Already signalled.
+ return 1;
+
+ if (update &&
+ unused_slot == n_threads &&
+ ACE_OS::thr_equal (signalled[i],
+ ACE_OS::NULL_thread))
+ unused_slot = i;
+ }
+
+ if (update && unused_slot < n_threads)
+ // Update the array using the first unused_slot.
+ signalled[unused_slot] = t_id;
+
+ return 0;
+}
+
+// Synchronize starts of threads, so that they all start before the
+// main thread cancels them. To avoid creating a static object, it is
+// dynamically allocated, before spawning any threads.
+static ACE_Barrier *thread_start = 0;
+
+extern "C" void
+handler (int /* signum */)
+{
+ if (signalled)
+ {
+ // No printout here, to be safe. Signal handlers must not
+ // acquire locks, etc.
+ const ACE_thread_t t_id = ACE_OS::thr_self ();
+
+ // Update the signalled indication.
+ (void) been_signalled (t_id, 1u /* update */);
+ }
+}
+
+static void *
+worker (int iterations)
+{
+#if defined (ACE_VXWORKS) && !defined (ACE_HAS_PTHREADS)
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) %s: stack size is %u\n"),
+ ACE_OS::thr_self (),
+ ACE_OS::thr_min_stack ()));
+#endif /* ACE_VXWORKS */
+
+#if !defined (ACE_LACKS_UNIX_SIGNALS)
+ // Cache this thread's ID.
+ const ACE_thread_t t_id = ACE_OS::thr_self ();
+#endif /* ! ACE_LACKS_UNIX_SIGNAL */
+
+ ACE_Thread_Manager *thr_mgr = ACE_Thread_Manager::instance ();
+
+ // After setting up the signal catcher, block on the start barrier.
+ thread_start->wait ();
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) worker starting loop\n")));
+
+ for (int i = 0; i < iterations; i++)
+ {
+ if ((i % 1000) == 0)
+ {
+#if !defined (ACE_LACKS_UNIX_SIGNALS)
+ if (been_signalled (t_id))
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) had received signal\n")));
+
+ // Only test for cancellation after we've been signaled,
+ // to avoid race conditions for suspend() and resume().
+ if (thr_mgr->testcancel (ACE_Thread::self ()) != 0)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) has been cancelled ")
+ ACE_TEXT ("before iteration %d!\n"),
+ i));
+ break;
+ }
+ }
+#else
+ if (thr_mgr->testcancel (ACE_Thread::self ()) != 0)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) has been cancelled ")
+ ACE_TEXT ("before iteration %d!\n"),
+ i));
+ break;
+ }
+#endif /* ! ACE_LACKS_UNIX_SIGNAL */
+ ACE_OS::sleep (1);
+ }
+ }
+
+ // Destructor removes thread from Thread_Manager.
+ return 0;
+}
+
+static const int DEFAULT_ITERATIONS = 10000;
+
+// Define a ACE_Task that will serve in the tests related to tasks.
+
+class ThrMgr_Task : public ACE_Task_Base {
+public:
+ ThrMgr_Task (ACE_Thread_Manager *);
+
+ virtual int svc (void);
+
+ static int errors;
+};
+
+int ThrMgr_Task::errors = 0;
+
+// Just be sure to set the ACE_Thread_Manager correctly.
+ThrMgr_Task::ThrMgr_Task (ACE_Thread_Manager *mgr)
+ : ACE_Task_Base (mgr)
+{
+}
+
+// svc just waits til it's been cancelled, then exits.
+int
+ThrMgr_Task::svc (void)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Task 0x%x, thread %t waiting to be cancelled\n"),
+ this));
+ ACE_thread_t me = ACE_Thread::self ();
+ for (int i = 0; i < 30 && !this->thr_mgr ()->testcancel (me); ++i)
+ ACE_OS::sleep (1);
+
+ if (this->thr_mgr ()->testcancel (me))
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Task 0x%x, thread %t cancelled; exiting\n"),
+ this));
+ }
+ else
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Task 0x%x, thread %t was not cancelled\n"),
+ this));
+ ++ThrMgr_Task::errors;
+ }
+ return 0;
+}
+
+
+// This function tests the task-based record keeping functions.
+static int
+test_task_record_keeping (ACE_Thread_Manager *mgr)
+{
+
+ int status = 0;
+
+ ThrMgr_Task t1 (mgr), t2 (mgr);
+ int t1_grp (20), t2_grp (30);
+
+ // Start two tasks, with multiple threads per task. Make sure that
+ // task_all_list() works.
+ if (-1 == t1.activate (THR_JOINABLE, 2, 0,
+ ACE_DEFAULT_THREAD_PRIORITY, t1_grp))
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("activate")), 1);
+ if (-1 == t2.activate (THR_JOINABLE, 3, 0,
+ ACE_DEFAULT_THREAD_PRIORITY, t2_grp))
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("activate")), 1);
+
+ ACE_Task_Base *task_list[10];
+ int num_tasks = mgr->task_all_list (task_list, 10);
+ if (2 != num_tasks)
+ {
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("Expected 2 tasks; got %d\n"),
+ num_tasks));
+ status = 1;
+ }
+ else
+ {
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Got %d tasks - correct\n"), num_tasks));
+ if (((task_list[0] == &t1 && task_list[1] == &t2)
+ || (task_list[1] == &t1 && task_list[0] == &t2))
+ && task_list[0] != task_list[1])
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("The Task IDs are correct\n")));
+ else
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("But Task ID values are wrong!\n")));
+ }
+ ACE_DEBUG ((LM_DEBUG, "Canceling grp %d\n", t1_grp));
+ if (-1 == mgr->cancel_grp (t1_grp))
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("cancel_grp")),
+ 1);
+ ACE_DEBUG ((LM_DEBUG, "Canceling grp %d\n", t2_grp));
+ if (-1 == mgr->cancel_grp (t2_grp))
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("cancel_grp")),
+ 1);
+
+ mgr->wait ();
+ if (ThrMgr_Task::errors > 0 && status == 0)
+ status = 1;
+
+ return status;
+}
+
+#endif /* ACE_HAS_THREADS */
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("Thread_Manager_Test"));
+ int status = 0;
+
+#if defined (ACE_HAS_THREADS)
+ size_t n_iterations = DEFAULT_ITERATIONS;
+
+ u_int i;
+
+ // Dynamically allocate signalled so that we can control when it
+ // gets deleted. Specifically, we need to delete it before the main
+ // thread's TSS is cleaned up.
+ ACE_NEW_RETURN (signalled,
+ ACE_thread_t[n_threads],
+ 1);
+ // Initialize each ACE_thread_t to avoid Purify UMR's.
+ for (i = 0; i < n_threads; ++i)
+ signalled[i] = ACE_OS::NULL_thread;
+
+ // And similarly, dynamically allocate the thread_start barrier.
+ ACE_NEW_RETURN (thread_start,
+ ACE_Barrier (n_threads + 1),
+ -1);
+
+ // Register a signal handler.
+ ACE_Sig_Action sa ((ACE_SignalHandler) handler, SIGINT);
+ ACE_UNUSED_ARG (sa);
+
+ ACE_Thread_Manager *thr_mgr = ACE_Thread_Manager::instance ();
+
+#if defined (ACE_VXWORKS) && !defined (ACE_HAS_PTHREADS)
+ // Assign thread (VxWorks task) names to test that feature.
+ ACE_thread_t *thread_name;
+ ACE_NEW_RETURN (thread_name,
+ ACE_thread_t[n_threads],
+ -1);
+
+ // And test the ability to specify stack size.
+ size_t *stack_size;
+ ACE_NEW_RETURN (stack_size,
+ size_t[n_threads],
+ -1);
+
+ for (i = 0; i < n_threads; ++i)
+ {
+ if (i < n_threads - 1)
+ {
+ ACE_NEW_RETURN (thread_name[i],
+ char[32],
+ -1);
+ ACE_OS::sprintf (thread_name[i],
+ ACE_TEXT ("thread%u"),
+ i);
+ }
+ else
+ // Pass an ACE_thread_t pointer of 0 for the last thread name.
+ thread_name[n_threads - 1] = 0;
+
+ stack_size[i] = 40000;
+ }
+#endif /* ACE_VXWORKS && !ACE_HAS_PTHREADS */
+
+ int grp_id = thr_mgr->spawn_n
+ (
+#if defined (ACE_VXWORKS) && !defined (ACE_HAS_PTHREADS)
+ thread_name,
+#endif /* ACE_VXWORKS && !ACE_HAS_PTHREADS */
+ n_threads,
+ (ACE_THR_FUNC) worker,
+ reinterpret_cast <void *> (n_iterations),
+ THR_BOUND
+#if defined (ACE_VXWORKS) && !defined (ACE_HAS_PTHREADS)
+ , ACE_DEFAULT_THREAD_PRIORITY
+ , -1
+ , 0
+ , stack_size
+#endif /* ACE_VXWORKS */
+ );
+
+ ACE_ASSERT (grp_id != -1);
+ thread_start->wait ();
+
+ // Wait for 1 second and then suspend every thread in the group.
+ ACE_OS::sleep (1);
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) suspending group\n")));
+ if (thr_mgr->suspend_grp (grp_id) == -1)
+ {
+ // Pthreads w/o UNIX 98 extensions doesn't support suspend/resume,
+ // so it's allowed to ENOTSUP; anything else is a hard fail.
+ ACE_ASSERT (errno == ENOTSUP);
+ ACE_DEBUG((LM_DEBUG,
+ ACE_TEXT (" OK: suspend_grp isn't supported with ")
+ ACE_TEXT ("Pthreads\n")));
+ }
+
+ // Wait for 1 more second and then resume every thread in the
+ // group.
+ ACE_OS::sleep (ACE_Time_Value (1));
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) resuming group\n")));
+
+ if (thr_mgr->resume_grp (grp_id) == -1)
+ {
+ ACE_ASSERT (errno == ENOTSUP);
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT (" OK: resume_grp isn't supported with ")
+ ACE_TEXT ("Pthreads\n")));
+ }
+
+ // Wait for 1 more second and then send a SIGINT to every thread in
+ // the group.
+ ACE_OS::sleep (ACE_Time_Value (1));
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) signaling group\n")));
+
+#if defined (ACE_HAS_WTHREADS)
+ thr_mgr->kill_grp (grp_id,
+ SIGINT);
+#elif !defined (ACE_HAS_PTHREADS_DRAFT4) && !defined(ACE_LACKS_PTHREAD_KILL)
+#if defined (CHORUS)
+ ACE_ASSERT (thr_mgr->kill_grp (grp_id,
+ SIGTHREADKILL) != -1);
+#else
+ ACE_ASSERT (thr_mgr->kill_grp (grp_id,
+ SIGINT) != -1);
+#endif /* CHORUS */
+#else
+ if (thr_mgr->kill_grp (grp_id,
+ SIGINT) == -1)
+ ACE_ASSERT (errno == ENOTSUP);
+#endif /* ACE_HAS_WTHREADS */
+
+ // Wait and then cancel all the threads.
+ ACE_OS::sleep (ACE_Time_Value (1));
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) cancelling group\n")));
+
+ ACE_ASSERT (thr_mgr->cancel_grp (grp_id) != -1);
+
+ // Perform a barrier wait until all the threads have shut down.
+ // But, wait for a limited time, just in case.
+ const ACE_Time_Value max_wait (600);
+ const ACE_Time_Value wait_time (ACE_OS::gettimeofday () + max_wait);
+ if (thr_mgr->wait (&wait_time) == -1)
+ {
+ if (errno == ETIME)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("maximum wait time of %d msec exceeded\n"),
+ max_wait.msec ()));
+ else
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("%p\n"), ACE_TEXT ("wait")));
+ status = -1;
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) main thread finished\n")));
+
+#if defined (ACE_VXWORKS) && !defined (ACE_HAS_PTHREADS)
+ for (i = 0; i < n_threads - 1; ++i)
+ {
+ delete [] thread_name[i];
+ // Don't delete the last thread_name, because it points to the
+ // name in the TCB. It was initially 0.
+ }
+ delete [] thread_name;
+ delete [] stack_size;
+#endif /* ACE_VXWORKS && !ACE_HAS_PTHREADS */
+
+ delete thread_start;
+ thread_start = 0;
+ delete [] signalled;
+ signalled = 0;
+
+ // Now test task record keeping
+ if (test_task_record_keeping (thr_mgr) != 0)
+ status = -1;
+
+#else
+ ACE_ERROR ((LM_INFO,
+ ACE_TEXT ("threads not supported on this platform\n")));
+#endif /* ACE_HAS_THREADS */
+
+ ACE_END_TEST;
+ return status;
+}
diff --git a/ACE/tests/Thread_Mutex_Test.cpp b/ACE/tests/Thread_Mutex_Test.cpp
new file mode 100644
index 00000000000..a463e72b523
--- /dev/null
+++ b/ACE/tests/Thread_Mutex_Test.cpp
@@ -0,0 +1,276 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Thread_Mutex_Test.cpp
+//
+// = DESCRIPTION
+// This test illustrates the functionality of the
+// ACE_Thread_Mutex. The test acquires and releases mutexes. No
+// command line arguments are needed to run the test.
+//
+// = AUTHOR
+// Prashant Jain <pjain@cs.wustl.edu> and Douglas C. Schmidt <schmidt@cs.wustl.edu>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/Thread_Manager.h"
+#include "ace/OS_NS_sys_time.h"
+#include "ace/OS_NS_time.h"
+#include "ace/OS_NS_unistd.h"
+
+ACE_RCSID(tests, Thread_Mutex_Test, "$Id$")
+
+#if defined (ACE_HAS_THREADS)
+
+#include "ace/Guard_T.h"
+
+// For all platforms except for Windows use the ACE_Thread_Mutex.
+// Since Windows only supports timed process mutexes and not
+// timed thread mutexes, use ACE_Process_Mutex.
+#if defined (ACE_HAS_WTHREADS)
+# include "ace/Process_Mutex.h"
+ typedef ACE_Process_Mutex ACE_TEST_MUTEX;
+#else
+# include "ace/Thread_Mutex.h"
+ typedef ACE_Thread_Mutex ACE_TEST_MUTEX;
+#endif
+
+#if !defined (ACE_HAS_MUTEX_TIMEOUTS)
+static int reported_notsup = 0;
+#endif /* ACE_HAS_MUTEX_TIMEOUTS */
+
+static void *
+test (void *args)
+{
+ ACE_TEST_MUTEX *mutex = (ACE_TEST_MUTEX *) args;
+ ACE_UNUSED_ARG (mutex); // Suppress ghs warning about unused local "mutex".
+ ACE_OS::srand (ACE_OS::time (0));
+
+ for (size_t i = 0; i < ACE_MAX_ITERATIONS / 2; i++)
+ {
+ int result = 0;
+
+ // First attempt to acquire the mutex with a timeout to verify
+ // that mutex timeouts are working.
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) = trying timed acquire on ")
+ ACE_TEXT ("iteration %d\n"),
+ i));
+
+ ACE_Time_Value delta (1, 0); // One second timeout
+ ACE_Time_Value timeout = ACE_OS::gettimeofday ();
+ timeout += delta; // Must pass absolute time to acquire().
+
+ if (mutex->acquire (timeout) != 0)
+ {
+ if (errno == ETIME)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) = mutex acquisition ")
+ ACE_TEXT ("timed out\n")));
+ else if (errno == ENOTSUP)
+ {
+#if !defined (ACE_HAS_MUTEX_TIMEOUTS)
+ if (!reported_notsup)
+ {
+ ACE_DEBUG ((LM_INFO,
+ ACE_TEXT ("(%P|%t) %p, but ACE_HAS_MUTEX_TIMEOUTS is not defined - Ok\n"),
+ ACE_TEXT ("mutex timed acquire")));
+ reported_notsup = 1;
+ }
+#else
+ ACE_DEBUG ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p - maybe ACE_HAS_MUTEX_TIMEOUTS should not be defined?\n"),
+ ACE_TEXT ("mutex timed acquire")));
+#endif /* ACE_HAS_MUTEX_TIMEOUTS */
+ }
+ else
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) %p\n%a"),
+ ACE_TEXT ("mutex timeout failed\n")));
+ return 0;
+ }
+ }
+ else
+ {
+ result = mutex->release ();
+ ACE_ASSERT (result == 0);
+ }
+
+ // Now try the standard mutex.
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) = trying to acquire on iteration %d\n"),
+ i));
+ result = mutex->acquire ();
+ ACE_ASSERT (result == 0);
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) = acquired on iteration %d\n"),
+ i));
+
+ // Sleep for a random amount of time between 0 and 2 seconds.
+ // Note that it's ok to use rand() here because we are running
+ // within the critical section defined by the Thread_Mutex.
+ ACE_OS::sleep (ACE_OS::rand () % 2);
+
+ result = mutex->release ();
+ ACE_ASSERT (result == 0);
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%P|%t) = released on iteration %d\n"),
+ i));
+
+ // Basic ACE_Guard usage - automatically acquire the mutex on
+ // guard construction and automatically release it on
+ // destruction.
+ {
+ // Construct an ACE_Guard to implicitly acquire the mutex.
+ ACE_Guard<ACE_TEST_MUTEX> guard (*mutex);
+ ACE_ASSERT (guard.locked () != 0);
+
+ // Perform some operation which might exit the current scope
+ // prematurely, e.g. by returning or throwing an exception.
+ // ...
+
+ // ACE_Guard object is destroyed when exiting scope and guard
+ // destructor automatically releases mutex.
+ }
+
+ // Use an ACE_Guard to automatically acquire a mutex, but release
+ // the mutex early.
+ {
+ // Construct an ACE_Guard to implicitly acquire the mutex.
+ ACE_Guard<ACE_TEST_MUTEX> guard (*mutex);
+ ACE_ASSERT (guard.locked () != 0);
+
+ // Perform some operation which might exit the current scope
+ // prematurely, e.g. by returning or throwing an exception.
+ // ...
+
+ // Release the mutex since we no longer need it.
+ guard.release ();
+ ACE_ASSERT (guard.locked () == 0);
+
+ // Do something else which does not require the mutex to be locked.
+ // ...
+
+ // ACE_Guard object's destructor will not release the mutex.
+ }
+
+ // Use an ACE_Guard to automatically acquire a mutex, but
+ // relinquish ownership of the lock so that the mutex is not
+ // automatically released on guard destruction. This is useful
+ // when an operation might not release the mutex in some
+ // conditions, in which case responsibility for releasing it is
+ // passed to someone else.
+ {
+ // Construct an ACE_Guard to implicitly acquire the mutex.
+ ACE_Guard<ACE_TEST_MUTEX> guard (*mutex);
+ ACE_ASSERT (guard.locked () != 0);
+
+ // Perform some operation which might exit the current scope
+ // prematurely, e.g. by returning or throwing an exception.
+ // ...
+
+ // Relinquish ownership of the mutex lock. Someone else must
+ // now release it.
+ guard.disown ();
+ ACE_ASSERT (guard.locked () == 0);
+
+ // ACE_Guard object's destructor will not release the mutex.
+ }
+ // We are now responsible for releasing the mutex.
+ result = mutex->release ();
+ ACE_ASSERT (result == 0);
+
+ // Construct an ACE_Guard without automatically acquiring the lock.
+ {
+ // Construct an ACE_Guard object without automatically
+ // acquiring the mutex or taking ownership of an existing
+ // lock. The third parameter tells the guard that the mutex
+ // has not been locked.
+ ACE_Guard<ACE_TEST_MUTEX> guard (*mutex, 0, 0);
+ ACE_ASSERT (guard.locked () == 0);
+
+ // Conditionally acquire the mutex.
+ if (i % 2 == 0)
+ {
+ guard.acquire ();
+ ACE_ASSERT (guard.locked () != 0);
+ }
+
+ // Perform some operation that might exit the current scope
+ // prematurely, e.g. by returning or throwing an exception.
+ // ...
+
+ // ACE_Guard object is destroyed when exiting scope and guard
+ // destructor automatically releases if it was acquired above.
+ }
+
+ // Use an ACE_Guard to take ownership of a previously acquired
+ // mutex.
+ timeout = ACE_OS::gettimeofday ();
+ timeout += delta; // Must pass absolute time to acquire().
+ if (mutex->acquire (timeout) == 0)
+ {
+ // Construct an ACE_Guard object without automatically
+ // acquiring the mutex, but instead take ownership of the
+ // existing lock. The third parameter tells the guard that
+ // the mutex has already been locked.
+ ACE_Guard<ACE_TEST_MUTEX> guard (*mutex, 0, 1);
+ ACE_ASSERT (guard.locked () != 0);
+
+ // Perform some operation which might exit the current scope
+ // prematurely, e.g. by returning or throwing an exception.
+ // ...
+
+ // ACE_Guard object is destroyed when exiting scope and guard
+ // destructor automatically releases mutex.
+ }
+ }
+
+ return 0;
+}
+#endif /* ACE_HAS_THREADS */
+
+static void
+spawn (void)
+{
+#if defined (ACE_HAS_THREADS)
+ ACE_TEST_MUTEX mutex;
+
+ const u_int n_threads = ACE_MAX_THREADS;
+
+ if (ACE_Thread_Manager::instance ()->spawn_n (n_threads,
+ ACE_THR_FUNC (test),
+ (void *) &mutex,
+ THR_NEW_LWP | THR_DETACHED) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("%p\n%a"),
+ ACE_TEXT ("thread create failed")));
+
+ // Wait for the threads to exit.
+ ACE_Thread_Manager::instance ()->wait ();
+
+#else
+ ACE_ERROR ((LM_INFO,
+ ACE_TEXT ("threads not supported on this platform\n")));
+#endif /* ACE_HAS_THREADS */
+}
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("Thread_Mutex_Test"));
+
+ spawn ();
+
+ ACE_END_TEST;
+ return 0;
+}
diff --git a/ACE/tests/Thread_Pool_Reactor_Resume_Test.cpp b/ACE/tests/Thread_Pool_Reactor_Resume_Test.cpp
new file mode 100644
index 00000000000..327ef0bc917
--- /dev/null
+++ b/ACE/tests/Thread_Pool_Reactor_Resume_Test.cpp
@@ -0,0 +1,391 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Thread_Pool_Reactor_Resume_Test.cpp
+//
+// = DESCRIPTION
+// This program is an additional torture test of thread pool
+// reactors. This test is based on Thread_Pool_Reactor_Test.cpp
+// in $ACE_ROOT/tests. This test differs from the other one
+// slightly. The TP reactor is instantiated with the
+// with a value of 1 for the <resume_flag> argument. The server
+// threads during the handle_input call resumes the handle that
+// would have been suspended by the reactor.
+//
+// Usage: Thread_Pool_Reactor_Test [-r <hostname:port#>]
+// [-s <server thr#>] [-c <client thr#>] [-d <delay>]
+// [-i <client conn attempt#>] [-n <client request# per conn>]
+//
+// Default value:
+// <hostname:port#>: ACE_DEFAULT_RENDEZVOUS
+// <server thr#>: ACE_MAX_THREADS
+// <client thr#>: ACE_MAX_ITERATIONS
+// <client conn attempt#>: ACE_MAX_ITERATIONS
+// <client req# per conn>: ACE_MAX_THREADS
+// <delay>: 50 usec
+//
+// = AUTHOR
+// Balachandran Natarajan <bala@cs.wustl.edu>
+//
+// ============================================================================
+
+#include "tests/test_config.h"
+#include "ace/OS_NS_string.h"
+#include "ace/OS_NS_unistd.h"
+#include "ace/Get_Opt.h"
+#include "ace/SOCK_Connector.h"
+#include "ace/SOCK_Acceptor.h"
+#include "ace/Acceptor.h"
+#include "ace/Thread_Manager.h"
+#include "ace/TP_Reactor.h"
+
+ACE_RCSID(tests, Atomic_Op_Test, "$Id$")
+
+#if defined (ACE_HAS_THREADS)
+
+#include "tests/Thread_Pool_Reactor_Resume_Test.h"
+typedef ACE_Strategy_Acceptor <Request_Handler, ACE_SOCK_ACCEPTOR> ACCEPTOR;
+
+// Accepting end point. This is actually "localhost:10010", but some
+// platform couldn't resolve the name so we use the IP address
+// directly here.
+static const ACE_TCHAR *rendezvous = ACE_TEXT ("127.0.0.1:10010");
+
+// Total number of server threads.
+static size_t svr_thrno = ACE_MAX_THREADS;
+
+
+#if defined (CHORUS) \
+ || defined (ACE_VXWORKS) // default network parameters (MAX_BINDS and system buffers) are too small for full test
+ // Add platforms that can't handle too many
+ // connection simultaneously here.
+#define ACE_LOAD_FACTOR /2
+#else
+#define ACE_LOAD_FACTOR
+#endif
+
+// Total number of client threads.
+static size_t cli_thrno = ACE_MAX_THREADS ACE_LOAD_FACTOR;
+
+// Total connection attemps of a client thread.
+static size_t cli_conn_no = ACE_MAX_ITERATIONS ACE_LOAD_FACTOR;
+
+// Total requests a client thread sends.
+static size_t cli_req_no = ACE_MAX_THREADS ACE_LOAD_FACTOR;
+
+// Delay before a thread sending the next request (in msec.)
+static int req_delay = 50;
+
+static void
+parse_arg (int argc, ACE_TCHAR *argv[])
+{
+ ACE_Get_Opt getopt (argc, argv, ACE_TEXT ("r:s:c:d:i:n:"));
+
+ int c;
+
+ while ((c = getopt ()) != -1)
+ {
+ switch (c)
+ {
+ case 'r': // hostname:port
+ rendezvous = getopt.opt_arg ();
+ break;
+ case 's':
+ svr_thrno = ACE_OS::atoi (getopt.opt_arg ());
+ break;
+ case 'c':
+ cli_thrno = ACE_OS::atoi (getopt.opt_arg ());
+ break;
+ case 'd':
+ req_delay = ACE_OS::atoi (getopt.opt_arg ());
+ break;
+ case 'i':
+ cli_conn_no = ACE_OS::atoi (getopt.opt_arg ());
+ break;
+ case 'n':
+ cli_req_no = ACE_OS::atoi (getopt.opt_arg ());
+ break;
+ default:
+ ACE_ERROR ((LM_ERROR,
+ "Usage: Thread_Pool_Reactor_Resume_Test [-r <hostname:port#>]"
+ "\t[-s <server thr#>] [-c <client thr#>] [-d <delay>]"
+ "\t[-i <client conn attempt#>]"
+ "[-n <client request# per conn>]\n"));
+ break;
+ }
+ }
+}
+
+Request_Handler::Request_Handler (ACE_Thread_Manager *thr_mgr)
+ : ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_MT_SYNCH> (thr_mgr),
+ nr_msgs_rcvd_(0)
+{
+ // Enable reference counting.
+ this->reference_counting_policy ().value
+ (ACE_Event_Handler::Reference_Counting_Policy::ENABLED);
+
+ // Make sure we use TP_Reactor with this class (that's the whole
+ // point, right?)
+ this->reactor (ACE_Reactor::instance ());
+}
+
+int
+Request_Handler::open (void *arg)
+{
+ // Open base class.
+ int result =
+ ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_MT_SYNCH>::open (arg);
+
+ // Return on error.
+ if (result == -1)
+ return -1;
+
+ // Else we have successfully registered with the Reactor. Give our
+ // ownership to the Reactor.
+ this->remove_reference ();
+
+ // Return result.
+ return result;
+}
+
+Request_Handler::~Request_Handler (void)
+{
+}
+
+int
+Request_Handler::resume_handler (void)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) resume_handler () called \n")));
+ return 1;
+}
+
+int
+Request_Handler::handle_input (ACE_HANDLE fd)
+{
+ ACE_TCHAR buffer[BUFSIZ];
+ ACE_TCHAR len = 0;
+ ssize_t result = this->peer ().recv (&len, sizeof (ACE_TCHAR));
+
+ if (result > 0
+ && this->peer ().recv_n (buffer, len * sizeof (ACE_TCHAR))
+ == static_cast<ssize_t> (len * sizeof (ACE_TCHAR)))
+ {
+ ++this->nr_msgs_rcvd_;
+
+ // Now the handle_input method has done what it can do, namely
+ // read the data from the socket we can just resume the handler
+ // at this point
+ ACE_DEBUG ((LM_DEBUG,
+ "(%t) svr input; fd: 0x%x; input: %s\n",
+ fd,
+ buffer));
+ if (ACE_OS::strcmp (buffer, ACE_TEXT ("shutdown")) == 0)
+ ACE_Reactor::instance()->end_reactor_event_loop ();
+
+ this->reactor ()->resume_handler (fd);
+ return 0;
+ }
+ else
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ "(%t) Errno is %d and result is %d\n",
+ errno, result));
+ ACE_DEBUG ((LM_DEBUG,
+ "(%t) Request_Handler: 0x%x peer closed (0x%x)\n",
+ this, fd));
+ }
+ return -1;
+}
+
+int
+Request_Handler::handle_close (ACE_HANDLE fd, ACE_Reactor_Mask)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ "(%t) svr close; fd: 0x%x, rcvd %d msgs\n",
+ fd,
+ this->nr_msgs_rcvd_));
+ if (this->nr_msgs_rcvd_ != cli_req_no)
+ ACE_ERROR((LM_ERROR,
+ "(%t) Handler 0x%x: Expected %d messages; got %d\n",
+ this,
+ cli_req_no,
+ this->nr_msgs_rcvd_));
+
+ return 0;
+}
+
+static int
+reactor_event_hook (ACE_Reactor *)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ "(%t) handling events ....\n"));
+
+ return 0;
+}
+
+static ACE_THR_FUNC_RETURN
+svr_worker (void *)
+{
+ // Server thread function.
+ int result =
+ ACE_Reactor::instance ()->run_reactor_event_loop (&reactor_event_hook);
+
+ if (result == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "(%t) %p\n",
+ "Error handling events"),
+ 0);
+
+ ACE_DEBUG ((LM_DEBUG,
+ "(%t) I am done handling events. Bye, bye\n"));
+
+ return 0;
+}
+
+static ACE_THR_FUNC_RETURN
+cli_worker (void *arg)
+{
+ // Client thread function.
+ ACE_INET_Addr addr (rendezvous);
+ ACE_SOCK_Stream stream;
+ ACE_SOCK_Connector connect;
+ ACE_Time_Value delay (0, req_delay);
+ size_t len = * reinterpret_cast<ACE_TCHAR *> (arg);
+
+ for (size_t i = 0 ; i < cli_conn_no; i++)
+ {
+ if (connect.connect (stream, addr) < 0)
+ {
+ ACE_ERROR ((LM_ERROR,
+ "(%t) %p\n",
+ "connect"));
+ continue;
+ }
+
+ for (size_t j = 0; j < cli_req_no; j++)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ "(%t) conn_worker handle = %x, req = %d\n",
+ stream.get_handle (),
+ j+1));
+ if (stream.send_n (arg,
+ (len + 1) * sizeof (ACE_TCHAR)) == -1)
+ {
+ ACE_ERROR ((LM_ERROR,
+ "(%t) %p\n",
+ "send_n"));
+ continue;
+ }
+ ACE_OS::sleep (delay);
+ }
+
+ stream.close ();
+ }
+
+ return 0;
+}
+
+static ACE_THR_FUNC_RETURN
+worker (void *)
+{
+ ACE_OS::sleep (3);
+ const ACE_TCHAR *msg = ACE_TEXT ("Message from Connection worker");
+ ACE_TCHAR buf [BUFSIZ];
+ buf[0] = static_cast<ACE_TCHAR> ((ACE_OS::strlen (msg) + 1));
+ ACE_OS::strcpy (&buf[1], msg);
+
+ ACE_INET_Addr addr (rendezvous);
+
+ ACE_DEBUG((LM_DEBUG,
+ "(%t) Spawning %d client threads...\n",
+ cli_thrno));
+ int grp = ACE_Thread_Manager::instance ()->spawn_n (cli_thrno,
+ &cli_worker,
+ buf);
+ ACE_ASSERT (grp != -1);
+
+ ACE_Thread_Manager::instance ()->wait_grp (grp);
+
+ ACE_DEBUG ((LM_DEBUG,
+ "(%t) Client threads done; shutting down...\n"));
+ ACE_SOCK_Stream stream;
+ ACE_SOCK_Connector connect;
+
+ if (connect.connect (stream, addr) == -1)
+ ACE_ERROR ((LM_ERROR,
+ "(%t) %p Error while connecting\n",
+ "connect"));
+
+ const ACE_TCHAR *sbuf = ACE_TEXT ("\011shutdown");
+
+ ACE_DEBUG ((LM_DEBUG,
+ "shutdown stream handle = %x\n",
+ stream.get_handle ()));
+
+ if (stream.send_n (sbuf, (ACE_OS::strlen (sbuf) + 1) * sizeof (ACE_TCHAR)) == -1)
+ ACE_ERROR ((LM_ERROR,
+ "(%t) %p\n",
+ "send_n"));
+
+ ACE_DEBUG ((LM_DEBUG,
+ "Sent message of length = %d\n",
+ ACE_OS::strlen (sbuf)));
+ stream.close ();
+
+ return 0;
+}
+
+int
+run_main (int argc, ACE_TCHAR *argv[])
+{
+ ACE_START_TEST (ACE_TEXT ("Thread_Pool_Reactor_Resume_Test"));
+ parse_arg (argc, argv);
+
+ // Changed the default
+ ACE_TP_Reactor sr;
+
+
+ ACE_Reactor new_reactor (&sr);
+ ACE_Reactor::instance (&new_reactor);
+
+ ACCEPTOR acceptor;
+ ACE_INET_Addr accept_addr (rendezvous);
+
+ if (acceptor.open (accept_addr) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("open")),
+ 1);
+
+ ACE_DEBUG((LM_DEBUG,
+ ACE_TEXT ("(%t) Spawning %d server threads...\n"),
+ svr_thrno));
+ ACE_Thread_Manager::instance ()->spawn_n (svr_thrno,
+ svr_worker);
+ ACE_Thread_Manager::instance ()->spawn (worker);
+
+ ACE_Thread_Manager::instance ()->wait ();
+
+ ACE_END_TEST;
+ return 0;
+}
+
+#else
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("Thread_Pool_Reactor_Test"));
+
+ ACE_ERROR ((LM_INFO,
+ "threads not supported on this platform\n"));
+
+ ACE_END_TEST;
+ return 0;
+}
+#endif /* ACE_HAS_THREADS */
diff --git a/ACE/tests/Thread_Pool_Reactor_Resume_Test.h b/ACE/tests/Thread_Pool_Reactor_Resume_Test.h
new file mode 100644
index 00000000000..f3f18a5c712
--- /dev/null
+++ b/ACE/tests/Thread_Pool_Reactor_Resume_Test.h
@@ -0,0 +1,56 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Thread_Pool_Reactor_Test.h
+//
+// = DESCRIPTION
+// This class gets its own header file to work around AIX C++
+// compiler "features" related to template instantiation... It is
+// only used by Thread_Pool_Reactor_Test.cpp.
+//
+// = AUTHOR
+// Irfan Pyarali <irfan@cs.wustl.edu>
+// Nanbor Wang <nanbor@cs.wustl.edu>
+//
+// ============================================================================
+
+#ifndef ACE_TESTS_THREAD_POOL_REACTOR_RESUME_TEST_H
+#define ACE_TESTS_THREAD_POOL_REACTOR_RESUME_TEST_H
+
+#include "ace/SOCK_Stream.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "ace/Svc_Handler.h"
+
+class Request_Handler : public ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_MT_SYNCH>
+{
+ // = TITLE
+ // This class is the Svc_Handler used by <Acceptor>.
+public:
+
+ /// The default constructor makes sure the right reactor is used.
+ Request_Handler (ACE_Thread_Manager *tm = 0);
+
+ /// Dtor..
+ ~Request_Handler (void);
+
+ virtual int open (void * = 0);
+
+protected:
+ virtual int handle_input (ACE_HANDLE fd = ACE_INVALID_HANDLE);
+ virtual int handle_close (ACE_HANDLE fd, ACE_Reactor_Mask = 0);
+ virtual int resume_handler (void);
+
+private:
+ size_t nr_msgs_rcvd_;
+};
+
+#endif /* ACE_TESTS_THREAD_POOL_REACTOR_RESUME_TEST_H */
diff --git a/ACE/tests/Thread_Pool_Reactor_Test.cpp b/ACE/tests/Thread_Pool_Reactor_Test.cpp
new file mode 100644
index 00000000000..ff0c3098e80
--- /dev/null
+++ b/ACE/tests/Thread_Pool_Reactor_Test.cpp
@@ -0,0 +1,344 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Thread_Pool_Reactor_Test.cpp
+//
+// = DESCRIPTION
+// This program is a torture test of thread pool reactors. It
+// starts by spawning several server threads waiting to handle
+// events. Several other client threads are spawned right after
+// to initiate connections to server threads. Each connection
+// adds a new Svc_Handler into the TP_Reactor and sends out
+// several "requests" to the server thread. After the connection
+// is closed, the Svc_Handler is removed from the TP_Reactor.
+// Each message is treated as a separate request by the server so
+// two consecutive requests might be serviced by two different
+// threads.
+//
+// Usage: Thread_Pool_Reactor_Test [-r <hostname:port#>]
+// [-s <server thr#>] [-c <client thr#>] [-d <delay>]
+// [-i <client conn attempt#>] [-n <client request# per conn>]
+//
+// Default value:
+// <hostname:port#>: ACE_DEFAULT_RENDEZVOUS
+// <server thr#>: ACE_MAX_THREADS
+// <client thr#>: ACE_MAX_ITERATIONS
+// <client conn attempt#>: ACE_MAX_ITERATIONS
+// <client req# per conn>: ACE_MAX_THREADS
+// <delay>: 50 usec
+//
+// = AUTHOR
+// Irfan Pyarali <irfan@cs.wustl.edu> and
+// Nanbor Wang <nanbor@cs.wustl.edu>
+//
+// ============================================================================
+
+#include "tests/test_config.h"
+#include "ace/OS_NS_string.h"
+#include "ace/OS_NS_unistd.h"
+#include "ace/Get_Opt.h"
+#include "ace/SOCK_Connector.h"
+#include "ace/SOCK_Acceptor.h"
+#include "ace/Acceptor.h"
+#include "ace/Thread_Manager.h"
+#include "ace/TP_Reactor.h"
+
+ACE_RCSID(tests, Atomic_Op_Test, "$Id$")
+
+#if defined (ACE_HAS_THREADS)
+
+#include "tests/Thread_Pool_Reactor_Test.h"
+typedef ACE_Strategy_Acceptor <Request_Handler, ACE_SOCK_ACCEPTOR> ACCEPTOR;
+
+// Accepting end point. This is actually "localhost:10010", but some
+// platform couldn't resolve the name so we use the IP address
+// directly here.
+static const ACE_TCHAR *rendezvous = ACE_TEXT ("127.0.0.1:10010");
+
+// Total number of server threads.
+static size_t svr_thrno = ACE_MAX_THREADS;
+
+#if defined (CHORUS) \
+ || defined (ACE_VXWORKS) // default network parameters (MAX_BINDS and system buffers) are too small for full test
+ // Add platforms that can't handle too many
+ // connection simultaneously here.
+#define ACE_LOAD_FACTOR /2
+#else
+#define ACE_LOAD_FACTOR
+#endif
+
+// Total number of client threads.
+static size_t cli_thrno = ACE_MAX_THREADS ACE_LOAD_FACTOR;
+
+// Total connection attemps of a client thread.
+static size_t cli_conn_no = ACE_MAX_ITERATIONS ACE_LOAD_FACTOR;
+
+// Total requests a client thread sends.
+static size_t cli_req_no = ACE_MAX_THREADS ACE_LOAD_FACTOR;
+
+// Delay before a thread sending the next request (in msec.)
+static int req_delay = 50;
+
+static void
+parse_arg (int argc, ACE_TCHAR *argv[])
+{
+ ACE_Get_Opt getopt (argc, argv, ACE_TEXT ("r:s:c:d:i:n:"));
+
+ int c;
+
+ while ((c = getopt ()) != -1)
+ {
+ switch (c)
+ {
+ case 'r': // hostname:port
+ rendezvous = getopt.opt_arg ();
+ break;
+ case 's':
+ svr_thrno = ACE_OS::atoi (getopt.opt_arg ());
+ break;
+ case 'c':
+ cli_thrno = ACE_OS::atoi (getopt.opt_arg ());
+ break;
+ case 'd':
+ req_delay = ACE_OS::atoi (getopt.opt_arg ());
+ break;
+ case 'i':
+ cli_conn_no = ACE_OS::atoi (getopt.opt_arg ());
+ break;
+ case 'n':
+ cli_req_no = ACE_OS::atoi (getopt.opt_arg ());
+ break;
+ default:
+ ACE_ERROR ((LM_ERROR,
+ "Usage: Thread_Pool_Reactor_Test [-r <hostname:port#>]"
+ "\t[-s <server thr#>] [-c <client thr#>] [-d <delay>]"
+ "\t[-i <client conn attempt#>]"
+ "[-n <client request# per conn>]\n"));
+ break;
+ }
+ }
+}
+
+Request_Handler::Request_Handler (ACE_Thread_Manager *thr_mgr)
+ : ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_MT_SYNCH> (thr_mgr),
+ nr_msgs_rcvd_(0)
+{
+ // Make sure we use TP_Reactor with this class (that's the whole
+ // point, right?)
+ this->reactor (ACE_Reactor::instance ());
+}
+
+int
+Request_Handler::handle_input (ACE_HANDLE fd)
+{
+ ACE_TCHAR buffer[BUFSIZ];
+ ACE_TCHAR len = 0;
+ ssize_t result = this->peer ().recv (&len, sizeof (ACE_TCHAR));
+
+ if (result > 0
+ && this->peer ().recv_n (buffer, len * sizeof (ACE_TCHAR))
+ == static_cast<ssize_t> (len * sizeof (ACE_TCHAR)))
+ {
+ ++this->nr_msgs_rcvd_;
+
+ ACE_DEBUG ((LM_DEBUG,
+ "(%t) svr input; fd: 0x%x; input: %s\n",
+ fd,
+ buffer));
+ if (ACE_OS::strcmp (buffer, ACE_TEXT ("shutdown")) == 0)
+ ACE_Reactor::instance()->end_reactor_event_loop ();
+ return 0;
+ }
+ else
+ ACE_DEBUG ((LM_DEBUG,
+ "(%t) Request_Handler: 0x%x peer closed (0x%x)\n",
+ this, fd));
+ return -1;
+}
+
+int
+Request_Handler::handle_close (ACE_HANDLE fd, ACE_Reactor_Mask)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ "(%t) svr close; fd: 0x%x, rcvd %d msgs\n",
+ fd,
+ this->nr_msgs_rcvd_));
+ if (this->nr_msgs_rcvd_ != cli_req_no)
+ ACE_ERROR((LM_ERROR,
+ "(%t) Handler 0x%x: Expected %d messages; got %d\n",
+ this,
+ cli_req_no,
+ this->nr_msgs_rcvd_));
+ this->destroy ();
+ return 0;
+}
+
+static int
+reactor_event_hook (ACE_Reactor *)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ "(%t) handling events ....\n"));
+
+ return 0;
+}
+
+static ACE_THR_FUNC_RETURN
+svr_worker (void *)
+{
+ // Server thread function.
+ int result =
+ ACE_Reactor::instance ()->run_reactor_event_loop (&reactor_event_hook);
+
+ if (result == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "(%t) %p\n",
+ "Error handling events"),
+ 0);
+
+ ACE_DEBUG ((LM_DEBUG,
+ "(%t) I am done handling events. Bye, bye\n"));
+
+ return 0;
+}
+
+static ACE_THR_FUNC_RETURN
+cli_worker (void *arg)
+{
+ // Client thread function.
+ ACE_INET_Addr addr (rendezvous);
+ ACE_SOCK_Stream stream;
+ ACE_SOCK_Connector connect;
+ ACE_Time_Value delay (0, req_delay);
+ size_t len = * reinterpret_cast<ACE_TCHAR *> (arg);
+
+ for (size_t i = 0 ; i < cli_conn_no; i++)
+ {
+ if (connect.connect (stream, addr) < 0)
+ {
+ ACE_ERROR ((LM_ERROR,
+ "(%t) %p\n",
+ "connect"));
+ continue;
+ }
+
+ for (size_t j = 0; j < cli_req_no; j++)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ "(%t) conn_worker handle 0x%x, req %d\n",
+ stream.get_handle (),
+ j+1));
+ if (stream.send_n (arg,
+ (len + 1) * sizeof (ACE_TCHAR)) == -1)
+ {
+ ACE_ERROR ((LM_ERROR,
+ "(%t) %p\n",
+ "send_n"));
+ continue;
+ }
+ ACE_OS::sleep (delay);
+ }
+
+ stream.close ();
+ }
+
+ return 0;
+}
+
+static ACE_THR_FUNC_RETURN
+worker (void *)
+{
+ ACE_OS::sleep (3);
+ const ACE_TCHAR *msg = ACE_TEXT ("Message from Connection worker");
+ ACE_TCHAR buf [BUFSIZ];
+ buf[0] = static_cast<ACE_TCHAR> ((ACE_OS::strlen (msg) + 1));
+ ACE_OS::strcpy (&buf[1], msg);
+
+ ACE_INET_Addr addr (rendezvous);
+
+ ACE_DEBUG((LM_DEBUG,
+ "(%t) Spawning %d client threads...\n",
+ cli_thrno));
+ int grp = ACE_Thread_Manager::instance ()->spawn_n (cli_thrno,
+ &cli_worker,
+ buf);
+ ACE_ASSERT (grp != -1);
+
+ ACE_Thread_Manager::instance ()->wait_grp (grp);
+
+ ACE_DEBUG ((LM_DEBUG,
+ "(%t) Client threads done; shutting down...\n"));
+ ACE_SOCK_Stream stream;
+ ACE_SOCK_Connector connect;
+
+ if (connect.connect (stream, addr) == -1)
+ ACE_ERROR ((LM_ERROR,
+ "(%t) %p Error while connecting\n",
+ "connect"));
+
+ const ACE_TCHAR *sbuf = ACE_TEXT ("\011shutdown");
+
+ ACE_DEBUG ((LM_DEBUG,
+ "shutdown stream handle = %x\n",
+ stream.get_handle ()));
+
+ if (stream.send_n (sbuf, (ACE_OS::strlen (sbuf) + 1) * sizeof (ACE_TCHAR)) == -1)
+ ACE_ERROR ((LM_ERROR,
+ "(%t) %p\n",
+ "send_n"));
+
+ stream.close ();
+
+ return 0;
+}
+
+int
+run_main (int argc, ACE_TCHAR *argv[])
+{
+ ACE_START_TEST (ACE_TEXT ("Thread_Pool_Reactor_Test"));
+ parse_arg (argc, argv);
+
+ // Changed the default
+ ACE_TP_Reactor sr;
+ ACE_Reactor new_reactor (&sr);
+ ACE_Reactor::instance (&new_reactor);
+
+ ACCEPTOR acceptor;
+ ACE_INET_Addr accept_addr (rendezvous);
+
+ if (acceptor.open (accept_addr) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("open")),
+ 1);
+
+ ACE_DEBUG((LM_DEBUG,
+ ACE_TEXT ("(%t) Spawning %d server threads...\n"),
+ svr_thrno));
+ ACE_Thread_Manager::instance ()->spawn_n (svr_thrno,
+ svr_worker);
+ ACE_Thread_Manager::instance ()->spawn (worker);
+
+ ACE_Thread_Manager::instance ()->wait ();
+
+ ACE_END_TEST;
+ return 0;
+}
+
+#else
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("Thread_Pool_Reactor_Test"));
+
+ ACE_ERROR ((LM_INFO,
+ "threads not supported on this platform\n"));
+
+ ACE_END_TEST;
+ return 0;
+}
+#endif /* ACE_HAS_THREADS */
diff --git a/ACE/tests/Thread_Pool_Reactor_Test.h b/ACE/tests/Thread_Pool_Reactor_Test.h
new file mode 100644
index 00000000000..0dfeab64528
--- /dev/null
+++ b/ACE/tests/Thread_Pool_Reactor_Test.h
@@ -0,0 +1,49 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Thread_Pool_Reactor_Test.h
+//
+// = DESCRIPTION
+// This class gets its own header file to work around AIX C++
+// compiler "features" related to template instantiation... It is
+// only used by Thread_Pool_Reactor_Test.cpp.
+//
+// = AUTHOR
+// Irfan Pyarali <irfan@cs.wustl.edu>
+// Nanbor Wang <nanbor@cs.wustl.edu>
+//
+// ============================================================================
+
+#ifndef ACE_TESTS_THREAD_POOL_REACTOR_TEST_H
+#define ACE_TESTS_THREAD_POOL_REACTOR_TEST_H
+
+#include "ace/SOCK_Stream.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "ace/Svc_Handler.h"
+
+class Request_Handler : public ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_MT_SYNCH>
+{
+ // = TITLE
+ // This class is the Svc_Handler used by <Acceptor>.
+public:
+ Request_Handler (ACE_Thread_Manager *tm = 0);
+ // The default constructor makes sure the right reactor is used.
+
+protected:
+ virtual int handle_input (ACE_HANDLE fd = ACE_INVALID_HANDLE);
+ virtual int handle_close (ACE_HANDLE fd, ACE_Reactor_Mask = 0);
+
+private:
+ size_t nr_msgs_rcvd_;
+};
+
+#endif /* ACE_TESTS_THREAD_POOL_REACTOR_TEST_H */
diff --git a/ACE/tests/Thread_Pool_Test.cpp b/ACE/tests/Thread_Pool_Test.cpp
new file mode 100644
index 00000000000..498404273ac
--- /dev/null
+++ b/ACE/tests/Thread_Pool_Test.cpp
@@ -0,0 +1,459 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Thread_Pool_Test.cpp
+//
+// = DESCRIPTION
+// This test program illustrates how the <ACE_Task>
+// synchronization mechanisms work in conjunction with the
+// <ACE_Thread_Manager>. If the <manual> flag is set input comes
+// from stdin until the user enters a return -- otherwise, the
+// input is generated automatically. All worker threads shutdown
+// when (1) they receive a message block of length 0 or (2) the
+// queue is deactivated.
+//
+// = AUTHOR
+// Karlheinz Dorn <Karlheinz.Dorn@med.siemens.de>,
+// Douglas C. Schmidt <schmidt@cs.wustl.edu>, and
+// Prashant Jain <pjain@cs.wustl.edu>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/Task.h"
+
+ACE_RCSID(tests, Thread_Pool_Test, "$Id$")
+
+#if defined (ACE_HAS_THREADS)
+#include "ace/Lock_Adapter_T.h"
+#include "ace/OS_NS_stdio.h"
+#include "ace/OS_NS_string.h"
+#include "ace/OS_NS_unistd.h"
+
+// Number of iterations to run the test.
+static size_t n_iterations = 100;
+
+// Controls whether the input is generated "manually" or automatically.
+static int manual = 0;
+
+class Thread_Pool : public ACE_Task<ACE_MT_SYNCH>
+{
+ // = TITLE
+ // Defines a thread pool abstraction based on the <ACE_Task>.
+public:
+ Thread_Pool (int n_threads);
+ // Create the thread pool containing <n_threads>.
+
+ ~Thread_Pool (void);
+ // Destructor...
+
+ int test_queue_deactivation_shutdown (void);
+ // Activate the task's thread pool, produce the messages that are
+ // consumed by the threads in the thread pool, and demonstate how to
+ // shutdown using the <ACE_Message_Queue::deactivate> method.
+
+ int test_empty_message_shutdown (void);
+ // Activate the task's thread pool, produce the messages that are,
+ // produce the messages that are consumed by the threads in the
+ // thread pool, and demonstrate how to shutdown by enqueueing
+ // "empty" messages into the queue.
+
+ virtual int svc (void);
+ // Iterate <n_iterations> time printing off a message and "waiting"
+ // for all other threads to complete this iteration.
+
+ virtual int put (ACE_Message_Block *mb,
+ ACE_Time_Value *tv = 0);
+ // Allows the producer to pass messages to the <Thread_Pool>.
+
+private:
+ virtual int open (void * = 0);
+ // Spawn the threads in the pool.
+
+ virtual int close (u_long);
+ // Close hook.
+
+ ACE_Lock_Adapter<ACE_Thread_Mutex> lock_adapter_;
+ // Serialize access to <ACE_Message_Block> reference count, which
+ // will be decremented by multiple threads.
+
+ int n_threads_;
+ // Number of threads to spawn.
+};
+
+Thread_Pool::~Thread_Pool (void)
+{
+}
+
+int
+Thread_Pool::close (u_long)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) worker thread closing down\n")));
+ return 0;
+}
+
+Thread_Pool::Thread_Pool (int n_threads)
+ : n_threads_ (n_threads)
+{
+}
+
+// Simply enqueue the Message_Block into the end of the queue.
+
+int
+Thread_Pool::put (ACE_Message_Block *mb,
+ ACE_Time_Value *tv)
+{
+ return this->putq (mb, tv);
+}
+
+// Iterate <n_iterations> printing off a message and "waiting" for all
+// other threads to complete this iteration.
+
+int
+Thread_Pool::svc (void)
+{
+ // Keep looping, reading a message out of the queue, until we get a
+ // message with a length == 0, which signals us to quit.
+
+ for (int count = 1; ; count++)
+ {
+ ACE_Message_Block *mb = 0;
+
+ int result = this->getq (mb);
+
+ ACE_ASSERT (result != -1 || errno == ESHUTDOWN);
+
+ if (result == -1 && errno == ESHUTDOWN)
+ {
+ // The queue has been deactivated, so let's bail out.
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) in iteration %d, queue len = %d, ")
+ ACE_TEXT ("queue deactivated, exiting\n"),
+ count,
+ this->msg_queue ()->message_count ()));
+
+ break;
+ }
+
+ size_t length = mb->length ();
+
+ if (length > 0)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) in iteration %d, queue len = %d, ")
+ ACE_TEXT ("length = %d, text = \"%*s\"\n"),
+ count,
+ this->msg_queue ()->message_count (),
+ length,
+ length - 1,
+ mb->rd_ptr ()));
+
+ // We're responsible for deallocating this.
+ mb->release ();
+
+ if (length == 0)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) in iteration %d, queue len = %d, ")
+ ACE_TEXT ("got \"empty\" message, exiting\n"),
+ count,
+ this->msg_queue ()->message_count ()));
+ break;
+ }
+ }
+
+ // Note that the <ACE_Task::svc_run> method automatically removes us
+ // from the <ACE_Thread_Manager> when the thread exits.
+ return 0;
+}
+
+int
+Thread_Pool::open (void *)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) producer start, dumping the Thread_Pool\n")));
+ this->dump ();
+
+ // Create a pool of worker threads.
+ if (this->activate (THR_NEW_LWP,
+ this->n_threads_) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("activate failed")),
+ -1);
+ return 0;
+}
+
+// Activate the task's thread pool, produce the messages that are
+// consumed by the threads in the thread pool, and demonstate how to
+// shutdown using the <ACE_Message_Queue::deactivate> method.
+
+int
+Thread_Pool::test_queue_deactivation_shutdown (void)
+{
+ if (this->open () == -1)
+ return -1;
+
+ ACE_Message_Block *mb = 0;
+
+ // Run the main loop that generates messages and enqueues them into
+ // the pool of threads managed by <ACE_Task>.
+
+ for (size_t count = 0;
+ ;
+ count++)
+ {
+ ssize_t n = 0;
+
+ // Allocate a new message.
+ ACE_NEW_RETURN (mb,
+ ACE_Message_Block (BUFSIZ,
+ ACE_Message_Block::MB_DATA,
+ 0,
+ 0,
+ 0,
+ &this->lock_adapter_),
+ -1);
+
+ if (manual)
+ {
+#if !defined (ACE_HAS_WINCE)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) enter a new message for ")
+ ACE_TEXT ("the task pool...")));
+ n = ACE_OS::read (ACE_STDIN,
+ mb->wr_ptr (),
+ mb->size ());
+#endif // ACE_HAS_WINCE
+ }
+ else
+ {
+ static size_t count = 0;
+
+ ACE_OS::sprintf (reinterpret_cast<ACE_TCHAR *> (mb->wr_ptr ()),
+ ACE_SIZE_T_FORMAT_SPECIFIER,
+ count);
+ n = ACE_OS::strlen (mb->rd_ptr ());
+
+ if (count == n_iterations)
+ n = 1; // Indicate that we need to shut down.
+ else
+ count++;
+
+ if (count == 0 || (count % 20 == 0))
+ ACE_OS::sleep (1);
+ }
+
+ if (n > 1)
+ {
+ // Send a normal message to the waiting threads and continue
+ // producing.
+ mb->wr_ptr (n * sizeof (ACE_TCHAR));
+
+ // Pass the message to the Thread_Pool.
+ if (this->put (mb) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT (" (%t) %p\n"),
+ ACE_TEXT ("put")));
+ }
+ else
+ {
+ // Release the <Message_Block> since we're shutting down and
+ // don't need it anymore.
+
+ mb->release ();
+ // Deactivate the message queue and return.
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\n(%t) deactivating queue for %d threads, ")
+ ACE_TEXT ("dump of task:\n"),
+ this->thr_count ()));
+ this->dump ();
+
+ // Deactivate the queue.
+ return this->msg_queue ()->deactivate ();
+ }
+ }
+}
+
+// Activate the task's thread pool, produce the messages that are,
+// produce the messages that are consumed by the threads in the thread
+// pool, and demonstrate how to shutdown by enqueueing "empty"
+// messages into the queue.
+
+int
+Thread_Pool::test_empty_message_shutdown (void)
+{
+ if (this->open () == -1)
+ return -1;
+
+ ACE_Message_Block *mb = 0;
+
+ // Run the main loop that generates messages and enqueues them into
+ // the pool of threads managed by <ACE_Task>.
+
+ for (size_t count = 0;
+ ;
+ count++)
+ {
+ ssize_t n = 0;
+
+ // Allocate a new message.
+ ACE_NEW_RETURN (mb,
+ ACE_Message_Block (BUFSIZ,
+ ACE_Message_Block::MB_DATA,
+ 0,
+ 0,
+ 0,
+ &this->lock_adapter_),
+ -1);
+
+ if (manual)
+ {
+#if !defined (ACE_HAS_WINCE)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) enter a new message for ")
+ ACE_TEXT ("the task pool...")));
+ n = ACE_OS::read (ACE_STDIN,
+ mb->wr_ptr (),
+ mb->size ());
+#endif // ACE_HAS_WINCE
+ }
+ else
+ {
+ static size_t count = 0;
+
+ ACE_OS::sprintf (reinterpret_cast<ACE_TCHAR *> (mb->wr_ptr ()),
+ ACE_SIZE_T_FORMAT_SPECIFIER,
+ count);
+ n = ACE_OS::strlen (mb->rd_ptr ());
+
+ if (count == n_iterations)
+ n = 1; // Indicate that we need to shut down.
+ else
+ count++;
+
+ if (count == 0 || (count % 20 == 0))
+ ACE_OS::sleep (1);
+ }
+
+ if (n > 1)
+ {
+ // Send a normal message to the waiting threads and continue
+ // producing.
+ mb->wr_ptr (n * sizeof (ACE_TCHAR));
+
+ // Pass the message to the Thread_Pool.
+ if (this->put (mb) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT (" (%t) %p\n"),
+ ACE_TEXT ("put")));
+ }
+ else
+ {
+ // Send a shutdown message to the waiting threads and return.
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\n(%t) sending shutdown message to %d threads, ")
+ ACE_TEXT ("dump of task:\n"),
+ this->thr_count ()));
+ this->dump ();
+
+ size_t i = 0;
+
+ // Enqueue an empty message to flag each consumer thread to
+ // inform it to shutdown.
+ for (i = this->thr_count ();
+ i > 0;
+ i--)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) end of input, ")
+ ACE_TEXT ("enqueueing \"empty\" message %d\n"),
+ i));
+
+ // Note the use of reference counting to avoid copying
+ // the message contents.
+ ACE_Message_Block *dup = mb->duplicate ();
+
+ if (this->put (dup) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT (" (%t) %p\n"),
+ ACE_TEXT ("put")));
+ }
+
+ mb->release ();
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\n(%t) end loop, dump of task:\n")));
+ this->dump ();
+
+ return 0;
+ }
+ }
+}
+
+#endif /* ACE_HAS_THREADS */
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("Thread_Pool_Test"));
+
+#if defined (ACE_HAS_THREADS)
+ int n_threads = ACE_MAX_THREADS;
+
+ // Create the worker tasks.
+ Thread_Pool thread_pool (n_threads);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) running test with %d threads\n"),
+ n_threads));
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) starting empty message shutdown test\n")));
+
+ // Activate the task's thread pool, produce the messages that are,
+ // produce the messages that are consumed by the threads in the
+ // thread pool, and demonstrate how to shutdown by enqueueing
+ // "empty" messages into the queue.
+ if (thread_pool.test_empty_message_shutdown () == -1)
+ return 1;
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) waiting for worker tasks to finish...\n")));
+ // Wait for all the threads to reach their exit point, at which
+ // point the barrier in the destructor of the <ACE_Task> portion of
+ // <Thread_Pool> will return.
+ if (thread_pool.wait () == -1)
+ return 1;
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) starting queue deactivation shutdown test\n")));
+
+ // Activate the task's thread pool, produce the messages that are
+ // consumed by the threads in the thread pool, and demonstate how to
+ // shutdown using the <ACE_Message_Queue::deactivate> method.
+ if (thread_pool.test_queue_deactivation_shutdown () == -1)
+ return 1;
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) waiting for worker tasks to finish...\n")));
+ // Wait for all the threads to reach their exit point, at which
+ // point the barrier in the destructor of the <ACE_Task> portion of
+ // <Thread_Pool> will return.
+ if (thread_pool.wait () == -1)
+ return 1;
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) all worker tasks destroyed, exiting test...\n")));
+#else
+ ACE_ERROR ((LM_INFO,
+ ACE_TEXT ("threads not supported on this platform\n")));
+#endif /* ACE_HAS_THREADS */
+ ACE_END_TEST;
+ return 0;
+}
diff --git a/ACE/tests/Time_Service_Test.cpp b/ACE/tests/Time_Service_Test.cpp
new file mode 100644
index 00000000000..faaaf4a5501
--- /dev/null
+++ b/ACE/tests/Time_Service_Test.cpp
@@ -0,0 +1,121 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Time_Service_Test
+//
+// = DESCRIPTION
+// This example tests the Time Service server and clerk
+// components. The test forks and execs two processes to run both
+// the clerk and the time server. The clerk and the server
+// communicate for a short duration after which the main process
+// kills both the processes. No command line arguments are needed
+// to run the test.
+//
+// = AUTHOR
+// Prashant Jain <pjain@cs.wustl.edu>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/Process.h"
+#include "ace/ACE.h"
+#include "ace/OS_NS_string.h"
+#include "ace/OS_NS_unistd.h"
+
+ACE_RCSID(tests, Time_Service_Test, "$Id$")
+
+#define APPLICATION \
+ACE_TEXT ("..") ACE_DIRECTORY_SEPARATOR_STR \
+ACE_TEXT ("netsvcs") ACE_DIRECTORY_SEPARATOR_STR \
+ACE_TEXT ("servers") ACE_DIRECTORY_SEPARATOR_STR \
+ACE_TEXT ("main") ACE_PLATFORM_EXE_SUFFIX \
+ACE_TEXT (" -f ") ACE_PLATFORM
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("Time_Service_Test"));
+
+ // Make sure that the backing store is not there. We need to make
+ // sure because this test kills the Time Clerk and on some platforms
+ // the Clerk is not allowed to do a graceful shutdown. By cleaning
+ // the backing store here, we are sure that we get a fresh start and
+ // no garbage data from a possible aborted run
+ ACE_TCHAR backing_store[MAXPATHLEN + 1];
+
+#if defined (ACE_DEFAULT_BACKING_STORE)
+ // Create a temporary file.
+ ACE_OS::strcpy (backing_store,
+ ACE_DEFAULT_BACKING_STORE);
+#else /* ACE_DEFAULT_BACKING_STORE */
+ if (ACE::get_temp_dir (backing_store,
+ MAXPATHLEN - 17) == -1) // -17 for ace-malloc-XXXXXX
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Temporary path too long, ")
+ ACE_TEXT ("defaulting to current directory\n")));
+ backing_store[0] = 0;
+ }
+
+ // Add the filename to the end
+ ACE_OS::strcat (backing_store,
+ ACE_TEXT ("ace-malloc-XXXXXX"));
+
+#endif /* ACE_DEFAULT_BACKING_STORE */
+
+ ACE_OS::unlink (backing_store);
+
+ const ACE_TCHAR *server_cl = APPLICATION ACE_TEXT ("server.conf");
+ ACE_Process_Options server_options;
+ server_options.command_line (server_cl);
+ ACE_Process server;
+
+ if (server.spawn (server_options) == -1)
+ ACE_ERROR_RETURN ((LM_DEBUG,
+ ACE_TEXT ("%n; %p (%s).\n"),
+ ACE_TEXT ("Server fork failed"),
+ server_cl),
+ -1);
+ else
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Server forked with pid = %d.\n"),
+ server.getpid ()));
+
+ ACE_OS::sleep (3);
+
+ const ACE_TCHAR *clerk_cl = APPLICATION ACE_TEXT ("clerk.conf");
+ ACE_Process_Options clerk_options;
+ clerk_options.command_line (clerk_cl);
+ ACE_Process clerk;
+
+ if (clerk.spawn (clerk_options) == -1)
+ ACE_ERROR_RETURN ((LM_DEBUG, ACE_TEXT ("%n; %p: (%s).\n"),
+ ACE_TEXT ("Clerk fork failed"), clerk_cl), -1);
+ else
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Clerk forked with pid = %d.\n"),
+ clerk.getpid ()));
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Sleeping...\n")));
+ ACE_OS::sleep (10);
+
+ if (clerk.terminate () == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("Terminate failed for clerk.\n")),
+ -1);
+
+ if (server.terminate () == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("Terminate failed for server.\n")),
+ -1);
+
+ // Because we kill the clerk process, on Win32 it may not do a
+ // graceful shutdown and the backing store file is left behind.
+ if (clerk.wait () != 0)
+ ACE_OS::unlink (backing_store);
+
+ ACE_END_TEST;
+ return 0;
+}
diff --git a/ACE/tests/Time_Value_Test.cpp b/ACE/tests/Time_Value_Test.cpp
new file mode 100644
index 00000000000..13fd8fe3bda
--- /dev/null
+++ b/ACE/tests/Time_Value_Test.cpp
@@ -0,0 +1,287 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Time_Value_Test.cpp
+//
+// = DESCRIPTION
+// This is a simple test of ACE_Time_Value. No command line arguments
+// are needed to run the test. It also tests the ACE_U_LongLong class.
+// Because ACE_U_LongLong is used for ACE_hrtime_t on some platforms,
+// this seems like a reasonable place to test it.
+//
+// = AUTHOR
+// Prashant Jain <pjain@cs.wustl.edu> and David Levine <levine@cs.wustl.edu>
+//
+// ============================================================================
+
+// Note, for this test the config.h file *must* come first!
+#include "ace/config-all.h"
+
+ACE_RCSID(tests, Time_Value_Test, "$Id$")
+
+// Force test of ACE_U_LongLong class on Solaris.
+#if defined (sun) && !defined (ACE_LACKS_LONGLONG_T)
+# include <limits.h>
+# undef ULLONG_MAX
+
+# if defined (ACE_HAS_HI_RES_TIMER)
+# undef ACE_HAS_HI_RES_TIMER
+# endif /* ACE_HAS_HI_RES_TIMER */
+
+# define ACE_LACKS_LONGLONG_T
+
+ // Force inlining, in case ACE_U_LongLong member function
+ // definitions are not in libACE.
+# if !defined (__ACE_INLINE__)
+# define __ACE_INLINE__
+# endif /* ! __ACE_INLINE__ */
+# if defined (ACE_NO_INLINE)
+# undef ACE_NO_INLINE
+# endif /* ACE_NO_INLINE */
+#endif /* sun && ! ACE_LACKS_LONGLONG_T */
+
+#include "test_config.h"
+#include "ace/ACE.h"
+#include "ace/Time_Value.h"
+
+#if !defined(ACE_LACKS_NUMERIC_LIMITS)
+// some platforms pollute the namespace by defining max() and min() macros
+#ifdef max
+#undef max
+#endif
+#ifdef min
+#undef min
+#endif
+#include <limits>
+#endif /* ACE_LACKS_NUMERIC_LIMITS */
+
+#if defined (sun) && !defined (ACE_LACKS_LONGLONG_T)
+static
+u_long
+check_ace_u_longlong (const ACE_TCHAR *const name,
+ const ACE_U_LongLong ull,
+ const u_long hi,
+ const u_long lo)
+{
+ if (ull.hi () == hi && ull.lo () == lo)
+ return 0;
+ else
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("%s; hi: %x, should be %x; ")
+ ACE_TEXT ("lo: %x, should be %x.\n"),
+ name, ull.hi (), hi, ull.lo (), lo),
+ 1);
+}
+
+static
+u_long
+test_ace_u_longlong (void)
+{
+ u_long errors = 0;
+
+ ACE_U_LongLong ull1 (0x21,1);
+ errors += check_ace_u_longlong (ACE_TEXT ("ull1"), ull1, 1, 0x21);
+
+ ACE_U_LongLong ull2 (0x20,2);
+ errors += check_ace_u_longlong (ACE_TEXT ("ull2"), ull2, 2, 0x20);
+
+ ull2 -= ull1;
+ errors += check_ace_u_longlong (ACE_TEXT ("ull2"), ull2, 0, 0xfffffffful);
+
+ ull2 += ull1;
+ errors += check_ace_u_longlong (ACE_TEXT ("ull2"), ull2, 2, 0x20);
+
+ ACE_U_LongLong ull3 = ull1 + ull1;
+ errors += check_ace_u_longlong (ACE_TEXT ("ull3"), ull3, 2, 0x42);
+
+ ACE_U_LongLong ull4 = ACE_U_LongLong (0x1111, 0) -
+ ACE_U_LongLong (0x1112, 0);
+ errors += check_ace_u_longlong (ACE_TEXT ("ull4"), ull4, 0xfffffffful, 0xfffffffful);
+
+ ACE_U_LongLong ull5 = ACE_U_LongLong (0x1111, 1) -
+ ACE_U_LongLong (0x1112, 0);
+ errors += check_ace_u_longlong (ACE_TEXT ("ull5"), ull5, 0, 0xfffffffful);
+
+ ++ull5;
+ errors += check_ace_u_longlong (ACE_TEXT ("ull5"), ull5, 1, 0);
+
+ ACE_U_LongLong ull6 = ull2 + ACE_U_LongLong (0, 1);
+ errors += check_ace_u_longlong (ACE_TEXT ("ull6"), ull6, 3, 0x20);
+
+ ull6 += ACE_U_LongLong (0xffffffff, 0xfff0);
+ errors += check_ace_u_longlong (ACE_TEXT ("ull6"), ull6, 0xfff4, 0x1f);
+
+ ++ull6;
+ errors += check_ace_u_longlong (ACE_TEXT ("ull6"), ull6, 0xfff4, 0x20);
+
+ // The hi part of ull6 will be lost in the following, because
+ // the quotient has only 32 bits.
+ errors += check_ace_u_longlong (ACE_TEXT ("ull6 / 1"),
+ (ACE_U_LongLong) (ull6 / 1u),
+ 0, 0x20);
+
+ // There's apparently a small loss in precision in
+ // ACE_U_LongLong::operator/. It calculates
+ // ull6 / 0xd0000 as 0x13b013b4 instead of 0x13b04ec4.
+ errors += check_ace_u_longlong (ACE_TEXT ("ull6 / 0x10000 / 0xd"),
+ (ACE_U_LongLong) (ull6 / 0x10000u / 0xd),
+ 0, 0x13b04ec4);
+
+ errors += check_ace_u_longlong (ACE_TEXT ("ull6 % 5"),
+ (ACE_U_LongLong) (ull6 % 5),
+ 0, 1);
+
+ errors += check_ace_u_longlong (ACE_TEXT ("ull6 % 0x20007"),
+ (ACE_U_LongLong) (ull6 % 0x20007),
+ 0, 0x3f63);
+
+ ACE_U_LongLong ull7 (12);
+ ull7 *= 3125;
+ errors += check_ace_u_longlong (ACE_TEXT ("12 * 3125"),
+ ull7,
+ 0, 37500);
+
+ ull7 *= 100;
+ errors += check_ace_u_longlong (ACE_TEXT ("37500 * 100"),
+ ull7,
+ 0, 3750000);
+
+ errors += check_ace_u_longlong (ACE_TEXT ("3750000 << 16"),
+ ull7 << 16 ,
+ 0x39, 0x38700000);
+
+ errors += check_ace_u_longlong (ACE_TEXT ("3750000 >> 16"),
+ ull7 >> 16,
+ 0, 0x39);
+
+ ull7 <<= 32;
+ errors += check_ace_u_longlong (ACE_TEXT ("3750000 <<= 32"),
+ ull7,
+ 3750000, 0);
+
+ ull7 >>= 12;
+ errors += check_ace_u_longlong (ACE_TEXT ("3750000 <<= 32 >>= 15"),
+ ull7,
+ 0x393, 0x87000000);
+
+ ACE_U_LongLong ull8 (0x0f0f, 0xf0f0);
+ ACE_U_LongLong ull9 (0xf0f0, 0xf0f0);
+ ull8 |= ull9;
+ errors += check_ace_u_longlong (ACE_TEXT ("ull8 |= ull9"),
+ ull8,
+ 0xf0f0, 0xffff);
+
+ ull9.lo (0x5678);
+ ull9.hi (0x1234);
+ ull8 &= ull9;
+ errors += check_ace_u_longlong (ACE_TEXT ("ull8 &= 0x12345678"),
+ ull9,
+ 0x1234, 0x5678);
+
+ return errors;
+}
+#endif /* sun && ! ACE_LACKS_LONGLONG_T */
+
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ int ret = 0;
+
+ ACE_START_TEST (ACE_TEXT ("Time_Value_Test"));
+
+ ACE_Time_Value tv1;
+ ACE_Time_Value tv2 (2);
+ ACE_Time_Value tv3 (100U);
+ ACE_Time_Value tv4 (1, 1000000);
+ ACE_Time_Value tv5 (2UL);
+ ACE_Time_Value tv6 (1, -1000000);
+ ACE_Time_Value tv7 (static_cast<long> (2.0));
+
+ // Beware! 2.5 gets truncated to 2!
+ // NOTE: this is intended to show what happens with
+ // ACE_Time_Value (2.5). Some compilers, such as g++ 2.7.2.3,
+ // actually warn about it without the case.
+ ACE_Time_Value tv8 (static_cast <long> (2.5));
+
+ // Test assignment operator, tv9 and tv6 must be the same after this
+ ACE_Time_Value tv9;
+ tv9 = tv6;
+
+ ACE_ASSERT (tv1 == ACE_Time_Value (0));
+ ACE_ASSERT (tv2 < tv3);
+ ACE_ASSERT (tv2 <= tv2);
+ ACE_ASSERT (tv2 >= tv4);
+ ACE_ASSERT (tv5 >= tv6);
+ ACE_ASSERT (tv2 == ACE_Time_Value (1, 1000000));
+ ACE_ASSERT (tv5 == tv4);
+ ACE_ASSERT (tv2 == tv4);
+ ACE_ASSERT (tv1 != tv2);
+ ACE_ASSERT (tv6 == tv1);
+ ACE_ASSERT (tv5 == tv7);
+ ACE_ASSERT (tv7 == tv8); // That's right! See above . . .
+ ACE_ASSERT (tv9 == tv6);
+
+ // test multiplication by double
+ // test simple multiplication
+ tv1.set (1, 1);
+ tv2.set (2, 2);
+ tv1 *= 2.0;
+ ACE_ASSERT (tv1.sec () == tv2.sec () && tv1.usec () == tv2.usec ());
+ tv1.set (1, 1);
+ tv2.set (-2, -2);
+ tv1 *= -2.0;
+ ACE_ASSERT (tv1.sec () == tv2.sec () && tv1.usec () == tv2.usec ());
+
+ // test usec shift
+ tv1.set (1, 999999);
+ tv2.set (19, 999990);
+ tv1 *= 10.0;
+ ACE_ASSERT ( tv1.sec () == tv2.sec () && tv1.usec () == tv2.usec ());
+ tv1.set (1, 999999);
+ tv2.set (-19, -999990);
+ tv1 *= -10.0;
+ ACE_ASSERT (tv1.sec () == tv2.sec () && tv1.usec () == tv2.usec ());
+
+#if !defined(ACE_LACKS_NUMERIC_LIMITS) && !defined (ACE_WIN64)
+ const time_t max_time_t = std::numeric_limits<time_t>::max ();
+ const time_t min_time_t = std::numeric_limits<time_t>::min ();
+#else
+ const time_t max_time_t = LONG_MAX;
+ const time_t min_time_t = LONG_MIN;
+#endif
+
+ // test results near limits
+ tv1.set ((max_time_t >> 1), 499999);
+ tv2.set ((-(max_time_t >> 1) << 1), -999998);
+ tv1 *= -2.0;
+ ACE_ASSERT (tv1.sec () == tv2.sec () && tv1.usec () == tv2.usec ());
+ tv1.set (max_time_t >> 1, 499999);
+ tv2.set (((max_time_t >> 1) << 1), 999998);
+ tv1 *= 2.0;
+ ACE_ASSERT (tv1.sec () == tv2.sec () && tv1.usec () == tv2.usec ());
+
+ // test saturated result
+ tv1.set (max_time_t - 1, 499999);
+ tv2.set (max_time_t, 999999);
+ tv1 *= max_time_t;
+ ACE_ASSERT (tv1.sec () == tv2.sec () && tv1.usec () == tv2.usec ());
+ tv1.set (max_time_t - 1, 499999);
+ tv2.set (min_time_t, -999999);
+ tv1 *= min_time_t;
+ ACE_ASSERT (tv1.sec () == tv2.sec () && tv1.usec () == tv2.usec ());
+
+#if defined (sun) && !defined (ACE_LACKS_LONGLONG_T)
+ if (test_ace_u_longlong () != 0)
+ ++ret;
+#endif /* sun && ! ACE_LACKS_LONGLONG_T */
+
+ ACE_END_TEST;
+
+ return ret;
+}
diff --git a/ACE/tests/Timeprobe_Test.cpp b/ACE/tests/Timeprobe_Test.cpp
new file mode 100644
index 00000000000..2935aca22bd
--- /dev/null
+++ b/ACE/tests/Timeprobe_Test.cpp
@@ -0,0 +1,124 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Timeprobe_Test.cpp
+//
+// = DESCRIPTION
+// This is a simple test of ACE Timeprobes.
+//
+// = AUTHOR
+// Irfan Pyarali <irfan@cs.wustl.edu>
+//
+// ============================================================================
+
+//#define ACE_ENABLE_TIMEPROBES
+//#define ACE_MT_TIMEPROBES
+//#define ACE_TSS_TIMEPROBES
+
+#include "tests/test_config.h"
+#include "ace/Singleton.h"
+#include "ace/Synch_Traits.h"
+#include "ace/Recursive_Thread_Mutex.h"
+#include "ace/Null_Mutex.h"
+#include "ace/OS_NS_unistd.h"
+#include "ace/Timeprobe.h"
+
+ACE_RCSID(tests, Timeprobe_Test, "$Id$")
+
+#if defined (ACE_ENABLE_TIMEPROBES)
+
+static const char *events_descriptions_0[] =
+{
+ "Event Zero",
+ "Event One",
+ "Event Two",
+ "Event Three",
+ "Event Four",
+ "Event Five",
+ "Event Six",
+ "Event Seven",
+ "Event Eight",
+ "Event Nine"
+};
+
+enum
+{
+ EVENT_ZERO = 0,
+ EVENT_ONE,
+ EVENT_TWO,
+ EVENT_THREE,
+ EVENT_FOUR,
+ EVENT_FIVE,
+ EVENT_SIX,
+ EVENT_SEVEN,
+ EVENT_EIGHT,
+ EVENT_NINE
+};
+
+static const char *events_descriptions_1[] =
+{
+ "Work start",
+ "Work end"
+};
+
+enum
+{
+ WORK_START = 100,
+ WORK_END
+};
+
+ACE_TIMEPROBE_EVENT_DESCRIPTIONS (events_descriptions_1, WORK_START);
+ACE_TIMEPROBE_EVENT_DESCRIPTIONS (events_descriptions_0, EVENT_ZERO);
+
+#endif /* ACE_ENABLE_TIMEPROBES */
+
+static void
+work (int time)
+{
+ ACE_FUNCTION_TIMEPROBE (WORK_START);
+ ACE_OS::sleep (time);
+}
+
+#if !defined (ACE_HAS_PURIFY)
+// Test creation of ACE_Singletons during static object construction.
+// Timeprobes can do that, when they're enabled. Purify would notice
+// the memory in use at program termination.
+static int
+create_singleton ()
+{
+ int *i = ACE_Singleton <int, ACE_SYNCH_RECURSIVE_MUTEX>::instance ();
+ *i = 3;
+
+ return *i;
+}
+
+int static_singleton_creator = create_singleton ();
+#endif /* ! ACE_HAS_PURIFY */
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("Timeprobe_Test"));
+
+ ACE_TIMEPROBE ("Starting Test");
+
+ for (int i = 0; i < 3; i++)
+ {
+ work (i);
+ ACE_TIMEPROBE (EVENT_ZERO + i);
+ }
+
+ ACE_TIMEPROBE ("Ending Test");
+
+ ACE_TIMEPROBE_PRINT;
+
+ ACE_END_TEST;
+
+ return 0;
+}
+
diff --git a/ACE/tests/Timer_Cancellation_Test.cpp b/ACE/tests/Timer_Cancellation_Test.cpp
new file mode 100644
index 00000000000..0db3da521ae
--- /dev/null
+++ b/ACE/tests/Timer_Cancellation_Test.cpp
@@ -0,0 +1,162 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Timer_Cancellation_Test.cpp
+//
+// = DESCRIPTION
+// A test to ensure the timer cancellation works correctly.
+//
+// = AUTHOR
+// Irfan Pyarali <irfan@oomworks.com>
+//
+// ============================================================================
+
+#include "tests/test_config.h"
+#include "ace/OS_NS_unistd.h"
+#include "ace/Reactor.h"
+#include "ace/TP_Reactor.h"
+#include "ace/Task.h"
+
+ACE_RCSID(tests, Timer_Cancellation_Test, "$Id$")
+
+#if defined (ACE_HAS_THREADS)
+
+class Deadlock : public ACE_Task_Base
+{
+public:
+
+ int svc (void);
+
+ int handle_timeout (const ACE_Time_Value &current_time,
+ const void *act);
+};
+
+int
+Deadlock::svc (void)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Deadlock starts accessing Reactor and Timer Queue....\n")));
+
+ this->reactor ()->schedule_timer (this,
+ 0,
+ ACE_Time_Value (1));
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Deadlock completes accessing Reactor and Timer Queue....\n")));
+
+ return 0;
+}
+
+int
+Deadlock::handle_timeout (const ACE_Time_Value &,
+ const void *)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Deadlock timeout\n")));
+
+ return 0;
+}
+
+class Event_Handler : public ACE_Event_Handler
+{
+public:
+
+ Event_Handler (Deadlock &deadlock);
+
+ int handle_timeout (const ACE_Time_Value &current_time,
+ const void *act);
+
+ int handle_close (ACE_HANDLE handle,
+ ACE_Reactor_Mask close_mask);
+
+ Deadlock &deadlock_;
+};
+
+Event_Handler::Event_Handler (Deadlock &deadlock)
+ : deadlock_ (deadlock)
+{
+}
+
+int
+Event_Handler::handle_timeout (const ACE_Time_Value &,
+ const void *)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Event_Handler timeout\n")));
+
+ return -1;
+}
+
+int
+Event_Handler::handle_close (ACE_HANDLE,
+ ACE_Reactor_Mask)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Event_Handler closed\n")));
+
+ // Activate Deadlock.
+ this->deadlock_.activate ();
+
+ // Give Deadlock a chance to deadlock... ;-)
+ ACE_OS::sleep (1);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Event Handler starts accessing Reactor....\n")));
+
+ // This is a superfluous call to the Reactor to acquire its lock.
+ this->reactor ()->max_notify_iterations ();
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Event Handler completes accessing Reactor....\n")));
+
+ return 0;
+}
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("Timer_Cancellation_Test"));
+
+ ACE_Reactor reactor (new ACE_TP_Reactor,
+ 1);
+
+ Deadlock deadlock;
+ deadlock.reactor (&reactor);
+
+ Event_Handler handler (deadlock);
+
+ // Scheduler a timer to kick things off.
+ reactor.schedule_timer (&handler,
+ 0,
+ ACE_Time_Value (1));
+
+ // Run the event loop for a while.
+ ACE_Time_Value timeout (4);
+ reactor.run_reactor_event_loop (timeout);
+
+ ACE_END_TEST;
+
+ return 0;
+}
+
+#else /* ACE_HAS_THREADS */
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("Timer_Cancellation_Test"));
+
+ ACE_ERROR ((LM_INFO,
+ ACE_TEXT ("threads not supported on this platform\n")));
+
+ ACE_END_TEST;
+
+ return 0;
+}
+
+#endif /* ACE_HAS_THREADS */
diff --git a/ACE/tests/Timer_Queue_Reference_Counting_Test.cpp b/ACE/tests/Timer_Queue_Reference_Counting_Test.cpp
new file mode 100644
index 00000000000..f21585938d0
--- /dev/null
+++ b/ACE/tests/Timer_Queue_Reference_Counting_Test.cpp
@@ -0,0 +1,676 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Timer_Queue_Reference_Counting_Test.cpp
+//
+// = DESCRIPTION
+// This test is used to check reference counting of the Event
+// Handler when it interacts with Timer Queues.
+//
+// = AUTHOR
+// Irfan Pyarali <irfan@oomworks.com>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/Get_Opt.h"
+#include "ace/Timer_Queue.h"
+#include "ace/Timer_Heap.h"
+#include "ace/Timer_List.h"
+#include "ace/Timer_Hash.h"
+#include "ace/Timer_Wheel.h"
+#include "ace/Reactor.h"
+#include "ace/Recursive_Thread_Mutex.h"
+#include "ace/Null_Mutex.h"
+#include "ace/OS_NS_unistd.h"
+
+ACE_RCSID(tests, Timer_Queue_Reference_Counting_Test, "$Id$")
+
+static int debug = 0;
+static const char *one_second_timeout = "one second timeout";
+static const char *two_second_timeout = "two second timeout";
+
+class Reference_Counted_Event_Handler : public ACE_Event_Handler
+{
+public:
+
+ Reference_Counted_Event_Handler (int expected_number_of_handle_close_calls);
+
+ ~Reference_Counted_Event_Handler (void);
+
+ int handle_timeout (const ACE_Time_Value &,
+ const void *);
+
+ int handle_close (ACE_HANDLE handle,
+ ACE_Reactor_Mask masks);
+
+ int expected_number_of_handle_close_calls_;
+ int number_of_handle_close_calls_;
+};
+
+Reference_Counted_Event_Handler::Reference_Counted_Event_Handler (int expected_number_of_handle_close_calls)
+ : expected_number_of_handle_close_calls_ (expected_number_of_handle_close_calls),
+ number_of_handle_close_calls_ (0)
+{
+ this->reference_counting_policy ().value
+ (ACE_Event_Handler::Reference_Counting_Policy::ENABLED);
+
+ if (debug)
+ ACE_DEBUG ((LM_DEBUG,
+ "Reference count in Reference_Counted_Event_Handler() is %d\n",
+ this->reference_count_.value ()));
+}
+
+Reference_Counted_Event_Handler::~Reference_Counted_Event_Handler (void)
+{
+ if (debug)
+ ACE_DEBUG ((LM_DEBUG,
+ "Reference count in ~Reference_Counted_Event_Handler() is %d\n",
+ this->reference_count_.value ()));
+
+ if (this->expected_number_of_handle_close_calls_ != -1)
+ ACE_ASSERT (this->number_of_handle_close_calls_ ==
+ this->expected_number_of_handle_close_calls_);
+}
+
+int
+Reference_Counted_Event_Handler::handle_timeout (const ACE_Time_Value &,
+ const void *arg)
+{
+ if (debug)
+ ACE_DEBUG ((LM_DEBUG,
+ "Reference count in Reference_Counted_Event_Handler::handle_timeout() for arg = %s is %d\n",
+ (const char *) arg,
+ this->reference_count_.value ()));
+
+ return 0;
+}
+
+int
+Reference_Counted_Event_Handler::handle_close (ACE_HANDLE handle,
+ ACE_Reactor_Mask masks)
+{
+ if (debug)
+ ACE_DEBUG ((LM_DEBUG,
+ "Reference_Counted_Event_Handler::handle_close() called with handle = %d and masks = %d. "
+ "Reference count is %d\n",
+ handle,
+ masks,
+ this->reference_count_.value ()));
+
+ ++this->number_of_handle_close_calls_;
+
+ return 0;
+}
+
+void
+cancellation (ACE_Timer_Queue &timer_queue,
+ int repeat_timer,
+ int cancel_timers,
+ int cancel_handler,
+ int second_timer,
+ int dont_call_handle_close)
+{
+ int result = 0;
+
+ int expected_number_of_handle_close_calls = -1;
+
+ if (cancel_timers)
+ {
+ if (!dont_call_handle_close)
+ {
+ if (cancel_handler)
+ expected_number_of_handle_close_calls = 1;
+ else if (second_timer)
+ expected_number_of_handle_close_calls = 2;
+ else
+ expected_number_of_handle_close_calls = 1;
+ }
+ }
+ else
+ {
+ if (second_timer)
+ expected_number_of_handle_close_calls = 2;
+ else
+ expected_number_of_handle_close_calls = 1;
+ }
+
+ Reference_Counted_Event_Handler *handler =
+ new Reference_Counted_Event_Handler (expected_number_of_handle_close_calls);
+
+ ACE_Event_Handler_var safe_handler (handler);
+
+ long first_timer_id = -1;
+ long second_timer_id = -1;
+
+ if (repeat_timer)
+ {
+ first_timer_id =
+ timer_queue.schedule (handler,
+ one_second_timeout,
+ ACE_Time_Value (1) + timer_queue.gettimeofday (),
+ ACE_Time_Value (1));
+ ACE_ASSERT (first_timer_id != -1);
+ }
+ else
+ {
+ first_timer_id =
+ timer_queue.schedule (handler,
+ one_second_timeout,
+ ACE_Time_Value (1) + timer_queue.gettimeofday ());
+ ACE_ASSERT (first_timer_id != -1);
+ }
+
+ if (second_timer)
+ {
+ second_timer_id =
+ timer_queue.schedule (handler,
+ two_second_timeout,
+ ACE_Time_Value (2) + timer_queue.gettimeofday (),
+ ACE_Time_Value (2));
+ ACE_ASSERT (second_timer_id != -1);
+ }
+
+ if (!cancel_timers)
+ return;
+
+ if (cancel_handler)
+ {
+ result =
+ timer_queue.cancel (handler,
+ dont_call_handle_close);
+
+ if (second_timer)
+ ACE_ASSERT (result == 2);
+ else
+ ACE_ASSERT (result == 1);
+ }
+ else
+ {
+ result =
+ timer_queue.cancel (first_timer_id,
+ 0,
+ dont_call_handle_close);
+ ACE_ASSERT (result == 1);
+
+ if (second_timer)
+ {
+ result =
+ timer_queue.cancel (second_timer_id,
+ 0,
+ dont_call_handle_close);
+ ACE_ASSERT (result == 1);
+ }
+ }
+}
+
+template <class TIMER_QUEUE>
+class cancellation_test
+{
+public:
+ cancellation_test (const char *);
+};
+
+template <class TIMER_QUEUE>
+cancellation_test<TIMER_QUEUE>::cancellation_test (const char *timer_queue_type)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ "\nCancellation test for %s\n\n",
+ timer_queue_type));
+
+ int configs[][5] = {
+ { 0, 0, 0, 0, 0, },
+ { 0, 0, 0, 0, 1, },
+ { 0, 0, 0, 1, 0, },
+ { 0, 0, 0, 1, 1, },
+ { 0, 0, 1, 0, 0, },
+ { 0, 0, 1, 0, 1, },
+ { 0, 0, 1, 1, 0, },
+ { 0, 0, 1, 1, 1, },
+ { 0, 1, 0, 0, 0, },
+ { 0, 1, 0, 0, 1, },
+ { 0, 1, 0, 1, 0, },
+ { 0, 1, 0, 1, 1, },
+ { 0, 1, 1, 0, 0, },
+ { 0, 1, 1, 0, 1, },
+ { 0, 1, 1, 1, 0, },
+ { 0, 1, 1, 1, 1, },
+ { 1, 0, 0, 0, 0, },
+ { 1, 0, 0, 0, 1, },
+ { 1, 0, 0, 1, 0, },
+ { 1, 0, 0, 1, 1, },
+ { 1, 0, 1, 0, 0, },
+ { 1, 0, 1, 0, 1, },
+ { 1, 0, 1, 1, 0, },
+ { 1, 0, 1, 1, 1, },
+ { 1, 1, 0, 0, 0, },
+ { 1, 1, 0, 0, 1, },
+ { 1, 1, 0, 1, 0, },
+ { 1, 1, 0, 1, 1, },
+ { 1, 1, 1, 0, 0, },
+ { 1, 1, 1, 0, 1, },
+ { 1, 1, 1, 1, 0, },
+ { 1, 1, 1, 1, 1, },
+ };
+
+ for (int i = 0;
+ i < (int) (sizeof configs / (sizeof (int) * 5));
+ i++)
+ {
+ TIMER_QUEUE timer_queue;
+
+ cancellation (timer_queue,
+ configs[i][0],
+ configs[i][1],
+ configs[i][2],
+ configs[i][3],
+ configs[i][4]);
+ }
+}
+
+typedef int (*Expire_Function) (ACE_Timer_Queue &timer_queue);
+
+int
+invoke_expire (ACE_Timer_Queue &timer_queue)
+{
+ return timer_queue.expire ();
+}
+
+int
+invoke_one_upcall (ACE_Timer_Queue &timer_queue)
+{
+ // Get the current time
+ ACE_Time_Value current_time (timer_queue.gettimeofday () +
+ timer_queue.timer_skew ());
+
+ // Look for a node in the timer queue whose timer <= the present
+ // time.
+ ACE_Timer_Node_Dispatch_Info dispatch_info;
+
+ if (timer_queue.dispatch_info (current_time,
+ dispatch_info))
+ {
+ const void *upcall_act = 0;
+
+ // Preinvoke.
+ timer_queue.preinvoke (dispatch_info,
+ current_time,
+ upcall_act);
+
+ // Call the functor
+ timer_queue.upcall (dispatch_info,
+ current_time);
+
+ // Postinvoke
+ timer_queue.postinvoke (dispatch_info,
+ current_time,
+ upcall_act);
+
+ // We have dispatched a timer
+ return 1;
+ }
+
+ return 0;
+}
+
+void
+expire (ACE_Timer_Queue &timer_queue,
+ Expire_Function expire_function)
+{
+ int events = 0;
+ int result = 0;
+
+ Reference_Counted_Event_Handler *handler =
+ new Reference_Counted_Event_Handler (1);
+
+ ACE_Event_Handler_var safe_handler (handler);
+
+ long timer_id =
+ timer_queue.schedule (handler,
+ one_second_timeout,
+ ACE_Time_Value (1) + timer_queue.gettimeofday (),
+ ACE_Time_Value (1));
+ ACE_ASSERT (timer_id != -1);
+
+ timer_id =
+ timer_queue.schedule (handler,
+ two_second_timeout,
+ ACE_Time_Value (2) + timer_queue.gettimeofday ());
+ ACE_ASSERT (result != -1);
+
+ events += 4;
+
+ for (int i = 0; i < events;)
+ {
+ ACE_Time_Value sleep_time;
+
+ ACE_Time_Value earliest_time =
+ timer_queue.earliest_time ();
+
+ ACE_Time_Value time_of_day =
+ timer_queue.gettimeofday ();
+
+ if (earliest_time > time_of_day)
+ sleep_time =
+ earliest_time - time_of_day;
+ else
+ sleep_time = ACE_Time_Value::zero;
+
+ ACE_OS::sleep (sleep_time);
+
+ result =
+ expire_function (timer_queue);
+
+ ACE_ASSERT (result >= 0);
+
+ i += result;
+ }
+}
+
+template<class TIMER_QUEUE>
+class expire_test
+{
+public:
+ expire_test (const char *);
+};
+
+template <class TIMER_QUEUE>
+expire_test<TIMER_QUEUE>::expire_test (const char *timer_queue_type)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ "\nExpire test for %s\n\n",
+ timer_queue_type));
+
+ TIMER_QUEUE timer_queue;
+
+ expire (timer_queue,
+ invoke_expire);
+}
+
+template<class TIMER_QUEUE>
+class upcall_test
+{
+public:
+ upcall_test (const char *);
+};
+
+template <class TIMER_QUEUE>
+upcall_test<TIMER_QUEUE>::upcall_test (const char *timer_queue_type)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ "\nOne upcall test for %s\n\n",
+ timer_queue_type));
+
+ TIMER_QUEUE timer_queue;
+
+ expire (timer_queue,
+ invoke_one_upcall);
+}
+
+class Simple_Event_Handler : public ACE_Event_Handler
+{
+public:
+
+ Simple_Event_Handler (void);
+
+ ~Simple_Event_Handler (void);
+
+ int handle_timeout (const ACE_Time_Value &,
+ const void *);
+
+ int handle_close (ACE_HANDLE,
+ ACE_Reactor_Mask);
+};
+
+Simple_Event_Handler::Simple_Event_Handler (void)
+{
+ if (debug)
+ ACE_DEBUG ((LM_DEBUG,
+ "Simple_Event_Handler()\n"));
+}
+
+Simple_Event_Handler::~Simple_Event_Handler (void)
+{
+ if (debug)
+ ACE_DEBUG ((LM_DEBUG,
+ "~Simple_Event_Handler()\n"));
+}
+
+int
+Simple_Event_Handler::handle_timeout (const ACE_Time_Value &,
+ const void *arg)
+{
+ if (debug)
+ ACE_DEBUG ((LM_DEBUG,
+ "Simple_Event_Handler::handle_timeout() for arg = %s\n",
+ (const char *) arg));
+ return 0;
+}
+
+int
+Simple_Event_Handler::handle_close (ACE_HANDLE handle,
+ ACE_Reactor_Mask masks)
+{
+ if (debug)
+ ACE_DEBUG ((LM_DEBUG,
+ "Simple_Event_Handler::handle_close() called with handle = %d and masks = %d.\n",
+ handle,
+ masks));
+
+ delete this;
+
+ return 0;
+}
+
+void
+simple (ACE_Timer_Queue &timer_queue)
+{
+ int events = 0;
+ int result = 0;
+
+ {
+ Simple_Event_Handler *handler =
+ new Simple_Event_Handler;
+
+ long timer_id =
+ timer_queue.schedule (handler,
+ one_second_timeout,
+ ACE_Time_Value (1) + timer_queue.gettimeofday (),
+ ACE_Time_Value (1));
+ ACE_ASSERT (timer_id != -1);
+
+ result =
+ timer_queue.cancel (timer_id,
+ 0,
+ 0);
+ ACE_ASSERT (result == 1);
+ }
+
+ {
+ Simple_Event_Handler *handler =
+ new Simple_Event_Handler;
+
+ long timer_id =
+ timer_queue.schedule (handler,
+ one_second_timeout,
+ ACE_Time_Value (1) + timer_queue.gettimeofday (),
+ ACE_Time_Value (1));
+ ACE_ASSERT (timer_id != -1);
+
+ events += 3;
+ }
+
+ for (int i = 0; i < events;)
+ {
+ ACE_OS::sleep (timer_queue.earliest_time () -
+ timer_queue.gettimeofday ());
+
+ result =
+ timer_queue.expire ();
+
+ ACE_ASSERT (result >= 0);
+
+ i += result;
+ }
+}
+
+template <class TIMER_QUEUE>
+class simple_test
+{
+public:
+ simple_test (const char *);
+};
+
+template <class TIMER_QUEUE>
+simple_test<TIMER_QUEUE>::simple_test (const char *timer_queue_type)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ "\nSimple test for %s\n\n",
+ timer_queue_type));
+
+ TIMER_QUEUE timer_queue;
+
+ simple (timer_queue);
+}
+
+static int heap = 1;
+static int list = 1;
+static int hash = 1;
+static int wheel = 1;
+static int test_cancellation = 1;
+static int test_expire = 1;
+static int test_one_upcall = 1;
+static int test_simple = 1;
+
+static int
+parse_args (int argc, ACE_TCHAR *argv[])
+{
+ ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("a:b:c:d:l:m:n:o:z:"));
+
+ int cc;
+ while ((cc = get_opt ()) != -1)
+ {
+ switch (cc)
+ {
+ case 'a':
+ heap = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'b':
+ list = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'c':
+ hash = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'd':
+ wheel = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'l':
+ test_cancellation = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'm':
+ test_expire = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'n':
+ test_one_upcall = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'o':
+ test_simple = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'z':
+ debug = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ default:
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("\nusage: %s \n\n")
+ ACE_TEXT ("\t[-a heap] (defaults to %d)\n")
+ ACE_TEXT ("\t[-b list] (defaults to %d)\n")
+ ACE_TEXT ("\t[-c hash] (defaults to %d)\n")
+ ACE_TEXT ("\t[-d wheel] (defaults to %d)\n")
+ ACE_TEXT ("\t[-l test_cancellation] (defaults to %d)\n")
+ ACE_TEXT ("\t[-m test_expire] (defaults to %d)\n")
+ ACE_TEXT ("\t[-n test_one_upcall] (defaults to %d)\n")
+ ACE_TEXT ("\t[-o test_simple] (defaults to %d)\n")
+ ACE_TEXT ("\t[-z debug] (defaults to %d)\n")
+ ACE_TEXT ("\n"),
+ argv[0],
+ heap,
+ list,
+ hash,
+ wheel,
+ test_cancellation,
+ test_expire,
+ test_one_upcall,
+ test_simple,
+ debug));
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+int
+run_main (int argc, ACE_TCHAR *argv[])
+{
+ ACE_START_TEST (ACE_TEXT ("Timer_Queue_Reference_Counting_Test"));
+
+ // Validate options.
+ int result =
+ parse_args (argc, argv);
+ if (result != 0)
+ return result;
+
+ if (test_cancellation)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ "\nCancellation test...\n\n"));
+
+ if (heap) { cancellation_test<ACE_Timer_Heap> test ("ACE_Timer_Heap"); ACE_UNUSED_ARG (test); }
+ if (list) { cancellation_test<ACE_Timer_List> test ("ACE_Timer_List"); ACE_UNUSED_ARG (test); }
+ if (hash) { cancellation_test<ACE_Timer_Hash> test ("ACE_Timer_Hash"); ACE_UNUSED_ARG (test); }
+ if (wheel) { cancellation_test<ACE_Timer_Wheel> test ("ACE_Timer_Wheel"); ACE_UNUSED_ARG (test); }
+ }
+
+ if (test_expire)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ "\nExpire test...\n\n"));
+
+ if (heap) { expire_test<ACE_Timer_Heap> test ("ACE_Timer_Heap"); ACE_UNUSED_ARG (test); }
+ if (list) { expire_test<ACE_Timer_List> test ("ACE_Timer_List"); ACE_UNUSED_ARG (test); }
+ if (hash) { expire_test<ACE_Timer_Hash> test ("ACE_Timer_Hash"); ACE_UNUSED_ARG (test); }
+ if (wheel) { expire_test<ACE_Timer_Wheel> test ("ACE_Timer_Wheel"); ACE_UNUSED_ARG (test); }
+ }
+
+ if (test_one_upcall)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ "\nOne upcall at a time test...\n\n"));
+
+ if (heap) { upcall_test<ACE_Timer_Heap> test ("ACE_Timer_Heap"); ACE_UNUSED_ARG (test); }
+ if (list) { upcall_test<ACE_Timer_List> test ("ACE_Timer_List"); ACE_UNUSED_ARG (test); }
+ if (hash) { upcall_test<ACE_Timer_Hash> test ("ACE_Timer_Hash"); ACE_UNUSED_ARG (test); }
+ if (wheel) { upcall_test<ACE_Timer_Wheel> test ("ACE_Timer_Wheel"); ACE_UNUSED_ARG (test); }
+ }
+
+ if (test_simple)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ "\nSimple test...\n\n"));
+
+ if (heap) { simple_test<ACE_Timer_Heap> test ("ACE_Timer_Heap"); ACE_UNUSED_ARG (test); }
+ if (list) { simple_test<ACE_Timer_List> test ("ACE_Timer_List"); ACE_UNUSED_ARG (test); }
+ if (hash) { simple_test<ACE_Timer_Hash> test ("ACE_Timer_Hash"); ACE_UNUSED_ARG (test); }
+ if (wheel) { simple_test<ACE_Timer_Wheel> test ("ACE_Timer_Wheel"); ACE_UNUSED_ARG (test); }
+ }
+
+ ACE_END_TEST;
+
+ return 0;
+}
+
diff --git a/ACE/tests/Timer_Queue_Test.cpp b/ACE/tests/Timer_Queue_Test.cpp
new file mode 100644
index 00000000000..5f364c2f21b
--- /dev/null
+++ b/ACE/tests/Timer_Queue_Test.cpp
@@ -0,0 +1,673 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Timer_Queue_Test.cpp
+//
+// = DESCRIPTION
+// This is a simple test of <ACE_Timer_Queue> and four of its
+// subclasses (<ACE_Timer_List>, <ACE_Timer_Heap>,
+// <ACE_Timer_Wheel>, and <ACE_Timer_Hash>). The test sets up a
+// bunch of timers and then adds them to a timer queue. The
+// functionality of the timer queue is then tested. No command
+// line arguments are needed to run the test.
+//
+// = AUTHORS
+// Douglas C. Schmidt <schmidt@cs.wustl.edu>,
+// Prashant Jain <pjain@cs.wustl.edu>, and
+// Darrell Brunsch <brunsch@cs.wustl.edu>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/Profile_Timer.h"
+#include "ace/Timer_Queue.h"
+#include "ace/Timer_List.h"
+#include "ace/Timer_Heap.h"
+#include "ace/Timer_Wheel.h"
+#include "ace/Timer_Hash.h"
+#include "ace/Timer_Queue.h"
+#include "ace/Recursive_Thread_Mutex.h"
+#include "ace/Null_Mutex.h"
+#include "ace/OS_NS_unistd.h"
+#include "ace/Containers_T.h"
+
+ACE_RCSID(tests, Timer_Queue_Test, "$Id$")
+
+static void
+randomize_array (ACE_Time_Value array[], int size)
+{
+ for (int i = 0; i < size; ++i)
+ {
+ int index = ACE_OS::rand() % size--;
+ ACE_Time_Value temp = array [index];
+ array [index] = array [size];
+ array [size] = temp;
+ }
+}
+
+// Number of iterations for the performance tests. Some platforms
+// have a very high ACE_DEFAULT_TIMERS (HP-UX is 400), so limit this
+// to a reasonable run time.
+#if (ACE_DEFAULT_TIMERS > 20)
+static int max_iterations = 2000;
+#else
+static int max_iterations = ACE_DEFAULT_TIMERS * 100;
+#endif
+
+// Amount of time between each timer.
+// (0 schedules all the timers to expire at exactly the same time.)
+// in milliseconds
+static int TIMER_DISTANCE = 50;
+
+// Array of timer ids assigned to us that we need to keep track of.
+static long *timer_ids = 0;
+
+class Example_Handler : public ACE_Event_Handler
+{
+public:
+ Example_Handler (void): close_count_ (0) {}
+
+ virtual int handle_close (ACE_HANDLE, ACE_Reactor_Mask mask)
+ {
+ ACE_ASSERT (mask == ACE_Event_Handler::TIMER_MASK);
+ this->close_count_++;
+ return 0;
+ }
+
+ virtual int handle_timeout (const ACE_Time_Value &,
+ const void *arg)
+ {
+ int *act = (int *) arg;
+ ACE_ASSERT (*act == 42 || *act == 007);
+ int result = 0;
+
+ if (*act == 007)
+ result = -1; // This is the special value to trigger a handle_close
+
+ delete act;
+ return result;
+ }
+
+ int close_count_;
+ // Keeps track of the number of times that <handle_close> is called.
+};
+
+static void
+test_functionality (ACE_Timer_Queue *tq)
+{
+ Example_Handler eh;
+
+ ACE_ASSERT (tq->is_empty () != 0);
+ ACE_ASSERT (ACE_Time_Value::zero == ACE_Time_Value (0));
+ long timer_id;
+ long timer_id2;
+
+ // Do a test on earliest_time.
+ ACE_Time_Value earliest_time = tq->gettimeofday ();
+
+ const void *timer_act = 0;
+ ACE_NEW (timer_act, int (1));
+ timer_id = tq->schedule (&eh, timer_act, earliest_time);
+
+ ACE_OS::sleep (ACE_Time_Value (0, 10));
+
+ ACE_NEW (timer_act, int (1));
+ timer_id2 = tq->schedule (&eh, timer_act, tq->gettimeofday ());
+
+ long result = tq->earliest_time () == earliest_time;
+ ACE_ASSERT (result != 0);
+
+ tq->cancel (timer_id, &timer_act);
+ delete (int *) timer_act;
+ tq->cancel (timer_id2, &timer_act);
+ delete (int *) timer_act;
+
+ ACE_ASSERT (tq->is_empty () == 1);
+ ACE_ASSERT (eh.close_count_ == 0);
+
+ ACE_NEW (timer_act, int (1));
+ timer_id = tq->schedule (&eh,
+ timer_act,
+ tq->gettimeofday ());
+ ACE_ASSERT (timer_id != -1);
+ ACE_ASSERT (tq->is_empty () == 0); //==
+
+ ACE_NEW (timer_act, int (42));
+ result = tq->schedule (&eh,
+ timer_act,
+ tq->gettimeofday ());
+ ACE_ASSERT (result != -1);
+ ACE_ASSERT (tq->is_empty () == 0); //==
+
+ ACE_NEW (timer_act, int (42));
+ result = tq->schedule (&eh,
+ timer_act,
+ tq->gettimeofday ());
+ ACE_ASSERT (result != -1);
+ ACE_ASSERT (tq->is_empty () == 0); //==
+
+ // The following method will trigger a call to <handle_close>.
+ ACE_ASSERT (eh.close_count_ == 0);
+ result = tq->cancel (timer_id, &timer_act, 0);
+ ACE_ASSERT (result == 1);
+ delete (int *) timer_act;
+
+ ACE_ASSERT (tq->is_empty () == 0);
+ ACE_ASSERT (eh.close_count_ == 1);
+
+ result = tq->expire ();
+ ACE_ASSERT (result == 2);
+
+ ACE_NEW (timer_act, int (007));
+ result = tq->schedule (&eh,
+ timer_act,
+ tq->gettimeofday ());
+ ACE_ASSERT (result != -1);
+
+ ACE_NEW (timer_act, int (42));
+ result = tq->schedule (&eh,
+ timer_act,
+ tq->gettimeofday () + ACE_Time_Value (100));
+ ACE_ASSERT (result != -1);
+
+ ACE_NEW (timer_act, int (42));
+ result = tq->schedule (&eh,
+ timer_act,
+ tq->gettimeofday () + ACE_Time_Value (100));
+ ACE_ASSERT (result != -1);
+
+ // The following will trigger a call to <handle_close> when it
+ // cancels the second timer. This happens because the first timer
+ // has an <act> of 007, which causes eh.handle_timeout () to return
+ // -1. Since -1 is returned, all timers that use <eh> will be
+ // cancelled (and <handle_close> will only be called on the first
+ // timer that is cancelled).
+ ACE_ASSERT (eh.close_count_ == 1);
+
+ result = tq->expire ();
+ ACE_ASSERT (result == 1);
+ ACE_ASSERT (eh.close_count_ == 2);
+
+ ACE_ASSERT (tq->is_empty () != 0);
+
+ ACE_NEW (timer_act, int (4));
+ timer_id = tq->schedule (&eh,
+ timer_act,
+ tq->gettimeofday ());
+ ACE_ASSERT (timer_id != -1);
+
+ ACE_NEW (timer_act, int (4));
+ timer_id2 = tq->schedule (&eh,
+ timer_act,
+ tq->gettimeofday ());
+ ACE_ASSERT (timer_id2 != -1);
+
+ // The following method will trigger a call to <handle_close>.
+ ACE_ASSERT (eh.close_count_ == 2);
+ result = tq->cancel (timer_id, &timer_act);
+ ACE_ASSERT (result != -1);
+ delete (int *) timer_act;
+
+ result = tq->cancel (timer_id2, &timer_act);
+ ACE_ASSERT (result != -1);
+ delete (int *) timer_act;
+
+ ACE_ASSERT (eh.close_count_ == 2); // Only one call to handle_close() even though two timers
+ ACE_ASSERT (tq->is_empty () != 0);
+
+ result = tq->expire ();
+ ACE_ASSERT (result == 0);
+
+ // This tests to make sure that <handle_close> is called when there
+ // is only one timer of the type in the queue
+ ACE_ASSERT (eh.close_count_ == 2);
+
+ ACE_NEW (timer_act, int (007));
+ result = tq->schedule (&eh,
+ timer_act,
+ tq->gettimeofday ());
+ ACE_ASSERT (result != -1);
+
+ result = tq->expire ();
+ ACE_ASSERT (result == 1);
+ ACE_ASSERT (eh.close_count_ == 3);
+
+ ACE_NEW (timer_act, int (6));
+ timer_id = tq->schedule (&eh,
+ timer_act,
+ tq->gettimeofday ());
+ ACE_ASSERT (timer_id != -1);
+
+ ACE_NEW (timer_act, int (7));
+ timer_id2 = tq->schedule (&eh,
+ timer_act,
+ tq->gettimeofday ());
+ ACE_ASSERT (timer_id2 != -1);
+
+ ACE_ASSERT (eh.close_count_ == 3);
+
+ result = tq->cancel (timer_id, &timer_act);
+ delete (int *) timer_act;
+ ACE_ASSERT (result == 1);
+ ACE_ASSERT (eh.close_count_ == 3);
+
+ result = tq->cancel (timer_id2, &timer_act);
+ delete (int *) timer_act;
+ ACE_ASSERT (result == 1);
+ ACE_ASSERT (eh.close_count_ == 3);
+
+ result = tq->expire ();
+ ACE_ASSERT (result == 0);
+ ACE_ASSERT (eh.close_count_ == 3);
+}
+
+static void
+test_performance (ACE_Timer_Queue *tq,
+ const ACE_TCHAR *test_name)
+{
+ Example_Handler eh;
+ ACE_Profile_Timer timer;
+ int i;
+ const void *timer_act = 0;
+
+ ACE_ASSERT (tq->is_empty () != 0);
+ ACE_ASSERT (ACE_Time_Value::zero == ACE_Time_Value (0));
+
+ // Test the amount of time required to schedule all the timers.
+
+ ACE_Time_Value *times = 0;
+ ACE_NEW (times, ACE_Time_Value[max_iterations]);
+
+ // Set up a bunch of times TIMER_DISTANCE ms apart.
+ for (i = 0; i < max_iterations; i++)
+ times[i] = tq->gettimeofday() + ACE_Time_Value(0, i * TIMER_DISTANCE * 1000);
+
+ ACE_Time_Value last_time = times[max_iterations-1];
+
+ timer.start ();
+
+ for (i = 0; i < max_iterations; i++)
+ {
+ ACE_NEW (timer_act, int (42));
+ timer_ids[i] = tq->schedule (&eh,
+ timer_act,
+ times[i]);
+ ACE_ASSERT (timer_ids[i] != -1);
+ }
+
+ ACE_ASSERT (tq->is_empty () == 0);
+
+ timer.stop ();
+
+ ACE_Profile_Timer::ACE_Elapsed_Time et;
+
+ timer.elapsed_time (et);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("time to schedule %d timers for %s\n"),
+ max_iterations, test_name));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("real time = %f secs, user time = %f secs, system time = %f secs\n"),
+ et.real_time, et.user_time, et.system_time));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("time per call = %f usecs\n"),
+ (et.user_time / ACE_timer_t (max_iterations)) * 1000000));
+
+ // Test the amount of time required to cancel all the timers.
+
+ timer.start ();
+
+ for (i = max_iterations - 1; i >= 0; i--)
+ {
+ tq->cancel (timer_ids[i], &timer_act);
+ delete (int *) timer_act;
+ }
+
+ timer.stop ();
+
+ ACE_ASSERT (tq->is_empty () != 0);
+
+ timer.elapsed_time (et);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("time to cancel %d timers for %s\n"),
+ max_iterations, test_name));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("real time = %f secs, user time = %f secs, system time = %f secs\n"),
+ et.real_time, et.user_time, et.system_time));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("time per call = %f usecs\n"),
+ (et.user_time / ACE_timer_t (max_iterations)) * 1000000));
+
+ // Test the amount of time required to schedule and expire all the
+ // timers.
+
+ timer.start ();
+
+ for (i = 0; i < max_iterations; i++)
+ {
+ ACE_NEW (timer_act, int (42));
+ long result = tq->schedule (&eh, timer_act, times[i]);
+ ACE_ASSERT (result != -1);
+ }
+
+ ACE_ASSERT (tq->is_empty () == 0);
+
+ // Expire all the timers.
+ tq->expire (last_time + ACE_Time_Value(1));
+
+ timer.stop ();
+
+ ACE_ASSERT (tq->is_empty () != 0);
+
+ timer.elapsed_time (et);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("time to schedule and expire %d timers for %s\n"),
+ max_iterations, test_name));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("real time = %f secs, user time = %f secs, system time = %f secs\n"),
+ et.real_time, et.user_time, et.system_time));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("time per call = %f usecs\n"),
+ (et.user_time / ACE_timer_t (max_iterations)) * 1000000));
+
+ randomize_array (times, max_iterations);
+
+ // Test the amount of time required to randomly cancel all the
+ // timers.
+
+ for (i = 0; i < max_iterations; i++)
+ {
+ ACE_NEW (timer_act, int (42));
+ timer_ids[i] = tq->schedule (&eh,
+ timer_act,
+ times[i]);
+ ACE_ASSERT (timer_ids[i] != -1);
+ }
+
+ ACE_ASSERT (tq->is_empty () == 0);
+
+ timer.start ();
+
+ for (i = max_iterations - 1; i >= 0; i--)
+ {
+ tq->cancel (timer_ids[i], &timer_act);
+ delete (int *) timer_act;
+ }
+
+ ACE_ASSERT (tq->is_empty () != 0);
+
+ timer.stop ();
+
+ timer.elapsed_time (et);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("time to randomly cancel %d timers for %s\n"),
+ max_iterations,
+ test_name));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("real time = %f secs, user time = %f secs, system time = %f secs\n"),
+ et.real_time,
+ et.user_time,
+ et.system_time));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("time per call = %f usecs\n"),
+ (et.user_time / ACE_timer_t (max_iterations)) * 1000000));
+
+ // Test the amount of time required to randomly schedule all the timers.
+
+ timer.start ();
+
+ for (i = 0; i < max_iterations; i++)
+ {
+ ACE_NEW (timer_act, int (42));
+ timer_ids[i] = tq->schedule (&eh,
+ timer_act,
+ times[i]);
+ ACE_ASSERT (timer_ids[i] != -1);
+ }
+
+ timer.stop ();
+
+ ACE_ASSERT (tq->is_empty () == 0);
+
+ timer.elapsed_time (et);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("time to randomly schedule %d timers for %s\n"),
+ max_iterations, test_name));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("real time = %f secs, user time = %f secs, system time = %f secs\n"),
+ et.real_time,
+ et.user_time,
+ et.system_time));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("time per call = %f usecs\n"),
+ (et.user_time / ACE_timer_t (max_iterations)) * 1000000));
+
+ // Test the amount of time required to expire all the timers.
+
+ timer.start ();
+
+ tq->expire (last_time + ACE_Time_Value(1));
+
+ ACE_ASSERT (tq->is_empty ());
+
+ timer.stop ();
+
+ timer.elapsed_time (et);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("time to expire %d randomly scheduled timers for %s\n"),
+ max_iterations, test_name));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("real time = %f secs, user time = %f secs, system time = %f secs\n"),
+ et.real_time, et.user_time, et.system_time));
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("time per call = %f usecs\n"),
+ (et.user_time / ACE_timer_t (max_iterations)) * 1000000));
+
+ delete [] times;
+}
+
+// This test function was contributed with Bugzilla #2447 to test validity
+// of ACE_Timer_Heap timer IDs around the boundary of having to enlarge
+// the heap.
+static void
+test_unique_timer_heap_ids (void)
+{
+ Example_Handler eh;
+ ACE_Timer_Heap timer_heap (44);
+ ACE_Time_Value anytime(1);
+ ACE_Bounded_Set<long> timer_ids (max_iterations);
+ long timer_id = -1;
+ bool all_unique = true;
+
+ for (int i = 0; i < 100; ++i)
+ {
+ timer_id = timer_heap.schedule (&eh, 0, anytime);
+ if (timer_id == -1)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Schedule timer %d %p\n"),
+ i,
+ ACE_TEXT ("test_unique_timer_heap_ids")));
+ continue;
+ }
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Schedule timer %d. Timer id = %d\n"),
+ i,
+ timer_id));
+ if (1 == timer_ids.insert (timer_id))
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("Pass %d, id %d is not unique\n"),
+ i,
+ timer_id));
+ all_unique = false;
+ }
+
+ if (i == 0 || i == 1 || i == 47 || i == 48)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Free Timer %d. Timer Id = %d\n"),
+ i,
+ timer_id));
+ timer_heap.cancel (timer_id);
+ if (timer_id == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("Failed to cancel timer")));
+
+ timer_ids.remove (timer_id);
+ }
+ }
+
+ if (all_unique)
+ ACE_DEBUG ((LM_INFO, ACE_TEXT ("All timer ids were unique.\n")));
+
+ return;
+}
+
+class Timer_Queue_Stack
+{
+ // = TITLE
+ // Keeps track of the <Timer_Queue>s that we're going to test.
+ //
+ // = DESCRIPTION
+ // This data structure is organized as a stack to make it easy to implement.
+public:
+ // = Initialization method
+ Timer_Queue_Stack (ACE_Timer_Queue *queue,
+ const ACE_TCHAR *name,
+ Timer_Queue_Stack *next = 0)
+ : queue_ (queue),
+ name_ (name),
+ next_ (next)
+ {}
+ // "Push" a new <queue> on the stack of <queue>s.
+
+ ACE_Timer_Queue *queue_;
+ // Pointer to the subclass of <ACE_Timer_Queue> that we're testing.
+
+ const ACE_TCHAR *name_;
+ // Name of the Queue that we're testing.
+
+ Timer_Queue_Stack *next_;
+ // Pointer to the next <Timer_Queue>.
+};
+
+int
+run_main (int argc, ACE_TCHAR *argv[])
+{
+ ACE_START_TEST (ACE_TEXT ("Timer_Queue_Test"));
+
+ ACE_OS::srand (ACE_OS::time (0L));
+
+ if (argc > 1)
+ max_iterations = ACE_OS::atoi (argv[1]);
+
+ // = Perform initializations.
+
+ Timer_Queue_Stack *tq_stack = 0;
+
+ // Add new Timer_Queue implementations here. Note that these will
+ // be executed in "reverse order".
+
+ // Timer_Hash (Heap)
+ ACE_NEW_RETURN (tq_stack,
+ Timer_Queue_Stack (new ACE_Timer_Hash_Heap,
+ ACE_TEXT ("ACE_Timer_Hash (Heap)"),
+ tq_stack),
+ -1);
+
+ // Timer_Hash
+ ACE_NEW_RETURN (tq_stack,
+ Timer_Queue_Stack (new ACE_Timer_Hash,
+ ACE_TEXT ("ACE_Timer_Hash"),
+ tq_stack),
+ -1);
+
+ // Timer_stack
+ ACE_NEW_RETURN (tq_stack,
+ Timer_Queue_Stack (new ACE_Timer_List,
+ ACE_TEXT ("ACE_Timer_List"),
+ tq_stack),
+ -1);
+
+ // Timer_Wheel without preallocated memory
+ ACE_NEW_RETURN (tq_stack,
+ Timer_Queue_Stack (new ACE_Timer_Wheel,
+ ACE_TEXT ("ACE_Timer_Wheel (non-preallocated)"),
+ tq_stack),
+ -1);
+
+ // Timer_Wheel with preallocated memory.
+ ACE_NEW_RETURN (tq_stack,
+ Timer_Queue_Stack (new ACE_Timer_Wheel (ACE_DEFAULT_TIMER_WHEEL_SIZE,
+ ACE_DEFAULT_TIMER_WHEEL_RESOLUTION,
+ max_iterations),
+ ACE_TEXT ("ACE_Timer_Wheel (preallocated)"),
+ tq_stack),
+ -1);
+ // Timer_Heap without preallocated memory.
+ ACE_NEW_RETURN (tq_stack,
+ Timer_Queue_Stack (new ACE_Timer_Heap,
+ ACE_TEXT ("ACE_Timer_Heap (non-preallocated)"),
+ tq_stack),
+ -1);
+
+ // Timer_Heap with preallocate memory.
+ ACE_NEW_RETURN (tq_stack,
+ Timer_Queue_Stack (new ACE_Timer_Heap (max_iterations, 1),
+ ACE_TEXT ("ACE_Timer_Heap (preallocated)"),
+ tq_stack),
+ -1);
+
+ // Timer_Heap without preallocated memory, using high-res time.
+ (void) ACE_High_Res_Timer::global_scale_factor ();
+ ACE_Timer_Heap *tq_heap = new ACE_Timer_Heap;
+ tq_heap->gettimeofday (&ACE_High_Res_Timer::gettimeofday_hr);
+ ACE_NEW_RETURN (tq_stack,
+ Timer_Queue_Stack (tq_heap,
+ ACE_TEXT ("ACE_Timer_Heap (high-res timer)"),
+ tq_stack),
+ -1);
+
+ // Create the Timer ID array
+ ACE_NEW_RETURN (timer_ids,
+ long[max_iterations],
+ -1);
+
+ Timer_Queue_Stack *tq_ptr = tq_stack;
+
+ while (tq_ptr != 0)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("**** starting test of %s\n"),
+ tq_ptr->name_));
+ test_functionality (tq_ptr->queue_);
+ test_performance (tq_ptr->queue_,
+ tq_ptr->name_);
+ delete tq_ptr->queue_;
+ Timer_Queue_Stack *temp = tq_ptr;
+ tq_ptr = tq_ptr->next_;
+ delete temp;
+ }
+ delete [] timer_ids;
+
+ ACE_DEBUG
+ ((LM_DEBUG,
+ ACE_TEXT ("**** starting unique IDs test for ACE_Timer_Heap\n")));
+ test_unique_timer_heap_ids ();
+
+ ACE_END_TEST;
+ return 0;
+}
+
diff --git a/ACE/tests/TkReactor_Test.cpp b/ACE/tests/TkReactor_Test.cpp
new file mode 100644
index 00000000000..e95169ffe90
--- /dev/null
+++ b/ACE/tests/TkReactor_Test.cpp
@@ -0,0 +1,316 @@
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// TkReactor_Test.cpp
+//
+// = DESCRIPTION
+// This is a simple test that illustrates the possibility to integrate
+// ACE to the Tk Main Loop. This program uses ACE_TkReactor class to
+// schedule three additional event sources:
+// 1. Events from button "Stop Test" (registed with Tk_CreateEventHandler)
+// 2. Events from button "Press Me" (registed with Tk_CreateEventHandler)
+// 3. Events from X timer (registed with Tk_CreateTimerHandler)
+// 4. Events from ACE timer (registed with ACE_TkReactor::schedule_timer)
+// 5. Events from the TCP/IP channel using ACE_Acceptor
+// No command line arguments are needed to run the test.
+//
+// = AUTHOR
+// Nagarajan Surendran <naga@cs.wustl.edu>
+//
+// ============================================================================
+
+#include "test_config.h"
+
+ACE_RCSID (tests,
+ TkReactor_Test,
+ "$Id$")
+
+#include "ace/Event_Handler.h"
+#include "ace/Acceptor.h"
+#include "ace/SOCK_Acceptor.h"
+#include "ace/SOCK_Connector.h"
+#include "ace/Service_Config.h"
+#include "ace/Thread_Manager.h"
+#include "ace/TkReactor.h"
+#include "ace/OS_NS_unistd.h"
+
+#include <tcl.h>
+#include <tk.h>
+
+Tcl_Interp* tcl_interp;
+void eval (const char *s)
+{
+ char buf[BUFSIZ];
+ strcpy (buf,s);
+ int st = Tcl_GlobalEval(tcl_interp,buf);
+ if (st != TCL_OK)
+ {
+ int n = strlen(s);
+ char* wrk = new char[n + 80];
+ sprintf(wrk, "tkerror \"%s\"", s);
+ Tcl_GlobalEval(tcl_interp, wrk);
+ delete wrk;
+ //exit(1);
+ }
+}
+
+// Port we listen on.
+static const u_short SERV_TCP_PORT = 6670;
+
+// counter for events from "Press Me" button.
+static int count1 = 0;
+
+// counter for events from Tk Timer.
+static int count2 = 0;
+
+// counter for events from ACE Timer.
+static int count3 = 0;
+
+static int quit = 0;
+// Callback for "Stop Test" buton - quit the program.
+void
+Quit (ClientData, XEvent *)
+{
+ ACE_DEBUG ((LM_DEBUG,"Quit called\n"));
+ quit = 1;
+}
+
+static void *
+client (void *)
+{
+ char buf[100];
+ size_t mes_len;
+ ACE_OS::sleep (1);
+
+ ACE_DEBUG ((LM_DEBUG,
+ " (%P) Client: Starting...\n"));
+
+ ACE_SOCK_Stream stream;
+ ACE_SOCK_Connector connector;
+ sprintf (buf, "Client: the life was good!");
+
+ mes_len = (int) htonl (ACE_OS::strlen (buf) + 1);
+
+ if (connector.connect (stream,
+ ACE_INET_Addr (SERV_TCP_PORT,
+ ACE_DEFAULT_SERVER_HOST)) == -1)
+ ACE_ERROR ((LM_ERROR,
+ "(%P) %p\n",
+ "Socket open"));
+
+ if (stream.send (4,
+ (void *) &mes_len,
+ sizeof (size_t),
+ (void *)buf,
+ ACE_OS::strlen (buf) + 1) == -1)
+
+ ACE_ERROR ((LM_ERROR,
+ "(%P) %p\n",
+ "Socket send"));
+
+ if (stream.close () == -1)
+ ACE_ERROR ((LM_ERROR,
+ "(%P) %p\n",
+ "Socket close"));
+
+ ACE_DEBUG ((LM_DEBUG,
+ "(%P) Client: Message has been sent, about to exit...\n"));
+ return 0;
+}
+
+// Callback for "Press Me" button.
+
+static int
+inc_count (ClientData client_data, Tcl_Interp *interp,int, const char **)
+{
+ ACE_DEBUG ((LM_DEBUG,"inc_count "));
+ char new_string[80];
+
+ sprintf (new_string,
+ "Events: [%d] [%d] [%d]",
+ count1++,
+ count2,
+ count3);
+
+ // sprintf (command,"set %s %s",(char *)client_data,new_string);
+ // eval (command);
+ const char *varValue = Tcl_SetVar (interp,(char *)client_data,new_string,TCL_LEAVE_ERR_MSG);
+ if (varValue == 0)
+ return TCL_ERROR;
+ return TCL_OK;
+}
+
+// Callback for X Timer.
+
+static void
+inc_tmo (ClientData client_data)
+{
+ char new_string[80];
+
+ if (count2 > 10)
+ ACE_OS::exit (0);
+ sprintf (new_string,
+ "Events: [%d] [%d] [%d]",
+ count1,
+ count2++,
+ count3);
+
+ // sprintf (command,"set %s %s",(char *)client_data,new_string);
+ // eval (command);
+ const char *varValue = Tcl_SetVar (tcl_interp,(char *)client_data,new_string,TCL_LEAVE_ERR_MSG);
+ if (varValue == 0)
+ ACE_ERROR ((LM_ERROR,"Tcl_SetVar failed in inc_tmo\n"));
+
+ (void) Tk_CreateTimerHandler (1000,
+ inc_tmo,
+ client_data);
+}
+
+class EV_handler : public ACE_Event_Handler
+{
+public:
+ virtual int handle_timeout (const ACE_Time_Value &,
+ const void *arg)
+ {
+ char new_string[80];
+ sprintf (new_string,
+ "Events: [%d] [%d] [%d]",
+ count1,
+ count2,
+ count3++);
+
+ // sprintf (command,"set %s %s",(char *)arg,new_string);
+ // eval (command);
+ const char *varValue = Tcl_SetVar (tcl_interp,(char *)arg,new_string,TCL_LEAVE_ERR_MSG);
+ if (varValue == 0)
+ ACE_ERROR_RETURN ((LM_ERROR,"Tcl_SetVar failed in handle_timeout\n"),-1);
+
+ return 0;
+ }
+};
+
+class Connection_Handler : public ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH>
+{
+public:
+ virtual int open (void *)
+ {
+ char buf[100];
+ int head;
+ ssize_t ret = this->peer ().recv_n ((char *) &head,
+ sizeof (int));
+ if (ret != sizeof (int))
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "(%P) %p\n",
+ "read header"),
+ -1);
+
+ ret = this->peer ().recv_n (buf,
+ (int) ntohl (head));
+
+ if (ret != (int) ntohl (head))
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "(%P) %p\n",
+ "read message"),
+ -1);
+ ACE_DEBUG ((LM_DEBUG,
+ " (%P)Server (ACE_SOCKET channel message): [%s]\n",
+ buf));
+ return 0;
+ }
+};
+
+int
+init (Tcl_Interp *interp)
+{
+ if (Tcl_Init (interp) == TCL_ERROR)
+ return TCL_ERROR;
+ if (Tk_Init (interp) == TCL_ERROR)
+ return TCL_ERROR;
+ return TCL_OK;
+}
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("TkReactor_Test"));
+
+ tcl_interp = Tcl_CreateInterp ();
+
+ if (init (tcl_interp) != TCL_OK) {
+ exit (1);
+ }
+
+ Tk_Window tk = 0;
+ tk = Tk_MainWindow(tcl_interp);
+ if (tk == 0)
+ {
+ ACE_ERROR_RETURN ((LM_ERROR, "Tk_Reactor_Test: %s\n", tcl_interp->result),1);
+ }
+
+ char tcl_cmd[] = "source TkReactor_Test.tcl";
+ if (Tcl_Eval (tcl_interp, tcl_cmd) != TCL_OK) {
+ exit (1);
+ }
+ // set up callback
+ char label_var_name[] = "label_var";
+ char pressme[] = "pressme";
+ Tcl_CreateCommand (tcl_interp,
+ pressme,
+ inc_count,
+ label_var_name,
+ 0);
+
+ // Register callback for X Timer
+ (void) Tk_CreateTimerHandler (1000,
+ inc_tmo,
+ label_var_name);
+
+ // It will perform Tk Main Loop
+ ACE_TkReactor reactor;
+ ACE_Reactor r (&reactor);
+
+ //Event Handler for ACE Timer.
+ EV_handler evh;
+
+ ACE_Acceptor <Connection_Handler, ACE_SOCK_ACCEPTOR> acceptor;
+
+ if (acceptor.open (ACE_INET_Addr ((u_short) SERV_TCP_PORT),
+ &r) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "%p\n",
+ "open"),
+ -1);
+
+ if (reactor.schedule_timer (&evh,
+ (const void *) "label_var",
+ ACE_Time_Value (2),
+ ACE_Time_Value (2))==-1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ " (%P|%t) can't register with reactor\n"),
+ -1);
+
+ ACE_Thread_Manager::instance ()->spawn ((ACE_THR_FUNC) client,
+ 0,
+ THR_NEW_LWP | THR_DETACHED);
+
+ while (!quit)
+ {
+ int result = reactor.handle_events ();
+ switch (result)
+ {
+ case 0:
+ // ACE_DEBUG ((LM_DEBUG,"handle_events timed out\n"));
+ break;
+ case -1:
+ ACE_DEBUG ((LM_DEBUG,"handle_events returned -1\n"));
+ quit = 1;
+ break;
+ }
+ }
+
+ ACE_END_TEST;
+ return 0;
+}
diff --git a/ACE/tests/TkReactor_Test.tcl b/ACE/tests/TkReactor_Test.tcl
new file mode 100644
index 00000000000..2d9207dc126
--- /dev/null
+++ b/ACE/tests/TkReactor_Test.tcl
@@ -0,0 +1,15 @@
+# This file works in conjunction with the C++ source code in TkReactor_Test.cpp
+
+
+# Create a frame.
+set label_var "label for all events"
+
+# Add the new dude button.
+button .pressme -text "Press me" -command pressme
+
+# Add a quit button.
+button .goodbye -text "Quit" -command exit
+
+label .label_for_event_one -textvariable label_var
+
+pack .label_for_event_one .goodbye .pressme -side top -anchor w
diff --git a/ACE/tests/Token_Strategy_Test.cpp b/ACE/tests/Token_Strategy_Test.cpp
new file mode 100644
index 00000000000..c2d9367b913
--- /dev/null
+++ b/ACE/tests/Token_Strategy_Test.cpp
@@ -0,0 +1,245 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = DESCRIPTION
+// This program tests the behavior of ACE_Token under a variety of scenarios
+// in order verify whether or not tokens are returned, and threads run, in
+// a LIFO or FIFO manner.
+//
+// = AUTHOR
+// Don Hinton <dhinton@ieee.org>
+//
+// ============================================================================
+
+#include "tests/test_config.h"
+#include "ace/Token.h"
+#include "ace/Task.h"
+#include "ace/Atomic_Op.h"
+#include "ace/Auto_IncDec_T.h"
+#include "ace/Vector_T.h"
+#include "ace/Stats.h"
+#include "ace/ACE.h"
+#include "ace/Barrier.h"
+
+ACE_RCSID(tests, Token_Strategy_Test, "$Id$")
+
+#if defined (ACE_HAS_THREADS)
+
+class Token_Strategy_Test : public ACE_Task<ACE_MT_SYNCH>
+{
+public:
+
+ Token_Strategy_Test (ACE_Token::QUEUEING_STRATEGY strategy = ACE_Token::FIFO,
+ int threads = 5, int invocations = 10);
+ ~Token_Strategy_Test (void);
+
+ int open (void *a = 0);
+ int svc (void);
+
+private:
+ // Number of threads for the test, must be 5 or more.
+ int threads_;
+
+ // Barrier used to try to synchronize the for loop in the svc() method.
+ ACE_Barrier barrier_;
+
+ // Token used to synchonize for loop.
+ ACE_Token token_;
+
+ // Token strategy to use, LIFO/FIFO.
+ ACE_Token::QUEUEING_STRATEGY strategy_;
+
+ // Number of loops.
+ int invocations_;
+
+ // Vector of token counts, one per thread.
+ ACE_Vector<ACE_INT32> vec_token_count_;
+
+ // This keeps a count of the number of threads who have the token--should always
+ // be 0 or 1;
+ ACE_Atomic_Op<ACE_Thread_Mutex, int> counter_;
+
+ // Number of active threads in svc() method.
+ ACE_Atomic_Op<ACE_Thread_Mutex, int> active_;
+
+ // Errors count, set in svc() and returned from open().
+ ACE_Atomic_Op<ACE_Thread_Mutex, int> errors_;
+
+ ACE_UNIMPLEMENTED_FUNC (Token_Strategy_Test (const Token_Strategy_Test &))
+ ACE_UNIMPLEMENTED_FUNC (Token_Strategy_Test &operator= (const Token_Strategy_Test &))
+};
+
+
+Token_Strategy_Test::Token_Strategy_Test (ACE_Token::QUEUEING_STRATEGY strategy, int threads, int invocations)
+ : threads_ (threads < 5 ? 5 : threads), // need at least 5 threads to satisfy test conditions.
+ barrier_ (threads_),
+ strategy_ (strategy),
+ invocations_ (invocations < 10 ? 10 : invocations), // insure we loop at least a few times.
+ vec_token_count_ (threads_)
+{
+ this->counter_ = 0;
+ this->active_ = 0;
+ this->errors_ = 0;
+
+ // Initialize the per thread counters used for generating stats.
+ for (int i = 0; i < this->threads_; ++i)
+ {
+ const ACE_UINT32 sample = 0;
+ this->vec_token_count_.push_back (sample);
+ }
+
+ this->token_.queueing_strategy (this->strategy_);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT (" (tid = %t) Token_Test::Token_Test (\n")
+ ACE_TEXT (" token_type = %s\n")
+ ACE_TEXT (" thread = %d\n")
+ ACE_TEXT (" invocations = %d\n"),
+ this->strategy_ == ACE_Token::FIFO ? ACE_TEXT ("FIFO") : ACE_TEXT ("LIFO"),
+ this->threads_,
+ this->invocations_));
+}
+
+Token_Strategy_Test::~Token_Strategy_Test (void)
+{}
+
+int
+Token_Strategy_Test::open (void *)
+{
+ // spawn threads in ace task...
+ // Make this Task into an Active Object.
+ this->activate (THR_BOUND | THR_DETACHED, this->threads_);
+
+ // Wait for all the threads to exit.
+ this->thr_mgr ()->wait ();
+ return this->errors_.value ();
+}
+
+int
+Token_Strategy_Test::svc (void)
+{
+ int current = this->active_.value ();
+ ACE_Auto_IncDec<ACE_Atomic_Op<ACE_Thread_Mutex, int> > active_counter (this->active_);
+ this->barrier_.wait ();
+
+
+ //ACE_DEBUG ((LM_DEBUG, ACE_TEXT (" (tid = %t) starting loop\n")));
+ for (int i = 0; i < this->invocations_; i++)
+ {
+ ACE_GUARD_RETURN (ACE_Token, lock, this->token_, -1);
+ this->vec_token_count_[current]++;
+ ACE_Auto_IncDec<ACE_Atomic_Op<ACE_Thread_Mutex, int> > token_count_counter (this->counter_);
+
+ // Turn this on to watch each thread grab the token. LIFO has the interesting
+ // behavior that two thread seem to take turns while all the other threads wait.
+ if (0)
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT (" (tid = %t) token count = %d, ")
+ ACE_TEXT ("waiters = %d, loop: %d/%d\n"),
+ this->counter_.value (),
+ this->token_.waiters (), i + 1,
+ this->invocations_));
+
+ // Yield, then simulate some work in order to give the other threads a chance to queue up.
+ ACE_Thread::yield ();
+ for (int k = 0; k != 100; ++k)
+ {
+ ACE::is_prime (k, 2, k/2);
+ }
+
+ // If we are the first thread to finish, compute the stats.
+ if (i + 1 == this->invocations_)
+ {
+ if (this->active_ == this->threads_)
+ {
+ ACE_Stats stats;
+ ACE_Stats_Value std_dev (2);
+ ACE_Stats_Value mean (2);
+ for (int i = 0; i < this->threads_; ++i)
+ {
+ stats.sample (this->vec_token_count_[i]);
+ }
+
+ //stats.print_summary (2);
+ stats.std_dev (std_dev);
+ stats.mean (mean);
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT (" (tid = %t) mean = %d.%d, std_dev = %d.%d, max = %d, min = %d\n"),
+ mean.whole (), mean.fractional (), std_dev.whole (), std_dev.fractional (),
+ stats.max_value (), stats.min_value ()));
+
+ // These are pretty simplistic tests, so let me know if you have a better idea.
+ // The assumption is that the standard deviation will be small when using the
+ // FIFO strategy since all threads will share the token more or less evenly.
+ // In contrast, the LIFO strategy will allow the two threads to alternate, thus
+ // several threads will have a low, or zero, token count and create a low mean and
+ // high standard deviation. If the the thread count is over say 4 or 5, the
+ // standard deviation will actually excide the mean, hence the test.
+ if (this->strategy_ == ACE_Token::LIFO &&
+ (mean.whole () > std_dev.whole () &&
+ mean.fractional () > std_dev.fractional ()))
+ {
+ ACE_DEBUG ((LM_ERROR,
+ ACE_TEXT (" (tid = %t) LIFO: mean greater than std_dev.\n")));
+ this->errors_++;
+ }
+ if (this->strategy_ == ACE_Token::FIFO &&
+ (mean.whole () < std_dev.whole () &&
+ mean.fractional () < std_dev.fractional ()))
+ {
+ ACE_DEBUG ((LM_ERROR,
+ ACE_TEXT (" (tid = %t) FIFO: mean less than std_dev.\n")));
+ this->errors_++;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+
+int run_test (ACE_Token::QUEUEING_STRATEGY strategy, int threads = 5,
+ int invocations = 10)
+{
+ Token_Strategy_Test test (strategy, threads, invocations);
+ return test.open () == 0 ? 0 : 1;
+}
+
+int
+run_main (int argc, ACE_TCHAR *argv[])
+{
+ ACE_START_TEST (ACE_TEXT ("Token_Strategy_Test"));
+ int retval = 0;
+
+ if (argc > 3)
+ {
+ // print usage
+ retval = 1;
+ }
+ else
+ {
+ int threads = 5;
+ int invocations = 100;
+
+ if (argc > 1) threads = ACE_OS::atoi (argv[1]);
+ if (argc > 2) invocations = ACE_OS::atoi (argv[2]);
+
+ // New test using ACE_Token::queueing_strategy ()
+ retval += run_test (ACE_Token::FIFO, threads, invocations);
+ retval += run_test (ACE_Token::LIFO, threads, invocations);
+ }
+
+ ACE_END_TEST;
+ return retval;
+}
+
+#else /* ACE_HAS_THREADS */
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("Token_Strategy_Test: your platform doesn't support threads\n")), 1);
+}
+#endif /* ACE_HAS_THREADS */
diff --git a/ACE/tests/Tokens_Test.cpp b/ACE/tests/Tokens_Test.cpp
new file mode 100644
index 00000000000..434b0b6c477
--- /dev/null
+++ b/ACE/tests/Tokens_Test.cpp
@@ -0,0 +1,330 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Tokens_Test.cpp
+//
+// = DESCRIPTION
+// This application tests the ACE Token library including local
+// and remote readers/writer and mutex locks, and token
+// collections. This is accomplished with the ACE Token Invariant
+// utilities that allow and application to check that
+// readers/writer and mutex lock invariants are always satisfied.
+// Throughout this test, ACE_ASSERTs are used in conjunction with
+// Token Invariant operations, so that errors are reported using
+// the ACE tests convention. This application performs a local
+// test and then fork_execs a token server and performs the same
+// test remotely.
+//
+// = AUTHOR
+// Tim Harrison <harrison@cs.wustl.edu>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/Process.h"
+#include "ace/Get_Opt.h"
+#include "ace/Local_Tokens.h"
+#include "ace/Token_Collection.h"
+#include "ace/Remote_Tokens.h"
+#include "ace/Thread_Manager.h"
+#include "ace/Token_Invariants.h"
+#include "ace/Barrier.h"
+#include "ace/OS_NS_unistd.h"
+
+ACE_RCSID(tests, Tokens_Test, "$Id$")
+
+#if defined (ACE_HAS_THREADS) && defined (ACE_HAS_TOKENS_LIBRARY)
+
+typedef ACE_Token_Invariant_Manager TOKEN_INVARIANTS;
+
+static const ACE_TCHAR *server_host = ACE_DEFAULT_SERVER_HOST;
+static const int server_port = 23456;
+
+// Synchronize starts of threads, so that they all start before one
+// has a chance to finish and clean up the TSS objects. To avoid
+// creating a static object, it is dynamically allocated, before
+// spawning any threads.
+static ACE_Barrier *thread_start;
+
+struct Test_Params
+{
+public:
+ ACE_Token_Proxy *token1_;
+ ACE_Token_Proxy *token2_;
+ const ACE_TCHAR *collection_name_;
+};
+
+static void *
+run_thread (void *vp)
+{
+ Test_Params *tp = (Test_Params *) vp;
+ ACE_Token_Collection collection (1, tp->collection_name_);
+ collection.insert (*(tp->token1_));
+ collection.insert (*(tp->token2_));
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) new thread.\n")));
+ thread_start->wait ();
+
+ int count = 50;
+ while (count--)
+ {
+ if (collection.acquire () == -1)
+ {
+ if (ACE_OS::last_error () == EDEADLK)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("deadlock detected in acquire")));
+ continue;
+ }
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%t) %p acquire failed\n"),
+ ACE_TEXT ("run_thread")));
+ return (void *) -1;
+ }
+
+ ACE_ASSERT ((TOKEN_INVARIANTS::instance ()->acquired (tp->token1_) == 1) ||
+ (TOKEN_INVARIANTS::instance ()->acquired (tp->token2_) == 1));
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) %s acquired.\n"),
+ collection.name ()));
+
+ TOKEN_INVARIANTS::instance ()->releasing (tp->token1_);
+ TOKEN_INVARIANTS::instance ()->releasing (tp->token2_);
+
+ if (collection.renew () == -1)
+ {
+ if (ACE_OS::last_error () == EDEADLK)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("deadlock detected")));
+ goto deadlock;
+ }
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%t) %p renew failed\n"),
+ ACE_TEXT ("run_thread")));
+ return (void *) -1;
+ }
+
+ ACE_ASSERT (TOKEN_INVARIANTS::instance ()->acquired (tp->token1_) == 1 ||
+ TOKEN_INVARIANTS::instance ()->acquired (tp->token2_) == 1);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) %s renewed.\n"),
+ collection.name ()));
+
+ deadlock:
+
+ TOKEN_INVARIANTS::instance ()->releasing (tp->token1_);
+ TOKEN_INVARIANTS::instance ()->releasing (tp->token2_);
+
+ if (collection.release () == -1)
+ {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%t) %p release failed\n"),
+ ACE_TEXT ("run_thread")));
+ return (void *) -1;
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) %s released.\n"),
+ collection.name ()));
+ }
+
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) thread finished.\n")));
+
+ return 0;
+}
+
+static int
+run_test (ACE_Token_Proxy *A,
+ ACE_Token_Proxy *B,
+ ACE_Token_Proxy *R,
+ ACE_Token_Proxy *W)
+{
+ // Parameters to be passed to the threads.
+ Test_Params tp1, tp2, tp3;
+
+ // tp1 and tp2 can run concurrently. Neither tp1 or tp3 can run
+ // when tp2 is running.
+ tp1.collection_name_ = ACE_TEXT ("A and Reader");
+ tp1.token1_ = A;
+ tp1.token2_ = R;
+
+ tp2.collection_name_ = ACE_TEXT ("A and Writer");
+ tp2.token1_ = A;
+ tp2.token2_ = W;
+
+ tp3.collection_name_ = ACE_TEXT ("B and Reader");
+ tp3.token1_ = B;
+ tp3.token2_ = R;
+
+ // Spawn off three threads.
+ ACE_Thread_Manager *mgr = ACE_Thread_Manager::instance ();
+
+ if (mgr->spawn (ACE_THR_FUNC (run_thread),
+ (void *) &tp1,
+ THR_BOUND) == -1)
+ ACE_ERROR_RETURN ((LM_DEBUG,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("spawn 1 failed")),
+ -1);
+
+ if (mgr->spawn (ACE_THR_FUNC (run_thread),
+ (void *) &tp2,
+ THR_BOUND) == -1)
+ ACE_ERROR_RETURN ((LM_DEBUG,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("spawn 2 failed")),
+ -1);
+
+ if (mgr->spawn (ACE_THR_FUNC (run_thread),
+ (void *) &tp3,
+ THR_BOUND) == -1)
+ ACE_ERROR_RETURN ((LM_DEBUG,
+ ACE_TEXT ("%p\n"),
+ ACE_TEXT ("spawn 3 failed")), -1);
+
+ // Wait for all threads to exit.
+ mgr->wait ();
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Test finished.\n")));
+ return 0;
+}
+#endif /* ACE_HAS_THREADS && ACE_HAS_TOKENS_LIBRARY */
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("Tokens_Test"));
+#if defined (ACE_HAS_THREADS)
+#if defined (ACE_HAS_TOKENS_LIBRARY)
+ ACE_Token_Proxy *A = 0, *B = 0, *R = 0, *W = 0;
+
+ ACE_NEW_RETURN (A,
+ ACE_Local_Mutex (ACE_TEXT ("L Mutex A"), 0, 0),
+ -1);
+ ACE_NEW_RETURN (B,
+ ACE_Local_Mutex (ACE_TEXT ("L Mutex B"), 0, 0),
+ -1);
+ ACE_NEW_RETURN (R,
+ ACE_Local_RLock (ACE_TEXT ("L Reader Lock"), 0, 0),
+ -1);
+ ACE_NEW_RETURN (W,
+ ACE_Local_WLock (ACE_TEXT ("L Writer Lock"), 0, 0),
+ -1);
+ ACE_NEW_RETURN (thread_start,
+ ACE_Barrier (3),
+ -1);
+
+ run_test (A, B, R, W);
+
+ const ACE_TCHAR *token_exe =
+ ACE_TEXT ("..") ACE_DIRECTORY_SEPARATOR_STR
+ ACE_TEXT ("netsvcs") ACE_DIRECTORY_SEPARATOR_STR
+ ACE_TEXT ("servers") ACE_DIRECTORY_SEPARATOR_STR
+ ACE_TEXT ("main") ACE_PLATFORM_EXE_SUFFIX;
+
+ int status = ACE_OS::access (token_exe, F_OK);
+ if (status == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("%p\n"),
+ token_exe));
+ else
+ {
+ const ACE_TCHAR *cl =
+ ACE_TEXT ("..") ACE_DIRECTORY_SEPARATOR_STR
+ ACE_TEXT ("netsvcs") ACE_DIRECTORY_SEPARATOR_STR
+ ACE_TEXT ("servers") ACE_DIRECTORY_SEPARATOR_STR
+ ACE_TEXT ("main") ACE_PLATFORM_EXE_SUFFIX
+ ACE_TEXT (" -f ") ACE_PLATFORM
+ ACE_TEXT ("tokens.conf");
+
+ ACE_Process_Options options;
+ options.command_line (cl);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Forking Token Service.\n")));
+
+ // Start up the token server for the remote test.
+ ACE_Process new_process;
+ if (new_process.spawn (options) == -1)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("%n; %p (%s), will not run remote test.\n"),
+ ACE_TEXT ("Server fork failed"),
+ cl));
+ else
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Server forked with pid = %d.\n"),
+ new_process.getpid ()));
+
+ // Wait for the server to start.
+ ACE_OS::sleep (3);
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Using Token Server on %s at port %d.\n"),
+ server_host,
+ server_port));
+ ACE_Remote_Mutex::set_server_address (ACE_INET_Addr (server_port,
+ server_host));
+
+ delete A;
+ delete B;
+ delete R;
+ delete W;
+
+ ACE_NEW_RETURN (A,
+ ACE_Remote_Mutex (ACE_TEXT ("R Mutex A"), 0, 1),
+ -1);
+ ACE_NEW_RETURN (B,
+ ACE_Remote_Mutex (ACE_TEXT ("R Mutex B"), 0, 1),
+ -1);
+ ACE_NEW_RETURN (R,
+ ACE_Remote_RLock (ACE_TEXT ("R Reader Lock"), 0, 1),
+ -1);
+ ACE_NEW_RETURN (W,
+ ACE_Remote_WLock (ACE_TEXT ("R Writer Lock"), 0, 1),
+ -1);
+
+ run_test (A, B, R, W);
+
+ // Wait for the server to finish.
+ ACE_OS::sleep (3);
+
+ // Kill the token server.
+ if (new_process.terminate () == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ ACE_TEXT ("Kill failed.\n")),
+ -1);
+ }
+
+ delete thread_start;
+ thread_start = 0;
+ delete A;
+ delete B;
+ delete R;
+ delete W;
+ }
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) main thread exiting.\n")));
+#else
+ ACE_ERROR ((LM_INFO,
+ ACE_TEXT ("ACE must be compiled with -DACE_HAS_TOKENS_LIBRARY to run this test\n")));
+#endif /* ACE_HAS_TOKENS_LIBRARY */
+#else
+ ACE_ERROR ((LM_INFO,
+ ACE_TEXT ("threads not supported on this platform\n")));
+#endif /* ACE_HAS_THREADS */
+ ACE_END_TEST;
+ return 0;
+}
diff --git a/ACE/tests/UNIXclerk.conf b/ACE/tests/UNIXclerk.conf
new file mode 100644
index 00000000000..6ea52b0b52b
--- /dev/null
+++ b/ACE/tests/UNIXclerk.conf
@@ -0,0 +1,3 @@
+# Note: hostname and port number need to be concatenated separated by ":"
+dynamic Logging_Strategy Service_Object * ACE:_make_ACE_Logging_Strategy() "-s log/Time_Service_Test_Clerk.log -f OSTREAM"
+dynamic Time_Server_Test Service_Object * netsvcs:_make_ACE_TS_Clerk_Processor () "-h localhost:10222 -t 4"
diff --git a/ACE/tests/UNIXserver.conf b/ACE/tests/UNIXserver.conf
new file mode 100644
index 00000000000..5dcfa378156
--- /dev/null
+++ b/ACE/tests/UNIXserver.conf
@@ -0,0 +1,7 @@
+# These are the services that can be linked into ACE.
+# You can replace the hardcoded "-p xxxxx" with "-p
+# $PORT" if you set your PORT environment variable.
+
+dynamic Logging_Strategy Service_Object * ACE:_make_ACE_Logging_Strategy() "-s log/Time_Service_Test_Server.log -f OSTREAM"
+dynamic Time_Service Service_Object * netsvcs:_make_ACE_TS_Server_Acceptor() "-p 10222"
+
diff --git a/ACE/tests/UNIXtokens.conf b/ACE/tests/UNIXtokens.conf
new file mode 100644
index 00000000000..d15155dc60d
--- /dev/null
+++ b/ACE/tests/UNIXtokens.conf
@@ -0,0 +1,5 @@
+# Solaris version
+
+dynamic Logging_Strategy Service_Object * ACE:_make_ACE_Logging_Strategy() "-s log/Tokens_Test_Server.log -f OSTREAM"
+dynamic Token_Service Service_Object * netsvcs:_make_ACE_Token_Acceptor() "-p 23456"
+
diff --git a/ACE/tests/UPIPE_SAP_Test.cpp b/ACE/tests/UPIPE_SAP_Test.cpp
new file mode 100644
index 00000000000..24d08fdc5f7
--- /dev/null
+++ b/ACE/tests/UPIPE_SAP_Test.cpp
@@ -0,0 +1,186 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// UPIPE_SAP_Test.cpp
+//
+// = DESCRIPTION
+// This is a test that uses <ACE_UPIPE_SAP> and <ACE_Thread> for
+// intra-process communication.
+//
+// = AUTHOR
+// Gerhard Lenzer <Gerhard.Lenzer@med.siemens.de>,
+// Douglas C. Schmidt <schmidt@cs.wustl.edu>, and
+// Prashant Jain <pjain@cs.wustl.edu>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include "ace/Stream.h"
+#include "ace/UPIPE_Acceptor.h"
+#include "ace/UPIPE_Connector.h"
+#include "ace/OS_NS_unistd.h"
+
+ACE_RCSID(tests, UPIPE_SAP_Test, "$Id$")
+
+#if defined (ACE_HAS_THREADS) && (defined (ACE_HAS_STREAM_PIPES) || \
+ (defined (ACE_WIN32) && \
+ defined (ACE_HAS_WINNT4) && (ACE_HAS_WINNT4 != 0)))
+
+// Global pattern
+static ACE_UPIPE_Addr addr (ACE_TEXT ("pattern"));
+
+// connector thread.
+
+static void *
+connector (void *)
+{
+ ACE_UPIPE_Stream c_stream;
+
+ ACE_OS::sleep (5);
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) connector starting connect\n")));
+ ACE_UPIPE_Connector con;
+
+ if (con.connect (c_stream, addr) == -1)
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) connector ACE_UPIPE_Connector failed\n")));
+
+ ACE_Message_Block *mb;
+
+ ACE_NEW_RETURN (mb, ACE_Message_Block (sizeof ("hello thanks") * sizeof (char)), 0);
+
+ mb->copy ("hello");
+
+ if (c_stream.send (mb) == -1)
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) error connector send\n")));
+
+ if (c_stream.recv (mb) == -1)
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) error connector recv\n")));
+
+ ACE_ASSERT (ACE_OS::strcmp (mb->rd_ptr (), "thanks") == 0);
+
+ // Free up the memory block.
+ mb->release ();
+
+ // Now try the send()/recv() interface.
+ char mytext[] = "This string is sent by connector as a buffer";
+
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) connector sending text\n")));
+ if (c_stream.send (mytext, sizeof (mytext)) == -1)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) buffer send from connector failed\n")));
+
+ char conbuf[BUFSIZ]; // Buffer to receive response.
+
+ int i = 0;
+
+ for (char c = ' '; c != '!'; i++)
+ {
+ if (c_stream.recv (&c, 1) == -1)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) buffer recv from connector failed\n")));
+ else
+ conbuf[i] = c;
+ }
+
+ conbuf[i] = '\0';
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) conbuf = %s\n"), conbuf));
+ ACE_ASSERT (ACE_OS::strcmp (conbuf, "this is the acceptor response!") == 0);
+
+ c_stream.close ();
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) exiting thread\n")));
+ return 0;
+}
+
+static void *
+acceptor (void *args)
+{
+ ACE_UPIPE_Acceptor *acceptor = (ACE_UPIPE_Acceptor *) args;
+ ACE_UPIPE_Stream s_stream;
+
+ if (acceptor->accept (s_stream) == -1)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("(%t) ACE_UPIPE_Acceptor.accept failed\n")));
+
+ ACE_Message_Block *mb = 0;
+
+ if (s_stream.recv (mb) == -1)
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) acceptor recv failed\n")));
+
+ ACE_ASSERT (ACE_OS::strcmp (mb->rd_ptr (), "hello") == 0);
+
+ mb->wr_ptr (mb->rd_ptr ());
+ mb->copy ("thanks");
+
+ if (s_stream.send (mb) == -1)
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) acceptor send failed\n")));
+
+ char s_buf[BUFSIZ];
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) acceptor sleeping on recv\n")));
+
+ if (s_stream.recv (s_buf, sizeof (s_buf)) == -1)
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) acceptor recv failed\n")));
+ else
+ ACE_ASSERT (ACE_OS::strcmp (s_buf,
+ "This string is sent by connector as a buffer") == 0);
+
+ const char svr_response[] = "this is the acceptor response!";
+ ACE_OS::strcpy (s_buf, svr_response);
+
+ if (s_stream.send (s_buf, sizeof (svr_response)) == -1)
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) acceptor send failed\n")));
+
+ s_stream.close ();
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) exiting thread\n")));
+ return 0;
+}
+#endif /* ACE_HAS_THREADS && defined ACE_HAS_STREAM_PIPES || (ACE_WIN32&&NT4)*/
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("UPIPE_SAP_Test"));
+
+#if defined (ACE_HAS_THREADS) && (defined (ACE_HAS_STREAM_PIPES) || \
+ (defined (ACE_WIN32) && \
+ defined (ACE_HAS_WINNT4) && (ACE_HAS_WINNT4 != 0)))
+
+ ACE_UPIPE_Acceptor acc (addr);
+
+ // Spawn a acceptor thread.
+ if (ACE_Thread_Manager::instance ()->spawn (ACE_THR_FUNC (acceptor),
+ (void *) &acc,
+ THR_NEW_LWP,
+ 0) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("spawn")), 1);
+
+ // Spawn a connector thread.
+ if (ACE_Thread_Manager::instance ()->spawn (ACE_THR_FUNC (connector),
+ (void *) 0,
+ THR_NEW_LWP,
+ 0) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("spawn")), 1);
+
+ ACE_Thread_Manager::instance ()->wait ();
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) joined with acceptor thread\n")));
+
+ // Close the acceptor
+ acc.close ();
+
+#else
+
+#if !defined (ACE_HAS_THREADS)
+ ACE_ERROR ((LM_INFO, ACE_TEXT ("threads not supported on this platform\n")));
+#else
+ ACE_ERROR ((LM_INFO, ACE_TEXT ("UPIPE is not supported on this platform\n")));
+#endif /* !defined (ACE_HAS_THREADS) */
+#endif /* defined (ACE_HAS_THREADS) && (defined (ACE_HAS_STREAM_PIPES) || defined (ACE_WIN32) && NT4) */
+
+ ACE_END_TEST;
+ return 0;
+}
+
diff --git a/ACE/tests/UUIDTest.cpp b/ACE/tests/UUIDTest.cpp
new file mode 100644
index 00000000000..119803f6d4d
--- /dev/null
+++ b/ACE/tests/UUIDTest.cpp
@@ -0,0 +1,89 @@
+// $Id$
+
+// Test the ACE UUID class which generates unique id's
+
+
+#include "test_config.h"
+#include "ace/UUID.h"
+
+class Tester
+{
+public:
+ int init (void);
+ int test (void);
+};
+
+
+int
+Tester::init (void)
+{
+ ///Initialise the UUID Generator
+ ACE_Utils::UUID_GENERATOR::instance ()->init ();
+ return 0;
+}
+
+int
+Tester::test (void)
+{
+ // Generate UUID
+ ACE_Utils::UUID* uuid = ACE_Utils::UUID_GENERATOR::instance ()->generateUUID ();
+ ACE_CString uuid_str (uuid->to_string ()->c_str ());
+ ACE_DEBUG ((LM_DEBUG,
+ "Generated UUID\n %s\n",
+ uuid_str.c_str ()));
+ delete uuid;
+
+ // Construct UUID from string
+ ACE_Utils::UUID new_uuid (uuid_str);
+ ACE_DEBUG ((LM_DEBUG,
+ "UUID Constructed from above Generated UUID\n %s\n",
+ new_uuid.to_string ()->c_str ()));
+
+ // Generate UUID with process and thread ids.
+ ACE_Utils::UUID* uuid_with_tp_id =
+ ACE_Utils::UUID_GENERATOR::instance ()->generateUUID (0x0001, 0xc0);
+ ACE_DEBUG ((LM_DEBUG,
+ "UUID with Thread and Process ID\n %s\n",
+ uuid_with_tp_id->to_string ()->c_str ()));
+
+ // Construct UUID from string
+ ACE_Utils::UUID new_uuid_with_tp_id (uuid_with_tp_id->to_string ()->c_str ());
+ ACE_DEBUG ((LM_DEBUG,
+ "UUID with Thread and Process ID reconstructed from above UUID \n %s\n",
+ new_uuid_with_tp_id.to_string ()->c_str ()));
+ delete uuid_with_tp_id;
+
+ return 0;
+}
+
+int run_main(int, ACE_TCHAR* [])
+{
+ ACE_START_TEST (ACE_TEXT ("UUIDTest"));
+
+ Tester tester;
+
+ if (tester.init () == -1)
+ {
+
+ ACE_DEBUG((LM_DEBUG,
+ "UUIDTest: Tester::init failed\n"));
+ return -1;
+ }
+
+ int testRetValue = tester.test();
+
+ if (testRetValue == 0)
+ {
+ ACE_DEBUG((LM_DEBUG,
+ "UUIDTest succeeded\n"));
+ }
+ else
+ {
+ ACE_DEBUG((LM_DEBUG,
+ "UUIDTest failed\n"));
+ }
+
+ ACE_END_TEST;
+
+ return testRetValue;
+}
diff --git a/ACE/tests/Unbounded_Set_Test.cpp b/ACE/tests/Unbounded_Set_Test.cpp
new file mode 100644
index 00000000000..dc4379b7720
--- /dev/null
+++ b/ACE/tests/Unbounded_Set_Test.cpp
@@ -0,0 +1,135 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Unbounded_Set_Test.cpp
+//
+// = DESCRIPTION
+// This test illustrates the use of ACE_Unbounded_Set.
+// No command line arguments are needed to run the test.
+//
+// = AUTHOR
+// Rudolf Weber <rfweber@tesionmail.de>,
+// ace/tests integration <Oliver.Kellogg@sysde.eads.net>
+//
+// ============================================================================
+
+#include "test_config.h"
+#include <ace/Unbounded_Set.h>
+#include <ace/Auto_Ptr.h>
+#include <ace/SString.h>
+
+ACE_RCSID(tests, Unbounded_Set_Test, "$Id$")
+
+struct MyNode
+{
+ unsigned k;
+ MyNode () : k (0) {}
+ MyNode (int pk) : k (pk) {}
+ MyNode (const MyNode& o) : k (o.k) {}
+ bool operator== (const MyNode& o) { return (k == o.k); }
+};
+
+size_t count_const_set (const ACE_Unbounded_Set<MyNode>& cubs)
+{
+ size_t number_of_elements = 0;
+ for (ACE_Unbounded_Set<MyNode>::const_iterator ci (cubs); !ci.done(); ci++)
+ number_of_elements++;
+ return number_of_elements;
+}
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ int r;
+ unsigned k;
+ MyNode node (1);
+
+ ACE_START_TEST (ACE_TEXT ("Unbounded_Set_Test"));
+
+ ACE_Unbounded_Set<MyNode> ubs;
+ ACE_ASSERT (ubs.size () == 0);
+
+ // Insert a value. Immediately remove it.
+ r = ubs.insert (node);
+ ACE_ASSERT (r == 0);
+ ACE_ASSERT (ubs.size () == 1);
+ r = ubs.remove (node);
+ ACE_ASSERT (r == 0);
+ ACE_ASSERT (ubs.size () == 0);
+
+ // Insert several different values.
+ for (node.k = 1; node.k <= 5; node.k++)
+ {
+ r = ubs.insert (node);
+ ACE_ASSERT (r == 0);
+ ACE_ASSERT (ubs.size () == node.k);
+ }
+
+ // Test assigment of sets.
+ // To do that, we also test some of the iterator methods.
+ typedef ACE_Unbounded_Set<MyNode> MySet;
+ MySet ubs2 = ubs; // Test a typedef of a set.
+ ACE_ASSERT (ubs2.size() == ubs.size());
+ {
+ MySet::ITERATOR it1 (ubs);
+ MySet::iterator it2 (ubs2);
+ for (k = 1; k <= 5; k++)
+ {
+ ACE_ASSERT (! it1.done ());
+ ACE_ASSERT (! it2.done ());
+ MyNode n1 = *it1;
+ MyNode n2 = *it2;
+ ACE_ASSERT (n1 == n2);
+ it1.advance ();
+ it2.advance ();
+ }
+ ACE_ASSERT (it1.done ());
+ ACE_ASSERT (it2.done ());
+ // Verify that a set may be emptied while an iterator on the set is
+ // in-scope but inactive:
+ ubs.reset ();
+ // Restore original set from ubs2
+ ubs = ubs2;
+ }
+
+ // Selective deletion of elements and element retrieval.
+ {
+ MySet::iterator it (ubs2);
+ int deleted = 0;
+ while (! it.done ())
+ {
+ MyNode n = *it;
+ it.advance (); /* Being friendly here: Move the iterator on
+ so that element removal does not interfere
+ with the current iterator position.
+ The less friendly case, removal under the
+ current iterator position, is below. */
+ if (n.k % 2 == 1)
+ {
+ r = ubs2.remove (n);
+ deleted++;
+ }
+ }
+ ACE_ASSERT (ubs2.size () + deleted == ubs.size());
+
+ MyNode node2 (2);
+ ACE_ASSERT (ubs2.find (node2) == 0);
+
+ MyNode node3 (3);
+ ACE_ASSERT (ubs2.find (node3) != 0);
+
+ ubs2.insert (node3);
+ }
+
+ size_t s = count_const_set (ubs);
+ ACE_ASSERT (s == ubs.size ());
+
+ ACE_END_TEST;
+ return 0;
+}
+
diff --git a/ACE/tests/Unload_libACE.cpp b/ACE/tests/Unload_libACE.cpp
new file mode 100644
index 00000000000..a9c52e30c4c
--- /dev/null
+++ b/ACE/tests/Unload_libACE.cpp
@@ -0,0 +1,259 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Unload_libACE.cpp
+//
+// = DESCRIPTION
+// This is a simple test of library unloading that uses
+// an application which has _not_ been linked with libACE
+// but uses dlopen() to dynamically load libACE
+// and then uses dlclose() to unload it.
+//
+// = AUTHORS
+// David Smith <dts@prismtech.com> and Don Sharp <Donald.Sharp@prismtech.com>
+//
+// ============================================================================
+
+#include <stdio.h>
+
+#undef UNLOAD_LIBACE_TEST
+
+#if defined (__GNUC__)
+#if !defined (ACE_VXWORKS) && !defined (__MINGW32__) && !defined (__CYGWIN32__)
+#define UNLOAD_LIBACE_TEST 1
+#endif /* !ACE_VXWORKS && !__MINGW32__ && !CYGWIN32 */
+#endif /* __GNUC__ */
+
+#if defined (__hpux) || defined (__SUNPRO_CC)
+#define UNLOAD_LIBACE_TEST 1
+#endif /* (__hpux) || (__SUNPRO_CC) */
+
+#if defined (ACE_AS_STATIC_LIBS)
+#undef UNLOAD_LIBACE_TEST
+#endif /* ACE_AS_STATIC_LIBS */
+
+#ifdef UNLOAD_LIBACE_TEST
+
+#include <errno.h>
+#include <dlfcn.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#define TIME_STAMP_FIELD_WIDTH 32
+
+static char *
+time_stamp ( char date_and_time[], int date_and_timelen, int format )
+{
+ static char const *const month_name[] =
+ {
+ "Jan",
+ "Feb",
+ "Mar",
+ "Apr",
+ "May",
+ "Jun",
+ "Jul",
+ "Aug",
+ "Sep",
+ "Oct",
+ "Nov",
+ "Dec"
+ };
+
+ static char const *const day_of_week_name[] =
+ {
+ "Sun",
+ "Mon",
+ "Tue",
+ "Wed",
+ "Thu",
+ "Fri",
+ "Sat"
+ };
+
+ char *ts = NULL;
+
+ if ( date_and_timelen >= TIME_STAMP_FIELD_WIDTH )
+ {
+ time_t timeval;
+ struct tm *now;
+
+ time ( &timeval );
+ now = localtime ( &timeval ); /* Get current local time. */
+
+ if ( format == 'Y' )
+ {
+ sprintf ( date_and_time,
+ "%3s %3s %2d %04d %02d:%02d:%02d.%06d",
+ day_of_week_name[now->tm_wday],
+ month_name[now->tm_mon],
+ ( int ) now->tm_mday,
+ ( int ) now->tm_year + 1900,
+ ( int ) now->tm_hour,
+ ( int ) now->tm_min, ( int ) now->tm_sec, ( int ) 0 );
+ }
+ else /* 'T' */
+ {
+ sprintf ( date_and_time,
+ "%3s %2d %02d:%02d:%02d.%03d %04d",
+ month_name[now->tm_mon],
+ ( int ) now->tm_mday,
+ ( int ) now->tm_hour,
+ ( int ) now->tm_min,
+ ( int ) now->tm_sec, ( int ) 0,
+ ( int ) now->tm_year + 1900 );
+ }
+
+ ts = date_and_time;
+ }
+ return ts;
+}
+
+int
+main ( int, char ** )
+{
+ char const *const program = "UnloadLibACE";
+
+ int status = 0;
+ void *handle = NULL;
+ char *ace_root = NULL;
+ char tbuf[BUFSIZ];
+ char ybuf[BUFSIZ];
+ FILE *logfp = NULL;
+
+ if (( logfp = fopen ( "log/UnloadLibACE.log", "w" )) != NULL )
+ {
+ setvbuf ( logfp, NULL, _IONBF, 0 );
+ // reassign stdout/stderr to log file
+ int fdno = fileno ( logfp );
+
+ dup2 ( fdno, fileno ( stdout ));
+ dup2 ( fdno, fileno ( stderr ));
+ setvbuf ( stdout, NULL, _IONBF, 0 );
+ setvbuf ( stderr, NULL, _IONBF, 0 );
+ fflush ( stdout );
+ fflush ( stderr );
+
+ printf ( "%s@LM_DEBUG@ Starting %s test at %s\n",
+ time_stamp ( tbuf, BUFSIZ, 'T' ),
+ program, time_stamp ( ybuf, BUFSIZ, 'Y' ));
+
+ if (( ace_root = getenv ( "ACE_ROOT" )) != NULL )
+ {
+ char buf[BUFSIZ];
+
+ strcpy ( buf, ace_root );
+#if defined (__hpux)
+ strcat ( buf, "/lib/libACE.sl" );
+#else
+ strcat ( buf, "/lib/libACE.so" );
+#endif /* (__hpux) */
+
+ handle = dlopen ( buf, RTLD_LAZY );
+ if ( handle == NULL )
+ {
+ // is it because of "No such file or directory" ?
+ if ( errno != ENOENT )
+ {
+ fprintf ( stderr,
+ "%s@LM_ERROR@ dlopen() returned NULL\n",
+ time_stamp ( tbuf, BUFSIZ, 'T' ));
+ fprintf ( stderr,
+ "%s@LM_ERROR@ dlerror() says: %s\n",
+ time_stamp ( tbuf, BUFSIZ, 'T' ), dlerror ());
+ status = 1;
+ }
+ else
+ {
+ printf ( "%s@LM_DEBUG@ dlopen() did not find %s\n",
+ time_stamp ( tbuf, BUFSIZ, 'T' ), buf);
+ status = 0;
+ }
+ }
+ else if ( dlclose ( handle ) != 0 )
+ {
+ fprintf ( stderr,
+ "%s@LM_ERROR@ dlclose() failed : %s\n",
+ time_stamp ( tbuf, BUFSIZ, 'T' ), strerror ( errno ));
+ status = 1;
+ }
+ }
+ else
+ {
+ fprintf ( stderr,
+ "%s@LM_ERROR@ ACE_ROOT environment variable not set\n",
+ time_stamp ( tbuf, BUFSIZ, 'T' ));
+ status = 1;
+ }
+
+ fflush ( stdout );
+ fflush ( stderr );
+ fflush ( logfp );
+
+ fclose ( logfp );
+ }
+ else
+ {
+ // Couldn't go into the log file !!!
+ printf ( "%s@LM_DEBUG@ Starting %s test at %s\n",
+ time_stamp ( tbuf, BUFSIZ, 'T' ),
+ program, time_stamp ( ybuf, BUFSIZ, 'Y' ));
+
+ fprintf ( stderr,
+ "%s@LM_ERROR@ Could not open log/UnloadLibACE.log : %s\n",
+ time_stamp ( tbuf, BUFSIZ, 'T' ), strerror ( errno ));
+ status = 1;
+ }
+
+ printf ( "%s@LM_DEBUG@ Ending %s test at %s\n",
+ time_stamp ( tbuf, BUFSIZ, 'T' ),
+ program, time_stamp ( ybuf, BUFSIZ, 'Y' ));
+
+ fflush ( stderr );
+ fflush ( stdout );
+ fclose ( stdout );
+ fclose ( stderr );
+
+ exit ( status );
+ return 0;
+}
+#else
+# if defined (WIN32) && defined (ACE_USES_WCHAR)
+// Borrow include list from ace_wchar.h
+# if defined (ACE_HAS_WINCE)
+# include /**/ <wtypes.h>
+# elif !defined (__BORLANDC__)
+# include /**/ <wchar.h>
+# endif /* ACE_HAS_WINCE || __BORLANDC__ */
+
+int
+wmain ( int, wchar_t ** )
+#else
+int
+main ( int, char ** )
+#endif /* (WIN32) && (ACE_USES_WCHAR) */
+{
+ char const *const program = "UnloadLibACE";
+
+ FILE *logfp = NULL;
+
+ if (( logfp = fopen ( "log/UnloadLibACE.log", "w" )) != NULL )
+ {
+ fprintf ( logfp, "@LM_DEBUG@ Starting %s test\n", program);
+ fprintf ( logfp, "@LM_DEBUG@ %s test not implemented for this platform\n",
+ program);
+ fprintf ( logfp, "@LM_DEBUG@ Ending %s test\n", program);
+
+ fflush ( logfp );
+ fclose ( logfp );
+ }
+ return 0;
+}
+#endif /* UNLOAD_LIBACE_TEST */
diff --git a/ACE/tests/Upgradable_RW_Test.cpp b/ACE/tests/Upgradable_RW_Test.cpp
new file mode 100644
index 00000000000..ca99f677496
--- /dev/null
+++ b/ACE/tests/Upgradable_RW_Test.cpp
@@ -0,0 +1,491 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Upgradable_RW_Test.cpp
+//
+// = DESCRIPTION
+// This test program verifies the functionality of the ACE_OS
+// implementation of readers/writer locks on Win32 and Posix
+// pthreads. Use the RW_Mutex define switch to use
+// readers/writer mutexes or regular mutexes.
+//
+// = AUTHOR
+// Michael Kircher <mk1@cs.wustl.edu>
+//
+// ============================================================================
+
+#include "Upgradable_RW_Test.h"
+#include "ace/OS_NS_stdio.h"
+#include "ace/OS_NS_sys_time.h"
+#include "ace/Atomic_Op.h"
+
+ACE_RCSID(tests, Upgradable_RW_Test, "$Id$")
+
+#if defined (ACE_HAS_THREADS)
+
+// Default number of iterations.
+static int n_iterations = 50;
+
+// Maximum string length used
+static const size_t MAX_STRING_SIZE = 200;
+
+// switch on RW mutexes, else use ordinary mutexes
+// #define RW_MUTEX 1
+
+// Default number of readers.
+static u_int n_readers = 10;
+
+// Default number of writers.
+static u_int n_writers = 0;
+
+// Number of entries in the hash map
+static u_int n_entries = 10;
+
+// Try to upgrade to a write lock, by default don't try.
+static u_int use_try_upgrade = 0;
+
+// number of readers, which were able to upgrade
+static u_int upgraded = 0;
+
+// count the number of find calls
+static u_int find_called = 0;
+
+// number of readers, failing or not allowed to upgrade
+static u_int not_upgraded = 0;
+
+// Thread creation flags.
+static long thr_flags = THR_NEW_LWP;
+
+// Lock for shared_data (upgraded, not_upgraded, hash_Map)
+#if defined (RW_MUTEX)
+static ACE_RW_Thread_Mutex rw_mutex;
+#else
+static ACE_Thread_Mutex mutex;
+#endif /* RW_MUTEX */
+
+// Count of the number of readers and writers.
+static ACE_Atomic_Op<ACE_Thread_Mutex, int> current_readers;
+static ACE_Atomic_Op<ACE_Thread_Mutex, int> current_writers;
+
+static Linked_List *linked_list_ptr;
+
+// Returns 1 if found,
+// 0 if not found,
+// -1 on an error
+static int
+find_last (void)
+{
+ find_called++;
+
+ char search_string[MAX_STRING_SIZE];
+ ACE_OS::sprintf (search_string,
+ "%d",
+ n_entries - 1);
+ ACE_CString cString (search_string);
+ Element *element_ptr = 0;
+
+ for (ACE_Double_Linked_List_Iterator<Element> iterator (*linked_list_ptr);
+ !iterator.done ();
+ iterator.advance ())
+ {
+ element_ptr = iterator.next ();
+ if (element_ptr)
+ if (*element_ptr->value () == cString)
+ return 1;
+ }
+
+ return 0;
+
+}
+
+// Explain usage and exit.
+static void
+print_usage_and_die (void)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("usage: %n [-r n_readers] [-w n_writers]\n")
+ ACE_TEXT (" [-e max_entries] [-u try update] ")
+ ACE_TEXT ("[-n iteration_count] [-f for FIFO threads]\n")));
+ ACE_OS::exit (1);
+}
+
+static void
+parse_args (int argc, ACE_TCHAR *argv[])
+{
+ ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("e:fr:w:n:u"));
+
+ int c;
+
+ while ((c = get_opt ()) != -1)
+ switch (c)
+ {
+ case 'e':
+ n_entries = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'f':
+ thr_flags = THR_BOUND | THR_SCHED_FIFO;
+ break;
+ case 'r':
+ n_readers = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'w':
+ n_writers = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'n':
+ n_iterations = ACE_OS::atoi (get_opt.opt_arg ());
+ break;
+ case 'u':
+ use_try_upgrade = 1;
+ break;
+ default:
+ print_usage_and_die ();
+ break;
+ }
+}
+
+// Iterate <n_iterations> each time checking that nobody modifies the data
+// while we have a read lock.
+
+int
+Reader_Task::svc (void)
+{
+ ACE_Profile_Timer timer;
+ ACE_Profile_Timer::ACE_Elapsed_Time elapsed_time;
+
+ barrier_.wait ();
+ // Wait at the barrier.
+
+ // We start an ACE_Profile_Timer here...
+ timer.start ();
+
+ for (int iterations = 1;
+ iterations <= n_iterations;
+ iterations++)
+ {
+ ACE_Thread::yield ();
+
+ int result = 0;
+
+ {
+#if defined (RW_MUTEX)
+ ACE_Read_Guard<ACE_RW_Thread_Mutex> g (rw_mutex);
+#else
+ ACE_Guard<ACE_Thread_Mutex> g (mutex);
+#endif /* RW_MUTEX */
+ find_last ();
+#if defined (RW_MUTEX)
+ if (use_try_upgrade)
+ result =
+ rw_mutex.tryacquire_write_upgrade ();
+#endif /* RW_MUTEX */
+
+ // True, when we were able to upgrade.
+ if (result == 0 && use_try_upgrade)
+ {
+ //find_last (); try to find something which is not in
+ //there
+ upgraded++;
+ continue;
+ }
+ }
+
+ if (result == -1 && errno == EBUSY // we tried and failed
+ || !use_try_upgrade) // we did not try at all
+ {
+#if defined (RW_MUTEX)
+ ACE_Write_Guard<ACE_RW_Thread_Mutex> g (rw_mutex);
+#else
+ ACE_Guard<ACE_Thread_Mutex> g (mutex);
+#endif /* RW_MUTEX */
+
+ not_upgraded++;
+ find_last ();
+ }
+ else if (result == -1 && errno != EBUSY)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT (" (%t) failure in upgrading to write lock!\n"),
+ 1));
+ }
+
+ // Stop the timer.
+ timer.stop ();
+ timer.elapsed_time (elapsed_time);
+
+ this->time_Calculation_.report_time (elapsed_time);
+
+ return 0;
+}
+
+// Iterate <n_iterations> each time modifying the global data and
+// checking that nobody steps on it while we can write it.
+
+int
+Writer_Task::svc (void)
+{
+ ACE_Profile_Timer timer;
+ ACE_Profile_Timer::ACE_Elapsed_Time elapsed_time;
+
+ barrier_.wait ();
+ // Wait at the barrier
+
+ // We start an ACE_Profile_Timer here...
+ timer.start ();
+
+ for (int iterations = 1;
+ iterations <= n_iterations;
+ iterations++)
+ {
+ ACE_Thread::yield ();
+
+#if defined (RW_MUTEX)
+ ACE_Write_Guard<ACE_RW_Thread_Mutex> g (rw_mutex);
+#else
+ ACE_Guard<ACE_Thread_Mutex> g (mutex);
+#endif /* RW_MUTEX */
+
+ find_last ();
+
+ current_writers--;
+ }
+
+ // Stop the timer.
+ timer.stop ();
+ timer.elapsed_time (elapsed_time);
+
+ this->time_Calculation_.report_time (elapsed_time);
+
+ return 0;
+}
+
+void
+Time_Calculation::report_time (ACE_Profile_Timer::ACE_Elapsed_Time &elapsed_time)
+{
+ ACE_Guard<ACE_Thread_Mutex> g (mutex_);
+
+ this->times_.real_time += elapsed_time.real_time;
+ this->times_.user_time += elapsed_time.user_time;
+ this->times_.system_time += elapsed_time.system_time;
+
+ this->reported_times_++;
+}
+
+void
+Time_Calculation ::print_stats (void)
+{
+ ACE_Profile_Timer::ACE_Elapsed_Time elapsed_time = this->times_;
+ u_int iterations = 1;
+
+ if (iterations > 0)
+ {
+ elapsed_time.real_time *= ACE_ONE_SECOND_IN_MSECS;
+ elapsed_time.user_time *= ACE_ONE_SECOND_IN_MSECS;
+ elapsed_time.system_time *= ACE_ONE_SECOND_IN_MSECS;
+
+ elapsed_time.real_time /= iterations;
+ elapsed_time.user_time /= iterations;
+ elapsed_time.system_time /= iterations;
+
+ double tmp = 0.0;
+
+ if (elapsed_time.real_time != 0.0)
+ tmp = 1000 / elapsed_time.real_time;
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("\n")
+ ACE_TEXT ("\treal_time\t = %0.06f ms, \n")
+ ACE_TEXT ("\tuser_time\t = %0.06f ms, \n")
+ ACE_TEXT ("\tsystem_time\t = %0.06f ms, \n")
+ ACE_TEXT ("\t%0.00f calls/second\n"),
+ elapsed_time.real_time < 0.0 ? 0.0 : elapsed_time.real_time,
+ elapsed_time.user_time < 0.0 ? 0.0 : elapsed_time.user_time,
+ elapsed_time.system_time < 0.0 ? 0.0 : elapsed_time.system_time,
+ tmp < 0.0 ? 0.0 : tmp));
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Number of reported times: %d\n"),
+ this->reported_times_));
+ }
+ else
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("\tNo time stats printed. Zero iterations or error ocurred.\n")));
+}
+
+static int
+init (void)
+{
+ char entry[MAX_STRING_SIZE];
+ ACE_CString *cString_ptr = 0;
+ Element *element_ptr = 0;
+
+ ACE_NEW_RETURN (linked_list_ptr,
+ Linked_List,
+ -1);
+
+ for (u_int i = 0; i < n_entries; i++)
+ {
+ ACE_OS::sprintf (entry, "%d", i);
+ ACE_NEW_RETURN (cString_ptr,
+ ACE_CString (entry),
+ -1);
+ ACE_NEW_RETURN (element_ptr,
+ Element (cString_ptr),
+ -1);
+ linked_list_ptr->insert_tail (element_ptr);
+ }
+ return 0;
+}
+
+#endif /* ACE_HAS_THREADS */
+
+// Spawn off threads.
+
+int
+run_main (int argc, ACE_TCHAR *argv[])
+{
+ ACE_START_TEST (ACE_TEXT ("Upgradable_RW_Test"));
+ int status = 0;
+
+#if defined (ACE_HAS_THREADS)
+ parse_args (argc, argv);
+#if !defined (RW_MUTEX)
+ use_try_upgrade = 0;
+ // make sure that we have to acquire the write lock
+#endif /* RW_MUTEX */
+
+ current_readers = 0; // Possibly already done
+ current_writers = 0; // Possibly already done
+
+ init ();
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT (" (%t) main thread starting\n")));
+
+ Time_Calculation time_Calculation;
+ // for the time calculation
+
+ ACE_Barrier thread_barrier (n_readers + n_writers);
+ // for a nice start of all threads (for much contention)
+
+ // Initialize the readers.
+ Reader_Task **reader_tasks = 0;
+
+ ACE_NEW_RETURN (reader_tasks,
+ Reader_Task *[n_readers],
+ -1);
+ u_int i = 0;
+
+ for (i = 0;
+ i < n_readers;
+ i++)
+ {
+ ACE_NEW_RETURN (reader_tasks[i],
+ Reader_Task (time_Calculation,
+ thread_barrier),
+ -1);
+
+ reader_tasks[i]->activate (thr_flags,
+ 1,
+ 0,
+ ACE_DEFAULT_THREAD_PRIORITY);
+ }
+
+ // Create all the writers
+ Writer_Task **writer_tasks = 0;
+
+ ACE_NEW_RETURN (writer_tasks,
+ Writer_Task *[n_writers],
+ -1);
+
+ for (i = 0;
+ i < n_writers;
+ i++)
+ {
+ ACE_NEW_RETURN (writer_tasks[i],
+ Writer_Task (time_Calculation,
+ thread_barrier),
+ -1);
+
+ writer_tasks[i]->activate (thr_flags,
+ 1,
+ 0,
+ ACE_DEFAULT_THREAD_PRIORITY);
+ }
+
+ // Wait a maximum of 1 second per iteration.
+ const ACE_Time_Value max_wait (n_iterations * 1);
+ const ACE_Time_Value wait_time (ACE_OS::gettimeofday () + max_wait);
+ if (ACE_Thread_Manager::instance ()->wait (&wait_time) == -1)
+ {
+ if (errno == ETIME)
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("maximum wait time of %d msec exceeded\n"),
+ max_wait.msec ()));
+ else
+ ACE_OS::perror (ACE_TEXT ("wait"));
+
+ status = -1;
+ }
+
+ // compute average time.
+ time_Calculation.print_stats ();
+
+ if (not_upgraded != 0 || upgraded != 0)
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("upgraded to not upgraded ratio = %f \n"),
+ (float) upgraded / (float) (not_upgraded + upgraded)));
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Number of times, that find was called: %d\n"),
+ find_called));
+
+
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT (" (%t) exiting main thread\n")));
+
+ // Delete the memory of the Double_Linked_List
+ ACE_CString *cString_ptr = 0;
+ Element *element_ptr = 0;
+
+ for (i = 0;
+ i < n_entries;
+ i++)
+ {
+ if ((element_ptr = linked_list_ptr->delete_head ()))
+ {
+ cString_ptr = element_ptr->value ();
+ delete cString_ptr;
+ delete element_ptr;
+ }
+ }
+
+ delete linked_list_ptr;
+
+ for (i = 0;
+ i < n_writers;
+ i++)
+ delete writer_tasks[i];
+
+ delete [] writer_tasks;
+
+ for (i = 0;
+ i < n_readers;
+ i++)
+ delete reader_tasks [i];
+
+ delete [] reader_tasks;
+#else
+ ACE_UNUSED_ARG (argc);
+ ACE_UNUSED_ARG (argv);
+ ACE_ERROR ((LM_INFO,
+ ACE_TEXT ("threads not supported on this platform\n")));
+#endif /* ACE_HAS_THREADS */
+
+ ACE_END_TEST;
+ return status;
+}
+
diff --git a/ACE/tests/Upgradable_RW_Test.h b/ACE/tests/Upgradable_RW_Test.h
new file mode 100644
index 00000000000..41c6c0dba1e
--- /dev/null
+++ b/ACE/tests/Upgradable_RW_Test.h
@@ -0,0 +1,147 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Upgradable_RW_Test.h
+//
+// = DESCRIPTION
+// This class gets its own header file to work around AIX C++
+// compiler "features" related to template instantiation... It is
+// only used by Upgradable_RW_Test.cpp.
+//
+// = AUTHOR
+// Michael Kircher <mk1@cs.wustl.edu>
+//
+// ============================================================================
+
+#ifndef ACE_TESTS_UPGRADABLE_RW_TEST_H
+#define ACE_TESTS_UPGRADABLE_RW_TEST_H
+
+#include "test_config.h"
+#include "ace/Barrier.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#include "ace/Task.h"
+#include "ace/Thread.h"
+#include "ace/Thread_Manager.h"
+#include "ace/Get_Opt.h"
+#include "ace/SString.h"
+#include "ace/Profile_Timer.h"
+
+class Element;
+
+class Element
+{
+ // = TITLE
+ // The members for the double linked list.
+ friend class ACE_Double_Linked_List<Element>;
+ friend class ACE_Double_Linked_List_Iterator_Base<Element>;
+ friend class ACE_Double_Linked_List_Iterator<Element>;
+ friend class ACE_Double_Linked_List_Reverse_Iterator<Element>;
+
+public:
+ Element (ACE_CString *item = 0,
+ Element *p = 0,
+ Element *n = 0)
+ : prev_ (p),
+ next_(n),
+ item_(item)
+ {
+ }
+
+ ACE_CString *value (void)
+ {
+ return this->item_;
+ }
+
+private:
+ Element *prev_;
+ Element *next_;
+ ACE_CString *item_;
+};
+
+typedef ACE_Double_Linked_List<Element> Linked_List;
+
+class Time_Calculation
+{
+ // = TITLE
+ // class to do time calculations thread safe
+public:
+ Time_Calculation (void)
+ : reported_times_ (0)
+ {
+ times_.real_time = 0;
+ times_.user_time = 0;
+ times_.system_time = 0;
+ }
+
+ void report_time (ACE_Profile_Timer::ACE_Elapsed_Time &elapsed_time);
+ // take the time of the thread and add it to
+
+ void print_stats (void);
+
+private:
+ ACE_Profile_Timer::ACE_Elapsed_Time times_;
+ // add the times incrementally
+
+ ACE_SYNCH_MUTEX mutex_;
+ // protect the time
+
+ unsigned int reported_times_;
+ // count how many threads gave me the elapsed_time
+};
+
+class Reader_Task : public ACE_Task_Base
+{
+ // = TITLE
+ // A Task for readers
+public:
+ Reader_Task (Time_Calculation &time_Calculation,
+ ACE_Barrier &barrier)
+ : time_Calculation_ (time_Calculation),
+ barrier_(barrier)
+ {
+ };
+
+ virtual int svc (void);
+
+private:
+ Time_Calculation &time_Calculation_;
+ // keep a reference to the time calculation class
+
+ ACE_Barrier &barrier_;
+ // keep this reference for the barrier, in order
+ // to allow a "nice" start
+};
+
+class Writer_Task : public ACE_Task_Base
+{
+ // = TITLE
+ // A Task for wirters.
+public:
+ Writer_Task (Time_Calculation &time_Calculation,
+ ACE_Barrier &barrier)
+ : time_Calculation_ (time_Calculation),
+ barrier_(barrier)
+ {
+ };
+
+ virtual int svc (void);
+
+private:
+ Time_Calculation &time_Calculation_;
+ // keep a reference to the time calculation class
+
+ ACE_Barrier &barrier_;
+ // keep this reference for the barrier, in order
+ // to allow a "nice" start
+};
+
+#endif /* ACE_TESTS_UPGRADABLE_RW_TEST_H */
diff --git a/ACE/tests/Vector_Test.cpp b/ACE/tests/Vector_Test.cpp
new file mode 100644
index 00000000000..3a71fa977bb
--- /dev/null
+++ b/ACE/tests/Vector_Test.cpp
@@ -0,0 +1,135 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// Vector_Test.cpp
+//
+// = DESCRIPTION
+// This is a simple test of the ACE_Vector class and its iterators.
+//
+// = AUTHOR
+// Gonzalo A. Diethelm <gonzalo.diethelm@aditiva.com>
+//
+// ============================================================================
+
+#include "test_config.h"
+
+ACE_RCSID(tests, Vector_Test, "$Id$")
+
+#include "ace/Vector_T.h"
+
+typedef size_t DATA;
+#if defined (__BORLANDC__) && (__BORLANDC__ <= 0x570)
+// Borland C++ Builder 6 and earlier don't handle the second template
+// argument correctly. We have to pass it explicitly
+typedef ACE_Vector<DATA, ACE_VECTOR_DEFAULT_SIZE> VECTOR;
+typedef ACE_Vector<DATA, ACE_VECTOR_DEFAULT_SIZE>::Iterator ITERATOR;
+#else
+typedef ACE_Vector<DATA> VECTOR;
+typedef ACE_Vector<DATA>::Iterator ITERATOR;
+#endif
+
+const size_t TOP = 100;
+const size_t LEFT = 10;
+const size_t RESIZE = 20;
+
+int run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("Vector_Test"));
+
+ VECTOR vector;
+ size_t i;
+
+ for (i = 0; i < TOP; ++i)
+ vector.push_back (i);
+
+ ACE_ASSERT (vector.size () == TOP);
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Size: %d\n"),
+ vector.size ()));
+
+ for (i = 0; i < TOP; ++i)
+ ACE_ASSERT (vector[i] == i);
+
+ // Test to be sure the iterator gets the correct count and entries.
+ ITERATOR iter (vector);
+ DATA *p_item = 0 ;
+ size_t iter_count = 0;
+ while (!iter.done ())
+ {
+ if (iter.next (p_item) == 0)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("Fail to get value on iter pass %d\n"),
+ iter_count));
+ if (*p_item != iter_count)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("Iter pass %d got %d\n"),
+ iter_count, *p_item));
+ iter_count++;
+ iter.advance();
+ }
+ if (iter_count != TOP)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("Iterated %d elements; expected %d\n"),
+ iter_count, TOP));
+
+ for (i = 0; i < (TOP - LEFT); ++i)
+ vector.pop_back ();
+
+ ACE_ASSERT (vector.size () == LEFT);
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Size: %d\n"),
+ vector.size ()));
+
+ for (i = 0; i < LEFT; ++i)
+ {
+ ACE_ASSERT (vector[i] == i);
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("vector[%d]:%d\n"),
+ i, vector[i]));
+ }
+
+ vector.resize(RESIZE, 0);
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("After resize\n")));
+
+ for (i = 0; i < RESIZE ; ++i)
+ {
+ // The original vector of size LEFT must have the same original contents
+ // the new elements should have the value 0 (this value is passed as
+ // second argument of the resize() call.
+ if (i < LEFT)
+ {
+ ACE_ASSERT (vector[i] == i);
+ }
+ else
+ {
+ ACE_ASSERT (vector[i] == 0);
+ }
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("vector[%d]:%d\n"),
+ i, vector[i]));
+ }
+
+ vector.clear ();
+ ACE_ASSERT (vector.size () == 0);
+ ACE_DEBUG ((LM_DEBUG,
+ ACE_TEXT ("Size: %d\n"),
+ vector.size ()));
+
+ VECTOR v1;
+ VECTOR v2;
+ v1.push_back (1);
+ v2.push_back (1);
+ v1.push_back (2);
+ v2.push_back (2);
+ if (v1 != v2)
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("Inequality test failed!\n")));
+ if (!(v1 == v2))
+ ACE_ERROR ((LM_ERROR, ACE_TEXT ("Equality test failed!\n")));
+
+ ACE_END_TEST;
+
+ return 0;
+}
+
diff --git a/ACE/tests/WFMO_Reactor_Test.cpp b/ACE/tests/WFMO_Reactor_Test.cpp
new file mode 100644
index 00000000000..2caf3a0e766
--- /dev/null
+++ b/ACE/tests/WFMO_Reactor_Test.cpp
@@ -0,0 +1,157 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// WFMO_Reactor_Test.cpp
+//
+// = DESCRIPTION
+// This is a simple test of the WFMO_Reactor. It makes sure that
+// removals and suspensions work correctly.
+//
+// = AUTHOR
+// Irfan Pyarali <irfan@oomworks.com>
+//
+// ============================================================================
+
+#include "tests/test_config.h"
+#include "ace/Reactor.h"
+#include "ace/WFMO_Reactor.h"
+#include "ace/Pipe.h"
+
+ACE_RCSID(tests, WFMO_Reactor_Test, "$Id$")
+
+#if defined (ACE_WIN32)
+
+static int number_of_handlers = 6;
+static int number_of_closes = 0;
+
+class Event_Handler : public ACE_Event_Handler
+{
+public:
+
+ Event_Handler (ACE_Reactor &reactor);
+
+ ~Event_Handler (void);
+
+ ACE_Pipe pipe_;
+
+};
+
+Event_Handler::Event_Handler (ACE_Reactor &reactor)
+{
+ this->reference_counting_policy ().value
+ (ACE_Event_Handler::Reference_Counting_Policy::ENABLED);
+
+ ACE_DEBUG ((LM_DEBUG,
+ "Reference count in Event_Handler() is %d\n",
+ this->reference_count_.value ()));
+
+ this->reactor (&reactor);
+
+ int result =
+ this->pipe_.open ();
+
+ ACE_ASSERT (result == 0);
+ ACE_UNUSED_ARG (result);
+
+ this->reactor ()->register_handler (this->pipe_.read_handle (),
+ this,
+ ACE_Event_Handler::READ_MASK);
+ ACE_ASSERT (result == 0);
+
+ this->reactor ()->register_handler (this->pipe_.write_handle (),
+ this,
+ ACE_Event_Handler::READ_MASK);
+ ACE_ASSERT (result == 0);
+}
+
+Event_Handler::~Event_Handler (void)
+{
+ ACE_DEBUG ((LM_DEBUG,
+ "Reference count in ~Event_Handler() is %d\n",
+ this->reference_count_.value ()));
+
+ ++number_of_closes;
+}
+
+void
+test (void)
+{
+ int result = 0;
+ int i = 0;
+
+ ACE_Reactor reactor (new ACE_WFMO_Reactor, 1);
+
+ ACE_Event_Handler_var *safe_event_handlers =
+ new ACE_Event_Handler_var[number_of_handlers];
+
+ Event_Handler **event_handlers =
+ new Event_Handler*[number_of_handlers];
+
+ for (i = 0; i < number_of_handlers; ++i)
+ {
+ event_handlers[i] =
+ new Event_Handler (reactor);
+
+ safe_event_handlers[i] =
+ event_handlers[i];
+ }
+
+ ACE_Time_Value timeout (0, 500 * 1000);
+
+ result = reactor.run_reactor_event_loop (timeout);
+ ACE_ASSERT (result != -1);
+
+ for (i = 0; i < number_of_handlers; ++i)
+ {
+ if (i % 2 == 0)
+ continue;
+
+ result = reactor.suspend_handler (event_handlers[i]->pipe_.read_handle ());
+ ACE_ASSERT (result == 0);
+
+ result = reactor.suspend_handler (event_handlers[i]->pipe_.write_handle ());
+ ACE_ASSERT (result == 0);
+ }
+
+ result = reactor.run_reactor_event_loop (timeout);
+ ACE_ASSERT (result != -1);
+
+ delete[] safe_event_handlers;
+ delete[] event_handlers;
+}
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("WFMO_Reactor_Test"));
+
+ test ();
+
+ ACE_ASSERT (number_of_closes == number_of_handlers);
+
+ ACE_END_TEST;
+
+ return 0;
+}
+
+#else /* ACE_WIN32 */
+
+int
+run_main (int, ACE_TCHAR *[])
+{
+ ACE_START_TEST (ACE_TEXT ("WFMO_Reactor_Test"));
+
+ ACE_ERROR ((LM_INFO,
+ ACE_TEXT ("WFMO_Reactor not supported on this platform\n")));
+
+ ACE_END_TEST;
+
+ return 0;
+}
+
+#endif /* ACE_WIN32 */
diff --git a/ACE/tests/Win32clerk.conf b/ACE/tests/Win32clerk.conf
new file mode 100644
index 00000000000..470f9b31b34
--- /dev/null
+++ b/ACE/tests/Win32clerk.conf
@@ -0,0 +1,3 @@
+# Note: hostname and port number need to be concatenated separated by ":"
+dynamic Logging_Strategy Service_Object * ACE:_make_ACE_Logging_Strategy() "-s c:\temp\log\Time_Client.log -f OSTREAM"
+dynamic Time_Server_Test Service_Object * netsvcs:_make_ACE_TS_Clerk_Processor () "-h localhost:10222 -t 4"
diff --git a/ACE/tests/Win32server.conf b/ACE/tests/Win32server.conf
new file mode 100644
index 00000000000..94a3b3906ec
--- /dev/null
+++ b/ACE/tests/Win32server.conf
@@ -0,0 +1,10 @@
+# These are the services that can be linked into ACE.
+# Note that you can replace the hardcoded "../lib/libnetsvcs.so" with
+# a relative path if you set your LD search path correctly -- ACE will
+# locate this for you automatically by reading your LD search path!
+# In addition, you can replace the hardcoded "-p 20xxx" with "-p
+# $PORTxxx" if you set your environment variables correctly.
+
+dynamic Logging_Strategy Service_Object * ACE:_make_ACE_Logging_Strategy() "-s c:\temp\log\Time_Server.log -f OSTREAM"
+dynamic Time_Service Service_Object * netsvcs:_make_ACE_TS_Server_Acceptor() "-p 10222"
+
diff --git a/ACE/tests/Win32tokens.conf b/ACE/tests/Win32tokens.conf
new file mode 100644
index 00000000000..e31eb04fc4d
--- /dev/null
+++ b/ACE/tests/Win32tokens.conf
@@ -0,0 +1,4 @@
+# NT version
+#
+dynamic Logging_Strategy Service_Object * ACE:_make_ACE_Logging_Strategy() "-s c:\temp\log\Tokens_Test_Server.log -f OSTREAM"
+dynamic Token_Service Service_Object * netsvcs:_make_ACE_Token_Acceptor() "-p 23456"
diff --git a/ACE/tests/XtAthenaReactor_Test.cpp b/ACE/tests/XtAthenaReactor_Test.cpp
new file mode 100644
index 00000000000..d5abb90c4e0
--- /dev/null
+++ b/ACE/tests/XtAthenaReactor_Test.cpp
@@ -0,0 +1,320 @@
+/* -*- C++ -*- */
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// XtReactor_Test.cpp
+//
+// = DESCRIPTION
+// This is a simple test that illustrates the possibility to integrate
+// ACE to the X Main Loop. This program uses ACE_XtReactor class to
+// schedule three additional event sources:
+// 1. Events from button "Stop Test" (registed with XtAddCallback)
+// 2. Events from button "Press Me" (registed with XtAddCallback)
+// 3. Events from X timer (registed with XtAppAddTimeOut)
+// 4. Events from ACE timer (registed with ACE_XtReactor::schedule_timer)
+// 5. Events from the TCP/IP channel using ACE_Acceptor
+// No command line arguments are needed to run the test.
+// Programs needs Athena Widgets to be compiled and run.
+//
+// = AUTHOR
+// Kirill Rybaltchenko <Kirill.Rybaltchenko@cern.ch>
+//
+// ============================================================================
+
+#include "test_config.h"
+
+ACE_RCSID (tests,
+ XtAthenaReactor_Test,
+ "$Id$")
+
+#include "ace/XtReactor.h"
+#include "ace/Event_Handler.h"
+#include "ace/Acceptor.h"
+#include "ace/SOCK_Acceptor.h"
+#include "ace/SOCK_Connector.h"
+#include "ace/Service_Config.h"
+#include "ace/Thread_Manager.h"
+
+#include "ace/OS_NS_unistd.h"
+
+#include /**/ <X11/Intrinsic.h>
+#include /**/ <X11/Xatom.h>
+#include /**/ <X11/Shell.h>
+
+#include /**/ <X11/Xaw/Command.h>
+#include /**/ <X11/Xaw/Label.h>
+#include /**/ <X11/Xaw/Box.h>
+#include /**/ <X11/StringDefs.h>
+
+static void set_label(Widget w, const char *p)
+{
+ XtVaSetValues (w, XtNlabel, p, 0);
+}
+#define LABEL_WIDGET labelWidgetClass
+#define BUTTON_WIDGET commandWidgetClass
+#define PRESS_ME_CALLBACK XtNcallback
+static Widget create_box(Widget parent, const char * name)
+{
+ return XtCreateWidget( (char*) name, boxWidgetClass, parent, 0, 0);
+}
+
+// Port we listen on.
+static const u_short SERV_TCP_PORT = 6670;
+
+// counter for events from "Press Me" button.
+static int count1 = 0;
+
+// counter for events from X Timer.
+static int count2 = 0;
+
+// counter for events from ACE Timer.
+static int count3 = 0;
+
+// Callback for "Stop Test" buton - quit the program.
+void
+Quit (Widget, XtPointer, XtPointer)
+{
+ ACE_OS::exit (0);
+}
+
+static void *
+client (void *)
+{
+ char buf[100];
+ size_t mes_len;
+ ACE_OS::sleep (1);
+
+ ACE_DEBUG ((LM_DEBUG,
+ " (%P) Client: Starting...\n"));
+
+ ACE_SOCK_Stream stream;
+ ACE_SOCK_Connector connector;
+ sprintf (buf, "Client: the life was good!");
+
+ mes_len = (int) htonl (ACE_OS::strlen (buf) + 1);
+
+ if (connector.connect (stream,
+ ACE_INET_Addr (SERV_TCP_PORT,
+ ACE_DEFAULT_SERVER_HOST)) == -1)
+ ACE_ERROR ((LM_ERROR,
+ "(%P) %p\n",
+ "Socket open"));
+
+ if (stream.send (4,
+ (void *) &mes_len,
+ sizeof (size_t),
+ (void *)buf,
+ ACE_OS::strlen (buf) + 1) == -1)
+
+ ACE_ERROR ((LM_ERROR,
+ "(%P) %p\n",
+ "Socket send"));
+
+ if (stream.close () == -1)
+ ACE_ERROR ((LM_ERROR,
+ "(%P) %p\n",
+ "Socket close"));
+
+ ACE_DEBUG ((LM_DEBUG,
+ "(%P) Client: Message has been sent, about to exit...\n"));
+ return 0;
+}
+
+// Callback for "Press Me" button.
+
+static void
+inc_count (Widget, XtPointer client_data, XtPointer)
+{
+ char new_string[80];
+
+ sprintf (new_string,
+ "Events: [%d] [%d] [%d]",
+ count1++,
+ count2,
+ count3);
+ set_label((Widget) client_data, new_string);
+}
+
+// Callback for X Timer.
+
+static void
+inc_tmo (void *w,XtIntervalId *)
+{
+ char new_string[80];
+
+ if (count2 > 10)
+ ACE_OS::exit (0);
+ sprintf (new_string,
+ "Events: [%d] [%d] [%d]",
+ count1,
+ count2++,
+ count3);
+
+ set_label((Widget) w, new_string);
+
+ (void) XtAppAddTimeOut (XtWidgetToApplicationContext ((Widget) w),
+ 1000,
+ inc_tmo,
+ (Widget) w);
+}
+
+class EV_handler : public ACE_Event_Handler
+{
+public:
+ virtual int handle_timeout (const ACE_Time_Value &,
+ const void *arg)
+ {
+ char new_string[80];
+ sprintf (new_string,
+ "Events: [%d] [%d] [%d]",
+ count1,
+ count2,
+ count3++);
+ set_label((Widget) arg, new_string);
+ return 0;
+ }
+};
+
+class Connection_Handler : public ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH>
+{
+public:
+ virtual int open (void *)
+ {
+ char buf[100];
+ int head;
+ ssize_t ret = this->peer ().recv_n ((char *) &head,
+ sizeof (int));
+ if (ret != sizeof (int))
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "(%P) %p\n",
+ "read header"),
+ -1);
+
+ ret = this->peer ().recv_n (buf,
+ (int) ntohl (head));
+
+ if (ret != (int) ntohl (head))
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "(%P) %p\n",
+ "read message"),
+ -1);
+ ACE_DEBUG ((LM_DEBUG,
+ " (%P)Server (ACE_SOCKET channel message): [%s]\n",
+ buf));
+ return 0;
+ }
+};
+
+#if defined (HummingBird_X)
+extern "C" void HCLXmInit (void);
+#endif /* HummingBird_X */
+
+int
+run_main (int argc, ACE_TCHAR *argv[])
+{
+ ACE_START_TEST (ACE_TEXT ("XtAthenaReactor_Test"));
+
+ XtAppContext app_context;
+ Widget topLevel, goodbye, PressMe, lbl, digits_rc;
+ Widget children[5];
+
+#if defined (HummingBird_X)
+ HCLXmInit ();
+#endif /* HummingBird_X */
+ topLevel = XtVaAppInitialize (&app_context,
+ "XTReactor_Test",
+ 0,
+ 0,
+ &argc,
+ argv,
+ 0,
+ 0);
+
+ digits_rc = create_box(topLevel, "digits_rc");
+
+ //"Stop Test" button.
+ goodbye = XtCreateWidget ( (char *) "goodbye",
+ BUTTON_WIDGET,
+ digits_rc,
+ 0,
+ 0);
+ set_label(goodbye, "Stop Test");
+
+ //"Press Me" button
+ PressMe = XtCreateWidget ((char *) "PressMe",
+ BUTTON_WIDGET,
+ digits_rc,
+ 0,
+ 0);
+
+ //Display for event counter
+ lbl = XtCreateWidget ((char *) "label_for_event_one",
+ LABEL_WIDGET,
+ digits_rc,
+ 0,
+ 0);
+ set_label(lbl, "label_for_all_events");
+ int ac = 0;
+ children[ac++] = goodbye;
+ children[ac++] = PressMe;
+ children[ac++] = lbl;
+ XtManageChildren (children, ac);
+ XtManageChild (digits_rc);
+
+ //Register callback for "Stop Test" button
+ XtAddCallback (goodbye, PRESS_ME_CALLBACK, Quit, 0);
+
+ //Register callback for "Press Me" button
+ XtAddCallback (PressMe,
+ PRESS_ME_CALLBACK,
+ inc_count,
+ (XtPointer) lbl);
+
+ // Register callback for X Timer
+ (void) XtAppAddTimeOut (app_context,
+ 1000,
+ inc_tmo,
+ (XtPointer) lbl);
+
+ XtRealizeWidget (topLevel);
+
+ // It will perform X Main Loop
+ ACE_XtReactor reactor (app_context);
+
+ ACE_Reactor r (&reactor);
+
+ //Event Handler for ACE Timer.
+ EV_handler evh;
+
+ ACE_Acceptor <Connection_Handler, ACE_SOCK_ACCEPTOR> acceptor;
+
+ if (acceptor.open (ACE_INET_Addr ((u_short) SERV_TCP_PORT),
+ &r) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "%p\n",
+ "open"),
+ -1);
+
+ if (reactor.schedule_timer (&evh,
+ (const void *) lbl,
+ ACE_Time_Value (2),
+ ACE_Time_Value (2))==-1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ " (%P|%t) can't register with reactor\n"),
+ -1);
+
+ ACE_Thread_Manager::instance ()->spawn ((ACE_THR_FUNC) client,
+ 0,
+ THR_NEW_LWP | THR_DETACHED);
+
+ XtAppMainLoop (XtWidgetToApplicationContext (topLevel));
+
+ ACE_END_TEST;
+ return 0;
+}
+
diff --git a/ACE/tests/XtMotifReactor_Test.cpp b/ACE/tests/XtMotifReactor_Test.cpp
new file mode 100644
index 00000000000..643b1e9dfbd
--- /dev/null
+++ b/ACE/tests/XtMotifReactor_Test.cpp
@@ -0,0 +1,327 @@
+/* -*- C++ -*- */
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// tests
+//
+// = FILENAME
+// XtReactor_Test.cpp
+//
+// = DESCRIPTION
+// This is a simple test that illustrates the possibility to integrate
+// ACE to the X Main Loop. This program uses ACE_XtReactor class to
+// schedule three additional event sources:
+// 1. Events from button "Stop Test" (registed with XtAddCallback)
+// 2. Events from button "Press Me" (registed with XtAddCallback)
+// 3. Events from X timer (registed with XtAppAddTimeOut)
+// 4. Events from ACE timer (registed with ACE_XtReactor::schedule_timer)
+// 5. Events from the TCP/IP channel using ACE_Acceptor
+// No command line arguments are needed to run the test.
+// The program needs Motif or lestiff to be compiled and run.
+//
+// = AUTHOR
+// Kirill Rybaltchenko <Kirill.Rybaltchenko@cern.ch>
+//
+// ============================================================================
+
+#include "test_config.h"
+
+ACE_RCSID (tests,
+ XtMotifReactor_Test,
+ "$Id$")
+#include "ace/XtReactor.h"
+#include "ace/Event_Handler.h"
+#include "ace/Acceptor.h"
+#include "ace/SOCK_Acceptor.h"
+#include "ace/SOCK_Connector.h"
+#include "ace/Service_Config.h"
+#include "ace/Thread_Manager.h"
+
+#include "ace/OS_NS_unistd.h"
+
+#include /**/ <X11/Intrinsic.h>
+#include /**/ <X11/Xatom.h>
+#include /**/ <X11/Shell.h>
+
+#include /**/ <Xm/Xm.h>
+#include /**/ <Xm/Label.h>
+#include /**/ <Xm/PushB.h>
+#include /**/ <Xm/RowColumn.h>
+
+static void set_label(Widget w, const char *p)
+{
+ XtVaSetValues (w,
+ XmNlabelString,
+ XmStringCreateLocalized( (char*) p),
+ 0);
+}
+#define LABEL_WIDGET xmLabelWidgetClass
+#define BUTTON_WIDGET xmPushButtonWidgetClass
+#define PRESS_ME_CALLBACK XmNactivateCallback
+static Widget create_box(Widget parent, const char *name)
+{
+ Arg al[10];
+ int ac = 0;
+ XtSetArg (al[ac], XmNnumColumns, 3); ac++;
+ XtSetArg (al[ac], XmNpacking, XmPACK_COLUMN); ac++;
+ XtSetArg (al[ac], XmNentryAlignment, XmALIGNMENT_CENTER); ac++;
+ return XmCreateRowColumn (parent, (char *) name, al, ac);
+}
+
+// Port we listen on.
+static const u_short SERV_TCP_PORT = 6670;
+
+// counter for events from "Press Me" button.
+static int count1 = 0;
+
+// counter for events from X Timer.
+static int count2 = 0;
+
+// counter for events from ACE Timer.
+static int count3 = 0;
+
+// Callback for "Stop Test" buton - quit the program.
+void
+Quit (Widget, XtPointer, XtPointer)
+{
+ ACE_OS::exit (0);
+}
+
+static void *
+client (void *)
+{
+ char buf[100];
+ size_t mes_len;
+ ACE_OS::sleep (1);
+
+ ACE_DEBUG ((LM_DEBUG,
+ " (%P) Client: Starting...\n"));
+
+ ACE_SOCK_Stream stream;
+ ACE_SOCK_Connector connector;
+ sprintf (buf, "Client: the life was good!");
+
+ mes_len = (int) htonl (ACE_OS::strlen (buf) + 1);
+
+ if (connector.connect (stream,
+ ACE_INET_Addr (SERV_TCP_PORT,
+ ACE_DEFAULT_SERVER_HOST)) == -1)
+ ACE_ERROR ((LM_ERROR,
+ "(%P) %p\n",
+ "Socket open"));
+
+ if (stream.send (4,
+ (void *) &mes_len,
+ sizeof (size_t),
+ (void *)buf,
+ ACE_OS::strlen (buf) + 1) == -1)
+
+ ACE_ERROR ((LM_ERROR,
+ "(%P) %p\n",
+ "Socket send"));
+
+ if (stream.close () == -1)
+ ACE_ERROR ((LM_ERROR,
+ "(%P) %p\n",
+ "Socket close"));
+
+ ACE_DEBUG ((LM_DEBUG,
+ "(%P) Client: Message has been sent, about to exit...\n"));
+ return 0;
+}
+
+// Callback for "Press Me" button.
+
+static void
+inc_count (Widget, XtPointer client_data, XtPointer)
+{
+ char new_string[80];
+
+ sprintf (new_string,
+ "Events: [%d] [%d] [%d]",
+ count1++,
+ count2,
+ count3);
+ set_label((Widget) client_data, new_string);
+}
+
+// Callback for X Timer.
+
+static void
+inc_tmo (void *w,XtIntervalId *)
+{
+ char new_string[80];
+
+ if (count2 > 10)
+ ACE_OS::exit (0);
+ sprintf (new_string,
+ "Events: [%d] [%d] [%d]",
+ count1,
+ count2++,
+ count3);
+
+ set_label((Widget) w, new_string);
+
+ (void) XtAppAddTimeOut (XtWidgetToApplicationContext ((Widget) w),
+ 1000,
+ inc_tmo,
+ (Widget) w);
+}
+
+class EV_handler : public ACE_Event_Handler
+{
+public:
+ virtual int handle_timeout (const ACE_Time_Value &,
+ const void *arg)
+ {
+ char new_string[80];
+ sprintf (new_string,
+ "Events: [%d] [%d] [%d]",
+ count1,
+ count2,
+ count3++);
+ set_label((Widget) arg, new_string);
+ return 0;
+ }
+};
+
+class Connection_Handler : public ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH>
+{
+public:
+ virtual int open (void *)
+ {
+ char buf[100];
+ int head;
+ ssize_t ret = this->peer ().recv_n ((char *) &head,
+ sizeof (int));
+ if (ret != sizeof (int))
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "(%P) %p\n",
+ "read header"),
+ -1);
+
+ ret = this->peer ().recv_n (buf,
+ (int) ntohl (head));
+
+ if (ret != (int) ntohl (head))
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "(%P) %p\n",
+ "read message"),
+ -1);
+ ACE_DEBUG ((LM_DEBUG,
+ " (%P)Server (ACE_SOCKET channel message): [%s]\n",
+ buf));
+ return 0;
+ }
+};
+
+#if defined (HummingBird_X)
+extern "C" void HCLXmInit (void);
+#endif /* HummingBird_X */
+
+int
+run_main (int argc, ACE_TCHAR *argv[])
+{
+ ACE_START_TEST (ACE_TEXT ("XtMotifReactor_Test"));
+
+ XtAppContext app_context;
+ Widget topLevel, goodbye, PressMe, lbl, digits_rc;
+ Widget children[5];
+
+#if defined (HummingBird_X)
+ HCLXmInit ();
+#endif /* HummingBird_X */
+ topLevel = XtVaAppInitialize (&app_context,
+ "XTReactor_Test",
+ 0,
+ 0,
+ &argc,
+ argv,
+ 0,
+ 0);
+
+ digits_rc = create_box(topLevel, "digits_rc");
+
+ //"Stop Test" button.
+ goodbye = XtCreateWidget ( (char *) "goodbye",
+ BUTTON_WIDGET,
+ digits_rc,
+ 0,
+ 0);
+ set_label(goodbye, "Stop Test");
+
+ //"Press Me" button
+ PressMe = XtCreateWidget ((char *) "PressMe",
+ BUTTON_WIDGET,
+ digits_rc,
+ 0,
+ 0);
+
+ //Display for event counter
+ lbl = XtCreateWidget ((char *) "label_for_event_one",
+ LABEL_WIDGET,
+ digits_rc,
+ 0,
+ 0);
+ set_label(lbl, "label_for_all_events");
+ int ac = 0;
+ children[ac++] = goodbye;
+ children[ac++] = PressMe;
+ children[ac++] = lbl;
+ XtManageChildren (children, ac);
+ XtManageChild (digits_rc);
+
+ //Register callback for "Stop Test" button
+ XtAddCallback (goodbye, PRESS_ME_CALLBACK, Quit, 0);
+
+ //Register callback for "Press Me" button
+ XtAddCallback (PressMe,
+ PRESS_ME_CALLBACK,
+ inc_count,
+ (XtPointer) lbl);
+
+ // Register callback for X Timer
+ (void) XtAppAddTimeOut (app_context,
+ 1000,
+ inc_tmo,
+ (XtPointer) lbl);
+
+ XtRealizeWidget (topLevel);
+
+ // It will perform X Main Loop
+ ACE_XtReactor reactor (app_context);
+
+ ACE_Reactor r (&reactor);
+
+ //Event Handler for ACE Timer.
+ EV_handler evh;
+
+ ACE_Acceptor <Connection_Handler, ACE_SOCK_ACCEPTOR> acceptor;
+
+ if (acceptor.open (ACE_INET_Addr ((u_short) SERV_TCP_PORT),
+ &r) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "%p\n",
+ "open"),
+ -1);
+
+ if (reactor.schedule_timer (&evh,
+ (const void *) lbl,
+ ACE_Time_Value (2),
+ ACE_Time_Value (2))==-1)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ " (%P|%t) can't register with reactor\n"),
+ -1);
+
+ ACE_Thread_Manager::instance ()->spawn ((ACE_THR_FUNC) client,
+ 0,
+ THR_NEW_LWP | THR_DETACHED);
+
+ XtAppMainLoop (XtWidgetToApplicationContext (topLevel));
+
+ ACE_END_TEST;
+ return 0;
+}
+
diff --git a/ACE/tests/acetest.mpb b/ACE/tests/acetest.mpb
new file mode 100644
index 00000000000..1d70ab5e07f
--- /dev/null
+++ b/ACE/tests/acetest.mpb
@@ -0,0 +1,20 @@
+// -*- MPC -*-
+// $Id$
+
+project : aceexe {
+
+ after += Test_Output
+ libs += Test_Output
+
+ Source_Files {
+ $(ACE_ROOT)/tests/Main.cpp
+ }
+ Header_Files {
+ }
+ Resource_Files {
+ }
+ Documentation_Files {
+ }
+ Inline_Files {
+ }
+} \ No newline at end of file
diff --git a/ACE/tests/dll_test_parent_lib.mpb b/ACE/tests/dll_test_parent_lib.mpb
new file mode 100644
index 00000000000..0949642442a
--- /dev/null
+++ b/ACE/tests/dll_test_parent_lib.mpb
@@ -0,0 +1,10 @@
+// -*- MPC -*-
+//
+// $Id$
+
+project {
+
+ after += DLL_Test_Parent_Lib
+ libs += DLL_Test_Parent
+
+}
diff --git a/ACE/tests/log/.cvsignore b/ACE/tests/log/.cvsignore
new file mode 100755
index 00000000000..397b4a7624e
--- /dev/null
+++ b/ACE/tests/log/.cvsignore
@@ -0,0 +1 @@
+*.log
diff --git a/ACE/tests/pharlap/run_pharlap_tests.bat b/ACE/tests/pharlap/run_pharlap_tests.bat
new file mode 100755
index 00000000000..910f2a678f5
--- /dev/null
+++ b/ACE/tests/pharlap/run_pharlap_tests.bat
@@ -0,0 +1,130 @@
+@echo off
+rem $Id$
+
+rem This file runs all the tests on PharLap ETS.
+rem To use this either give it no arguments to run all the tests or
+rem pass it the test name (without the extention) to run only one
+rem test
+
+setlocal
+
+set arg=%1
+
+if not "%1" == "" goto runtest
+
+:runall
+
+rem call %0 ACE_Init_Test
+call %0 Atomic_Op_Test
+call %0 Barrier_Test
+call %0 Basic_Types_Test
+call %0 Buffer_Stream_Test
+call %0 CDR_Test
+call %0 Collection_Test
+call %0 Conn_Test
+call %0 Cached_Conn_Test
+call %0 Cached_Accept_Conn_Test
+call %0 DLL_Test
+call %0 DLList_Test
+call %0 Enum_Interfaces_Test
+call %0 Env_Value_Test
+call %0 Future_Test
+call %0 Handle_Set_Test
+call %0 Hash_Map_Manager_Test
+call %0 Lazy_Map_Manager_Test
+call %0 Hash_Map_Bucket_Iterator_Test
+call %0 High_Res_Timer_Test
+call %0 IOStream_Test
+call %0 Map_Manager_Test
+call %0 Cache_Map_Manager_Test
+call %0 Map_Test
+rem call %0 Mem_Map_Test not supported
+call %0 Message_Block_Test
+call %0 Message_Queue_Notifications_Test
+call %0 Message_Queue_Test
+call %0 MT_Reactor_Timer_Test
+rem call %0 MM_Shared_Memory_Test not supported
+call %0 MT_SOCK_Test
+call %0 Naming_Test
+call %0 New_Fail_Test
+call %0 Notify_Performance_Test
+call %0 Object_Manager_Test
+call %0 OrdMultiSet_Test
+call %0 Pipe_Test
+call %0 Priority_Buffer_Test
+call %0 Dynamic_Priority_Test
+call %0 Priority_Reactor_Test
+call %0 Priority_Task_Test
+call %0 Process_Mutex_Test
+call %0 Process_Strategy_Test
+call %0 RB_Tree_Test
+call %0 Reactors_Test
+call %0 Reactor_Exceptions_Test
+call %0 Reactor_Notify_Test
+call %0 Reactor_Performance_Test
+call %0 Reactor_Timer_Test
+call %0 Reader_Writer_Test
+call %0 Thread_Pool_Reactor_Test
+call %0 Recursive_Mutex_Test
+call %0 Reverse_Lock_Test
+call %0 Semaphore_Test
+call %0 Service_Config_Test
+call %0 Sigset_Ops_Test
+call %0 Simple_Message_Block_Test
+call %0 Svc_Handler_Test
+call %0 SOCK_Test
+call %0 SOCK_Connector_Test
+call %0 SOCK_Send_Recv_Test
+rem call %0 SPIPE_Test not supported
+call %0 SString_Test
+call %0 SV_Shared_Memory_Test
+call %0 Task_Test
+call %0 Thread_Manager_Test
+call %0 Thread_Mutex_Test
+call %0 Thread_Pool_Test
+call %0 Timer_Queue_Test
+call %0 Timeprobe_Test
+if exist ..\netsvcs\servers\main.exe call %0 Time_Service_Test
+call %0 Time_Value_Test
+call %0 Tokens_Test
+call %0 TSS_Test
+call %0 UPIPE_SAP_Test
+call %0 Upgradable_RW_Test
+goto done
+
+:runtest
+
+echo Running %arg%
+if not exist %arg%_ETS.exe goto nofile
+
+RUNEMB -LOGHOST -NODIALOG %arg%_ETS.exe > log\%arg%.log
+if errorlevel 0 goto fine
+echo.
+echo %arg% has FAILED!!!
+echo.
+type log\%arg%.log | find /I "Abnormal program termination"
+type log/%arg%.log | find /I "target halted"
+type log/%arg%.log | find /I "Fatal error"
+type log\%arg%.log | find /I "assertion failed"
+type log\%arg%.log | find /I "not supported"
+type log\%arg%.log | find /I "no such file or directory"
+type log\%arg%.log | find /I "invalid argument"
+type log\%arg%.log | find /I "timeout"
+type log\%arg%.log | find /I "bad file number"
+type log\%arg%.log | find /I "Win32 structured exception"
+echo.
+
+goto done
+
+:nofile
+echo %arg%.exe not found
+goto done
+
+:fine
+
+rem We should check the log files here to make sure the test ended correctly
+rem type log\%arg%.log | find "Ending"
+
+:done
+
+endlocal
diff --git a/ACE/tests/rtems_init.c b/ACE/tests/rtems_init.c
new file mode 100644
index 00000000000..81750a913e9
--- /dev/null
+++ b/ACE/tests/rtems_init.c
@@ -0,0 +1,210 @@
+/*
+ * RTEMS Network configuration/initialization
+ *
+ * This file is a merger of the netdemo/init.c and networkconfig.h
+ * with some modifications to support loopback only. This file
+ * is OK for a starting point for a real networked application.
+ * --joel sherrill 16 Mar 2001
+ *
+ * This program may be distributed and used for any purpose.
+ * I ask only that you:
+ * 1. Leave this author information intact.
+ * 2. Document any changes you make.
+ *
+ * W. Eric Norum
+ * Saskatchewan Accelerator Laboratory
+ * University of Saskatchewan
+ * Saskatoon, Saskatchewan, CANADA
+ * eric@skatter.usask.ca
+ *
+ * $Id$
+ */
+
+#include <bsp.h>
+
+#define CONFIGURE_TEST_NEEDS_CONSOLE_DRIVER
+#define CONFIGURE_TEST_NEEDS_CLOCK_DRIVER
+#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
+
+#define CONFIGURE_EXECUTIVE_RAM_SIZE (512*1024)
+#define CONFIGURE_MAXIMUM_SEMAPHORES 20
+#define CONFIGURE_MAXIMUM_TASKS 20
+
+#define CONFIGURE_MICROSECONDS_PER_TICK 10000
+
+#define CONFIGURE_INIT_TASK_STACK_SIZE (10*1024)
+#define CONFIGURE_INIT_TASK_PRIORITY 120
+#define CONFIGURE_INIT_TASK_INITIAL_MODES (RTEMS_PREEMPT | \
+ RTEMS_NO_TIMESLICE | \
+ RTEMS_NO_ASR | \
+ RTEMS_INTERRUPT_LEVEL(0))
+
+#define CONFIGURE_INIT
+rtems_task Init (rtems_task_argument argument);
+
+#include <confdefs.h>
+
+#include <stdio.h>
+#include <rtems/rtems_bsdnet.h>
+/* start of #include "../networkconfig.h" */
+
+/*
+ * Network configuration
+ *
+ ************************************************************
+ * EDIT THIS FILE TO REFLECT YOUR NETWORK CONFIGURATION *
+ * BEFORE RUNNING ANY RTEMS PROGRAMS WHICH USE THE NETWORK! *
+ ************************************************************
+ *
+ * $Id$
+ */
+
+#ifndef _RTEMS_NETWORKCONFIG_H_
+#define _RTEMS_NETWORKCONFIG_H_
+
+#ifndef RTEMS_BSP_NETWORK_DRIVER_NAME
+#warning "RTEMS_BSP_NETWORK_DRIVER_NAME is not defined"
+#define RTEMS_BSP_NETWORK_DRIVER_NAME "no_network1"
+#endif
+
+#ifndef RTEMS_BSP_NETWORK_DRIVER_ATTACH
+#warning "RTEMS_BSP_NETWORK_DRIVER_ATTACH is not defined"
+#define RTEMS_BSP_NETWORK_DRIVER_ATTACH 0
+#endif
+
+/* #define RTEMS_USE_BOOTP */
+
+#include <bsp.h>
+
+/*
+ * Define RTEMS_SET_ETHERNET_ADDRESS if you want to specify the
+ * Ethernet address here. If RTEMS_SET_ETHERNET_ADDRESS is not
+ * defined the driver will choose an address.
+ */
+#define RTEMS_SET_ETHERNET_ADDRESS
+#if (defined (RTEMS_SET_ETHERNET_ADDRESS))
+/* static char ethernet_address[6] = { 0x08, 0x00, 0x3e, 0x12, 0x28, 0xb1 }; */
+static char ethernet_address[6] = { 0x00, 0x80, 0x7F, 0x22, 0x61, 0x77 };
+
+#endif
+
+#define RTEMS_USE_LOOPBACK
+#define RTEMS_USE_LOOPBACK_ONLY
+#ifdef RTEMS_USE_LOOPBACK
+/*
+ * Loopback interface
+ */
+int rtems_bsdnet_loopattach(struct rtems_bsdnet_ifconfig *, int);
+
+#ifdef RTEMS_USE_LOOPBACK_ONLY
+static struct rtems_bsdnet_ifconfig netdriver_config = {
+#else
+static struct rtems_bsdnet_ifconfig loopback_config = {
+#endif
+ "lo0", /* name */
+ rtems_bsdnet_loopattach, /* attach function */
+
+ NULL, /* link to next interface */
+
+ "127.0.0.1", /* IP address */
+ "255.0.0.0", /* IP net mask */
+};
+#endif
+
+/*
+ * Default network interface
+ */
+#ifndef RTEMS_USE_LOOPBACK_ONLY
+static struct rtems_bsdnet_ifconfig netdriver_config = {
+ RTEMS_BSP_NETWORK_DRIVER_NAME, /* name */
+ RTEMS_BSP_NETWORK_DRIVER_ATTACH, /* attach function */
+
+#ifdef RTEMS_USE_LOOPBACK
+ &loopback_config, /* link to next interface */
+#else
+ NULL, /* No more interfaces */
+#endif
+
+#if (defined (RTEMS_USE_BOOTP))
+ NULL, /* BOOTP supplies IP address */
+ NULL, /* BOOTP supplies IP net mask */
+#else
+ "XXX.YYY.ZZZ.XYZ", /* IP address */
+ "255.255.255.0", /* IP net mask */
+#endif /* !RTEMS_USE_BOOTP */
+
+#if (defined (RTEMS_SET_ETHERNET_ADDRESS))
+ ethernet_address, /* Ethernet hardware address */
+#else
+ NULL, /* Driver supplies hardware address */
+#endif
+ 0 /* Use default driver parameters */
+};
+#endif
+
+/*
+ * Network configuration
+ */
+struct rtems_bsdnet_config rtems_bsdnet_config = {
+ &netdriver_config,
+
+#if (defined (RTEMS_USE_BOOTP))
+ rtems_bsdnet_do_bootp,
+#else
+ NULL,
+#endif
+
+ 0, /* Default network task priority */
+ 0, /* Default mbuf capacity */
+ 0, /* Default mbuf cluster capacity */
+
+#if (!defined (RTEMS_USE_BOOTP))
+ "rtems_host", /* Host name */
+ "nodomain.com", /* Domain name */
+ "XXX.YYY.ZZZ.1", /* Gateway */
+ "XXX.YYY.ZZZ.1", /* Log host */
+ {"XXX.YYY.ZZZ.1" }, /* Name server(s) */
+ {"XXX.YYY.ZZZ.1" }, /* NTP server(s) */
+
+ /*
+ * A real example -- DO NOT USE THIS YOURSELF!!!
+ */
+
+#if 0
+ "dy4", /* Host name */
+ "NOT_oarcorp.com", /* Domain name */
+ "192.168.1.2", /* Gateway */
+ "192.168.1.2", /* Log host */
+ {"192.168.1.2" }, /* Name server(s) */
+ {"192.168.1.2" }, /* NTP server(s) */
+#endif
+#endif /* !RTEMS_USE_BOOTP */
+
+};
+
+/*
+ * For TFTP test application
+ */
+#if (defined (RTEMS_USE_BOOTP))
+#define RTEMS_TFTP_TEST_HOST_NAME "BOOTP_HOST"
+#define RTEMS_TFTP_TEST_FILE_NAME "BOOTP_FILE"
+#else
+#define RTEMS_TFTP_TEST_HOST_NAME "XXX.YYY.ZZZ.XYZ"
+#define RTEMS_TFTP_TEST_FILE_NAME "tftptest"
+#endif
+
+#endif /* _RTEMS_NETWORKCONFIG_H_ */
+/* end of #include "../networkconfig.h" */
+
+/*
+ * RTEMS Startup Task
+ */
+rtems_task
+Init (rtems_task_argument ignored)
+{
+ int doSocket(void);
+
+ rtems_bsdnet_initialize_network ();
+ rtems_bsdnet_show_inet_routes ();
+ exit (0);
+}
diff --git a/ACE/tests/run_test.lst b/ACE/tests/run_test.lst
new file mode 100644
index 00000000000..815d0e8c808
--- /dev/null
+++ b/ACE/tests/run_test.lst
@@ -0,0 +1,174 @@
+# $Id$
+#
+# This is the list of tests that need to be run by run_test.pl.
+# Each line has its own test, and a test can be followed by a
+# list of platforms it runs or does not run on.
+#
+# Example: Foo_Test: !linux
+# Example: Bar_Test:
+# Example: Baz_Test: Win32 !Borland
+#
+# Foo_Test runs on all configurations except for linux
+#
+# Bar_Test runs on all configurations
+#
+# Baz_Test only runs on Win32 configurations but not on Borland
+# configurations.
+
+ACE_Init_Test: MSVC
+ACE_Test
+Aio_Platform_Test
+Arg_Shifter_Test
+Array_Map_Test
+Atomic_Op_Test
+Auto_Event_Test
+Auto_IncDec_Test: !DISABLE_ToFix_LynxOS_PPC
+Barrier_Test: !DISABLE_ToFix_LynxOS_PPC
+Based_Pointer_Test: !DISABLE_ToFix_LynxOS_PPC !STATIC !VxWorks !ACE_FOR_TAO
+Basic_Types_Test
+Bound_Ptr_Test: !DISABLE_ToFix_LynxOS_PPC !ACE_FOR_TAO
+Buffer_Stream_Test: !DISABLE_ToFix_LynxOS_PPC
+Bug_1576_Regression_Test
+Bug_1890_Regression_Test
+Bug_2368_Regression_Test
+Bug_2497_Regression_Test
+Bug_2540_Regression_Test
+CDR_Array_Test: !ACE_FOR_TAO
+CDR_File_Test: !ACE_FOR_TAO
+CDR_Test
+Cache_Map_Manager_Test
+Cached_Accept_Conn_Test: !VxWorks !ACE_FOR_TAO
+Cached_Allocator_Test: !ACE_FOR_TAO
+Cached_Conn_Test: !VxWorks !ACE_FOR_TAO
+Capabilities_Test: !DISABLE_ToFix_LynxOS_PPC !DISABLE_ToFix_LynxOS_x86 !ACE_FOR_TAO
+Codecs_Test: !DISABLE_ToFix_LynxOS_PPC !DISABLE_ToFix_LynxOS_x86 !ACE_FOR_TAO
+Collection_Test
+Config_Test: !LynxOS !VxWorks !ACE_FOR_TAO
+Conn_Test: !DISABLE_ToFix_LynxOS_PPC !DISABLE_ToFix_LynxOS_x86 !ACE_FOR_TAO
+DLL_Test: !Unicos !STATIC !KCC_Linux
+DLList_Test: !ACE_FOR_TAO
+Date_Time_Test: !ACE_FOR_TAO
+Dev_Poll_Reactor_Test: !nsk
+Dirent_Test
+Dynamic_Priority_Test
+Enum_Interfaces_Test: !LynxOS
+Env_Value_Test: !WinCE
+FIFO_Test: !ACE_FOR_TAO
+Framework_Component_Test: !STATIC !nsk
+Future_Set_Test: !DISABLE_ToFix_LynxOS_PPC !nsk !ACE_FOR_TAO
+Future_Test: !DISABLE_ToFix_LynxOS_PPC !nsk !ACE_FOR_TAO
+Get_Opt_Test
+Handle_Set_Test: !ACE_FOR_TAO
+Hash_Map_Bucket_Iterator_Test
+Hash_Map_Manager_Test
+High_Res_Timer_Test: !ACE_FOR_TAO
+INET_Addr_Test
+IOStream_Test
+Lazy_Map_Manager_Test
+Log_Msg_Test: !LynxOS !ACE_FOR_TAO
+Logging_Strategy_Test: !DISABLE_ToFix_LynxOS_PPC !STATIC !ST
+Manual_Event_Test: !DISABLE_ToFix_LynxOS_PPC
+MEM_Stream_Test: !DISABLE_ToFix_LynxOS_PPC !DISABLE_ToFix_LynxOS_x86 !VxWorks !nsk !ACE_FOR_TAO
+MM_Shared_Memory_Test: !Unicos !VxWorks !nsk !ACE_FOR_TAO
+MT_Reactor_Timer_Test: !DISABLE_ToFix_LynxOS_PPC !DISABLE_ToFix_LynxOS_x86
+MT_Reactor_Upcall_Test: !DISABLE_ToFix_LynxOS_PPC !nsk
+MT_Reference_Counted_Event_Handler_Test: !DISABLE_ToFix_LynxOS_PPC !DISABLE_ToFix_LynxOS_x86
+MT_Reference_Counted_Notify_Test: !DISABLE_ToFix_LynxOS_PPC
+MT_SOCK_Test: !DISABLE_ToFix_LynxOS_PPC !DISABLE_ToFix_LynxOS_x86
+Malloc_Test: !VxWorks !LynxOS !ACE_FOR_TAO
+Map_Manager_Test: !ACE_FOR_TAO
+Map_Test: !ACE_FOR_TAO
+Max_Default_Port_Test: !DISABLE_ToFix_LynxOS_PPC !ST
+Mem_Map_Test: !Unicos !VxWorks !nsk !ACE_FOR_TAO
+Memcpy_Test: !ACE_FOR_TAO
+Message_Block_Test: !DISABLE_ToFix_LynxOS_PPC !ACE_FOR_TAO
+Message_Queue_Notifications_Test: !DISABLE_ToFix_LynxOS_PPC
+Message_Queue_Test: !ACE_FOR_TAO
+Message_Queue_Test_Ex: !ACE_FOR_TAO
+Multicast_Test: !ST !NO_MCAST !nsk !LynxOS
+Multihomed_INET_Addr_Test: !ACE_FOR_TAO
+Naming_Test: !LynxOS !Unicos !VxWorks !nsk !ACE_FOR_TAO
+Network_Adapters_Test: !DISABLE_ToFix_LynxOS_PPC !DISABLE_ToFix_LynxOS_x86
+New_Fail_Test: ALL !DISABLED
+NonBlocking_Conn_Test
+Notify_Performance_Test: !nsk !ACE_FOR_TAO
+OS_Test
+Object_Manager_Test
+Obstack_Test
+OrdMultiSet_Test
+Pipe_Test: !VxWorks
+Priority_Buffer_Test
+Priority_Reactor_Test: !DISABLE_ToFix_LynxOS_PPC !ACE_FOR_TAO
+Priority_Task_Test: !DISABLE_ToFix_LynxOS_PPC !Unicos
+Proactor_Scatter_Gather_Test: !VxWorks !nsk !ACE_FOR_TAO
+Proactor_Test: !VxWorks !LynxOS !nsk !ACE_FOR_TAO !BAD_AIO
+Proactor_Timer_Test: !VxWorks !nsk !ACE_FOR_TAO
+Process_Manager_Test: !VxWorks !ACE_FOR_TAO
+Process_Manual_Event_Test: !HPUX !VxWorks !ACE_FOR_TAO
+Process_Mutex_Test: !VxWorks !ACE_FOR_TAO
+Process_Semaphore_Test: !VxWorks !ACE_FOR_TAO
+RB_Tree_Test
+Reactor_Dispatch_Order_Test
+Reactor_Exceptions_Test: !DISABLE_ToFix_LynxOS_PPC
+Reactor_Notify_Test: !DISABLE_ToFix_LynxOS_PPC !ST !ACE_FOR_TAO
+Reactor_Notification_Queue_Test
+Reactor_Performance_Test: !DISABLE_ToFix_LynxOS_PPC !ACE_FOR_TAO
+Reactor_Registration_Test
+Reactor_Timer_Test: !ACE_FOR_TAO
+Reactors_Test: !DISABLE_ToFix_LynxOS_PPC
+Reader_Writer_Test: !DISABLE_ToFix_LynxOS_PPC
+Recursive_Condition_Test: !DISABLE_ToFix_LynxOS_PPC !ST
+Recursive_Mutex_Test: !DISABLE_ToFix_LynxOS_PPC !ST
+Refcounted_Auto_Ptr_Test: !DISABLE_ToFix_LynxOS_PPC !ACE_FOR_TAO
+Reference_Counted_Event_Handler_Test
+Reverse_Lock_Test
+Sendfile_Test
+Signal_Test
+SOCK_Connector_Test
+SOCK_Netlink_Test: !ACE_FOR_TAO
+SOCK_Send_Recv_Test
+SOCK_Test
+SPIPE_Test: !VxWorks !nsk !ACE_FOR_TAO
+SString_Test: !ACE_FOR_TAO
+SV_Shared_Memory_Test: !DISABLE_ToFix_LynxOS_PPC !DISABLE_ToFix_LynxOS_x86 !MSVC !Unicos !VxWorks !RH_7.1 !nsk !ACE_FOR_TAO
+Semaphore_Test: !ACE_FOR_TAO
+Service_Config_Test: !DISABLE_ToFix_LynxOS_PPC !STATIC
+Sigset_Ops_Test
+Simple_Message_Block_Test
+Svc_Handler_Test: !ACE_FOR_TAO
+TP_Reactor_Test: !DISABLE_ToFix_LynxOS_PPC !DISABLE_ToFix_LynxOS_x86 !ACE_FOR_TAO
+TSS_Test: !DISABLE_ToFix_LynxOS_PPC
+TSS_Static_Test
+Task_Test: !DISABLE_ToFix_LynxOS_PPC
+Task_Ex_Test: !DISABLE_ToFix_LynxOS_PPC
+Thread_Manager_Test: !DISABLE_ToFix_LynxOS_PPC !Unicos
+Thread_Mutex_Test: !DISABLE_ToFix_LynxOS_PPC
+Thread_Pool_Reactor_Resume_Test: !DISABLE_ToFix_LynxOS_PPC !ST
+Thread_Pool_Reactor_Test: !DISABLE_ToFix_LynxOS_PPC
+Thread_Pool_Test: !DISABLE_ToFix_LynxOS_PPC
+Time_Service_Test: !STATIC !DISABLED !missing_netsvcs TOKEN !Unicos
+Time_Value_Test
+Timeprobe_Test
+Timer_Cancellation_Test: !DISABLE_ToFix_LynxOS_PPC
+Timer_Queue_Reference_Counting_Test
+Timer_Queue_Test: !ACE_FOR_TAO
+Token_Strategy_Test: !DISABLE_ToFix_LynxOS_PPC !ST !nsk
+Tokens_Test: MSVC !DISABLED TOKEN !Unicos
+UPIPE_SAP_Test: !VxWorks !nsk !ACE_FOR_TAO
+Unbounded_Set_Test
+Upgradable_RW_Test: !ACE_FOR_TAO
+Vector_Test
+WFMO_Reactor_Test: !nsk
+INET_Addr_Test_IPV6: !nsk
+Max_Default_Port_Test_IPV6: !nsk
+Multicast_Test_IPV6: !NO_MCAST !nsk
+Multihomed_INET_Addr_Test_IPV6: !nsk !ACE_FOR_TAO
+Proactor_Test_IPV6: !nsk !ACE_FOR_TAO !BAD_AIO
+SOCK_Send_Recv_Test_IPV6
+SOCK_Dgram_Test
+SOCK_Dgram_Bcast_Test: !DISABLE_ToFix_LynxOS_PPC !DISABLE_ToFix_LynxOS_x86 !ACE_FOR_TAO
+SOCK_SEQPACK_SCTP_Test: !MSVC !nsk !ACE_FOR_TAO
+SOCK_Test_IPv6: !nsk
+Process_Strategy_Test: !VxWorks !LynxOS !ACE_FOR_TAO
+Recursive_Condition_Bug_Test: !DISABLE_ToFix_LynxOS_PPC !ST
+UnloadLibACE: !STATIC !WinCE
diff --git a/ACE/tests/run_test.pl b/ACE/tests/run_test.pl
new file mode 100755
index 00000000000..4e5a6c5747a
--- /dev/null
+++ b/ACE/tests/run_test.pl
@@ -0,0 +1,524 @@
+eval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}'
+ & eval 'exec perl -S $0 $argv:q'
+ if 0;
+
+# $Id$
+# -*- perl -*-
+# This file is for running the tests in the ACE tests directory.
+# It is usually used for auto_compiles.
+
+if (defined $ENV{ACE_ROOT}) {
+ use lib "$ENV{ACE_ROOT}/bin";
+} else {
+ use lib '../bin';
+}
+if (defined $ENV{top_srcdir}) {
+ use lib "$ENV{top_srcdir}/bin";
+}
+
+use PerlACE::Run_Test;
+
+use Cwd;
+use English;
+use Getopt::Std;
+use FileHandle;
+
+$config_list = new PerlACE::ConfigList;
+
+################################################################################
+
+sub check_for_more_configs ()
+{
+ my $fh = new FileHandle;
+
+ if ($fh->open ("< ../ace/ACE_COMPONENTS.list")) {
+ while (<$fh>) {
+ if (m/ Other /) {
+ print "Adding 'Other' as my config\n" if defined $opt_d;
+ $config_list->add_one_config ('OTHER');
+ }
+ if (m/ Token /) {
+ print "Adding 'Token' as my config\n" if defined $opt_d;
+ $config_list->add_one_config ('TOKEN');
+ }
+ }
+
+ $fh->close ();
+ }
+ elsif (defined $opt_d) {
+ print "Could not open ACE_COMPONENTS.list file\n" if defined $opt_d;
+ print "Assuming TOKEN and OTHER subsets are included\n" if defined $opt_d;
+ $config_list->add_one_config ('OTHER');
+ $config_list->add_one_config ('TOKEN');
+ }
+
+ my $P = new PerlACE::Process ("../netsvcs/servers/main");
+
+ if (!-x $P->Executable ()) {
+ $config_list->add_one_config ('missing_netsvcs');
+ }
+
+ if (defined $opt_v) {
+ $config_list->add_one_config ('VxWorks');
+ }
+}
+
+################################################################################
+
+sub record_resources ()
+{
+ if ($config_list->check_config ('CHECK_RESOURCES')) {
+ if (!defined $ENV{'LOGNAME'}) {
+ $user=`whoami`;
+ }
+ else {
+ $user = $ENV{'LOGNAME'};
+ }
+
+ $start_test_resources=`ipcs | egrep $user`;
+ }
+}
+
+################################################################################
+
+sub check_resources
+{
+ my($oh) = shift;
+ if ($config_list->check_config ('CHECK_RESOURCES')) {
+ if (defined $opt_v) {
+ print $oh "memShow();\n";
+ }
+ else {
+ $end_test_resources=`ipcs | egrep $user`;
+
+ if ("$start_test_resources" ne "$end_test_resources") {
+ print STDERR "Warning: the ACE tests _may_ have leaked OS ".
+ "resources!\n";
+ print STDERR "Warning: Before: $start_test_resources\n";
+ print STDERR "Warning: After: $end_test_resources\n";
+ }
+ }
+ }
+}
+
+################################################################################
+
+sub run_program ($)
+{
+ my $program = shift;
+
+ unlink <log/$program*.log>;
+ unlink "core";
+
+ my $P;
+
+ if ($config_list->check_config ('Valgrind')) {
+ $P = new PerlACE::Process ($program);
+ $P->IgnoreExeSubDir(1);
+ }
+ else {
+ $P = new PerlACE::Process ($program);
+
+ ### Try to run the program
+
+ if (! -x $P->Executable ()) {
+ print STDERR "Error: " . $P->Executable () .
+ " does not exist or is not runnable\n";
+ return;
+ }
+ }
+
+ print "auto_run_tests: tests/$program\n";
+ my $start_time = time();
+ $status = $P->SpawnWaitKill (400);
+ my $time = time() - $start_time;
+
+ ### Check for problems
+
+ if ($status == -1) {
+ print STDERR "Error: $program FAILED (time out)\n";
+ $P->Kill ();
+ $P->TimedWait (1);
+ }
+ elsif ($status != 0) {
+ print STDERR "Error: $program FAILED with exit status $status\n";
+ }
+
+ print "\nauto_run_tests_finished: test/$program Time:$time"."s Result:$status\n";
+
+ check_log ($program);
+
+ if ($config_list->check_config ('Codeguard')) {
+ check_codeguard_log ($program);
+ }
+}
+
+################################################################################
+
+sub run_vxworks_command ($)
+{
+ my $program = shift;
+
+ unlink <log/$program*.log>;
+ unlink "core";
+
+ my $P = new PerlACE::ProcessVX ($program);
+
+ ## check module existence
+ if (! -e $P->Executable ()) {
+ print STDERR "Error: " . $P->Executable() .
+ " does not exist\n";
+ return;
+ }
+
+ print "auto_run_tests: tests/$program\n";
+ my $start_time = time();
+ $status = $P->SpawnWaitKill (400);
+ my $time = time() - $start_time;
+
+ ### Check for problems
+
+ if ($status == -1) {
+ print STDERR "Error: $program FAILED (time out)\n";
+ $P->Kill ();
+ $P->TimedWait (1);
+ }
+ elsif ($status != 0) {
+ print STDERR "Error: $program FAILED with exit status $status\n";
+ }
+
+ print "\nauto_run_tests_finished: test/$program Time:$time"."s Result:$status\n";
+
+ check_log ($program);
+}
+
+################################################################################
+
+sub output_vxworks_commands
+{
+ my($oh) = shift;
+ my($program) = shift;
+ my($length) = length($program) + 2;
+
+ if (defined $ENV{'ACE_RUN_VX_CHECK_RESOURCES'}) {
+ print $oh "memShow();\n";
+ }
+
+ print $oh "write(2, \"\\n$program\\n\", $length);\n" .
+ "ld 1,0, \"" . $program . ".out\"\n" .
+ "vx_execae ace_main\n" .
+ "unld \"" . $program . ".out\"\n";
+}
+
+################################################################################
+
+sub purify_program ($)
+{
+ ### @todo
+
+ my $program = shift;
+
+ $program_exe = $program;
+
+ print STDERR "Purifying $program\n";
+
+ system ("purify ".
+ "/run ".
+ "/save-data=purify_results\$program.pfy ".
+ "/save-text-data=purify_results\$program.txt ".
+ "/AllocCallStackLength=20 ".
+ "/ErrorCallStackLength=20 ".
+ "/HandlesInUseAtExit ".
+ "/InUseAtExit ".
+ "/LeaksAtExit ".
+ "$program_exe");
+}
+
+################################################################################
+
+sub check_log ($)
+{
+ my $program = shift;
+
+ ### Check the logs
+ local $log_suffix;
+ if (defined $ENV{"ACE_WINCE_TEST_CONTROLLER"}) {
+ $log_suffix = ".txt";
+ }
+ else {
+ $log_suffix = ".log";
+ }
+ local $log = "log/".$program.$log_suffix;
+
+ if (-e "core") {
+ print STDERR "Error: $program dumped core\n";
+ unlink "core";
+ }
+
+ if (! -e $log ) {
+ print STDERR "Error: No log file ($log) is present\n";
+ }
+ else {
+ if (open (LOG, "<".$log) == 0) {
+ print STDERR "Error: Cannot open log file $log\n";
+ }
+ else {
+ my $print_log = 0;
+ my $starting_matched = 0;
+ my $ending_matched = 0;
+
+ while (<LOG>) {
+ chomp;
+
+ if (m/Starting/) {
+ $starting_matched = 1;
+ }
+
+ if (m/Ending/) {
+ $ending_matched = 1;
+ }
+
+ if (/LM\_ERROR\@(.*)$/) {
+ print STDERR "Error: ($log): $1\n";
+ $print_log = 1;
+ }
+ if (/LM\_WARNING\@(.*)$/) {
+ print STDERR "Warning: ($log): $1\n";
+ $print_log = 1;
+ }
+ }
+
+ close (LOG); # ignore errors
+
+ if ($starting_matched == 0) {
+ print STDERR "Error ($log): no line with 'Starting'\n";
+ $print_log = 1;
+ }
+
+ if ($ending_matched == 0) {
+ print STDERR "Error ($log): no line with 'Ending'\n";
+ $print_log = 1;
+ }
+
+ if ($print_log == 1) {
+ print STDERR "======= Begin Log File \n";
+ if (open (LOG, "<".$log) == 0) {
+ print STDERR "Error: Cannot open log file $log\n";
+ }
+ else {
+ my @log = <LOG>;
+ print STDERR @log;
+ close (LOG);
+ }
+ print STDERR "======= End Log File \n";
+ }
+
+ # Now check for any sub-logs. If either the main log or a
+ # sub-log has an error, print the sub-log.
+ opendir (THISDIR, "log");
+ local $sublognames = "$program\-.*".$log_suffix;
+ @sublogs = grep (/^$sublognames/, readdir (THISDIR));
+ closedir (THISDIR);
+ foreach $log (@sublogs) {
+ # Just like the main log, but no start/end check
+ if (open (LOG, "<log/".$log) == 0) {
+ print STDERR "Error: Cannot open sublog file $log\n";
+ }
+ else {
+ my $number_starting = 0;
+ my $number_ending = 0;
+ while (<LOG>) {
+ chomp;
+ if (m/Starting/) {
+ $number_starting++;
+ }
+ if (m/Ending/) {
+ $number_ending++;
+ }
+ if (/LM\_ERROR\@(.*)$/) {
+ print STDERR "Error: ($log): $1\n";
+ $print_log = 1;
+ }
+ if (/LM\_WARNING\@(.*)$/) {
+ print STDERR "Warning: ($log): $1\n";
+ $print_log = 1;
+ }
+ }
+
+ if ($number_starting == 0) {
+ print STDERR "Error ($log): no line with 'Starting'\n";
+ $print_log = 1;
+ }
+
+ if ($number_ending == 0) {
+ print STDERR "Error ($log): no line with 'Ending'\n";
+ $print_log = 1;
+ }
+
+ if ($number_starting != $number_ending) {
+ print STDERR "Error ($log): Number of 'Starting' does not match number of 'Ending' ($number_starting != $number_ending)\n";
+ $print_log = 1;
+ }
+
+ close (LOG); # ignore errors
+ if ($print_log == 1) {
+ print STDERR "======= Begin Sublog File ".$log."\n";
+ if (open (LOG, "<log/".$log) == 0) {
+ print STDERR "Error: Cannot open sublog file $log\n";
+ }
+ else {
+ my @log = <LOG>;
+ print STDERR @log;
+ close (LOG);
+ }
+ print STDERR "======= End Sublog File \n";
+ }
+ }
+ }
+ }
+ }
+}
+
+sub check_codeguard_log ($)
+{
+ my $program = shift;
+
+ ### Check the logs
+
+ local $log = $program.".cgl";
+
+ if (-e $log ) {
+ print STDERR "======= Begin Codeguard Log File \n";
+ if (open (LOG, "<".$log) == 0) {
+ print STDERR "Error: Cannot open codeguard log file $log\n";
+ }
+ else {
+ my @log = <LOG>;
+ print STDERR @log;
+ close (LOG);
+ }
+ print STDERR "======= End Codeguard Log File \n";
+ }
+}
+
+################################################################################
+
+sub delete_temp_files ()
+{
+ my @files = ('ace_pipe_name', 'pattern');
+ my $file = '';
+
+ if (!opendir (DIR, $tmp)) {
+ warn "Cannot open temp directory $tmp\n";
+ return;
+ }
+
+ foreach $file (readdir (DIR)) {
+ if ($file =~ /^ace_temp_file/ || $file =~ /^Naming_Test/) {
+ push @files, $tmp . '/' . $file;
+ }
+ }
+ closedir (DIR);
+
+ PerlACE::check_n_cleanup_files ('MEM_Acceptor_*');
+ PerlACE::check_n_cleanup_files ('backing_store_*');
+}
+
+################################################################################
+
+if (!getopts ('dhtvo:') || $opt_h) {
+ print "run_test.pl [-h] [-v] [-o <output file>] [-t file1 file2 ...]\n";
+ print "\n";
+ print "Runs the tests listed in run_test.lst\n";
+ print "\n";
+ print "Options:\n";
+ print " -d Debug mode (do not run tests)\n";
+ print " -h Display this help\n";
+ print " -t Runs all the tests passed via the cmd line\n";
+ print " -v Generate commands for VxWorks\n";
+ print " -o Put VxWorks commands in <output file>\n";
+ print "\n";
+ print "Pass in configs using \"-Config XXXXX\"\n";
+ print "\n";
+ print "Possible Configs: CHECK_RESOURCES Purify Codeguard Valgrind ",
+ $config_list->list_configs (), "\n";
+ exit (1);
+}
+
+## since we can't use "our" to get rid of warnings.
+$opt_h = $opt_h if (defined $opt_h);
+$opt_t = $opt_t if (defined $opt_t);
+$opt_g = $opt_g if (defined $opt_g);
+
+if (!($tmp = $ENV{TMP}) && !($tmp = $ENV{TEMP})) {
+ $tmp="/tmp";
+}
+
+check_for_more_configs ();
+
+if ($config_list->check_config ('VxWorks')) {
+ $opt_v = 1;
+}
+
+@tests = ();
+
+if (defined $opt_t) {
+ @tests = @ARGV;
+}
+else {
+ $config_list->load ("run_test.lst");
+ @tests = $config_list->valid_entries ();
+}
+
+if (defined $opt_d) {
+ $config_list->dump ();
+}
+
+record_resources () if (!defined $opt_d);
+
+my($oh) = \*STDOUT;
+if (defined $opt_v && defined $opt_o) {
+ $oh = new FileHandle();
+ if ($opt_o != 1) {
+ if (!open($oh, ">$opt_o")) {
+ print STDERR "ERROR: Unable to write to $opt_o\n";
+ exit(1);
+ }
+ }
+
+ print $oh "#\n" .
+ "# ACE one-button test for VxWorks 5.x.\n" .
+ "# To use: -> < run_test.vxworks > run_test.log\n" .
+ "#\n" .
+ "# NOTE: if you build with a shared ACE library, be sure to load\n" .
+ "# that first:\n" .
+ "# -> ld < ../ace/libACE.so\n" .
+ "# and unld it after running the tests.\n" .
+ "#\n" .
+ "# The output logs can be checked from a Unix host:\n" .
+ "# % ./run_tests.check log/*.log\n\n";
+
+ foreach $test (@tests) {
+ output_vxworks_commands ($oh, $test);
+ }
+}
+else {
+ foreach $test (@tests) {
+ if (defined $opt_d) {
+ print "Would run test $test now\n";
+ }
+ elsif ($config_list->check_config ('Purify')) {
+ purify_program ($test);
+ }
+ if (defined $opt_v) {
+ run_vxworks_command ($test);
+ }
+ else {
+ run_program ($test);
+ }
+ }
+}
+
+check_resources ($oh) if (!defined $opt_d);
+
+delete_temp_files ();
diff --git a/ACE/tests/run_tests.check b/ACE/tests/run_tests.check
new file mode 100755
index 00000000000..2f6ee6ccd34
--- /dev/null
+++ b/ACE/tests/run_tests.check
@@ -0,0 +1,41 @@
+#! /bin/sh -f
+# $Id$
+#
+# Checks one ore more ACE test log file(s) for expected results.
+
+IFS="|"
+tmp=/tmp
+
+# These patterns must be contained in log file.
+SUCCESS_MSGS="Starting|Ending"
+
+# These patterns should not be contained in log file.
+if [ "$1" != "log/Cached_Accept_Conn_Test.log" ]; then
+ ERROR_MSGS="assertion failed|not supported|No such file or directory|Invalid argument|timeout|Bad file number"
+else
+ # "No such file or directory" is allowed in Cached_Accept_Conn_Test.log
+ ERROR_MSGS="assertion failed|not supported|Invalid argument|timeout|Bad file number"
+fi
+status=0
+
+for arg do
+ for i in $SUCCESS_MSGS; do
+ egrep $i $arg >/dev/null 2>&1
+ if [ $? -eq 1 ]; then
+ echo Error in $arg: no line with $i
+ status=1
+ fi
+ done
+
+ for i in $ERROR_MSGS; do
+ #### The /dev/null arg to egrep causes the filename to be printed
+ #### out. The sed command strips off the leading 'log/' and
+ #### trailing '.log'.
+ egrep $i $arg /dev/null | sed -e 's%^log/%%' -e 's%[.]log:%: %'
+ if [ $? -ne 0 ]; then status=1; fi
+ done
+done
+
+exit $status
+
+# EOF
diff --git a/ACE/tests/run_tests_remote.sh b/ACE/tests/run_tests_remote.sh
new file mode 100755
index 00000000000..149a9174d92
--- /dev/null
+++ b/ACE/tests/run_tests_remote.sh
@@ -0,0 +1,246 @@
+#!/bin/sh
+# $Id$
+#
+# This is the UNIX version of the one-button ACE tests.
+# Contributed originally by Michael Rueger <m_rueger@SYSCOMP.DE> and
+# modified substantially by the DOC group.
+#
+# It also supports remote invocation on a CHORUS/ClassiX/MVME target.
+# For that environment, these steps are required:
+# 1) Create a "log" directory below the root mount point on the host.
+# 2) Mount the "tests" directory on the target, and add it to the PATH
+# on the target.
+# 3) cd to the directory that contains this script on the host.
+# 4) Create a symlink to the "log" directory create in step 1) above.
+# 5) ./run_tests.sh <target_hostname>
+
+if [ -x /bin/rm ]; then
+ RM=/bin/rm
+elif [ -x /usr/bin/rm ]; then
+ RM=/usr/bin/rm
+else
+ echo "Can't find rm, aborting." 1>&2
+ exit 1
+fi
+
+usage="usage: $0 [-p] <target>
+ -p: purify tests"
+
+purify=0
+purify_with_old_gcc=0
+
+####
+#### Interpret command arguments.
+####
+for arg in "$@"; do
+ case $arg in
+ -p ) purify=1
+ shift
+ ;;
+
+ -'?' ) echo $usage
+ exit 0
+ ;;
+
+ -*) echo $0: unknown option $arg
+ echo $usage
+ exit 1
+ ;;
+ esac
+done
+
+if [ ! "$ACE_ROOT" ]; then
+ ACE_ROOT=..
+ export ACE_ROOT
+fi
+
+# Some tests fork/exec copies of themselves (e.g. Pipe_Test). If execvp
+# ends up getting used, the PATH has to include "." or the test won't work.
+PATH=.:$PATH
+export PATH
+
+IFS="|"
+tmp=/tmp
+compilation_log="log/compilations.log"
+shlib_suffix=".so"
+
+LD_LIBRARY_PATH=$ACE_ROOT/ace:${LD_LIBRARY_PATH:-/usr/lib}
+export LD_LIBRARY_PATH
+
+#### If uname isn't on the user's PATH, store any string
+#### in $sysname.
+sysname=`uname -s 2>&1`
+
+if [ $sysname = 'HP-UX' ]; then
+ SHLIB_PATH=$ACE_ROOT/ace:${SHLIB_PATH:-/usr/lib}
+ export SHLIB_PATH
+ shlib_suffix=".sl"
+fi
+
+if [ $sysname = 'AIX' ]; then
+ LIBPATH=$ACE_ROOT/ace:${LIBPATH:-/usr/lib:/lib}
+ export LIBPATH
+fi
+
+if echo $sysname | grep -q CYGWIN; then
+ shlib_suffix=".dll"
+fi
+
+if [ $purify -eq 1 ]; then
+ if echo $PWD | egrep 'gcc|g++'; then
+ purify_with_old_gcc=1
+ fi
+fi
+
+####
+#### Process command line arguments.
+####
+target=
+run_command=
+chorus=1
+if [ $# -eq 1 ]; then
+ target=$1
+ if rsh $target help | head -1 | egrep -i CHORUS > /dev/null; then
+ run_command=arun
+ chorus=
+ else
+ #### Only support Chorus/MVME, for now.
+ echo $0: host $1 does not appear to be Chorus/MVME: not supported.
+ exit 1
+ fi
+elif [ $# -ne 0 ]; then
+ echo $usage
+ exit 1
+fi
+
+run()
+{
+ $RM -f core log/$1.log
+
+ if [ ! -f "$1" ]; then
+ echo 1>&2 "Making $1 . . ."
+ remove_exe_after_test="true"
+ make BIN="$1" >> "$compilation_log"
+ else
+ remove_exe_after_test=""
+ fi
+
+ echo "running $1"
+ if [ -z "$chorus" ]; then
+ #### Assumes that the PATH has been set on the target.
+ rsh $target $run_command $1
+ else
+ ./$1
+ fi
+ status=$?
+
+ if [ $status -ne 0 ]; then
+ echo \"$1\" FAILED with exit status $status!!!!
+ fi
+
+ if [ -f core ]; then
+ echo \"$1\" dumped core!!!!
+ fi
+
+ if [ -f log/$1.log ]; then
+ sh ./run_tests.check log/$1.log
+ else
+ echo "No log file (log/$1.log) is present"
+ fi
+
+ if [ "$remove_exe_after_test" ]; then
+ echo 1>&2 "Discarding $1"
+ rm -f "$1" ".obj/$1.o"
+ fi
+}
+
+LynxOS=1
+if [ $sysname = 'LynxOS' ]; then
+ LynxOS=
+fi
+
+Unicos=1
+if [ $sysname = 'unicos' ]; then
+ Unicos=
+fi
+
+ace_version=`head -1 ../VERSION | sed 's/.*version \([0-9.]*\).*/\1/'`
+
+if [ ! "$chorus" ]; then
+ user=${LOGNAME:-`whoami`}
+ start_test_resources=`ipcs | egrep $user`
+fi # ! chorus
+
+ACE_BUILD_COMPONENTS=`$ACE_ROOT/bin/ace_components --ace`
+OTHER=`echo $ACE_BUILD_COMPONENTS | egrep ' Other '`
+TOKEN=`echo $ACE_BUILD_COMPONENTS | egrep ' Token '`
+
+libDLL_Test=
+if [ -f libDLL_Test$shlib_suffix ]; then
+ libDLL_Test=1
+fi
+
+netsvcs_main=
+if [ -f ../netsvcs/servers/main ]; then
+ netsvcs_main=1
+fi
+
+# Testing for this flag always disables the test
+DISABLED=
+
+echo "Starting ACE version $ace_version tests . . ."
+
+mv -f "$compilation_log" "$compilation_log.bak" > /dev/null 2>&1
+
+if [ $sysname != 'procnto' ]; then
+ # Limit the amount of memory required by the tests to 64Mb.
+ ulimit -d 65536
+fi # ! procnto
+
+# Redirection gets confused when rsh is involved (Chorus)
+for i in `cat run_tests_remote.lst | tr "\012" "$IFS"`; do
+
+ if [ "$i" != "" ]; then
+
+ case $i in
+ */*)
+ p=`dirname $i | sed 's%/% \&\& test $%g'`;
+ precond="\$$p";
+ test=`basename $i`;
+ ;;
+ *)
+ precond="";
+ test=$i;
+ ;;
+ esac
+
+# echo =****= $precond ===== $test;
+
+ if test -z "$precond"; then
+ run $test
+ elif eval test $precond; then
+ run $test
+ else
+ if echo $precond | egrep '(DISABLED)|(OTHER)' > /dev/null; then :; else
+ echo Skipping $test on this platform
+ fi
+ fi
+ fi
+done
+
+echo "Finished ACE version $ace_version tests."
+
+$RM -f ace_pipe_name pattern \
+ $tmp/ace_temp_file* \
+ $tmp/ace_test_file \
+ $tmp/Naming_Test*
+
+if [ ! "$chorus" ]; then
+ end_test_resources=`ipcs | egrep $user`
+ if [ "$start_test_resources" != "$end_test_resources" ]; then
+ echo WARNING: the ACE tests _may_ have leaked OS resources!
+ ipcs
+ fi
+fi
+
+# EOF
diff --git a/ACE/tests/test_config.h b/ACE/tests/test_config.h
new file mode 100644
index 00000000000..21ff4cdf67c
--- /dev/null
+++ b/ACE/tests/test_config.h
@@ -0,0 +1,174 @@
+// -*- C++ -*-
+
+// ============================================================================
+/**
+ * @file test_config.h
+ *
+ * $Id$
+ *
+ * This file factors out common macros and other utilities used by the
+ * ACE automated regression tests. It also shows how to redirect ACE_DEBUG/ACE_ERROR
+ * output to a file.
+ *
+ * @author Prashant Jain <pjain@cs.wustl.edu>
+ * @author Tim Harrison <harrison@cs.wustl.edu>
+ * @author David Levine <levine@cs.wustl.edu>
+ */
+// ============================================================================
+
+#ifndef ACE_TEST_CONFIG_H
+#define ACE_TEST_CONFIG_H
+
+// This first #undef protects against command-line definitions.
+#undef ACE_NDEBUG
+
+#include "ace/config-all.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+#if defined (ACE_NLOGGING)
+// ACE_NLOGGING must not be set if the tests are to produce any output.
+#undef ACE_NLOGGING
+#endif /* ACE_NLOGGING */
+
+#include "ace/OS_NS_errno.h"
+#include "ace/OS_NS_stdio.h"
+#include "ace/Log_Msg.h"
+
+#if defined (ACE_HAS_WINCE)
+// Note that Pocket PC 2002 will NOT create a directory if it does not start with a leading '\'.
+// PPC 2002 only accepts '\log' as a valid directory name, while 'log\' works under WinCE 3.0.
+# define ACE_LOG_DIRECTORY_FOR_MKDIR ACE_TEXT ("\\log")
+# define ACE_LOG_DIRECTORY ACE_TEXT ("\\log\\")
+# define MAKE_PIPE_NAME(X) ACE_TEXT ("\\\\.\\pipe\\"#X)
+#elif defined (ACE_WIN32)
+# define ACE_LOG_DIRECTORY ACE_TEXT ("log\\")
+# define MAKE_PIPE_NAME(X) ACE_TEXT ("\\\\.\\pipe\\"#X)
+#else
+# define ACE_LOG_DIRECTORY ACE_TEXT ("log/")
+# define MAKE_PIPE_NAME(X) ACE_TEXT (X)
+#endif /* ACE_WIN32 */
+
+#if defined (ACE_HAS_WINCE)
+#define ACE_LOG_FILE_EXT_NAME ACE_TEXT (".txt")
+#else
+#define ACE_LOG_FILE_EXT_NAME ACE_TEXT (".log")
+#endif /* ACE_HAS_WINCE */
+
+#if defined (ACE_HAS_WINCE) || defined (ACE_HAS_PHARLAP)
+const size_t ACE_MAX_CLIENTS = 4;
+#else
+const size_t ACE_MAX_CLIENTS = 30;
+#endif /* ACE_HAS_WINCE */
+
+const size_t ACE_NS_MAX_ENTRIES = 1000;
+const size_t ACE_DEFAULT_USECS = 1000;
+const size_t ACE_MAX_TIMERS = 4;
+const size_t ACE_MAX_DELAY = 10;
+const size_t ACE_MAX_INTERVAL = 0;
+const size_t ACE_MAX_ITERATIONS = 10;
+const size_t ACE_MAX_PROCESSES = 10;
+const size_t ACE_MAX_THREADS = 4;
+
+#define ACE_START_TEST(NAME) \
+ const ACE_TCHAR *program = NAME; \
+ ACE_LOG_MSG->open (program, ACE_Log_Msg::OSTREAM | ACE_Log_Msg::VERBOSE_LITE); \
+ if (ace_file_stream::instance()->set_output (program) != 0) \
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("set_output failed")), -1); \
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) Starting %s test at %D\n"), program))
+
+#define ACE_END_TEST \
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) Ending %s test at %D\n"), program)); \
+ ace_file_stream::instance()->close ()
+
+#define ACE_CLOSE_TEST_LOG ace_file_stream::instance()->close ()
+
+#define ACE_APPEND_LOG(NAME) \
+ const ACE_TCHAR *program = NAME; \
+ ACE_LOG_MSG->open (program, ACE_Log_Msg::OSTREAM | ACE_Log_Msg::VERBOSE_LITE); \
+ if (ace_file_stream::instance()->set_output (program, 1) != 0) \
+ ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("set_output failed")), -1); \
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) Starting %s test at %D\n"), program));
+
+#define ACE_END_LOG \
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) Ending %s test at %D\n\n"), program)); \
+ ACE_LOG_MSG->set_flags(ACE_Log_Msg::SILENT); \
+ ace_file_stream::instance()->close ();
+
+#if defined (VXWORKS)
+ // This is the only way I could figure out to avoid an error
+ // about attempting to unlink a non-existant file.
+
+#include "ace/OS_NS_fcntl.h"
+
+#define ACE_INIT_LOG(NAME) \
+ ACE_TCHAR temp[MAXPATHLEN]; \
+ ACE_OS::sprintf (temp, ACE_TEXT ("%s%s%s"), \
+ ACE_LOG_DIRECTORY, \
+ ACE::basename (NAME, ACE_DIRECTORY_SEPARATOR_CHAR), \
+ ACE_LOG_FILE_EXT_NAME); \
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) Deleting old log file %s (if any)\n\n"), temp)); \
+ int fd_init_log; \
+ if ((fd_init_log = ACE_OS::open (temp, \
+ O_WRONLY|O_CREAT, \
+ S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) != ERROR) \
+ { \
+ ACE_OS::close (fd_init_log); \
+ ACE_OS::unlink (temp); \
+ }
+
+#if defined (ghs)
+# // Rename main to ace_main for compatibility with run_tests.vxworks.
+# undef ACE_MAIN
+# define ACE_MAIN ace_main
+#endif /* ghs */
+#else /* ! VXWORKS */
+# if !defined (ACE_WIN32) && defined (ACE_USES_WCHAR)
+# define ACE_INIT_LOG_FMT ACE_TEXT ("%ls%ls%ls")
+# else
+# define ACE_INIT_LOG_FMT ACE_TEXT ("%s%s%s")
+# endif /* !ACE_WIN32 && ACE_USES_WCHAR */
+#define ACE_INIT_LOG(NAME) \
+ ACE_TCHAR temp[MAXPATHLEN]; \
+ ACE_OS::sprintf (temp, ACE_INIT_LOG_FMT, \
+ ACE_LOG_DIRECTORY, \
+ ACE::basename (NAME, ACE_DIRECTORY_SEPARATOR_CHAR), \
+ ACE_LOG_FILE_EXT_NAME); \
+ ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) Deleting old log file %s (if any)\n\n"), temp)); \
+ ACE_OS::unlink (temp);
+#endif /* ! VXWORKS */
+
+#if defined (ACE_LACKS_IOSTREAM_TOTALLY)
+#define OFSTREAM FILE
+#else
+#define OFSTREAM ofstream
+#endif /* ACE_LACKS_IOSTREAM_TOTALLY */
+
+#include "tests/Test_Output_Export.h"
+
+class Test_Output_Export ACE_Test_Output
+{
+public:
+ ACE_Test_Output (void);
+ ~ACE_Test_Output (void);
+ static ACE_Test_Output *instance (void);
+ int set_output (const ACE_TCHAR *filename, int append = 0);
+ OFSTREAM *output_file (void);
+ void close (void);
+ const ACE_TCHAR *dll_name (void);
+ const ACE_TCHAR *name (void);
+ static void close_singleton (void);
+
+private:
+ static ACE_Test_Output *instance_;
+
+ OFSTREAM *output_file_;
+};
+
+typedef ACE_Test_Output ace_file_stream;
+
+Test_Output_Export void randomize (int array[], size_t size);
+
+#endif /* ACE_TEST_CONFIG_H */
diff --git a/ACE/tests/tests.mpc b/ACE/tests/tests.mpc
new file mode 100644
index 00000000000..ceb8d3ca78c
--- /dev/null
+++ b/ACE/tests/tests.mpc
@@ -0,0 +1,1358 @@
+// -*- MPC -*-
+// $Id$
+
+project(Test_Output) : acelib, script {
+ sharedname = Test_Output
+ dynamicflags = TEST_OUTPUT_BUILD_DLL
+ Source_Files {
+ Test_Output.cpp
+ }
+ Header_Files {
+ Test_Output_Export.h
+ test_config.h
+ }
+ Resource_Files {
+ }
+ Script_Files {
+ run_test.pl
+ run_test.lst
+ }
+
+ verbatim(automake,local) {
+dist_check_SCRIPTS = run_test.pl run_test.lst
+TESTS = $(noinst_PROGRAMS)
+TESTS_ENVIRONMENT = $(srcdir)/run_test.pl -t
+ }
+}
+
+project(Framework Component DLL) : acelib {
+ sharedname = Framework_Component_DLL
+ dynamicflags = FRAMEWORK_COMPONENT_DLL_BUILD_DLL
+
+ Source_Files {
+ Framework_Component_DLL.cpp
+ }
+ Header_Files {
+ Framework_Component_DLL.h
+ Framework_Component_DLL_Export.h
+ }
+ Resource_Files {
+ }
+}
+
+
+project(DLL Test Parent Lib) : acelib {
+ sharedname = DLL_Test_Parent
+ dynamicflags = DLL_TEST_PARENT_BUILD_DLL
+
+ Source_Files {
+ DLL_Test_Parent.cpp
+ }
+ Header_Files {
+ DLL_Test_Parent_Export.h
+ test_config.h
+ }
+ Resource_Files {
+ }
+}
+
+project(DLL Test Lib) : acelib, dll_test_parent_lib {
+ sharedname = DLL_Test_Lib
+ dynamicflags = ACE_SVC_BUILD_DLL
+
+ Source_Files {
+ DLL_Test_Impl.cpp
+ }
+ Header_Files {
+ test_config.h
+ }
+ Resource_Files {
+ }
+}
+
+project(Based Pointer Test Lib) : acelib {
+ avoids += ace_for_tao
+ sharedname = Based_Pointer_Test_Lib
+ dynamicflags = ACE_SVC_BUILD_DLL
+
+ Source_Files {
+ Based_Pointer_Test_Lib.cpp
+ }
+ Resource_Files {
+ }
+}
+
+project(Service Config DLL) : acelib {
+ sharedname = Service_Config_DLL
+ dynamicflags = SERVICE_CONFIG_DLL_BUILD_DLL
+
+ Source_Files {
+ Service_Config_DLL.cpp
+ }
+ Header_Files {
+ Service_Config_DLL.h
+ Service_Config_DLL_Export.h
+ }
+ Resource_Files {
+ }
+}
+
+project(ACE Init Test) : acetest {
+ exename = ACE_Init_Test
+ Source_Files {
+ ACE_Init_Test.cpp
+ }
+ Resource_Files {
+ ACE_Init_Test.rc
+ }
+}
+
+project(ACE Test) : acetest {
+ exename = ACE_Test
+ Source_Files {
+ ACE_Test.cpp
+ }
+}
+
+project(Aio Platform Test) : acetest {
+ exename = Aio_Platform_Test
+ Source_Files {
+ Aio_Platform_Test.cpp
+ }
+}
+
+project(Arg Shifter Test) : acetest {
+ exename = Arg_Shifter_Test
+ Source_Files {
+ Arg_Shifter_Test.cpp
+ }
+}
+
+project(Array Map Test) : acetest {
+ exename = Array_Map_Test
+ Source_Files {
+ Array_Map_Test.cpp
+ }
+}
+
+project(ARGV Test) : acetest {
+ exename = ARGV_Test
+ Source_Files {
+ ARGV_Test.cpp
+ }
+}
+
+project(Atomic Op Test) : acetest {
+ exename = Atomic_Op_Test
+ Source_Files {
+ Atomic_Op_Test.cpp
+ }
+}
+
+project(Auto Event Test) : acetest {
+ exename = Auto_Event_Test
+ Source_Files {
+ Auto_Event_Test.cpp
+ }
+}
+
+project(Auto IncDec Test) : acetest {
+ exename = Auto_IncDec_Test
+ Source_Files {
+ Auto_IncDec_Test.cpp
+ }
+}
+
+project(Barrier Test) : acetest {
+ exename = Barrier_Test
+ Source_Files {
+ Barrier_Test.cpp
+ }
+}
+
+project(Basic Types Test) : acetest {
+ exename = Basic_Types_Test
+ Source_Files {
+ Basic_Types_Test.cpp
+ }
+}
+
+project(Bound Ptr Test) : acetest {
+ avoids += ace_for_tao
+ exename = Bound_Ptr_Test
+ Source_Files {
+ Bound_Ptr_Test.cpp
+ }
+}
+
+project(Buffer Stream Test) : acetest {
+ exename = Buffer_Stream_Test
+ Source_Files {
+ Buffer_Stream_Test.cpp
+ }
+}
+
+project(Bug_1576_Regression_Test) : acetest {
+ exename = Bug_1576_Regression_Test
+ Source_Files {
+ Bug_1576_Regression_Test.cpp
+ }
+}
+
+project(Bug_1890_Regression_Test) : acetest {
+ exename = Bug_1890_Regression_Test
+ Source_Files {
+ Bug_1890_Regression_Test.cpp
+ }
+}
+
+project(Bug_2368_Regression_Test) : acetest {
+ exename = Bug_2368_Regression_Test
+ Source_Files {
+ Bug_2368_Regression_Test.cpp
+ }
+}
+
+project(Bug_2497_Regression_Test) : acetest {
+ exename = Bug_2497_Regression_Test
+ Source_Files {
+ Bug_2497_Regression_Test.cpp
+ }
+}
+
+project(Bug_2540_Regression_Test) : acetest {
+ exename = Bug_2540_Regression_Test
+ Source_Files {
+ Bug_2540_Regression_Test.cpp
+ }
+}
+
+project(Cache Map Manager Test) : acetest {
+ exename = Cache_Map_Manager_Test
+ Source_Files {
+ Cache_Map_Manager_Test.cpp
+ }
+}
+
+project(Memcpy_Test) : acetest {
+ avoids += ace_for_tao
+ exename = Memcpy_Test
+ Source_Files {
+ Memcpy_Test.cpp
+ }
+}
+
+project(Cached Accept Conn Test) : acetest {
+ avoids += ace_for_tao
+ exename = Cached_Accept_Conn_Test
+ Source_Files {
+ Cached_Accept_Conn_Test.cpp
+ }
+}
+
+project(Cached Allocator Test) : acetest {
+ avoids += ace_for_tao
+ exename = Cached_Allocator_Test
+ Source_Files {
+ Cached_Allocator_Test.cpp
+ }
+}
+
+project(Cached Conn Test) : acetest {
+ avoids += ace_for_tao
+ exename = Cached_Conn_Test
+ Source_Files {
+ Cached_Conn_Test.cpp
+ }
+}
+
+project(Capabilities Test) : acetest {
+ avoids += ace_for_tao
+ exename = Capabilities_Test
+ Source_Files {
+ Capabilities_Test.cpp
+ }
+}
+
+project(CDR File Test) : acetest {
+ avoids += ace_for_tao
+ exename = CDR_File_Test
+ Source_Files {
+ CDR_File_Test.cpp
+ CE_fostream.cpp
+ }
+}
+
+project(CDR Test) : acetest {
+ exename = CDR_Test
+ Source_Files {
+ CDR_Test.cpp
+ }
+}
+
+project(Collection Test) : acetest {
+ exename = Collection_Test
+ Source_Files {
+ Collection_Test.cpp
+ }
+}
+
+project(Config Test) : acetest {
+ avoids += ace_for_tao
+ exename = Config_Test
+ Source_Files {
+ Config_Test.cpp
+ }
+ Documentation_Files {
+ Config_Test.ini
+ Config_Test_Import_1.ini
+ }
+}
+
+project(Conn Test) : acetest {
+ avoids += ace_for_tao
+ exename = Conn_Test
+ Source_Files {
+ Conn_Test.cpp
+ }
+}
+
+project(Date Time Test) : acetest {
+ avoids += ace_for_tao
+ exename = Date_Time_Test
+ Source_Files {
+ Date_Time_Test.cpp
+ }
+}
+
+project(Dev Poll Reactor Test) : acetest {
+ exename = Dev_Poll_Reactor_Test
+ Source_Files {
+ Dev_Poll_Reactor_Test.cpp
+ }
+}
+
+project(Dirent Test) : acetest {
+
+ exename = Dirent_Test
+ Source_Files {
+ Dirent_Test.cpp
+ }
+}
+
+project(DLList Test) : acetest {
+ avoids += ace_for_tao
+ exename = DLList_Test
+ Source_Files {
+ DLList_Test.cpp
+ }
+}
+
+project(DLL Test) : acetest, dll_test_parent_lib {
+ after += DLL_Test_Lib
+ libs += DLL_Test_Lib
+ exename = DLL_Test
+ Source_Files {
+ DLL_Test.cpp
+ }
+}
+
+project(Enum Interfaces Test) : acetest {
+ exename = Enum_Interfaces_Test
+ Source_Files {
+ Enum_Interfaces_Test.cpp
+ }
+}
+
+project(Env Value Test) : acetest {
+ exename = Env_Value_Test
+ Source_Files {
+ Env_Value_Test.cpp
+ }
+}
+
+project(Future Test) : acetest {
+ avoids += ace_for_tao
+ exename = Future_Test
+ Source_Files {
+ Future_Test.cpp
+ }
+}
+
+project(Future Set Test) : acetest {
+ avoids += ace_for_tao
+ exename = Future_Set_Test
+ Source_Files {
+ Future_Set_Test.cpp
+ }
+}
+
+project(Get Opt Test) : acetest {
+ exename = Get_Opt_Test
+ Source_Files {
+ Get_Opt_Test.cpp
+ }
+}
+
+project(Handle Set Test) : acetest {
+ avoids += ace_for_tao
+ exename = Handle_Set_Test
+ Source_Files {
+ Handle_Set_Test.cpp
+ }
+}
+
+project(High Res Timer Test) : acetest {
+ avoids += ace_for_tao
+ exename = High_Res_Timer_Test
+ Source_Files {
+ High_Res_Timer_Test.cpp
+ }
+}
+
+project(Hash Map Manager Test) : acetest {
+ exename = Hash_Map_Manager_Test
+ Source_Files {
+ Hash_Map_Manager_Test.cpp
+ }
+}
+
+project(Hash Map Bucket Iterator Test) : acetest {
+ exename = Hash_Map_Bucket_Iterator_Test
+ Source_Files {
+ Hash_Map_Bucket_Iterator_Test.cpp
+ }
+}
+
+project(INET Addr Test) : acetest {
+ exename = INET_Addr_Test
+ Source_Files {
+ INET_Addr_Test.cpp
+ }
+}
+
+project(IOStream Test) : acetest {
+ exename = IOStream_Test
+ Source_Files {
+ IOStream_Test.cpp
+ }
+}
+
+project(Lazy Map Manager Test) : acetest {
+ exename = Lazy_Map_Manager_Test
+ Source_Files {
+ Lazy_Map_Manager_Test.cpp
+ }
+}
+
+project(Log Msg Test) : acetest {
+ avoids += ace_for_tao
+ exename = Log_Msg_Test
+ Source_Files {
+ Log_Msg_Test.cpp
+ }
+}
+
+project(Logging Strategy Test) : acetest {
+ exename = Logging_Strategy_Test
+ Source_Files {
+ Logging_Strategy_Test.cpp
+ }
+}
+
+project(Malloc Test) : acetest {
+ avoids += ace_for_tao
+ exename = Malloc_Test
+ Source_Files {
+ Malloc_Test.cpp
+ }
+}
+
+project(Manual_Event Test) : acetest {
+ exename = Manual_Event_Test
+ Source_Files {
+ Manual_Event_Test.cpp
+ }
+}
+
+project(Map Test) : acetest {
+ avoids += ace_for_tao
+ exename = Map_Test
+ Source_Files {
+ Map_Test.cpp
+ }
+}
+
+project(Map Manager Test) : acetest {
+ avoids += ace_for_tao
+ exename = Map_Manager_Test
+ Source_Files {
+ Map_Manager_Test.cpp
+ }
+}
+
+project(Max Default Port Test) : acetest {
+ exename = Max_Default_Port_Test
+ Source_Files {
+ Max_Default_Port_Test.cpp
+ }
+}
+
+project(MEM Stream Test) : acetest {
+ avoids += ace_for_tao
+ exename = MEM_Stream_Test
+ Source_Files {
+ MEM_Stream_Test.cpp
+ }
+}
+
+project(Mem Map Test) : acetest {
+ avoids += ace_for_tao
+ exename = Mem_Map_Test
+ Source_Files {
+ Mem_Map_Test.cpp
+ }
+}
+
+project(MM Shared Memory Test) : acetest {
+ avoids += ace_for_tao
+ exename = MM_Shared_Memory_Test
+ Source_Files {
+ MM_Shared_Memory_Test.cpp
+ }
+}
+
+project(MT Reactor Timer Test) : acetest {
+ exename = MT_Reactor_Timer_Test
+ Source_Files {
+ MT_Reactor_Timer_Test.cpp
+ }
+}
+
+project(MT Reactor Upcall Test) : acetest {
+ exename = MT_Reactor_Upcall_Test
+ Source_Files {
+ MT_Reactor_Upcall_Test.cpp
+ }
+}
+
+project(MT SOCK Test) : acetest {
+ exename = MT_SOCK_Test
+ Source_Files {
+ MT_SOCK_Test.cpp
+ }
+}
+
+project(Message Block Test) : acetest {
+ avoids += ace_for_tao
+ exename = Message_Block_Test
+ Source_Files {
+ Message_Block_Test.cpp
+ }
+}
+
+project(Message Queue Test) : acetest {
+ avoids += ace_for_tao
+ exename = Message_Queue_Test
+ Source_Files {
+ Message_Queue_Test.cpp
+ }
+}
+
+project(Message Queue Test Ex) : acetest {
+ avoids += ace_for_tao
+ exename = Message_Queue_Test_Ex
+ Source_Files {
+ Message_Queue_Test_Ex.cpp
+ }
+}
+
+project(Message Queue Notifications Test) : acetest {
+ exename = Message_Queue_Notifications_Test
+ Source_Files {
+ Message_Queue_Notifications_Test.cpp
+ }
+}
+
+project(Multicast Test) : acetest {
+ exename = Multicast_Test
+ Source_Files {
+ Multicast_Test.cpp
+ }
+}
+
+project(Multihomed INET Addr Test) : acetest {
+ avoids += ace_for_tao
+ exename = Multihomed_INET_Addr_Test
+ Source_Files {
+ Multihomed_INET_Addr_Test.cpp
+ }
+}
+
+project(Network_Adapters_Test) : acetest {
+ exename = Network_Adapters_Test
+ Source_Files {
+ Network_Adapters_Test.cpp
+ }
+}
+
+project(New Fail Test) : acetest {
+ exename = New_Fail_Test
+ Source_Files {
+ New_Fail_Test.cpp
+ }
+}
+
+project(Notify Performance Test) : acetest {
+ avoids += ace_for_tao
+ exename = Notify_Performance_Test
+ Source_Files {
+ Notify_Performance_Test.cpp
+ }
+}
+
+project(Object Manager Test) : acetest {
+ exename = Object_Manager_Test
+ Source_Files {
+ Object_Manager_Test.cpp
+ }
+}
+
+project(Obstack Test) : acetest {
+ exename = Obstack_Test
+ Source_Files {
+ Obstack_Test.cpp
+ }
+}
+
+project(OrdMultiSet Test) : acetest {
+ exename = OrdMultiSet_Test
+ Source_Files {
+ OrdMultiSet_Test.cpp
+ }
+}
+
+project(OS Test) : acetest {
+ exename = OS_Test
+ Source_Files {
+ OS_Test.cpp
+ }
+}
+
+project(Proactor Scatter Gather Test) : acetest {
+ avoids += ace_for_tao
+ exename = Proactor_Scatter_Gather_Test
+ Source_Files {
+ Proactor_Scatter_Gather_Test.cpp
+ }
+}
+
+project(Proactor Test) : acetest {
+ avoids += ace_for_tao
+ exename = Proactor_Test
+ Source_Files {
+ Proactor_Test.cpp
+ }
+}
+
+project(Proactor Timer Test) : acetest {
+ avoids += ace_for_tao
+ exename = Proactor_Timer_Test
+ Source_Files {
+ Proactor_Timer_Test.cpp
+ }
+}
+
+project(Process Manual Event Test) : acetest {
+ exename = Process_Manual_Event_Test
+ Source_Files {
+ Process_Manual_Event_Test.cpp
+ }
+}
+
+project(Process Mutex Test) : acetest {
+ avoids += ace_for_tao
+ exename = Process_Mutex_Test
+ Source_Files {
+ Process_Mutex_Test.cpp
+ }
+}
+
+project(Process Semaphore Test) : acetest {
+ avoids += ace_for_tao
+ exename = Process_Semaphore_Test
+ Source_Files {
+ Process_Semaphore_Test.cpp
+ }
+}
+
+project(Process Strategy Test) : acetest {
+ avoids += ace_for_tao // Requires ace/File_Lock
+ exename = Process_Strategy_Test
+ Source_Files {
+ Process_Strategy_Test.cpp
+ }
+}
+
+project(Priority Buffer Test) : acetest {
+ exename = Priority_Buffer_Test
+ Source_Files {
+ Priority_Buffer_Test.cpp
+ }
+}
+
+project(Dynamic Priority Test) : acetest {
+ exename = Dynamic_Priority_Test
+ Source_Files {
+ Dynamic_Priority_Test.cpp
+ }
+}
+
+project(Priority Task Test) : acetest {
+ exename = Priority_Task_Test
+ Source_Files {
+ Priority_Task_Test.cpp
+ }
+}
+
+project(Priority Reactor Test) : acetest {
+ avoids += ace_for_tao
+ exename = Priority_Reactor_Test
+ Source_Files {
+ Priority_Reactor_Test.cpp
+ }
+}
+
+project(Process Manager Test) : acetest {
+ avoids += ace_for_tao
+ exename = Process_Manager_Test
+ Source_Files {
+ Process_Manager_Test.cpp
+ }
+}
+
+project(Pipe Test) : acetest {
+ exename = Pipe_Test
+ Source_Files {
+ Pipe_Test.cpp
+ }
+}
+
+project(RB Tree Test) : acetest {
+ exename = RB_Tree_Test
+ Source_Files {
+ RB_Tree_Test.cpp
+ }
+}
+
+project(Reactors Test) : acetest {
+ exename = Reactors_Test
+ Source_Files {
+ Reactors_Test.cpp
+ }
+}
+
+project(Reactor Exceptions Test) : acetest {
+ exename = Reactor_Exceptions_Test
+ Source_Files {
+ Reactor_Exceptions_Test.cpp
+ }
+}
+
+project(Reactor Notify Test) : acetest {
+ avoids += ace_for_tao
+ exename = Reactor_Notify_Test
+ Source_Files {
+ Reactor_Notify_Test.cpp
+ }
+}
+
+project(Reactor Notification Queue Test) : acetest {
+ exename = Reactor_Notification_Queue_Test
+ Source_Files {
+ Reactor_Notification_Queue_Test.cpp
+ }
+}
+
+project(Reactor Dispatch Order Test) : acetest {
+ exename = Reactor_Dispatch_Order_Test
+ Source_Files {
+ Reactor_Dispatch_Order_Test.cpp
+ }
+}
+
+project(Reactor Performance Test) : acetest {
+ avoids += ace_for_tao
+ exename = Reactor_Performance_Test
+ Source_Files {
+ Reactor_Performance_Test.cpp
+ }
+}
+
+project(Reactor Timer Test) : acetest {
+ avoids += ace_for_tao
+ exename = Reactor_Timer_Test
+ Source_Files {
+ Reactor_Timer_Test.cpp
+ }
+}
+
+project(Reader Writer Test) : acetest {
+ exename = Reader_Writer_Test
+ Source_Files {
+ Reader_Writer_Test.cpp
+ }
+}
+
+project(Recursive Condition Bug Test) : acetest {
+ exename = Recursive_Condition_Bug_Test
+ Source_Files {
+ Recursive_Condition_Bug_Test.cpp
+ }
+}
+
+project(Recursive Condition Test) : acetest {
+ exename = Recursive_Condition_Test
+ Source_Files {
+ Recursive_Condition_Test.cpp
+ }
+}
+
+project(Recursive Mutex Test) : acetest {
+ exename = Recursive_Mutex_Test
+ Source_Files {
+ Recursive_Mutex_Test.cpp
+ }
+}
+
+project(Refcounted Auto Ptr Test) : acetest {
+ avoids += ace_for_tao
+ exename = Refcounted_Auto_Ptr_Test
+ Source_Files {
+ Refcounted_Auto_Ptr_Test.cpp
+ }
+}
+
+project(Reverse Lock Test) : acetest {
+ exename = Reverse_Lock_Test
+ Source_Files {
+ Reverse_Lock_Test.cpp
+ }
+}
+
+project(Semaphore Test) : acetest {
+ avoids += ace_for_tao
+ exename = Semaphore_Test
+ Source_Files {
+ Semaphore_Test.cpp
+ }
+}
+
+project(Sendfile Test) : acetest {
+ exename = Sendfile_Test
+ Source_Files {
+ Sendfile_Test.cpp
+ }
+}
+
+project(Signal Test) : acetest {
+ exename = Signal_Test
+ Source_Files {
+ Signal_Test.cpp
+ }
+}
+
+project(Sigset Ops Test) : acetest {
+ exename = Sigset_Ops_Test
+ Source_Files {
+ Sigset_Ops_Test.cpp
+ }
+}
+
+project(Simple Message Block Test) : acetest {
+ exename = Simple_Message_Block_Test
+ Source_Files {
+ Simple_Message_Block_Test.cpp
+ }
+}
+
+project(SOCK Test) : acetest {
+ exename = SOCK_Test
+ Source_Files {
+ SOCK_Test.cpp
+ }
+}
+
+project(SOCK Dgram Test) : acetest {
+ exename = SOCK_Dgram_Test
+ Source_Files {
+ SOCK_Dgram_Test.cpp
+ }
+}
+
+project(SOCK Connector Test) : acetest {
+ exename = SOCK_Connector_Test
+ Source_Files {
+ SOCK_Connector_Test.cpp
+ }
+}
+
+project(SOCK Netlink Test) : acetest {
+ avoids += ace_for_tao
+ exename = SOCK_Netlink_Test
+ Source_Files {
+ SOCK_Netlink_Test.cpp
+ }
+}
+
+project(SOCK Send Recv Test) : acetest {
+ exename = SOCK_Send_Recv_Test
+ Source_Files {
+ SOCK_Send_Recv_Test.cpp
+ }
+}
+
+project(SPIPE Test) : acetest {
+ avoids += ace_for_tao
+ exename = SPIPE_Test
+ Source_Files {
+ SPIPE_Test.cpp
+ }
+}
+
+project(SString Test) : acetest {
+ exename = SString_Test
+ Source_Files {
+ SString_Test.cpp
+ }
+}
+
+project(SV Shared Memory Test) : acetest {
+ avoids += ace_for_tao
+ exename = SV_Shared_Memory_Test
+ Source_Files {
+ SV_Shared_Memory_Test.cpp
+ }
+}
+
+project(Svc Handler Test) : acetest {
+ avoids += ace_for_tao
+ exename = Svc_Handler_Test
+ Source_Files {
+ Svc_Handler_Test.cpp
+ }
+}
+
+project(Task Test) : acetest {
+ exename = Task_Test
+ Source_Files {
+ Task_Test.cpp
+ }
+}
+
+project(Task_Ex Test) : acetest {
+ exename = Task_Ex_Test
+ Source_Files {
+ Task_Ex_Test.cpp
+ }
+}
+
+project(Thread Manager Test) : acetest {
+ exename = Thread_Manager_Test
+ Source_Files {
+ Thread_Manager_Test.cpp
+ }
+}
+
+project(Thread Mutex Test) : acetest {
+ exename = Thread_Mutex_Test
+ Source_Files {
+ Thread_Mutex_Test.cpp
+ }
+}
+
+project(Thread Pool Test) : acetest {
+ exename = Thread_Pool_Test
+ Source_Files {
+ Thread_Pool_Test.cpp
+ }
+}
+
+project(Timeprobe Test) : acetest {
+ exename = Timeprobe_Test
+ Source_Files {
+ Timeprobe_Test.cpp
+ }
+}
+
+project(Time Service Test) : acetest {
+ exename = Time_Service_Test
+ Source_Files {
+ Time_Service_Test.cpp
+ }
+}
+
+project(Time Value Test) : acetest {
+ exename = Time_Value_Test
+ Source_Files {
+ Time_Value_Test.cpp
+ }
+}
+
+project(Timer Queue Test) : acetest {
+ avoids += ace_for_tao
+ exename = Timer_Queue_Test
+ Source_Files {
+ Timer_Queue_Test.cpp
+ }
+}
+
+project(Token Strategy Test) : acetest {
+ exename = Token_Strategy_Test
+ Source_Files {
+ Token_Strategy_Test.cpp
+ }
+}
+
+project(TP Reactor Test) : acetest {
+ avoids += ace_for_tao
+ exename = TP_Reactor_Test
+ Source_Files {
+ TP_Reactor_Test.cpp
+ }
+}
+
+project(TSS Test) : acetest {
+ exename = TSS_Test
+ Source_Files {
+ TSS_Test.cpp
+ }
+}
+
+project(TSS Static Test) : acetest {
+ exename = TSS_Static_Test
+ Source_Files {
+ TSS_Static_Test.cpp
+ }
+}
+
+project(Vector Test) : acetest {
+ exename = Vector_Test
+ Source_Files {
+ Vector_Test.cpp
+ }
+}
+
+project(UPIPE SAP Test) : acetest {
+ avoids += ace_for_tao
+ exename = UPIPE_SAP_Test
+ Source_Files {
+ UPIPE_SAP_Test.cpp
+ }
+}
+
+project(Upgradable RW Test) : acetest {
+ avoids += ace_for_tao
+ exename = Upgradable_RW_Test
+ Source_Files {
+ Upgradable_RW_Test.cpp
+ }
+}
+
+project(Naming Test) : acetest {
+ avoids += ace_for_tao
+ exename = Naming_Test
+ requires += ace_other
+
+ Source_Files {
+ Naming_Test.cpp
+ }
+}
+
+project(Thread Pool Reactor Test) : acetest {
+ exename = Thread_Pool_Reactor_Test
+ requires += ace_other
+
+ Source_Files {
+ Thread_Pool_Reactor_Test.cpp
+ }
+}
+
+project(Thread Pool Reactor Resume Test) : acetest {
+ exename = Thread_Pool_Reactor_Resume_Test
+ requires += ace_other
+
+ Source_Files {
+ Thread_Pool_Reactor_Resume_Test.cpp
+ }
+}
+
+project(XtMotifReactor Test) : acetest, ace_xtreactor, ace_motif {
+ exename = XtMotifReactor_Test
+
+ Source_Files {
+ XtMotifReactor_Test.cpp
+ }
+}
+
+project(XtAthenaReactor Test) : acetest, ace_xtreactor, ace_athena {
+ exename = XtAthenaReactor_Test
+ Source_Files {
+ XtAthenaReactor_Test.cpp
+ }
+}
+
+project(FlReactor Test) : acetest, ace_flreactor {
+ exename = FlReactor_Test
+
+ Source_Files {
+ FlReactor_Test.cpp
+ }
+}
+
+project(TkReactor Test) : acetest,ace_tkreactor {
+ exename = TkReactor_Test
+
+ Source_Files {
+ TkReactor_Test.cpp
+ }
+}
+
+project(Codecs Test) : acetest {
+ avoids += ace_for_tao
+ exename = Codecs_Test
+ requires += ace_codecs
+
+ Source_Files {
+ Codecs_Test.cpp
+ }
+}
+
+project(Tokens Test) : acetest {
+ exename = Tokens_Test
+ requires += ace_token
+
+ Source_Files {
+ Tokens_Test.cpp
+ }
+}
+
+project(CDR Array Test) : acetest {
+ avoids += ace_for_tao
+ exename = CDR_Array_Test
+ Source_Files {
+ CDR_Array_Test.cpp
+ }
+}
+
+project(Service Config Test) : acetest {
+ after += Service_Config_DLL
+ exename = Service_Config_Test
+ Source_Files {
+ Service_Config_Test.cpp
+ }
+}
+
+project(Framework Component Test) : acetest {
+ after += Framework_Component_DLL
+ exename = Framework_Component_Test
+ Source_Files {
+ Framework_Component_Test.cpp
+ }
+}
+
+project(FIFO Test) : acetest {
+ avoids += ace_for_tao
+ exename = FIFO_Test
+ Source_Files {
+ FIFO_Test.cpp
+ }
+ Header_Files {
+ }
+}
+
+project(WFMO Reactor Test) : acetest {
+ exename = WFMO_Reactor_Test
+ Source_Files {
+ WFMO_Reactor_Test.cpp
+ }
+ Header_Files {
+ }
+}
+
+project(NonBlocking Conn Test) : acetest {
+ exename = NonBlocking_Conn_Test
+ Source_Files {
+ NonBlocking_Conn_Test.cpp
+ }
+ Header_Files {
+ }
+}
+
+project(Reference Counted Event Handler Test) : acetest {
+ exename = Reference_Counted_Event_Handler_Test
+ Source_Files {
+ Reference_Counted_Event_Handler_Test.cpp
+ }
+ Header_Files {
+ }
+}
+
+project(MT Ref Counted Event Handler Test) : acetest {
+ exename = MT_Reference_Counted_Event_Handler_Test
+ Source_Files {
+ MT_Reference_Counted_Event_Handler_Test.cpp
+ }
+ Header_Files {
+ }
+}
+
+project(MT Reference Counted Notify Test) : acetest {
+ exename = MT_Reference_Counted_Notify_Test
+ Source_Files {
+ MT_Reference_Counted_Notify_Test.cpp
+ }
+ Header_Files {
+ }
+}
+
+project(Timer Cancellation Test) : acetest {
+ exename = Timer_Cancellation_Test
+ Source_Files {
+ Timer_Cancellation_Test.cpp
+ }
+ Header_Files {
+ }
+}
+
+project(Timer Queue Reference Counting Test) : acetest {
+ exename = Timer_Queue_Reference_Counting_Test
+ Source_Files {
+ Timer_Queue_Reference_Counting_Test.cpp
+ }
+ Header_Files {
+ }
+}
+
+project(Reactor Registration Test) : acetest {
+ exename = Reactor_Registration_Test
+ Source_Files {
+ Reactor_Registration_Test.cpp
+ }
+ Header_Files {
+ }
+}
+
+project(UUIDTest) : acetest {
+ avoids += ace_for_tao
+ exename = UUIDTest
+ requires += ace_uuid
+ Source_Files {
+ UUIDTest.cpp
+ }
+}
+
+project(Unbounded Set Test) : acetest {
+ exename = Unbounded_Set_Test
+ Source_Files {
+ Unbounded_Set_Test.cpp
+ }
+}
+
+project(INET Addr Test IPV6) : acetest {
+ exename = INET_Addr_Test_IPV6
+ Source_Files {
+ INET_Addr_Test_IPV6.cpp
+ }
+}
+
+project(Max Default Port Test IPV6) : acetest {
+ exename = Max_Default_Port_Test_IPV6
+ Source_Files {
+ Max_Default_Port_Test_IPV6.cpp
+ }
+}
+
+project(Multicast Test IPV6) : acetest {
+ exename = Multicast_Test_IPV6
+ Source_Files {
+ Multicast_Test_IPV6.cpp
+ }
+}
+
+project(Multihomed INET Addr Test IPV6) : acetest {
+ avoids += ace_for_tao
+ exename = Multihomed_INET_Addr_Test_IPV6
+ Source_Files {
+ Multihomed_INET_Addr_Test_IPV6.cpp
+ }
+}
+
+project(Proactor Test IPV6) : acetest {
+ avoids += ace_for_tao
+ exename = Proactor_Test_IPV6
+ Source_Files {
+ Proactor_Test_IPV6.cpp
+ }
+}
+
+project(SOCK Send Recv Test IPV6) : acetest {
+ exename = SOCK_Send_Recv_Test_IPV6
+ Source_Files {
+ SOCK_Send_Recv_Test_IPV6.cpp
+ }
+}
+
+project(SOCK Test IPv6) : acetest {
+ exename = SOCK_Test_IPv6
+ Source_Files {
+ SOCK_Test_IPv6.cpp
+ }
+}
+
+project(SOCK_Dgram_Bcast_Test) : acetest {
+ avoids += ace_for_tao
+ exename = SOCK_Dgram_Bcast_Test
+ Source_Files {
+ SOCK_Dgram_Bcast_Test.cpp
+ }
+}
+
+project(SOCK_SEQPACK_SCTP_Test) : acetest {
+ avoids += ace_for_tao
+ exename = SOCK_SEQPACK_SCTP_Test
+ Source_Files {
+ SOCK_SEQPACK_SCTP_Test.cpp
+ }
+}
+
+project(QtReactor Test) : acetest, ace_qtreactor {
+ exename = QtReactor_Test
+ MOC_Files {
+ QtReactor_Test.h
+ }
+ Source_Files {
+ QtReactor_Test_moc.cpp
+ QtReactor_Test.cpp
+ }
+}
+
+project(Based Pointer Test) : acetest {
+ avoids += ace_for_tao
+ after += Based_Pointer_Test_Lib
+ exename = Based_Pointer_Test
+ Source_Files {
+ Based_Pointer_Test.cpp
+ }
+}
+
+project(Library Unload) {
+ avoids += wince
+ exename = UnloadLibACE
+ staticflags += ACE_AS_STATIC_LIBS
+ Source_Files {
+ Unload_libACE.cpp
+ }
+ Resource_Files {
+ }
+}
diff --git a/ACE/tests/tests.mwc b/ACE/tests/tests.mwc
new file mode 100644
index 00000000000..e3eb1548302
--- /dev/null
+++ b/ACE/tests/tests.mwc
@@ -0,0 +1,9 @@
+// -*- MPC -*-
+// $Id$
+
+workspace {
+ exclude {
+ pharlap
+ log
+ }
+}
diff --git a/ACE/tests/tests_pharlap_msvc.lnk b/ACE/tests/tests_pharlap_msvc.lnk
new file mode 100644
index 00000000000..39af043e409
--- /dev/null
+++ b/ACE/tests/tests_pharlap_msvc.lnk
@@ -0,0 +1,72 @@
+! $Id$
+! Application linker command file for ACE tests.
+
+! Visual C++ Compiler with PC-Compatible Target
+@vc.emb
+
+! PC-Compatible Screen Driver
+!@pcat_sc.emb
+
+! PC-Compatible Keyboard Driver
+!@pcat_kb.emb
+
+! Multithread Support, Debug version
+@vcmtd.emb
+
+! Structured Exception Handling
+@strucexc.emb
+
+! Floating Point Emulator
+!@fpem.emb
+
+! MS-DOS Compatible File System
+!@lfs.emb
+
+! DLL Loader
+!@ldr.emb
+
+! TCP/IP Support
+@winsock.emb
+
+! TCP/IP Driver
+!@eth-smc.emb ! SMC 8003/8216/8416
+!@eth-smc9.emb ! SMC 91C92/91C94
+@eth-3com.emb ! 3Com 3C509
+!@eth-ne2k.emb ! NE2000
+!@eth-dec.emb ! Digital 2114x
+!@ppp16550.emb ! PPP 8250/16450/16550
+!@slp16550.emb ! SLIP/CSLIP 8250/16450/16550
+
+! MicroWeb Server
+!@microweb.emb
+
+! FTP Server
+!@ftpserve.emb
+
+! Event Logging
+!@log.emb
+
+! PC Card Support
+!@pccard.emb
+
+! PC Card Enablers
+!@cs-ser.emb ! Serial Ports
+!@cs-ide.emb ! ATA Disk Drives
+!@cs-3com.emb ! 3Com Ethernet
+!@cs-ne2k.emb ! NE2000 Ethernet
+
+! M-Systems Flash Support
+!@pcfd.emb ! PC-FD
+!@dochip2.emb ! DiskOnChip 2000
+
+! The section below contains the user-specified switches from the
+! Extra Application Link File Switches section of the Extra Linker Switches
+! property sheet.
+!
+
+! 32K stack works well. The 8K default is way too small
+-stack 32767
+
+! Many of the ACE tests are too large to load in the default space without
+! running over the ROM area at some point, so go up.
+-offset 10_0000h