diff --git a/ACE/ace/Asynch_IO.h b/ACE/ace/Asynch_IO.h index 60cc3f172769f..cd150e5cfdb28 100644 --- a/ACE/ace/Asynch_IO.h +++ b/ACE/ace/Asynch_IO.h @@ -380,6 +380,7 @@ class ACE_Export ACE_Asynch_Read_Stream : public ACE_Asynch_Operation /// class. friend class ACE_POSIX_Asynch_Read_Stream_Result; friend class ACE_WIN32_Asynch_Read_Stream_Result; + friend class ACE_Uring_Asynch_Read_Stream_Result; public: /// The number of bytes which were requested at the start of the @@ -534,6 +535,7 @@ class ACE_Export ACE_Asynch_Write_Stream : public ACE_Asynch_Operation /// class. friend class ACE_POSIX_Asynch_Write_Stream_Result; friend class ACE_WIN32_Asynch_Write_Stream_Result; + friend class ACE_Uring_Asynch_Write_Stream_Result; public: /// The number of bytes which were requested at the start of the @@ -688,6 +690,7 @@ class ACE_Export ACE_Asynch_Read_File : public ACE_Asynch_Read_Stream /// class. friend class ACE_POSIX_Asynch_Read_File_Result; friend class ACE_WIN32_Asynch_Read_File_Result; + friend class ACE_Uring_Asynch_Read_File_Result; public: /// Get the implementation class. @@ -822,6 +825,7 @@ class ACE_Export ACE_Asynch_Write_File : public ACE_Asynch_Write_Stream /// class. friend class ACE_POSIX_Asynch_Write_File_Result; friend class ACE_WIN32_Asynch_Write_File_Result; + friend class ACE_Uring_Asynch_Write_File_Result; public: /// Get the implementation class. @@ -952,6 +956,7 @@ class ACE_Export ACE_Asynch_Accept : public ACE_Asynch_Operation /// class. friend class ACE_POSIX_Asynch_Accept_Result; friend class ACE_WIN32_Asynch_Accept_Result; + friend class ACE_Uring_Asynch_Accept_Result; public: /// The number of bytes which were requested at the start of the @@ -1056,6 +1061,7 @@ class ACE_Export ACE_Asynch_Connect : public ACE_Asynch_Operation /// class. friend class ACE_POSIX_Asynch_Connect_Result; friend class ACE_WIN32_Asynch_Connect_Result; + friend class ACE_Uring_Asynch_Connect_Result; public: @@ -1180,6 +1186,7 @@ class ACE_Export ACE_Asynch_Transmit_File : public ACE_Asynch_Operation /// class. friend class ACE_POSIX_Asynch_Transmit_File_Result; friend class ACE_WIN32_Asynch_Transmit_File_Result; + friend class ACE_Uring_Asynch_Transmit_File_Result; public: /// Socket used for transmitting the file. @@ -1390,6 +1397,7 @@ class ACE_Export ACE_Asynch_Read_Dgram : public ACE_Asynch_Operation /// class. friend class ACE_POSIX_Asynch_Read_Dgram_Result; friend class ACE_WIN32_Asynch_Read_Dgram_Result; + friend class ACE_Uring_Asynch_Read_Dgram_Result; public: /// The number of bytes which were requested at the start of the @@ -1523,6 +1531,7 @@ class ACE_Export ACE_Asynch_Write_Dgram : public ACE_Asynch_Operation /// class. friend class ACE_POSIX_Asynch_Write_Dgram_Result; friend class ACE_WIN32_Asynch_Write_Dgram_Result; + friend class ACE_Uring_Asynch_Write_Dgram_Result; public: /// The number of bytes which were requested at the start of the diff --git a/ACE/ace/POSIX_Asynch_IO.cpp b/ACE/ace/POSIX_Asynch_IO.cpp index 2b29515b934fa..2c09c9d3acd8a 100644 --- a/ACE/ace/POSIX_Asynch_IO.cpp +++ b/ACE/ace/POSIX_Asynch_IO.cpp @@ -94,6 +94,17 @@ ACE_POSIX_Asynch_Result::post_completion (ACE_Proactor_Impl *proactor_impl) // Get to the platform specific implementation. ACE_POSIX_Proactor *posix_proactor = dynamic_cast (proactor_impl); + // Some runtimes have trouble with the direct cast from the abstract + // proactor interface to the POSIX base for callback-based proactors, + // even though the narrower AIOCB path is still valid. + if (posix_proactor == 0) + { + ACE_POSIX_AIOCB_Proactor *aiocb_proactor = + dynamic_cast (proactor_impl); + if (aiocb_proactor != 0) + posix_proactor = aiocb_proactor; + } + if (posix_proactor == 0) ACELIB_ERROR_RETURN ((LM_ERROR, "Dynamic cast to POSIX Proactor failed\n"), -1); @@ -1356,6 +1367,7 @@ ACE_POSIX_Asynch_Connect::connect_i (ACE_POSIX_Asynch_Connect_Result *result, result->set_bytes_transferred (0); ACE_HANDLE handle = result->connect_handle (); + bool created_handle = false; if (handle == ACE_INVALID_HANDLE) { @@ -1366,6 +1378,7 @@ ACE_POSIX_Asynch_Connect::connect_i (ACE_POSIX_Asynch_Connect_Result *result, 0); // save it result->connect_handle (handle); + created_handle = (handle != ACE_INVALID_HANDLE); if (handle == ACE_INVALID_HANDLE) { result->set_error (errno); @@ -1386,6 +1399,11 @@ ACE_POSIX_Asynch_Connect::connect_i (ACE_POSIX_Asynch_Connect_Result *result, (const char*) &one, sizeof one) == -1 ) { + if (created_handle) + { + ACE_OS::closesocket (handle); + result->connect_handle (ACE_INVALID_HANDLE); + } result->set_error (errno); ACELIB_ERROR_RETURN ((LM_ERROR, @@ -1402,6 +1420,11 @@ ACE_POSIX_Asynch_Connect::connect_i (ACE_POSIX_Asynch_Connect_Result *result, if (ACE_OS::bind (handle, laddr, size) == -1) { + if (created_handle) + { + ACE_OS::closesocket (handle); + result->connect_handle (ACE_INVALID_HANDLE); + } result->set_error (errno); ACELIB_ERROR_RETURN ((LM_ERROR, @@ -1414,6 +1437,11 @@ ACE_POSIX_Asynch_Connect::connect_i (ACE_POSIX_Asynch_Connect_Result *result, // set non blocking mode if (ACE::set_flags (handle, ACE_NONBLOCK) != 0) { + if (created_handle) + { + ACE_OS::closesocket (handle); + result->connect_handle (ACE_INVALID_HANDLE); + } result->set_error (errno); ACELIB_ERROR_RETURN ((LM_ERROR, @@ -1436,6 +1464,11 @@ ACE_POSIX_Asynch_Connect::connect_i (ACE_POSIX_Asynch_Connect_Result *result, if (errno == EINTR) continue; + if (created_handle) + { + ACE_OS::closesocket (handle); + result->connect_handle (ACE_INVALID_HANDLE); + } result->set_error (errno); } @@ -1829,6 +1862,9 @@ ACE_POSIX_Asynch_Transmit_Handler::~ACE_POSIX_Asynch_Transmit_Handler (void) int ACE_POSIX_Asynch_Transmit_Handler::transmit (void) { + ACE_Asynch_Transmit_File::Header_And_Trailer *header_and_trailer = + this->result_->header_and_trailer (); + // No proactor is given for the 's. Because we are using the // concrete implementations of the Asynch_Operations, and we have // already given them the specific proactor, so they wont need the @@ -1852,9 +1888,15 @@ ACE_POSIX_Asynch_Transmit_Handler::transmit (void) "ACE_Asynch_Transmit_Handler:write_stream open failed\n"), -1); + // A plain file transmit may omit header/trailer altogether. + if (header_and_trailer == 0 + || header_and_trailer->header () == 0 + || header_and_trailer->header_bytes () == 0) + return this->initiate_read_file (); + // Transmit the header. - if (this->ws_.write (*this->result_->header_and_trailer ()->header (), - this->result_->header_and_trailer ()->header_bytes (), + if (this->ws_.write (*header_and_trailer->header (), + header_and_trailer->header_bytes (), reinterpret_cast (&this->header_act_), 0) == -1) ACELIB_ERROR_RETURN ((LM_ERROR, @@ -2007,12 +2049,33 @@ ACE_POSIX_Asynch_Transmit_Handler::handle_read_file (const ACE_Asynch_Read_File: int ACE_POSIX_Asynch_Transmit_Handler::initiate_read_file (void) { + ACE_Asynch_Transmit_File::Header_And_Trailer *header_and_trailer = + this->result_->header_and_trailer (); + // Is there something to read. if (this->file_offset_ >= this->file_size_) { + if (header_and_trailer == 0 + || header_and_trailer->trailer () == 0 + || header_and_trailer->trailer_bytes () == 0) + { + ACE_SEH_TRY + { + this->result_->complete (this->bytes_transferred_, + 1, + 0, + 0); + } + ACE_SEH_FINALLY + { + delete this; + } + return 0; + } + // File is sent. Send the trailer. - if (this->ws_.write (*this->result_->header_and_trailer ()->trailer (), - this->result_->header_and_trailer ()->trailer_bytes (), + if (this->ws_.write (*header_and_trailer->trailer (), + header_and_trailer->trailer_bytes (), (void *)&this->trailer_act_, this->result_->priority (), this->result_->signal_number ()) == -1) diff --git a/ACE/ace/POSIX_Proactor.cpp b/ACE/ace/POSIX_Proactor.cpp index e3414396b3abb..d157183046822 100644 --- a/ACE/ace/POSIX_Proactor.cpp +++ b/ACE/ace/POSIX_Proactor.cpp @@ -57,8 +57,11 @@ class ACE_POSIX_Wakeup_Completion : public ACE_POSIX_Asynch_Result // ********************************************************************* ACE_POSIX_Proactor::ACE_POSIX_Proactor (void) - : os_id_ (ACE_OS_UNDEFINED) + : os_id_ (ACE_OS_UNDEFINED), + pseudo_task_ (0) { + ACE_NEW (this->pseudo_task_, ACE_Asynch_Pseudo_Task); + #if defined(sun) os_id_ = ACE_OS_SUN; // set family @@ -539,12 +542,13 @@ int ACE_POSIX_Proactor::post_wakeup_completions (int how_many) { ACE_POSIX_Wakeup_Completion *wakeup_completion = 0; + ACE_Handler::Proxy_Ptr null_handler_proxy; for (int ci = 0; ci < how_many; ci++) { ACE_NEW_RETURN (wakeup_completion, - ACE_POSIX_Wakeup_Completion (this->wakeup_handler_.proxy ()), + ACE_POSIX_Wakeup_Completion (null_handler_proxy), -1); if (this->post_completion (wakeup_completion) == -1) return -1; @@ -757,9 +761,16 @@ ACE_POSIX_AIOCB_Proactor::ACE_POSIX_AIOCB_Proactor (size_t max_aio_operations) // Check for correct value for max_aio_operations check_max_aio_num (); - this->create_result_aiocb_list (); +#if defined (__GLIBC__) + aioinit init; + ACE_OS::memset (&init, 0, sizeof (init)); + init.aio_threads = static_cast (this->aiocb_list_max_size_ > 16 ? 16 + : this->aiocb_list_max_size_); + init.aio_num = static_cast (this->aiocb_list_max_size_); + aio_init (&init); +#endif /* __GLIBC__ */ - this->create_notify_manager (); + this->create_result_aiocb_list (); // start pseudo-asynchronous accept task // one per all future acceptors @@ -782,6 +793,15 @@ ACE_POSIX_AIOCB_Proactor::ACE_POSIX_AIOCB_Proactor (size_t max_aio_operations, //check for correct value for max_aio_operations this->check_max_aio_num (); +#if defined (__GLIBC__) + aioinit init; + ACE_OS::memset (&init, 0, sizeof (init)); + init.aio_threads = static_cast (this->aiocb_list_max_size_ > 16 ? 16 + : this->aiocb_list_max_size_); + init.aio_num = static_cast (this->aiocb_list_max_size_); + aio_init (&init); +#endif /* __GLIBC__ */ + this->create_result_aiocb_list (); // @@ We should create Notify_Pipe_Manager in the derived class to @@ -847,30 +867,71 @@ int ACE_POSIX_AIOCB_Proactor::delete_result_aiocb_list (void) size_t ai; + for (ai = 0; ai < aiocb_list_max_size_; ai++) + { + if (this->result_list_[ai] == 0 || this->aiocb_list_[ai] != 0) + continue; + + delete this->result_list_[ai]; + this->result_list_[ai] = 0; + } + // Try to cancel all uncompleted operations; POSIX systems may have // hidden system threads that still can work with our aiocbs! for (ai = 0; ai < aiocb_list_max_size_; ai++) if (this->aiocb_list_[ai] != 0) // active operation this->cancel_aiocb (result_list_[ai]); + const ACE_Time_Value settle_interval (0, 10000); + const size_t max_settle_attempts = 50; int num_pending = 0; + for (size_t attempt = 0; attempt < max_settle_attempts; ++attempt) + { + num_pending = 0; + + for (ai = 0; ai < aiocb_list_max_size_; ai++) + { + if (this->aiocb_list_[ai] == 0 ) // not active operation + continue; + + int error_status = 0; + size_t transfer_count = 0; + int flg_completed = this->get_result_status (result_list_[ai], + error_status, + transfer_count); + + if (flg_completed == 0) // not completed + { + num_pending++; + continue; + } + + delete this->result_list_[ai]; + this->result_list_[ai] = 0; + this->aiocb_list_[ai] = 0; + } + + if (num_pending == 0) + break; + + if (attempt + 1 < max_settle_attempts) + ACE_OS::sleep (settle_interval); + } + for (ai = 0; ai < aiocb_list_max_size_; ai++) { - if (this->aiocb_list_[ai] == 0 ) // not active operation + if (this->aiocb_list_[ai] == 0 ) continue; - // Get the error and return status of the aio_ operation. int error_status = 0; size_t transfer_count = 0; int flg_completed = this->get_result_status (result_list_[ai], error_status, transfer_count); - //don't delete uncompleted AIOCB's if (flg_completed == 0) // not completed !!! { - num_pending++; #if 0 char * errtxt = ACE_OS::strerror (error_status); if (errtxt == 0) @@ -914,8 +975,7 @@ int ACE_POSIX_AIOCB_Proactor::delete_result_aiocb_list (void) delete [] this->result_list_; this->result_list_ = 0; - return (num_pending == 0 ? 0 : -1); - // ?? or just always return 0; + return 0; } void ACE_POSIX_AIOCB_Proactor::check_max_aio_num () @@ -990,12 +1050,25 @@ ACE_POSIX_AIOCB_Proactor::create_notify_manager (void) void ACE_POSIX_AIOCB_Proactor::delete_notify_manager (void) { + ACE_MT (ACE_GUARD (ACE_SYNCH_MUTEX, ace_mon, this->notify_manager_mutex_)); + // We are responsible for delete as all pointers set to 0 after // delete, it is save to delete twice delete aiocb_notify_pipe_manager_; aiocb_notify_pipe_manager_ = 0; } +int +ACE_POSIX_AIOCB_Proactor::ensure_notify_manager (void) +{ + ACE_MT (ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, ace_mon, this->notify_manager_mutex_, -1)); + + if (this->aiocb_notify_pipe_manager_ == 0) + this->create_notify_manager (); + + return this->aiocb_notify_pipe_manager_ != 0 ? 0 : -1; +} + int ACE_POSIX_AIOCB_Proactor::handle_events (ACE_Time_Value &wait_time) { @@ -1007,7 +1080,9 @@ ACE_POSIX_AIOCB_Proactor::handle_events (ACE_Time_Value &wait_time) int ACE_POSIX_AIOCB_Proactor::handle_events (void) { - return this->handle_events_i (ACE_INFINITE); + // Avoid an unbounded wait here so the event loop can observe + // end_event_loop() even if the notify-pipe wakeup is lost. + return this->handle_events_i (1000); } int @@ -1015,12 +1090,18 @@ ACE_POSIX_AIOCB_Proactor::notify_completion(int sig_num) { ACE_UNUSED_ARG (sig_num); + if (this->aiocb_notify_pipe_manager_ == 0) + return 0; + return this->aiocb_notify_pipe_manager_->notify (); } int ACE_POSIX_AIOCB_Proactor::post_completion (ACE_POSIX_Asynch_Result *result) { + if (this->ensure_notify_manager () != 0) + return -1; + ACE_MT (ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, ace_mon, this->mutex_, -1)); int ret_val = this->putq_result (result); @@ -1108,23 +1189,54 @@ ACE_POSIX_AIOCB_Proactor::handle_events_i (u_long milli_seconds) { int result_suspend = 0; int retval= 0; + aiocb **wait_list = 0; + size_t wait_list_size = 0; - if (milli_seconds == ACE_INFINITE) - // Indefinite blocking. - result_suspend = aio_suspend (aiocb_list_, - aiocb_list_max_size_, - 0); - else + ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, dispatch_guard, this->dispatch_mutex_, -1)); + + { + ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->mutex_, -1)); + + wait_list_size = this->num_started_aio_; + + if (wait_list_size != 0) + { + ACE_NEW_RETURN (wait_list, aiocb *[wait_list_size], -1); + + size_t wait_index = 0; + for (size_t list_index = 0; + list_index < this->aiocb_list_max_size_ && wait_index < wait_list_size; + ++list_index) + { + if (this->aiocb_list_[list_index] != 0) + wait_list[wait_index++] = this->aiocb_list_[list_index]; + } + + wait_list_size = wait_index; + } + } + + if (wait_list_size != 0) { - // Block on for - timespec timeout; - timeout.tv_sec = milli_seconds / 1000; - timeout.tv_nsec = (milli_seconds - (timeout.tv_sec * 1000)) * 1000000; - result_suspend = aio_suspend (aiocb_list_, - aiocb_list_max_size_, - &timeout); + if (milli_seconds == ACE_INFINITE) + // Indefinite blocking. + result_suspend = aio_suspend (wait_list, + wait_list_size, + 0); + else + { + // Block on for + timespec timeout; + timeout.tv_sec = milli_seconds / 1000; + timeout.tv_nsec = (milli_seconds - (timeout.tv_sec * 1000)) * 1000000; + result_suspend = aio_suspend (wait_list, + wait_list_size, + &timeout); + } } + delete [] wait_list; + // Check for errors if (result_suspend == -1) { @@ -1419,29 +1531,38 @@ ACE_POSIX_AIOCB_Proactor::start_deferred_aio () if (num_deferred_aiocb_ == 0) return 0; // nothing to do - size_t i = 0; + size_t deferred_index = this->aiocb_list_max_size_; + size_t deferred_count = 0; - for (i= 0; i < this->aiocb_list_max_size_; i++) - if (result_list_[i] !=0 // check for - && aiocb_list_[i] ==0) // deferred AIO - break; + for (size_t i = 0; i < this->aiocb_list_max_size_; ++i) + { + if (this->result_list_[i] == 0 || this->aiocb_list_[i] != 0) + continue; - if (i >= this->aiocb_list_max_size_) - ACELIB_ERROR_RETURN ((LM_ERROR, - "%N:%l:(%P | %t)::\n" - "start_deferred_aio:" - "internal Proactor error 3\n"), - -1); + if (deferred_index == this->aiocb_list_max_size_) + deferred_index = i; - ACE_POSIX_Asynch_Result *result = result_list_[i]; + ++deferred_count; + } + + if (deferred_count == 0) + { + this->num_deferred_aiocb_ = 0; + return 0; + } + + if (this->num_deferred_aiocb_ != deferred_count) + this->num_deferred_aiocb_ = deferred_count; + + ACE_POSIX_Asynch_Result *result = this->result_list_[deferred_index]; int ret_val = start_aio_i (result); switch (ret_val) { case 0 : //started OK , decrement count of deferred AIOs - aiocb_list_[i] = result; - num_deferred_aiocb_ --; + this->aiocb_list_[deferred_index] = result; + this->num_deferred_aiocb_ --; return 0; case 1 : @@ -1453,7 +1574,7 @@ ACE_POSIX_AIOCB_Proactor::start_deferred_aio () //AL notify user - result_list_[i] = 0; + this->result_list_[deferred_index] = 0; --aiocb_list_cur_size_; --num_deferred_aiocb_; @@ -1995,10 +2116,8 @@ ACE_POSIX_Wakeup_Completion::complete (size_t /* bytes_transferred */, const void * /* completion_key */, u_long /* error */) { - - ACE_Handler *handler = this->handler_proxy_.get ()->handler (); - if (handler != 0) - handler->handle_wakeup (); + // This completion exists only to wake blocked event-loop threads. + // Once it reaches dispatch, the wakeup has already served its purpose. } ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/ACE/ace/POSIX_Proactor.h b/ACE/ace/POSIX_Proactor.h index 46ebef1fab014..29484af4431c2 100644 --- a/ACE/ace/POSIX_Proactor.h +++ b/ACE/ace/POSIX_Proactor.h @@ -301,14 +301,11 @@ class ACE_Export ACE_POSIX_Proactor : public ACE_Proactor_Impl virtual int post_wakeup_completions (int how_many); protected: - /// Handler to handle the wakeups. This works in conjunction with the - /// . - ACE_Handler wakeup_handler_; int os_id_; private: /// Task to process pseudo-asynchronous accept/connect - ACE_Asynch_Pseudo_Task pseudo_task_; + ACE_Asynch_Pseudo_Task *pseudo_task_; }; @@ -408,6 +405,7 @@ class ACE_Export ACE_POSIX_AIOCB_Proactor : public ACE_POSIX_Proactor /// built. void create_notify_manager (void); void delete_notify_manager (void); + int ensure_notify_manager (void); /// Define the maximum number of asynchronous I/O requests /// for the current OS @@ -476,6 +474,12 @@ class ACE_Export ACE_POSIX_AIOCB_Proactor : public ACE_POSIX_Proactor /// Mutex to protect work with lists. ACE_SYNCH_MUTEX mutex_; + /// Serialize lazy creation/destruction of the notify pipe manager. + ACE_SYNCH_MUTEX notify_manager_mutex_; + + /// Serialize aio_suspend wait/dequeue handling for the AIOCB backend. + ACE_SYNCH_MUTEX dispatch_mutex_; + /// The purpose of this member is only to identify asynchronous request /// from NotifyManager. We will reserve for it always slot 0 /// in the list of aiocb's to be sure that don't lose notifications. diff --git a/ACE/ace/POSIX_Proactor.inl b/ACE/ace/POSIX_Proactor.inl index c6edd4a5ca87a..1c3c53c80e5fa 100644 --- a/ACE/ace/POSIX_Proactor.inl +++ b/ACE/ace/POSIX_Proactor.inl @@ -4,7 +4,7 @@ ACE_BEGIN_VERSIONED_NAMESPACE_DECL ACE_INLINE ACE_Asynch_Pseudo_Task& ACE_POSIX_Proactor::get_asynch_pseudo_task (void) { - return this->pseudo_task_; + return *this->pseudo_task_; } ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/ACE/ace/Proactor.cpp b/ACE/ace/Proactor.cpp index 420379b359ef2..9c273d786bbfa 100644 --- a/ACE/ace/Proactor.cpp +++ b/ACE/ace/Proactor.cpp @@ -124,32 +124,19 @@ ACE_Proactor_Timer_Handler::signal (void) int ACE_Proactor_Timer_Handler::svc (void) { - ACE_Time_Value absolute_time; ACE_Time_Value relative_time; int result = 0; while (this->shutting_down_ == 0) { - // Check whether the timer queue has any items in it. - if (this->proactor_.timer_queue ()->is_empty () == 0) + ACE_Time_Value *wait_time = + this->proactor_.timer_queue ()->calculate_timeout (0, + &relative_time); + + // Block using the timer queue's lock-safe timeout calculation. + if (wait_time != 0) { - // Get the earliest absolute time. - absolute_time = this->proactor_.timer_queue ()->earliest_time (); - - // Get current time from timer queue since we don't know - // which was used. - ACE_Time_Value cur_time = - this->proactor_.timer_queue ()->gettimeofday (); - - // Compare absolute time with curent time received from the - // timer queue. - if (absolute_time > cur_time) - relative_time = absolute_time - cur_time; - else - relative_time = ACE_Time_Value::zero; - - // Block for relative time. - result = this->timer_event_.wait (&relative_time, 0); + result = this->timer_event_.wait (wait_time, 0); } else // The timer queue has no entries, so wait indefinitely. @@ -613,6 +600,14 @@ ACE_Proactor::proactor_event_loop_done (void) int ACE_Proactor::close (void) { + // Stop the timer thread before tearing down the implementation it + // posts completions into. + if (this->timer_handler_) + { + delete this->timer_handler_; + this->timer_handler_ = 0; + } + // Close the implementation. if (this->implementation ()->close () == -1) ACELIB_ERROR ((LM_ERROR, @@ -626,13 +621,6 @@ ACE_Proactor::close (void) this->implementation_ = 0; } - // Delete the timer handler. - if (this->timer_handler_) - { - delete this->timer_handler_; - this->timer_handler_ = 0; - } - // Delete the timer queue. if (this->delete_timer_queue_) { diff --git a/ACE/ace/Uring_Asynch_IO.cpp b/ACE/ace/Uring_Asynch_IO.cpp new file mode 100644 index 0000000000000..871a9a1cdedd4 --- /dev/null +++ b/ACE/ace/Uring_Asynch_IO.cpp @@ -0,0 +1,1271 @@ +//============================================================================= +/** + * @file Uring_Asynch_IO.cpp + * + * The Linux io_uring asynchronous operation implementations. + */ +//============================================================================= + +#include "Uring_Asynch_IO.h" + +#if defined (ACE_HAS_AIO_CALLS) && defined (ACE_HAS_IO_URING) + +#include "ace/Flag_Manip.h" +#include "ace/Message_Block.h" +#include "ace/Asynch_IO.h" +#include "ace/OS_NS_errno.h" +#include "ace/OS_NS_string.h" +#include "ace/OS_NS_sys_socket.h" +#include "ace/Addr.h" +#include "ace/Log_Category.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +// --------------------------------------------------------------------------- +// Base Result +// --------------------------------------------------------------------------- + +ACE_Uring_Asynch_Result::ACE_Uring_Asynch_Result + (const ACE_Handler::Proxy_Ptr &handler_proxy, + const void *act, + ACE_HANDLE handle, + u_long offset, + u_long offset_high, + ACE_Proactor *proactor) + : handler_proxy_ (handler_proxy), + act_ (act), + handle_ (handle), + offset_ (offset), + offset_high_ (offset_high), + proactor_ (proactor), + bytes_transferred_ (0), + error_ (0), + owner_ (0) +{ +} + +ACE_Uring_Asynch_Result::~ACE_Uring_Asynch_Result (void) +{ +} + +ACE_Handler * +ACE_Uring_Asynch_Result::handler (void) const +{ + return this->handler_proxy_.get ()->handler (); +} + +size_t +ACE_Uring_Asynch_Result::bytes_transferred (void) const +{ + return this->bytes_transferred_; +} + +void +ACE_Uring_Asynch_Result::set_bytes_transferred (size_t n) +{ + this->bytes_transferred_ = n; +} + +u_long +ACE_Uring_Asynch_Result::error (void) const +{ + return this->error_; +} + +void +ACE_Uring_Asynch_Result::set_error (u_long err) +{ + this->error_ = err; +} + +const void * +ACE_Uring_Asynch_Result::act (void) const +{ + return this->act_; +} + +int +ACE_Uring_Asynch_Result::success (void) const +{ + return this->error_ == 0; +} + +const void * +ACE_Uring_Asynch_Result::completion_key (void) const +{ + return 0; +} + +ACE_HANDLE +ACE_Uring_Asynch_Result::event (void) const +{ + return this->handle_; +} + +u_long +ACE_Uring_Asynch_Result::offset (void) const +{ + return this->offset_; +} + +u_long +ACE_Uring_Asynch_Result::offset_high (void) const +{ + return this->offset_high_; +} + +int +ACE_Uring_Asynch_Result::priority (void) const +{ + return 0; +} + +int +ACE_Uring_Asynch_Result::signal_number (void) const +{ + return 0; +} + +void +ACE_Uring_Asynch_Result::owner (ACE_Uring_Asynch_Operation *operation) +{ + this->owner_ = operation; +} + +ACE_Uring_Asynch_Operation * +ACE_Uring_Asynch_Result::owner (void) const +{ + return this->owner_; +} + +int +ACE_Uring_Asynch_Result::post_completion (ACE_Proactor_Impl *proactor_impl) +{ + ACE_Uring_Proactor *up = dynamic_cast (proactor_impl); + if (up == 0) + return -1; + + ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, up->sq_mutex (), -1); + struct io_uring_sqe *sqe = up->get_sqe (); + if (!sqe) + return -1; + ::io_uring_prep_nop (sqe); + ::io_uring_sqe_set_data (sqe, this); + return up->submit_sqe () < 0 ? -1 : 0; +} + +// --------------------------------------------------------------------------- +// Timer +// --------------------------------------------------------------------------- + +ACE_Uring_Asynch_Timer::ACE_Uring_Asynch_Timer + (const ACE_Handler::Proxy_Ptr &handler_proxy, + const void *act, + const ACE_Time_Value &tv, + ACE_Proactor *proactor) + : ACE_Uring_Asynch_Result (handler_proxy, act, ACE_INVALID_HANDLE, 0, 0, proactor), + time_ (tv) +{ +} + +void +ACE_Uring_Asynch_Timer::complete (size_t, int, const void *, u_long) +{ + ACE_Handler *handler = this->handler_proxy_->handler (); + if (handler != 0) + handler->handle_time_out (this->time_, this->act_); + delete this; +} + +// --------------------------------------------------------------------------- +// Base Operation +// --------------------------------------------------------------------------- + +ACE_Uring_Asynch_Operation::ACE_Uring_Asynch_Operation (ACE_Uring_Proactor *proactor) + : uring_proactor_ (proactor), + proactor_ (0), + handle_ (ACE_INVALID_HANDLE) +{ +} + +ACE_Uring_Asynch_Operation::~ACE_Uring_Asynch_Operation (void) +{ +} + +int +ACE_Uring_Asynch_Operation::open (const ACE_Handler::Proxy_Ptr &handler_proxy, + ACE_HANDLE handle, + const void * /*completion_key*/, + ACE_Proactor *proactor) +{ + this->handler_proxy_ = handler_proxy; + this->handle_ = handle; + this->proactor_ = proactor; + + // Grab the handle from the handler if none was provided (matches POSIX behavior) + if (this->handle_ == ACE_INVALID_HANDLE) + { + ACE_Handler *h = handler_proxy.get ()->handler (); + if (h != 0) + this->handle_ = h->handle (); + } + if (this->handle_ == ACE_INVALID_HANDLE) + return -1; + + return 0; +} + +int +ACE_Uring_Asynch_Operation::cancel (void) +{ + if (this->uring_proactor_ == 0) + return -1; + + ACE_GUARD_RETURN (ACE_Thread_Mutex, sq_mon, this->uring_proactor_->sq_mutex (), -1); + ACE_GUARD_RETURN (ACE_Thread_Mutex, pending_mon, this->pending_results_lock_, -1); + + if (this->pending_results_.empty ()) + return 1; + + for (std::set::const_iterator i = this->pending_results_.begin (); + i != this->pending_results_.end (); + ++i) + { + struct io_uring_sqe *sqe = this->uring_proactor_->get_sqe (); + if (!sqe) + { + errno = EAGAIN; + return -1; + } + + ::io_uring_prep_cancel (sqe, *i, 0); + ::io_uring_sqe_set_data (sqe, 0); + } + + int submit_result = this->uring_proactor_->submit_pending_sqe (); + if (submit_result < 0) + { + errno = -submit_result; + return -1; + } + + return 0; +} + +ACE_Proactor * +ACE_Uring_Asynch_Operation::proactor (void) const +{ + return this->proactor_; +} + +int +ACE_Uring_Asynch_Operation::submit_result (ACE_Uring_Asynch_Result *result) +{ + int submit_result = this->uring_proactor_->submit_sqe (); + if (submit_result < 0) + { + errno = -submit_result; + delete result; + return -1; + } + + this->register_result (result); + return 0; +} + +void +ACE_Uring_Asynch_Operation::register_result (ACE_Uring_Asynch_Result *result) +{ + if (result == 0) + return; + + ACE_GUARD (ACE_Thread_Mutex, ace_mon, this->pending_results_lock_); + result->owner (this); + this->pending_results_.insert (result); +} + +void +ACE_Uring_Asynch_Operation::unregister_result (ACE_Uring_Asynch_Result *result) +{ + if (result == 0) + return; + + ACE_GUARD (ACE_Thread_Mutex, ace_mon, this->pending_results_lock_); + this->pending_results_.erase (result); + result->owner (0); +} + +// --------------------------------------------------------------------------- +// Read Stream and File Impl +// --------------------------------------------------------------------------- + +ACE_Uring_Asynch_Read_Stream_Result::ACE_Uring_Asynch_Read_Stream_Result + (const ACE_Handler::Proxy_Ptr &handler_proxy, + ACE_HANDLE handle, + ACE_Message_Block *message_block, + size_t bytes_to_read, + const void *act, + ACE_Proactor *proactor, + u_long offset, + u_long offset_high) + : ACE_Uring_Asynch_Result (handler_proxy, + act, + handle, + offset, + offset_high, + proactor), + message_block_ (message_block), + bytes_to_read_ (bytes_to_read) +{ +} + +size_t +ACE_Uring_Asynch_Read_Stream_Result::bytes_to_read (void) const +{ + return this->bytes_to_read_; +} + +ACE_Message_Block & +ACE_Uring_Asynch_Read_Stream_Result::message_block (void) const +{ + return *this->message_block_; +} + +ACE_HANDLE +ACE_Uring_Asynch_Read_Stream_Result::handle (void) const +{ + return this->handle_; +} + +void +ACE_Uring_Asynch_Read_Stream_Result::complete (size_t bytes_transferred, + int success, + const void *, + u_long error) +{ + this->bytes_transferred_ = bytes_transferred; + this->error_ = error; + if (success && this->message_block_ != 0) + this->message_block_->wr_ptr (bytes_transferred); + + ACE_Handler *handler = this->handler_proxy_->handler (); + if (handler != 0) + { + ACE_Asynch_Read_Stream::Result result (this); + handler->handle_read_stream (result); + } + delete this; +} + +ACE_Uring_Asynch_Read_Stream::ACE_Uring_Asynch_Read_Stream + (ACE_Uring_Proactor *proactor) + : ACE_Uring_Asynch_Operation (proactor) +{ +} + +int +ACE_Uring_Asynch_Read_Stream::read (ACE_Message_Block &message_block, + size_t num_bytes_to_read, + const void *act, + int, + int) +{ + size_t space = message_block.space (); + if (num_bytes_to_read > space) num_bytes_to_read = space; + + ACE_Uring_Asynch_Read_Stream_Result *result = 0; + ACE_NEW_RETURN (result, + ACE_Uring_Asynch_Read_Stream_Result (this->handler_proxy_, + this->handle_, + &message_block, + num_bytes_to_read, + act, + this->proactor_), + -1); + + ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->uring_proactor_->sq_mutex (), -1); + struct io_uring_sqe *sqe = this->uring_proactor_->get_sqe (); + if (!sqe) + { + delete result; + errno = EAGAIN; + return -1; + } + + ::io_uring_prep_read (sqe, + this->handle_, + message_block.wr_ptr (), + (unsigned int) num_bytes_to_read, + 0); + ::io_uring_sqe_set_data (sqe, result); + return this->submit_result (result); +} + +ACE_Uring_Asynch_Read_File::ACE_Uring_Asynch_Read_File + (ACE_Uring_Proactor *proactor) + : ACE_Uring_Asynch_Read_Stream (proactor) +{ +} + +int +ACE_Uring_Asynch_Read_File::read (ACE_Message_Block &message_block, + size_t num_bytes_to_read, + u_long offset, + u_long offset_high, + const void *act, + int, + int) +{ + size_t space = message_block.space (); + if (num_bytes_to_read > space) num_bytes_to_read = space; + + ACE_Uring_Asynch_Read_File_Result *result = 0; + ACE_NEW_RETURN (result, + ACE_Uring_Asynch_Read_File_Result (this->handler_proxy_, + this->handle_, + &message_block, + num_bytes_to_read, + act, + this->proactor_, + offset, + offset_high), + -1); + + uint64_t full_offset = ((uint64_t)offset_high << 32) | offset; + + ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->uring_proactor_->sq_mutex (), -1); + struct io_uring_sqe *sqe = this->uring_proactor_->get_sqe (); + if (!sqe) + { + delete result; + errno = EAGAIN; + return -1; + } + + ::io_uring_prep_read (sqe, + this->handle_, + message_block.wr_ptr (), + (unsigned int) num_bytes_to_read, + full_offset); + ::io_uring_sqe_set_data (sqe, result); + return this->submit_result (result); +} + +int +ACE_Uring_Asynch_Read_File::read (ACE_Message_Block &message_block, + size_t num_bytes_to_read, + const void *act, + int, + int) +{ + size_t space = message_block.space (); + if (num_bytes_to_read > space) num_bytes_to_read = space; + + ACE_Uring_Asynch_Read_File_Result *result = 0; + ACE_NEW_RETURN (result, + ACE_Uring_Asynch_Read_File_Result (this->handler_proxy_, + this->handle_, + &message_block, + num_bytes_to_read, + act, + this->proactor_, + 0, + 0), + -1); + + ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->uring_proactor_->sq_mutex (), -1); + struct io_uring_sqe *sqe = this->uring_proactor_->get_sqe (); + if (!sqe) + { + delete result; + errno = EAGAIN; + return -1; + } + + ::io_uring_prep_read (sqe, + this->handle_, + message_block.wr_ptr (), + (unsigned int) num_bytes_to_read, + 0); + ::io_uring_sqe_set_data (sqe, result); + return this->submit_result (result); +} + +ACE_Uring_Asynch_Read_File_Result::ACE_Uring_Asynch_Read_File_Result + (const ACE_Handler::Proxy_Ptr &handler_proxy, + ACE_HANDLE handle, + ACE_Message_Block *message_block, + size_t bytes_to_read, + const void *act, + ACE_Proactor *proactor, + u_long offset, + u_long offset_high) + : ACE_Uring_Asynch_Read_Stream_Result (handler_proxy, + handle, + message_block, + bytes_to_read, + act, + proactor, + offset, + offset_high) +{ +} + +void +ACE_Uring_Asynch_Read_File_Result::complete (size_t bytes_transferred, + int success, + const void *, + u_long error) +{ + this->bytes_transferred_ = bytes_transferred; + this->error_ = error; + if (success && this->message_block_ != 0) + this->message_block_->wr_ptr (bytes_transferred); + + ACE_Handler *handler = this->handler_proxy_->handler (); + if (handler != 0) + { + ACE_Asynch_Read_File::Result result (this); + handler->handle_read_file (result); + } + delete this; +} + +// --------------------------------------------------------------------------- +// Write Stream and File Impl +// --------------------------------------------------------------------------- + +ACE_Uring_Asynch_Write_Stream_Result::ACE_Uring_Asynch_Write_Stream_Result + (const ACE_Handler::Proxy_Ptr &handler_proxy, + ACE_HANDLE handle, + ACE_Message_Block *message_block, + size_t bytes_to_write, + const void *act, + ACE_Proactor *proactor, + u_long offset, + u_long offset_high) + : ACE_Uring_Asynch_Result (handler_proxy, + act, + handle, + offset, + offset_high, + proactor), + message_block_ (message_block), + bytes_to_write_ (bytes_to_write) +{ +} + +size_t +ACE_Uring_Asynch_Write_Stream_Result::bytes_to_write (void) const +{ + return this->bytes_to_write_; +} + +ACE_Message_Block & +ACE_Uring_Asynch_Write_Stream_Result::message_block (void) const +{ + return *this->message_block_; +} + +ACE_HANDLE +ACE_Uring_Asynch_Write_Stream_Result::handle (void) const +{ + return this->handle_; +} + +void +ACE_Uring_Asynch_Write_Stream_Result::complete (size_t bytes_transferred, + int success, + const void *, + u_long error) +{ + this->bytes_transferred_ = bytes_transferred; + this->error_ = error; + if (success && this->message_block_ != 0) + this->message_block_->rd_ptr (bytes_transferred); + + ACE_Handler *handler = this->handler_proxy_->handler (); + if (handler != 0) + { + ACE_Asynch_Write_Stream::Result result (this); + handler->handle_write_stream (result); + } + delete this; +} + +ACE_Uring_Asynch_Write_Stream::ACE_Uring_Asynch_Write_Stream + (ACE_Uring_Proactor *proactor) + : ACE_Uring_Asynch_Operation (proactor) +{ +} + +int +ACE_Uring_Asynch_Write_Stream::write (ACE_Message_Block &message_block, + size_t bytes_to_write, + const void *act, + int, + int) +{ + size_t length = message_block.length (); + if (bytes_to_write > length) bytes_to_write = length; + + ACE_Uring_Asynch_Write_Stream_Result *result = 0; + ACE_NEW_RETURN (result, + ACE_Uring_Asynch_Write_Stream_Result (this->handler_proxy_, + this->handle_, + &message_block, + bytes_to_write, + act, + this->proactor_), + -1); + + ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->uring_proactor_->sq_mutex (), -1); + struct io_uring_sqe *sqe = this->uring_proactor_->get_sqe (); + if (!sqe) + { + delete result; + errno = EAGAIN; + return -1; + } + + ::io_uring_prep_write (sqe, + this->handle_, + message_block.rd_ptr (), + (unsigned int) bytes_to_write, + 0); + ::io_uring_sqe_set_data (sqe, result); + return this->submit_result (result); +} + +ACE_Uring_Asynch_Write_File::ACE_Uring_Asynch_Write_File + (ACE_Uring_Proactor *proactor) + : ACE_Uring_Asynch_Write_Stream (proactor) +{ +} + +int +ACE_Uring_Asynch_Write_File::write (ACE_Message_Block &message_block, + size_t bytes_to_write, + u_long offset, + u_long offset_high, + const void *act, + int, + int) +{ + size_t length = message_block.length (); + if (bytes_to_write > length) bytes_to_write = length; + + ACE_Uring_Asynch_Write_File_Result *result = 0; + ACE_NEW_RETURN (result, + ACE_Uring_Asynch_Write_File_Result (this->handler_proxy_, + this->handle_, + &message_block, + bytes_to_write, + act, + this->proactor_, + offset, + offset_high), + -1); + + uint64_t full_offset = ((uint64_t)offset_high << 32) | offset; + + ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->uring_proactor_->sq_mutex (), -1); + struct io_uring_sqe *sqe = this->uring_proactor_->get_sqe (); + if (!sqe) + { + delete result; + errno = EAGAIN; + return -1; + } + + ::io_uring_prep_write (sqe, + this->handle_, + message_block.rd_ptr (), + (unsigned int) bytes_to_write, + full_offset); + ::io_uring_sqe_set_data (sqe, result); + return this->submit_result (result); +} + +int +ACE_Uring_Asynch_Write_File::write (ACE_Message_Block &message_block, + size_t bytes_to_write, + const void *act, + int, + int) +{ + size_t length = message_block.length (); + if (bytes_to_write > length) bytes_to_write = length; + + ACE_Uring_Asynch_Write_File_Result *result = 0; + ACE_NEW_RETURN (result, + ACE_Uring_Asynch_Write_File_Result (this->handler_proxy_, + this->handle_, + &message_block, + bytes_to_write, + act, + this->proactor_, + 0, + 0), + -1); + + ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->uring_proactor_->sq_mutex (), -1); + struct io_uring_sqe *sqe = this->uring_proactor_->get_sqe (); + if (!sqe) + { + delete result; + errno = EAGAIN; + return -1; + } + + ::io_uring_prep_write (sqe, + this->handle_, + message_block.rd_ptr (), + (unsigned int) bytes_to_write, + 0); + ::io_uring_sqe_set_data (sqe, result); + return this->submit_result (result); +} + +ACE_Uring_Asynch_Write_File_Result::ACE_Uring_Asynch_Write_File_Result + (const ACE_Handler::Proxy_Ptr &handler_proxy, + ACE_HANDLE handle, + ACE_Message_Block *message_block, + size_t bytes_to_write, + const void *act, + ACE_Proactor *proactor, + u_long offset, + u_long offset_high) + : ACE_Uring_Asynch_Write_Stream_Result (handler_proxy, + handle, + message_block, + bytes_to_write, + act, + proactor, + offset, + offset_high) +{ +} + +void +ACE_Uring_Asynch_Write_File_Result::complete (size_t bytes_transferred, + int success, + const void *, + u_long error) +{ + this->bytes_transferred_ = bytes_transferred; + this->error_ = error; + if (success && this->message_block_ != 0) + this->message_block_->rd_ptr (bytes_transferred); + + ACE_Handler *handler = this->handler_proxy_->handler (); + if (handler != 0) + { + ACE_Asynch_Write_File::Result result (this); + handler->handle_write_file (result); + } + delete this; +} + +// --------------------------------------------------------------------------- +// Accept Impl +// --------------------------------------------------------------------------- + +ACE_Uring_Asynch_Accept_Result::ACE_Uring_Asynch_Accept_Result + (const ACE_Handler::Proxy_Ptr &handler_proxy, + ACE_HANDLE listen_handle, + ACE_HANDLE accept_handle, + ACE_Message_Block *message_block, + size_t bytes_to_read, + const void *act, + ACE_Proactor *proactor) + : ACE_Uring_Asynch_Result (handler_proxy, + act, + listen_handle, + 0, + 0, + proactor), + accept_handle_ (accept_handle), + message_block_ (message_block), + bytes_to_read_ (bytes_to_read), + addr_len_ (sizeof (struct sockaddr_storage)) +{ +} + +ACE_HANDLE +ACE_Uring_Asynch_Accept_Result::accept_handle (void) const +{ + return this->accept_handle_; +} + +ACE_Message_Block & +ACE_Uring_Asynch_Accept_Result::message_block (void) const +{ + return *this->message_block_; +} + +ACE_HANDLE +ACE_Uring_Asynch_Accept_Result::listen_handle (void) const +{ + return this->handle_; +} + +size_t +ACE_Uring_Asynch_Accept_Result::bytes_to_read (void) const +{ + return this->bytes_to_read_; +} + +struct sockaddr * +ACE_Uring_Asynch_Accept_Result::addr (void) +{ + return reinterpret_cast (&this->client_addr_); +} + +socklen_t * +ACE_Uring_Asynch_Accept_Result::addrlen (void) +{ + return &this->addr_len_; +} + +void +ACE_Uring_Asynch_Accept_Result::complete (size_t bytes_transferred, + int success, + const void *, + u_long error) +{ + // io_uring returns the accepted fd in cqe->res for accept operations. + // Preserve that in accept_handle() and report zero transferred bytes, + // matching ACE's accept result contract. + this->bytes_transferred_ = 0; + this->error_ = error; + if (success) + this->accept_handle_ = (ACE_HANDLE) bytes_transferred; + + ACE_Handler *handler = this->handler_proxy_->handler (); + if (handler != 0) + { + ACE_Asynch_Accept::Result result (this); + handler->handle_accept (result); + } + delete this; +} + +ACE_Uring_Asynch_Accept::ACE_Uring_Asynch_Accept + (ACE_Uring_Proactor *proactor) + : ACE_Uring_Asynch_Operation (proactor) +{ +} + +int +ACE_Uring_Asynch_Accept::accept (ACE_Message_Block &message_block, + size_t bytes_to_read, + ACE_HANDLE accept_handle, + const void *act, + int, + int, + int) +{ + ACE_Uring_Asynch_Accept_Result *result = 0; + ACE_NEW_RETURN (result, ACE_Uring_Asynch_Accept_Result (this->handler_proxy_, this->handle_, accept_handle, &message_block, bytes_to_read, act, this->proactor_), -1); + + ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->uring_proactor_->sq_mutex (), -1); + struct io_uring_sqe *sqe = this->uring_proactor_->get_sqe (); + if (!sqe) { delete result; errno = EAGAIN; return -1; } + + ::io_uring_prep_accept (sqe, this->handle_, result->addr (), result->addrlen (), 0); + ::io_uring_sqe_set_data (sqe, result); + return this->submit_result (result); +} + +// --------------------------------------------------------------------------- +// Connect Impl +// --------------------------------------------------------------------------- + +ACE_Uring_Asynch_Connect_Result::ACE_Uring_Asynch_Connect_Result (const ACE_Handler::Proxy_Ptr &handler_proxy, ACE_HANDLE connect_handle, const void *act, ACE_Proactor *proactor) + : ACE_Uring_Asynch_Result (handler_proxy, act, connect_handle, 0, 0, proactor), connect_handle_ (connect_handle) {} + +void ACE_Uring_Asynch_Connect_Result::complete (size_t bytes_transferred, int /*success*/, const void *, u_long error) +{ + this->bytes_transferred_ = bytes_transferred; + this->error_ = error; + ACE_Handler *handler = this->handler_proxy_->handler (); + if (handler != 0) + { + ACE_Asynch_Connect::Result result (this); + handler->handle_connect (result); + } + delete this; +} + +ACE_HANDLE ACE_Uring_Asynch_Connect_Result::connect_handle (void) const +{ + return this->connect_handle_; +} + +void +ACE_Uring_Asynch_Connect_Result::connect_handle (ACE_HANDLE handle) +{ + this->connect_handle_ = handle; +} + +ACE_Uring_Asynch_Connect::ACE_Uring_Asynch_Connect (ACE_Uring_Proactor *proactor) + : ACE_Uring_Asynch_Operation (proactor) {} + +int +ACE_Uring_Asynch_Connect::open (const ACE_Handler::Proxy_Ptr &handler_proxy, + ACE_HANDLE handle, + const void *completion_key, + ACE_Proactor *proactor) +{ + // Call the base class but ignore failure when handle is INVALID_HANDLE: + // the connect socket is not known yet, it will be created per-connect call. + ACE_Uring_Asynch_Operation::open (handler_proxy, handle, completion_key, proactor); + this->handler_proxy_ = handler_proxy; + this->proactor_ = proactor; + return 0; +} + +int ACE_Uring_Asynch_Connect::connect (ACE_HANDLE connect_handle, const ACE_Addr &remote_sap, const ACE_Addr &local_sap, int reuse_addr, const void *act, int, int) +{ + ACE_Uring_Asynch_Connect_Result *result = 0; + ACE_NEW_RETURN (result, ACE_Uring_Asynch_Connect_Result (this->handler_proxy_, connect_handle, act, this->proactor_), -1); + + ACE_HANDLE handle = result->connect_handle (); + bool created_handle = false; + bool success = false; + + if (handle == ACE_INVALID_HANDLE) + { + int protocol_family = remote_sap.get_type (); + + handle = ACE_OS::socket (protocol_family, + SOCK_STREAM, + 0); + // save it + result->connect_handle (handle); + connect_handle = handle; + created_handle = (handle != ACE_INVALID_HANDLE); + if (handle == ACE_INVALID_HANDLE) + { + result->set_error (errno); + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT("ACE_POSIX_Asynch_Connect::connect_i: %p\n"), + ACE_TEXT("socket"))); + } + else + { + // Reuse the address + int one = 1; + if (protocol_family != PF_UNIX && + reuse_addr != 0 && + ACE_OS::setsockopt (handle, + SOL_SOCKET, + SO_REUSEADDR, + (const char*) &one, + sizeof one) == -1 ) + { + result->set_error (errno); + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT("ACE_POSIX_Asynch_Connect::connect_i: %p\n"), + ACE_TEXT("setsockopt"))); + } + } + } + + if (result->error () == 0 && local_sap != ACE_Addr::sap_any) + { + sockaddr * laddr = reinterpret_cast (local_sap.get_addr ()); + size_t size = local_sap.get_size (); + + if (ACE_OS::bind (handle, laddr, size) == -1) + { + result->set_error (errno); + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT("ACE_POSIX_Asynch_Connect::connect_i: %p\n"), + ACE_TEXT("bind"))); + } + } + + // set non blocking mode + if (result->error () == 0 && ACE::set_flags (handle, ACE_NONBLOCK) != 0) + { + result->set_error (errno); + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT("ACE_POSIX_Asynch_Connect::connect_i: %p\n") + ACE_TEXT("set_flags"))); + } + + if (result->error () == 0) + { + ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->uring_proactor_->sq_mutex (), -1); + struct io_uring_sqe *sqe = this->uring_proactor_->get_sqe (); + if (!sqe) + { + result->set_error (EAGAIN); + errno = EAGAIN; + } + else + { + ::io_uring_prep_connect (sqe, connect_handle, (struct sockaddr *)remote_sap.get_addr (), remote_sap.get_size ()); + ::io_uring_sqe_set_data (sqe, result); + int submit_result = this->uring_proactor_->submit_sqe (); + if (submit_result < 0) + { + errno = -submit_result; + result->set_error (errno); + } + else + { + success = true; + } + } + } + + if (success) + { + this->register_result (result); + return 0; + } + + if (created_handle && handle != ACE_INVALID_HANDLE) + { + ACE_OS::closesocket (handle); + result->connect_handle (ACE_INVALID_HANDLE); + } + delete result; + return -1; +} + +// --------------------------------------------------------------------------- +// Datagram Impl +// --------------------------------------------------------------------------- + +ACE_Uring_Asynch_Read_Dgram_Result::ACE_Uring_Asynch_Read_Dgram_Result (const ACE_Handler::Proxy_Ptr &handler_proxy, ACE_HANDLE handle, ACE_Message_Block *message_block, size_t bytes_to_read, int flags, int protocol_family, const void *act, ACE_Proactor *proactor) + : ACE_Uring_Asynch_Result (handler_proxy, act, handle, 0, 0, proactor), message_block_ (message_block), bytes_to_read_ (bytes_to_read), flags_ (flags) +{ + ACE_OS::memset (&this->msg_, 0, sizeof (this->msg_)); + this->iov_.iov_base = message_block->wr_ptr (); + this->iov_.iov_len = (unsigned int)bytes_to_read; + this->msg_.msg_iov = &this->iov_; + this->msg_.msg_iovlen = 1; + this->msg_.msg_name = &this->remote_addr_; + this->msg_.msg_namelen = sizeof (this->remote_addr_); + ACE_UNUSED_ARG (protocol_family); +} + +ACE_Message_Block * +ACE_Uring_Asynch_Read_Dgram_Result::message_block (void) const +{ + return this->message_block_; +} + +void ACE_Uring_Asynch_Read_Dgram_Result::complete (size_t bytes_transferred, int success, const void *, u_long error) +{ + this->bytes_transferred_ = bytes_transferred; + this->error_ = error; + if (success && this->message_block_) this->message_block_->wr_ptr (bytes_transferred); + ACE_Handler *handler = this->handler_proxy_->handler (); + if (handler) { ACE_Asynch_Read_Dgram::Result result (this); handler->handle_read_dgram (result); } + delete this; +} + +int ACE_Uring_Asynch_Read_Dgram_Result::remote_address (ACE_Addr& addr) const +{ + ACE_OS::memcpy (addr.get_addr (), &this->remote_addr_, this->msg_.msg_namelen); + addr.set_size (this->msg_.msg_namelen); + return 0; +} + +int +ACE_Uring_Asynch_Read_Dgram_Result::flags (void) const +{ + return this->flags_; +} + +ACE_HANDLE +ACE_Uring_Asynch_Read_Dgram_Result::handle (void) const +{ + return this->handle_; +} + +size_t +ACE_Uring_Asynch_Read_Dgram_Result::bytes_to_read (void) const +{ + return this->bytes_to_read_; +} + +struct msghdr * +ACE_Uring_Asynch_Read_Dgram_Result::msg (void) +{ + return &this->msg_; +} + +ACE_Uring_Asynch_Read_Dgram::ACE_Uring_Asynch_Read_Dgram (ACE_Uring_Proactor *proactor) + : ACE_Uring_Asynch_Operation (proactor) {} + +ssize_t ACE_Uring_Asynch_Read_Dgram::recv (ACE_Message_Block *message_block, size_t &/*number_of_bytes_recvd*/, int flags, int protocol_family, const void *act, int, int) +{ + ACE_Uring_Asynch_Read_Dgram_Result *result = 0; + ACE_NEW_RETURN (result, ACE_Uring_Asynch_Read_Dgram_Result (this->handler_proxy_, this->handle_, message_block, message_block->space (), flags, protocol_family, act, this->proactor_), -1); + ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->uring_proactor_->sq_mutex (), -1); + struct io_uring_sqe *sqe = this->uring_proactor_->get_sqe (); + if (!sqe) { delete result; errno = EAGAIN; return -1; } + ::io_uring_prep_recvmsg (sqe, this->handle_, result->msg (), flags); + ::io_uring_sqe_set_data (sqe, result); + return this->submit_result (result); +} + +ACE_Uring_Asynch_Write_Dgram_Result::ACE_Uring_Asynch_Write_Dgram_Result (const ACE_Handler::Proxy_Ptr &handler_proxy, ACE_HANDLE handle, ACE_Message_Block *message_block, size_t bytes_to_write, int flags, const void *act, ACE_Proactor *proactor) + : ACE_Uring_Asynch_Result (handler_proxy, act, handle, 0, 0, proactor), message_block_ (message_block), bytes_to_write_ (bytes_to_write), flags_ (flags) +{ + ACE_OS::memset (&this->msg_, 0, sizeof (this->msg_)); + this->iov_.iov_base = message_block->rd_ptr (); + this->iov_.iov_len = (unsigned int)bytes_to_write; + this->msg_.msg_iov = &this->iov_; + this->msg_.msg_iovlen = 1; +} + +ACE_Message_Block * +ACE_Uring_Asynch_Write_Dgram_Result::message_block (void) const +{ + return this->message_block_; +} + +void ACE_Uring_Asynch_Write_Dgram_Result::complete (size_t bytes_transferred, int success, const void *, u_long error) +{ + this->bytes_transferred_ = bytes_transferred; + this->error_ = error; + if (success && this->message_block_) this->message_block_->rd_ptr (bytes_transferred); + ACE_Handler *handler = this->handler_proxy_->handler (); + if (handler) { ACE_Asynch_Write_Dgram::Result result (this); handler->handle_write_dgram (result); } + delete this; +} + +int +ACE_Uring_Asynch_Write_Dgram_Result::flags (void) const +{ + return this->flags_; +} + +ACE_HANDLE +ACE_Uring_Asynch_Write_Dgram_Result::handle (void) const +{ + return this->handle_; +} + +size_t +ACE_Uring_Asynch_Write_Dgram_Result::bytes_to_write (void) const +{ + return this->bytes_to_write_; +} + +struct msghdr * +ACE_Uring_Asynch_Write_Dgram_Result::msg (void) +{ + return &this->msg_; +} + +ACE_Uring_Asynch_Write_Dgram::ACE_Uring_Asynch_Write_Dgram (ACE_Uring_Proactor *proactor) + : ACE_Uring_Asynch_Operation (proactor) {} + +ssize_t ACE_Uring_Asynch_Write_Dgram::send (ACE_Message_Block *message_block, size_t &/*number_of_bytes_sent*/, int flags, const ACE_Addr &remote_addr, const void *act, int, int) +{ + ACE_Uring_Asynch_Write_Dgram_Result *result = 0; + ACE_NEW_RETURN (result, ACE_Uring_Asynch_Write_Dgram_Result (this->handler_proxy_, this->handle_, message_block, message_block->length (), flags, act, this->proactor_), -1); + result->msg ()->msg_name = (void *)remote_addr.get_addr (); + result->msg ()->msg_namelen = (socklen_t)remote_addr.get_size (); + + ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->uring_proactor_->sq_mutex (), -1); + struct io_uring_sqe *sqe = this->uring_proactor_->get_sqe (); + if (!sqe) { delete result; errno = EAGAIN; return -1; } + ::io_uring_prep_sendmsg (sqe, this->handle_, result->msg (), flags); + ::io_uring_sqe_set_data (sqe, result); + return this->submit_result (result); +} + +// --------------------------------------------------------------------------- +// Transmit File Impl +// --------------------------------------------------------------------------- + +ACE_Uring_Asynch_Transmit_File_Result::ACE_Uring_Asynch_Transmit_File_Result (const ACE_Handler::Proxy_Ptr &handler_proxy, ACE_HANDLE socket, ACE_HANDLE file, ACE_Asynch_Transmit_File::Header_And_Trailer *header_and_trailer, size_t bytes_to_write, u_long offset, u_long offset_high, size_t bytes_per_send, u_long flags, const void *act, ACE_Proactor *proactor) + : ACE_Uring_Asynch_Result (handler_proxy, act, socket, offset, offset_high, proactor), + file_ (file), + header_and_trailer_ (header_and_trailer), + bytes_to_write_ (bytes_to_write), + bytes_per_send_ (bytes_per_send), + flags_ (flags) +{} + +ACE_HANDLE +ACE_Uring_Asynch_Transmit_File_Result::socket (void) const +{ + return this->handle_; +} + +ACE_HANDLE +ACE_Uring_Asynch_Transmit_File_Result::file (void) const +{ + return this->file_; +} + +ACE_Asynch_Transmit_File::Header_And_Trailer * +ACE_Uring_Asynch_Transmit_File_Result::header_and_trailer (void) const +{ + return this->header_and_trailer_; +} + +size_t +ACE_Uring_Asynch_Transmit_File_Result::bytes_to_write (void) const +{ + return this->bytes_to_write_; +} + +size_t +ACE_Uring_Asynch_Transmit_File_Result::bytes_per_send (void) const +{ + return this->bytes_per_send_; +} + +u_long +ACE_Uring_Asynch_Transmit_File_Result::flags (void) const +{ + return this->flags_; +} + +void ACE_Uring_Asynch_Transmit_File_Result::complete (size_t bytes_transferred, int /*success*/, const void *, u_long error) +{ + this->bytes_transferred_ = bytes_transferred; + this->error_ = error; + ACE_Handler *handler = this->handler_proxy_->handler (); + if (handler) { ACE_Asynch_Transmit_File::Result result (this); handler->handle_transmit_file (result); } + delete this; +} + +ACE_Uring_Asynch_Transmit_File::ACE_Uring_Asynch_Transmit_File (ACE_Uring_Proactor *proactor) + : ACE_Uring_Asynch_Operation (proactor) {} + +int ACE_Uring_Asynch_Transmit_File::transmit_file (ACE_HANDLE file, ACE_Asynch_Transmit_File::Header_And_Trailer *header_and_trailer, size_t bytes_to_write, u_long offset, u_long offset_high, size_t bytes_per_send, u_long flags, const void *act, int, int) +{ + ACE_UNUSED_ARG (file); + ACE_UNUSED_ARG (header_and_trailer); + ACE_UNUSED_ARG (bytes_to_write); + ACE_UNUSED_ARG (offset); + ACE_UNUSED_ARG (offset_high); + ACE_UNUSED_ARG (bytes_per_send); + ACE_UNUSED_ARG (flags); + ACE_UNUSED_ARG (act); + + // The previous implementation used splice(file -> socket), which is not + // valid on Linux because one splice endpoint must be a pipe. Fail fast + // until a real async transmit-file strategy is implemented for io_uring. + errno = ENOTSUP; + ACELIB_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("ACE_Uring_Asynch_Transmit_File::transmit_file: ") + ACE_TEXT ("not supported yet\n")), + -1); +} + +ACE_END_VERSIONED_NAMESPACE_DECL + +#endif /* ACE_HAS_AIO_CALLS && ACE_HAS_IO_URING */ diff --git a/ACE/ace/Uring_Asynch_IO.h b/ACE/ace/Uring_Asynch_IO.h new file mode 100644 index 0000000000000..9fac81f8a4c2b --- /dev/null +++ b/ACE/ace/Uring_Asynch_IO.h @@ -0,0 +1,623 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file Uring_Asynch_IO.h + * + * The implementation classes for the Linux io_uring asynchronous + * operations are defined here in this file. + */ +//============================================================================= + +#ifndef ACE_URING_ASYNCH_IO_H +#define ACE_URING_ASYNCH_IO_H + +#include /**/ "ace/pre.h" + +#include /**/ "ace/config-all.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +#pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#if defined (ACE_HAS_AIO_CALLS) && defined (ACE_HAS_IO_URING) + +#include "ace/Asynch_IO_Impl.h" +#include "ace/Guard_T.h" +#include "ace/Time_Value.h" +#include "ace/Uring_Proactor.h" + +#include +#include + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +class ACE_Uring_Asynch_Operation; + +/** + * @class ACE_Uring_Asynch_Result + * + * @brief Base class for io_uring completion tokens. + * + * Concrete asynchronous result types derive from this class and adapt + * an io_uring completion back into the corresponding ACE result + * callback. + */ +class ACE_Export ACE_Uring_Asynch_Result + : public virtual ACE_Asynch_Result_Impl +{ +public: + ACE_Uring_Asynch_Result (const ACE_Handler::Proxy_Ptr &handler_proxy, + const void *act, + ACE_HANDLE handle, + u_long offset, + u_long offset_high, + ACE_Proactor *proactor); + + virtual ~ACE_Uring_Asynch_Result (void); + + virtual void complete (size_t bytes_transferred, + int success, + const void *completion_key, + u_long error = 0) = 0; + + virtual size_t bytes_transferred (void) const; + virtual void set_bytes_transferred (size_t n); + virtual u_long error (void) const; + virtual void set_error (u_long err); + virtual const void *act (void) const; + virtual int success (void) const; + virtual const void *completion_key (void) const; + virtual ACE_HANDLE event (void) const; + virtual u_long offset (void) const; + virtual u_long offset_high (void) const; + virtual int priority (void) const; + virtual int signal_number (void) const; + virtual int post_completion (ACE_Proactor_Impl *proactor); + + ACE_Handler *handler (void) const; + + void owner (ACE_Uring_Asynch_Operation *operation); + ACE_Uring_Asynch_Operation *owner (void) const; + +protected: + ACE_Handler::Proxy_Ptr handler_proxy_; + const void *act_; + ACE_HANDLE handle_; + u_long offset_; + u_long offset_high_; + ACE_Proactor *proactor_; + size_t bytes_transferred_; + u_long error_; + ACE_Uring_Asynch_Operation *owner_; +}; + +/** + * @class ACE_Uring_Asynch_Timer + * + * @brief Result object used for timer completions posted into the ring. + */ +class ACE_Export ACE_Uring_Asynch_Timer : public ACE_Uring_Asynch_Result +{ +public: + ACE_Uring_Asynch_Timer (const ACE_Handler::Proxy_Ptr &handler_proxy, + const void *act, + const ACE_Time_Value &tv, + ACE_Proactor *proactor); + + virtual void complete (size_t bytes_transferred, + int success, + const void *completion_key, + u_long error = 0); + +private: + ACE_Time_Value time_; +}; + +/** + * @class ACE_Uring_Asynch_Operation + * + * @brief Base class for io_uring-backed asynchronous operations. + */ +class ACE_Export ACE_Uring_Asynch_Operation + : public virtual ACE_Asynch_Operation_Impl +{ +public: + virtual int open (const ACE_Handler::Proxy_Ptr &handler_proxy, + ACE_HANDLE handle, + const void *completion_key, + ACE_Proactor *proactor); + + virtual int cancel (void); + virtual ACE_Proactor *proactor (void) const; + + int submit_result (ACE_Uring_Asynch_Result *result); + void register_result (ACE_Uring_Asynch_Result *result); + void unregister_result (ACE_Uring_Asynch_Result *result); + +protected: + ACE_Uring_Asynch_Operation (ACE_Uring_Proactor *proactor); + virtual ~ACE_Uring_Asynch_Operation (void); + + ACE_Uring_Proactor *uring_proactor_; + ACE_Proactor *proactor_; + ACE_Handler::Proxy_Ptr handler_proxy_; + ACE_HANDLE handle_; + ACE_Thread_Mutex pending_results_lock_; + std::set pending_results_; +}; + +// --------------------------------------------------------------------------- +// Read stream and file +// --------------------------------------------------------------------------- + +/** + * @class ACE_Uring_Asynch_Read_Stream_Result + * + * @brief io_uring implementation of the read stream/file result. + */ +class ACE_Export ACE_Uring_Asynch_Read_Stream_Result + : public ACE_Uring_Asynch_Result, + public ACE_Asynch_Read_File_Result_Impl +{ +public: + ACE_Uring_Asynch_Read_Stream_Result (const ACE_Handler::Proxy_Ptr &handler_proxy, + ACE_HANDLE handle, + ACE_Message_Block *message_block, + size_t bytes_to_read, + const void *act, + ACE_Proactor *proactor, + u_long offset = 0, + u_long offset_high = 0); + + virtual void complete (size_t bytes_transferred, + int success, + const void *completion_key, + u_long error = 0); + + virtual size_t bytes_to_read (void) const; + virtual ACE_Message_Block &message_block (void) const; + virtual ACE_HANDLE handle (void) const; + +protected: + ACE_Message_Block *message_block_; + size_t bytes_to_read_; +}; + +class ACE_Export ACE_Uring_Asynch_Read_Stream + : public ACE_Uring_Asynch_Operation, + public virtual ACE_Asynch_Read_Stream_Impl +{ +public: + ACE_Uring_Asynch_Read_Stream (ACE_Uring_Proactor *proactor); + + virtual int read (ACE_Message_Block &message_block, + size_t num_bytes_to_read, + const void *act, + int priority, + int signal_number); +}; + +class ACE_Export ACE_Uring_Asynch_Read_File + : public ACE_Uring_Asynch_Read_Stream, + public ACE_Asynch_Read_File_Impl +{ +public: + ACE_Uring_Asynch_Read_File (ACE_Uring_Proactor *proactor); + + virtual int read (ACE_Message_Block &message_block, + size_t num_bytes_to_read, + u_long offset, + u_long offset_high, + const void *act, + int priority, + int signal_number); + + virtual int read (ACE_Message_Block &message_block, + size_t num_bytes_to_read, + const void *act, + int priority, + int signal_number); +}; + +class ACE_Export ACE_Uring_Asynch_Read_File_Result + : public ACE_Uring_Asynch_Read_Stream_Result +{ +public: + ACE_Uring_Asynch_Read_File_Result (const ACE_Handler::Proxy_Ptr &handler_proxy, + ACE_HANDLE handle, + ACE_Message_Block *message_block, + size_t bytes_to_read, + const void *act, + ACE_Proactor *proactor, + u_long offset = 0, + u_long offset_high = 0); + + virtual void complete (size_t bytes_transferred, + int success, + const void *completion_key, + u_long error = 0); +}; + +// --------------------------------------------------------------------------- +// Write stream and file +// --------------------------------------------------------------------------- + +/** + * @class ACE_Uring_Asynch_Write_Stream_Result + * + * @brief io_uring implementation of the write stream/file result. + */ +class ACE_Export ACE_Uring_Asynch_Write_Stream_Result + : public ACE_Uring_Asynch_Result, + public ACE_Asynch_Write_File_Result_Impl +{ +public: + ACE_Uring_Asynch_Write_Stream_Result + (const ACE_Handler::Proxy_Ptr &handler_proxy, + ACE_HANDLE handle, + ACE_Message_Block *message_block, + size_t bytes_to_write, + const void *act, + ACE_Proactor *proactor, + u_long offset = 0, + u_long offset_high = 0); + + virtual void complete (size_t bytes_transferred, + int success, + const void *completion_key, + u_long error = 0); + + virtual size_t bytes_to_write (void) const; + virtual ACE_Message_Block &message_block (void) const; + virtual ACE_HANDLE handle (void) const; + +protected: + ACE_Message_Block *message_block_; + size_t bytes_to_write_; +}; + +class ACE_Export ACE_Uring_Asynch_Write_Stream + : public ACE_Uring_Asynch_Operation, + public virtual ACE_Asynch_Write_Stream_Impl +{ +public: + ACE_Uring_Asynch_Write_Stream (ACE_Uring_Proactor *proactor); + + virtual int write (ACE_Message_Block &message_block, + size_t bytes_to_write, + const void *act, + int priority, + int signal_number); +}; + +class ACE_Export ACE_Uring_Asynch_Write_File + : public ACE_Uring_Asynch_Write_Stream, + public ACE_Asynch_Write_File_Impl +{ +public: + ACE_Uring_Asynch_Write_File (ACE_Uring_Proactor *proactor); + + virtual int write (ACE_Message_Block &message_block, + size_t bytes_to_write, + u_long offset, + u_long offset_high, + const void *act, + int priority, + int signal_number); + + virtual int write (ACE_Message_Block &message_block, + size_t bytes_to_write, + const void *act, + int priority, + int signal_number); +}; + +class ACE_Export ACE_Uring_Asynch_Write_File_Result + : public ACE_Uring_Asynch_Write_Stream_Result +{ +public: + ACE_Uring_Asynch_Write_File_Result + (const ACE_Handler::Proxy_Ptr &handler_proxy, + ACE_HANDLE handle, + ACE_Message_Block *message_block, + size_t bytes_to_write, + const void *act, + ACE_Proactor *proactor, + u_long offset = 0, + u_long offset_high = 0); + + virtual void complete (size_t bytes_transferred, + int success, + const void *completion_key, + u_long error = 0); +}; + +// --------------------------------------------------------------------------- +// Accept and connect +// --------------------------------------------------------------------------- + +/** + * @class ACE_Uring_Asynch_Accept_Result + * + * @brief io_uring implementation of the accept result. + */ +class ACE_Export ACE_Uring_Asynch_Accept_Result + : public ACE_Uring_Asynch_Result, + public ACE_Asynch_Accept_Result_Impl +{ +public: + ACE_Uring_Asynch_Accept_Result (const ACE_Handler::Proxy_Ptr &handler_proxy, + ACE_HANDLE listen_handle, + ACE_HANDLE accept_handle, + ACE_Message_Block *message_block, + size_t bytes_to_read, + const void *act, + ACE_Proactor *proactor); + + virtual void complete (size_t bytes_transferred, + int success, + const void *completion_key, + u_long error = 0); + + virtual ACE_HANDLE accept_handle (void) const; + virtual ACE_Message_Block &message_block (void) const; + virtual ACE_HANDLE listen_handle (void) const; + virtual size_t bytes_to_read (void) const; + + struct sockaddr *addr (void); + socklen_t *addrlen (void); + +private: + ACE_HANDLE accept_handle_; + ACE_Message_Block *message_block_; + size_t bytes_to_read_; + struct sockaddr_storage client_addr_; + socklen_t addr_len_; +}; + +class ACE_Export ACE_Uring_Asynch_Accept + : public ACE_Uring_Asynch_Operation, + public ACE_Asynch_Accept_Impl +{ +public: + ACE_Uring_Asynch_Accept (ACE_Uring_Proactor *proactor); + + virtual int accept (ACE_Message_Block &message_block, + size_t bytes_to_read, + ACE_HANDLE accept_handle, + const void *act, + int priority, + int signal_number, + int addr_family); +}; + +class ACE_Export ACE_Uring_Asynch_Connect_Result + : public ACE_Uring_Asynch_Result, + public ACE_Asynch_Connect_Result_Impl +{ +public: + ACE_Uring_Asynch_Connect_Result (const ACE_Handler::Proxy_Ptr &handler_proxy, + ACE_HANDLE connect_handle, + const void *act, + ACE_Proactor *proactor); + + virtual void complete (size_t bytes_transferred, + int success, + const void *completion_key, + u_long error = 0); + + virtual ACE_HANDLE connect_handle (void) const; + void connect_handle (ACE_HANDLE handle); + +private: + ACE_HANDLE connect_handle_; +}; + +class ACE_Export ACE_Uring_Asynch_Connect + : public ACE_Uring_Asynch_Operation, + public ACE_Asynch_Connect_Impl +{ +public: + ACE_Uring_Asynch_Connect (ACE_Uring_Proactor *proactor); + + virtual int open (const ACE_Handler::Proxy_Ptr &handler_proxy, + ACE_HANDLE handle, + const void *completion_key, + ACE_Proactor *proactor); + + virtual int connect (ACE_HANDLE connect_handle, + const ACE_Addr &remote_sap, + const ACE_Addr &local_sap, + int reuse_addr, + const void *act, + int priority, + int signal_number); +}; + +// --------------------------------------------------------------------------- +// Datagram (UDP) +// --------------------------------------------------------------------------- + +/** + * @class ACE_Uring_Asynch_Read_Dgram_Result + * + * @brief io_uring implementation of the datagram read result. + */ +class ACE_Export ACE_Uring_Asynch_Read_Dgram_Result + : public ACE_Uring_Asynch_Result, + public ACE_Asynch_Read_Dgram_Result_Impl +{ +public: + ACE_Uring_Asynch_Read_Dgram_Result + (const ACE_Handler::Proxy_Ptr &handler_proxy, + ACE_HANDLE handle, + ACE_Message_Block *message_block, + size_t bytes_to_read, + int flags, + int protocol_family, + const void *act, + ACE_Proactor *proactor); + + virtual void complete (size_t bytes_transferred, + int success, + const void *completion_key, + u_long error = 0); + + virtual ACE_Message_Block *message_block (void) const; + virtual int remote_address (ACE_Addr &addr) const; + virtual int flags (void) const; + virtual ACE_HANDLE handle (void) const; + virtual size_t bytes_to_read (void) const; + + struct msghdr *msg (void); + +private: + ACE_Message_Block *message_block_; + size_t bytes_to_read_; + int flags_; + struct msghdr msg_; + struct iovec iov_; + struct sockaddr_storage remote_addr_; +}; + +class ACE_Export ACE_Uring_Asynch_Read_Dgram + : public ACE_Uring_Asynch_Operation, + public ACE_Asynch_Read_Dgram_Impl +{ +public: + ACE_Uring_Asynch_Read_Dgram (ACE_Uring_Proactor *proactor); + + virtual ssize_t recv (ACE_Message_Block *message_block, + size_t &number_of_bytes_recvd, + int flags, + int protocol_family, + const void *act, + int priority, + int signal_number); +}; + +class ACE_Export ACE_Uring_Asynch_Write_Dgram_Result + : public ACE_Uring_Asynch_Result, + public ACE_Asynch_Write_Dgram_Result_Impl +{ +public: + ACE_Uring_Asynch_Write_Dgram_Result + (const ACE_Handler::Proxy_Ptr &handler_proxy, + ACE_HANDLE handle, + ACE_Message_Block *message_block, + size_t bytes_to_write, + int flags, + const void *act, + ACE_Proactor *proactor); + + virtual void complete (size_t bytes_transferred, + int success, + const void *completion_key, + u_long error = 0); + + virtual ACE_Message_Block *message_block (void) const; + virtual int flags (void) const; + virtual ACE_HANDLE handle (void) const; + virtual size_t bytes_to_write (void) const; + + struct msghdr *msg (void); + +private: + ACE_Message_Block *message_block_; + size_t bytes_to_write_; + int flags_; + struct msghdr msg_; + struct iovec iov_; +}; + +class ACE_Export ACE_Uring_Asynch_Write_Dgram + : public ACE_Uring_Asynch_Operation, + public ACE_Asynch_Write_Dgram_Impl +{ +public: + ACE_Uring_Asynch_Write_Dgram (ACE_Uring_Proactor *proactor); + + virtual ssize_t send (ACE_Message_Block *message_block, + size_t &number_of_bytes_sent, + int flags, + const ACE_Addr &remote_addr, + const void *act, + int priority, + int signal_number); +}; + +// --------------------------------------------------------------------------- +// Transmit file +// --------------------------------------------------------------------------- + +/** + * @class ACE_Uring_Asynch_Transmit_File_Result + * + * @brief io_uring implementation of the transmit file result. + */ +class ACE_Export ACE_Uring_Asynch_Transmit_File_Result + : public ACE_Uring_Asynch_Result, + public ACE_Asynch_Transmit_File_Result_Impl +{ +public: + ACE_Uring_Asynch_Transmit_File_Result + (const ACE_Handler::Proxy_Ptr &handler_proxy, + ACE_HANDLE socket, + ACE_HANDLE file, + ACE_Asynch_Transmit_File::Header_And_Trailer *header_and_trailer, + size_t bytes_to_write, + u_long offset, + u_long offset_high, + size_t bytes_per_send, + u_long flags, + const void *act, + ACE_Proactor *proactor); + + virtual void complete (size_t bytes_transferred, + int success, + const void *completion_key, + u_long error = 0); + + virtual ACE_HANDLE socket (void) const; + virtual ACE_HANDLE file (void) const; + virtual ACE_Asynch_Transmit_File::Header_And_Trailer * + header_and_trailer (void) const; + virtual size_t bytes_to_write (void) const; + virtual size_t bytes_per_send (void) const; + virtual u_long flags (void) const; + +private: + ACE_HANDLE file_; + ACE_Asynch_Transmit_File::Header_And_Trailer *header_and_trailer_; + size_t bytes_to_write_; + size_t bytes_per_send_; + u_long flags_; +}; + +class ACE_Export ACE_Uring_Asynch_Transmit_File + : public ACE_Uring_Asynch_Operation, + public ACE_Asynch_Transmit_File_Impl +{ +public: + ACE_Uring_Asynch_Transmit_File (ACE_Uring_Proactor *proactor); + + virtual int transmit_file + (ACE_HANDLE file, + ACE_Asynch_Transmit_File::Header_And_Trailer *header_and_trailer, + size_t bytes_to_write, + u_long offset, + u_long offset_high, + size_t bytes_per_send, + u_long flags, + const void *act, + int priority, + int signal_number); +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#endif /* ACE_HAS_AIO_CALLS && ACE_HAS_IO_URING */ + +#include /**/ "ace/post.h" +#endif /* ACE_URING_ASYNCH_IO_H */ diff --git a/ACE/ace/Uring_Proactor.cpp b/ACE/ace/Uring_Proactor.cpp new file mode 100644 index 0000000000000..a80eed8d10844 --- /dev/null +++ b/ACE/ace/Uring_Proactor.cpp @@ -0,0 +1,448 @@ +//============================================================================= +/** + * @file Uring_Proactor.cpp + * + * The Linux io_uring Proactor implementation. + */ +//============================================================================= + +#include "Uring_Proactor.h" + +#if defined (ACE_HAS_AIO_CALLS) && defined (ACE_HAS_IO_URING) + +#include "Uring_Asynch_IO.h" +#include "ace/Countdown_Time.h" +#include "ace/Log_Category.h" +#include "ace/OS_NS_errno.h" +#include "ace/OS_NS_sys_time.h" +#include + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_Uring_Proactor::ACE_Uring_Proactor (size_t entries) + : is_initialized_ (false) +{ + ACE_TRACE ("ACE_Uring_Proactor::ACE_Uring_Proactor"); + + int ret = ::io_uring_queue_init (entries, &this->ring_, 0); + if (ret < 0) + { + errno = -ret; + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("ACE_Uring_Proactor::io_uring_queue_init"))); + } + else + { + this->is_initialized_ = true; + } +} + +ACE_Uring_Proactor::~ACE_Uring_Proactor (void) +{ + ACE_TRACE ("ACE_Uring_Proactor::~ACE_Uring_Proactor"); + this->close (); +} + +int +ACE_Uring_Proactor::close (void) +{ + if (this->is_initialized_) + { + ::io_uring_queue_exit (&this->ring_); + this->is_initialized_ = false; + } + return 0; +} + +int +ACE_Uring_Proactor::register_handle (ACE_HANDLE, const void *) +{ + return 0; +} + +int +ACE_Uring_Proactor::handle_events (ACE_Time_Value &wait_time) +{ + ACE_Countdown_Time countdown (&wait_time); + return this->process_cqes (32, &wait_time); +} + +int +ACE_Uring_Proactor::handle_events (void) +{ + return this->process_cqes (32); +} + +int +ACE_Uring_Proactor::wake_up_dispatch_threads (void) +{ + return 0; +} + +int +ACE_Uring_Proactor::close_dispatch_threads (int) +{ + return 0; +} + +size_t +ACE_Uring_Proactor::number_of_threads (void) const +{ + return 1; +} + +void +ACE_Uring_Proactor::number_of_threads (size_t) +{ +} + +ACE_HANDLE +ACE_Uring_Proactor::get_handle (void) const +{ + return ACE_INVALID_HANDLE; +} + +int +ACE_Uring_Proactor::process_cqes (int max_to_process, const ACE_Time_Value *wait_time) +{ + if (!this->is_initialized_) + return -1; + + if (max_to_process < 1) + max_to_process = 1; + + int processed = 0; + std::set dispatched_handlers; + + while (processed < max_to_process) + { + ACE_Uring_Asynch_Result *result = 0; + size_t bytes_transferred = 0; + int error = 0; + int ret = 0; + bool should_wait = (processed == 0); + + { + ACE_GUARD (ACE_Thread_Mutex, guard, this->cq_mutex_); + struct io_uring_cqe *cqe = 0; + + if (should_wait) + { + if (wait_time != 0) + { + if (*wait_time == ACE_Time_Value::zero) + ret = ::io_uring_peek_cqe (&this->ring_, &cqe); + else + { + ACE_Time_Value local_wait_time = *wait_time; + struct __kernel_timespec timeout; + timeout.tv_sec = local_wait_time.sec (); + timeout.tv_nsec = local_wait_time.usec () * 1000; + ret = ::io_uring_wait_cqe_timeout (&this->ring_, + &cqe, + const_cast<__kernel_timespec *> (&timeout)); + } + } + else + { + ret = ::io_uring_wait_cqe (&this->ring_, &cqe); + } + } + else + { + ret = ::io_uring_peek_cqe (&this->ring_, &cqe); + } + + if (ret < 0) + { + if (ret == -ETIME || ret == -EAGAIN || ret == -EINTR) + return processed; + + errno = -ret; + return -1; + } + + result = + static_cast (io_uring_cqe_get_data (cqe)); + + if (result != 0) + { + const void *handler = result->handler (); + if (handler != 0 + && dispatched_handlers.find (handler) != dispatched_handlers.end ()) + return processed; + + if (result->owner () != 0) + result->owner ()->unregister_result (result); + } + + error = (cqe->res < 0) ? -cqe->res : 0; + bytes_transferred = (cqe->res > 0) ? cqe->res : 0; + ::io_uring_cqe_seen (&this->ring_, cqe); + } + + ++processed; + + if (result != 0) + { + ACE_Handler *handler = result->handler (); + if (handler != 0) + dispatched_handlers.insert (handler); + + result->complete (bytes_transferred, + error == 0 ? 1 : 0, + 0, + error); + } + } + + return processed; +} + +ACE_Thread_Mutex & +ACE_Uring_Proactor::sq_mutex (void) +{ + return this->sq_mutex_; +} + +struct io_uring_sqe * +ACE_Uring_Proactor::get_sqe (void) +{ + return ::io_uring_get_sqe (&this->ring_); +} + +int +ACE_Uring_Proactor::submit_sqe (void) +{ + return ::io_uring_submit (&this->ring_); +} + +int +ACE_Uring_Proactor::submit_pending_sqe (void) +{ + if (::io_uring_sq_ready (&this->ring_) == 0) + return 0; + + return ::io_uring_submit (&this->ring_); +} + +ACE_Asynch_Read_Stream_Impl *ACE_Uring_Proactor::create_asynch_read_stream (void) +{ + ACE_Uring_Asynch_Read_Stream *ret = 0; + ACE_NEW_RETURN (ret, ACE_Uring_Asynch_Read_Stream (this), 0); + return ret; +} + +ACE_Asynch_Write_Stream_Impl *ACE_Uring_Proactor::create_asynch_write_stream (void) +{ + ACE_Uring_Asynch_Write_Stream *ret = 0; + ACE_NEW_RETURN (ret, ACE_Uring_Asynch_Write_Stream (this), 0); + return ret; +} + +ACE_Asynch_Read_File_Impl *ACE_Uring_Proactor::create_asynch_read_file (void) +{ + ACE_Uring_Asynch_Read_File *ret = 0; + ACE_NEW_RETURN (ret, ACE_Uring_Asynch_Read_File (this), 0); + return ret; +} + +ACE_Asynch_Write_File_Impl *ACE_Uring_Proactor::create_asynch_write_file (void) +{ + ACE_Uring_Asynch_Write_File *ret = 0; + ACE_NEW_RETURN (ret, ACE_Uring_Asynch_Write_File (this), 0); + return ret; +} + +ACE_Asynch_Accept_Impl *ACE_Uring_Proactor::create_asynch_accept (void) +{ + ACE_Uring_Asynch_Accept *ret = 0; + ACE_NEW_RETURN (ret, ACE_Uring_Asynch_Accept (this), 0); + return ret; +} + +ACE_Asynch_Connect_Impl *ACE_Uring_Proactor::create_asynch_connect (void) +{ + ACE_Uring_Asynch_Connect *ret = 0; + ACE_NEW_RETURN (ret, ACE_Uring_Asynch_Connect (this), 0); + return ret; +} + +ACE_Asynch_Transmit_File_Impl *ACE_Uring_Proactor::create_asynch_transmit_file (void) +{ + ACE_Uring_Asynch_Transmit_File *ret = 0; + ACE_NEW_RETURN (ret, ACE_Uring_Asynch_Transmit_File (this), 0); + return ret; +} + +ACE_Asynch_Read_Dgram_Impl *ACE_Uring_Proactor::create_asynch_read_dgram (void) +{ + ACE_Uring_Asynch_Read_Dgram *ret = 0; + ACE_NEW_RETURN (ret, ACE_Uring_Asynch_Read_Dgram (this), 0); + return ret; +} + +ACE_Asynch_Write_Dgram_Impl *ACE_Uring_Proactor::create_asynch_write_dgram (void) +{ + ACE_Uring_Asynch_Write_Dgram *ret = 0; + ACE_NEW_RETURN (ret, ACE_Uring_Asynch_Write_Dgram (this), 0); + return ret; +} + +ACE_Asynch_Read_Stream_Result_Impl * +ACE_Uring_Proactor::create_asynch_read_stream_result + (const ACE_Handler::Proxy_Ptr &handler_proxy, + ACE_HANDLE handle, + ACE_Message_Block &message_block, + size_t bytes_to_read, + const void *act, + ACE_HANDLE, + int, + int) +{ + ACE_Uring_Asynch_Read_Stream_Result *ret = 0; + ACE_NEW_RETURN (ret, + ACE_Uring_Asynch_Read_Stream_Result (handler_proxy, + handle, + &message_block, + bytes_to_read, + act, + 0), + 0); + return ret; +} + +ACE_Asynch_Write_Stream_Result_Impl * +ACE_Uring_Proactor::create_asynch_write_stream_result + (const ACE_Handler::Proxy_Ptr &handler_proxy, + ACE_HANDLE handle, + ACE_Message_Block &message_block, + size_t bytes_to_write, + const void *act, + ACE_HANDLE, + int, + int) +{ + ACE_Uring_Asynch_Write_Stream_Result *ret = 0; + ACE_NEW_RETURN (ret, + ACE_Uring_Asynch_Write_Stream_Result (handler_proxy, + handle, + &message_block, + bytes_to_write, + act, + 0), + 0); + return ret; +} + +ACE_Asynch_Read_File_Result_Impl * +ACE_Uring_Proactor::create_asynch_read_file_result + (const ACE_Handler::Proxy_Ptr &handler_proxy, + ACE_HANDLE handle, + ACE_Message_Block &message_block, + size_t bytes_to_read, + const void *act, + u_long offset, + u_long offset_high, + ACE_HANDLE, + int, + int) +{ + ACE_Uring_Asynch_Read_File_Result *ret = 0; + ACE_NEW_RETURN (ret, + ACE_Uring_Asynch_Read_File_Result (handler_proxy, + handle, + &message_block, + bytes_to_read, + act, + 0, + offset, + offset_high), + 0); + return ret; +} + +ACE_Asynch_Write_File_Result_Impl * +ACE_Uring_Proactor::create_asynch_write_file_result + (const ACE_Handler::Proxy_Ptr &handler, + ACE_HANDLE handle, + ACE_Message_Block &message_block, + size_t bytes_to_write, + const void *act, + u_long offset, + u_long offset_high, + ACE_HANDLE, + int, + int) +{ + ACE_Uring_Asynch_Write_File_Result *ret = 0; + ACE_NEW_RETURN (ret, ACE_Uring_Asynch_Write_File_Result (handler, handle, &message_block, bytes_to_write, act, 0, offset, offset_high), 0); + return ret; +} + +ACE_Asynch_Read_Dgram_Result_Impl * +ACE_Uring_Proactor::create_asynch_read_dgram_result (const ACE_Handler::Proxy_Ptr &handler_proxy, ACE_HANDLE handle, ACE_Message_Block *message_block, size_t bytes_to_read, int flags, int protocol_family, const void* act, ACE_HANDLE, int, int) +{ + ACE_Uring_Asynch_Read_Dgram_Result *ret = 0; + ACE_NEW_RETURN (ret, ACE_Uring_Asynch_Read_Dgram_Result (handler_proxy, handle, message_block, bytes_to_read, flags, protocol_family, act, 0), 0); + return ret; +} + +ACE_Asynch_Write_Dgram_Result_Impl * +ACE_Uring_Proactor::create_asynch_write_dgram_result (const ACE_Handler::Proxy_Ptr &handler_proxy, ACE_HANDLE handle, ACE_Message_Block *message_block, size_t bytes_to_write, int flags, const void* act, ACE_HANDLE, int, int) +{ + ACE_Uring_Asynch_Write_Dgram_Result *ret = 0; + ACE_NEW_RETURN (ret, ACE_Uring_Asynch_Write_Dgram_Result (handler_proxy, handle, message_block, bytes_to_write, flags, act, 0), 0); + return ret; +} + +ACE_Asynch_Accept_Result_Impl * +ACE_Uring_Proactor::create_asynch_accept_result (const ACE_Handler::Proxy_Ptr &handler_proxy, ACE_HANDLE listen_handle, ACE_HANDLE accept_handle, ACE_Message_Block &message_block, size_t bytes_to_read, const void* act, ACE_HANDLE, int, int) +{ + ACE_Uring_Asynch_Accept_Result *ret = 0; + ACE_NEW_RETURN (ret, ACE_Uring_Asynch_Accept_Result (handler_proxy, listen_handle, accept_handle, &message_block, bytes_to_read, act, 0), 0); + return ret; +} + +ACE_Asynch_Connect_Result_Impl * +ACE_Uring_Proactor::create_asynch_connect_result (const ACE_Handler::Proxy_Ptr &handler_proxy, ACE_HANDLE connect_handle, const void* act, ACE_HANDLE, int, int) +{ + ACE_Uring_Asynch_Connect_Result *ret = 0; + ACE_NEW_RETURN (ret, ACE_Uring_Asynch_Connect_Result (handler_proxy, connect_handle, act, 0), 0); + return ret; +} + +ACE_Asynch_Transmit_File_Result_Impl * +ACE_Uring_Proactor::create_asynch_transmit_file_result (const ACE_Handler::Proxy_Ptr &handler_proxy, ACE_HANDLE socket, ACE_HANDLE file, ACE_Asynch_Transmit_File::Header_And_Trailer *header_and_trailer, size_t bytes_to_write, u_long offset, u_long offset_high, size_t bytes_per_send, u_long flags, const void *act, ACE_HANDLE, int, int) +{ + ACE_Uring_Asynch_Transmit_File_Result *ret = 0; + ACE_NEW_RETURN (ret, ACE_Uring_Asynch_Transmit_File_Result (handler_proxy, socket, file, header_and_trailer, bytes_to_write, offset, offset_high, bytes_per_send, flags, act, 0), 0); + return ret; +} + +ACE_Asynch_Result_Impl * +ACE_Uring_Proactor::create_asynch_timer (const ACE_Handler::Proxy_Ptr &handler_proxy, const void *act, const ACE_Time_Value &tv, ACE_HANDLE, int, int) +{ + ACE_Uring_Asynch_Timer *ret = 0; + ACE_NEW_RETURN (ret, ACE_Uring_Asynch_Timer (handler_proxy, act, tv, 0), 0); + return ret; +} + +int +ACE_Uring_Proactor::post_wakeup_completions (int count) +{ + ACE_GUARD (ACE_Thread_Mutex, guard, this->sq_mutex_); + for (int i = 0; i < count; ++i) + { + struct io_uring_sqe *sqe = ::io_uring_get_sqe (&this->ring_); + if (!sqe) break; + ::io_uring_prep_nop (sqe); + ::io_uring_sqe_set_data (sqe, 0); + } + return ::io_uring_submit (&this->ring_); +} + +ACE_END_VERSIONED_NAMESPACE_DECL + +#endif /* ACE_HAS_AIO_CALLS && ACE_HAS_IO_URING */ diff --git a/ACE/ace/Uring_Proactor.h b/ACE/ace/Uring_Proactor.h new file mode 100644 index 0000000000000..f09cf945236ad --- /dev/null +++ b/ACE/ace/Uring_Proactor.h @@ -0,0 +1,211 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file Uring_Proactor.h + * + * The implementation classes for the Linux io_uring Proactor are + * defined here in this file. + */ +//============================================================================= + +#ifndef ACE_URING_PROACTOR_H +#define ACE_URING_PROACTOR_H + +#include /**/ "ace/pre.h" + +#include /**/ "ace/config-all.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +#pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#if defined (ACE_HAS_AIO_CALLS) && defined (ACE_HAS_IO_URING) + +#include "ace/Proactor_Impl.h" +#include "ace/Thread_Mutex.h" + +#include + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +class ACE_Uring_Asynch_Result; + +/** + * @class ACE_Uring_Proactor + * + * @brief Linux io_uring implementation of the Proactor. + * + * This class provides the factory methods and completion dispatch + * support needed by the ACE asynchronous operation classes when the + * backend is implemented on top of Linux io_uring. + */ +class ACE_Export ACE_Uring_Proactor : public ACE_Proactor_Impl +{ +public: + ACE_Uring_Proactor (size_t entries = 256); + virtual ~ACE_Uring_Proactor (void); + + virtual int close (void); + + virtual int register_handle (ACE_HANDLE handle, + const void *completion_key); + + virtual int handle_events (ACE_Time_Value &wait_time); + virtual int handle_events (void); + + virtual int wake_up_dispatch_threads (void); + virtual int close_dispatch_threads (int wait); + virtual size_t number_of_threads (void) const; + virtual void number_of_threads (size_t threads); + virtual ACE_HANDLE get_handle (void) const; + + // Methods used to create Asynch I/O factory and result objects. + + virtual ACE_Asynch_Read_Stream_Impl *create_asynch_read_stream (void); + virtual ACE_Asynch_Write_Stream_Impl *create_asynch_write_stream (void); + virtual ACE_Asynch_Read_File_Impl *create_asynch_read_file (void); + virtual ACE_Asynch_Write_File_Impl *create_asynch_write_file (void); + virtual ACE_Asynch_Accept_Impl *create_asynch_accept (void); + virtual ACE_Asynch_Connect_Impl *create_asynch_connect (void); + virtual ACE_Asynch_Transmit_File_Impl *create_asynch_transmit_file (void); + virtual ACE_Asynch_Read_Dgram_Impl *create_asynch_read_dgram (void); + virtual ACE_Asynch_Write_Dgram_Impl *create_asynch_write_dgram (void); + + virtual ACE_Asynch_Read_Stream_Result_Impl * + create_asynch_read_stream_result (const ACE_Handler::Proxy_Ptr &handler_proxy, + ACE_HANDLE handle, + ACE_Message_Block &message_block, + size_t bytes_to_read, + const void *act, + ACE_HANDLE event = ACE_INVALID_HANDLE, + int priority = 0, + int signal_number = ACE_SIGRTMIN); + + virtual ACE_Asynch_Write_Stream_Result_Impl * + create_asynch_write_stream_result (const ACE_Handler::Proxy_Ptr &handler_proxy, + ACE_HANDLE handle, + ACE_Message_Block &message_block, + size_t bytes_to_write, + const void *act, + ACE_HANDLE event = ACE_INVALID_HANDLE, + int priority = 0, + int signal_number = ACE_SIGRTMIN); + + virtual ACE_Asynch_Read_File_Result_Impl * + create_asynch_read_file_result (const ACE_Handler::Proxy_Ptr &handler_proxy, + ACE_HANDLE handle, + ACE_Message_Block &message_block, + size_t bytes_to_read, + const void *act, + u_long offset, + u_long offset_high, + ACE_HANDLE event = ACE_INVALID_HANDLE, + int priority = 0, + int signal_number = ACE_SIGRTMIN); + + virtual ACE_Asynch_Write_File_Result_Impl * + create_asynch_write_file_result (const ACE_Handler::Proxy_Ptr &handler_proxy, + ACE_HANDLE handle, + ACE_Message_Block &message_block, + size_t bytes_to_write, + const void *act, + u_long offset, + u_long offset_high, + ACE_HANDLE event = ACE_INVALID_HANDLE, + int priority = 0, + int signal_number = ACE_SIGRTMIN); + + virtual ACE_Asynch_Read_Dgram_Result_Impl * + create_asynch_read_dgram_result (const ACE_Handler::Proxy_Ptr &handler_proxy, + ACE_HANDLE handle, + ACE_Message_Block *message_block, + size_t bytes_to_read, + int flags, + int protocol_family, + const void *act, + ACE_HANDLE event = ACE_INVALID_HANDLE, + int priority = 0, + int signal_number = ACE_SIGRTMIN); + + virtual ACE_Asynch_Write_Dgram_Result_Impl * + create_asynch_write_dgram_result (const ACE_Handler::Proxy_Ptr &handler_proxy, + ACE_HANDLE handle, + ACE_Message_Block *message_block, + size_t bytes_to_write, + int flags, + const void *act, + ACE_HANDLE event = ACE_INVALID_HANDLE, + int priority = 0, + int signal_number = ACE_SIGRTMIN); + + virtual ACE_Asynch_Accept_Result_Impl * + create_asynch_accept_result (const ACE_Handler::Proxy_Ptr &handler_proxy, + ACE_HANDLE listen_handle, + ACE_HANDLE accept_handle, + ACE_Message_Block &message_block, + size_t bytes_to_read, + const void *act, + ACE_HANDLE event = ACE_INVALID_HANDLE, + int priority = 0, + int signal_number = ACE_SIGRTMIN); + + virtual ACE_Asynch_Connect_Result_Impl * + create_asynch_connect_result (const ACE_Handler::Proxy_Ptr &handler_proxy, + ACE_HANDLE connect_handle, + const void *act, + ACE_HANDLE event = ACE_INVALID_HANDLE, + int priority = 0, + int signal_number = ACE_SIGRTMIN); + + virtual ACE_Asynch_Transmit_File_Result_Impl * + create_asynch_transmit_file_result + (const ACE_Handler::Proxy_Ptr &handler_proxy, + ACE_HANDLE socket, + ACE_HANDLE file, + ACE_Asynch_Transmit_File::Header_And_Trailer *header_and_trailer, + size_t bytes_to_write, + u_long offset, + u_long offset_high, + size_t bytes_per_send, + u_long flags, + const void *act, + ACE_HANDLE event = ACE_INVALID_HANDLE, + int priority = 0, + int signal_number = ACE_SIGRTMIN); + + virtual ACE_Asynch_Result_Impl * + create_asynch_timer (const ACE_Handler::Proxy_Ptr &handler_proxy, + const void *act, + const ACE_Time_Value &tv, + ACE_HANDLE event = ACE_INVALID_HANDLE, + int priority = 0, + int signal_number = 0); + + virtual int post_wakeup_completions (int how_many); + + /// Serialize SQE preparation and submission. + ACE_Thread_Mutex &sq_mutex (void); + + /// Access to the underlying ring for operation implementations. + struct io_uring_sqe *get_sqe (void); + int submit_sqe (void); + int submit_pending_sqe (void); + +protected: + int process_cqes (int max_to_process, + const ACE_Time_Value *wait_time = 0); + +private: + struct io_uring ring_; + bool is_initialized_; + mutable ACE_Thread_Mutex sq_mutex_; + mutable ACE_Thread_Mutex cq_mutex_; +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#endif /* ACE_HAS_AIO_CALLS && ACE_HAS_IO_URING */ + +#include /**/ "ace/post.h" +#endif /* ACE_URING_PROACTOR_H */ diff --git a/ACE/ace/ace.mpc b/ACE/ace/ace.mpc index f1e84d4019836..c6808bceaa6b7 100644 --- a/ACE/ace/ace.mpc +++ b/ACE/ace/ace.mpc @@ -279,6 +279,8 @@ project(ACE) : ace_output, acedefaults, install, other, codecs, token, svcconf, UPIPE_Acceptor.cpp UPIPE_Connector.cpp UPIPE_Stream.cpp + Uring_Asynch_IO.cpp + Uring_Proactor.cpp WFMO_Reactor.cpp WIN32_Asynch_IO.cpp WIN32_Proactor.cpp @@ -465,6 +467,11 @@ project(ACE) : ace_output, acedefaults, install, other, codecs, token, svcconf, Timer_Wheel.h Truncate.h UPIPE_Addr.h + Uring_Asynch_IO.h + Uring_Proactor.h + WFMO_Reactor.h + WIN32_Asynch_IO.h + WIN32_Proactor.h Value_Ptr.h Version.h Versioned_Namespace.h diff --git a/ACE/include/makeinclude/platform_linux.GNU b/ACE/include/makeinclude/platform_linux.GNU index 52d4a5bfc54de..99b0da19b9778 100644 --- a/ACE/include/makeinclude/platform_linux.GNU +++ b/ACE/include/makeinclude/platform_linux.GNU @@ -69,6 +69,10 @@ ifeq ($(threads),1) LIBS += -lrt endif +ifeq ($(uring),1) + LIBS += -luring +endif + ifeq ($(optimize),1) SOFLAGS += -Wl,-O3 endif diff --git a/ACE/tests/Proactor_Contract_Test.cpp b/ACE/tests/Proactor_Contract_Test.cpp new file mode 100644 index 0000000000000..ca2231ec5e37b --- /dev/null +++ b/ACE/tests/Proactor_Contract_Test.cpp @@ -0,0 +1,741 @@ +// ============================================================================ +/** + * @file Proactor_Contract_Test.cpp + * + * Focused regression coverage for common ACE Proactor contracts and + * backend-specific edge cases. + */ +// ============================================================================ + +#include "test_config.h" + +#if defined (ACE_HAS_WIN32_OVERLAPPED_IO) || defined (ACE_HAS_AIO_CALLS) + +#include "ace/Asynch_IO.h" +#include "ace/FILE_Connector.h" +#include "ace/FILE_IO.h" +#include "ace/Get_Opt.h" +#include "ace/INET_Addr.h" +#include "ace/Message_Block.h" +#include "ace/OS_NS_dirent.h" +#include "ace/OS_NS_errno.h" +#include "ace/OS_NS_fcntl.h" +#include "ace/OS_NS_sys_socket.h" +#include "ace/OS_NS_unistd.h" +#include "ace/Proactor.h" +#include "ace/SOCK_Acceptor.h" +#include "ace/SOCK_Connector.h" +#include "ace/SOCK_Stream.h" +#include "ace/Time_Value.h" +#include "Proactor_Test_Backend.h" + +namespace +{ + Proactor_Test_Backend::Type proactor_type = Proactor_Test_Backend::BACKEND_DEFAULT; + + class Accept_Handler : public ACE_Handler + { + public: + Accept_Handler (void) + : done_ (false) + , success_ (false) + , bytes_transferred_ (static_cast (-1)) + , accept_handle_ (ACE_INVALID_HANDLE) + , error_ (0) + { + } + + virtual void handle_accept (const ACE_Asynch_Accept::Result &result) + { + this->done_ = true; + this->success_ = result.success () != 0; + this->bytes_transferred_ = result.bytes_transferred (); + this->accept_handle_ = result.accept_handle (); + this->error_ = result.error (); + } + + bool done_; + bool success_; + size_t bytes_transferred_; + ACE_HANDLE accept_handle_; + u_long error_; + }; + + class Dummy_Handler : public ACE_Handler + { + }; + + class Connect_Handler : public ACE_Handler + { + public: + Connect_Handler (void) + : done_ (false) + , success_ (false) + , connect_handle_ (ACE_INVALID_HANDLE) + , error_ (0) + { + } + + virtual void handle_connect (const ACE_Asynch_Connect::Result &result) + { + this->done_ = true; + this->success_ = result.success () != 0; + this->connect_handle_ = result.connect_handle (); + this->error_ = result.error (); + } + + bool done_; + bool success_; + ACE_HANDLE connect_handle_; + u_long error_; + }; + + class Transmit_Handler : public ACE_Handler + { + public: + Transmit_Handler (void) + : done_ (false) + , success_ (false) + , bytes_transferred_ (0) + , error_ (0) + { + } + + virtual void handle_transmit_file (const ACE_Asynch_Transmit_File::Result &result) + { + this->done_ = true; + this->success_ = result.success () != 0; + this->bytes_transferred_ = result.bytes_transferred (); + this->error_ = result.error (); + } + + bool done_; + bool success_; + size_t bytes_transferred_; + u_long error_; + }; + + size_t + count_open_fds (void) + { +#if defined (ACE_WIN32) + return 0; +#else + size_t count = 0; + ACE_DIR *dir = ACE_OS::opendir (ACE_TEXT ("/proc/self/fd")); + if (dir == 0) + return 0; + + for (ACE_DIRENT *entry = ACE_OS::readdir (dir); + entry != 0; + entry = ACE_OS::readdir (dir)) + { + if (ACE_OS::strcmp (entry->d_name, ".") != 0 + && ACE_OS::strcmp (entry->d_name, "..") != 0) + ++count; + } + + ACE_OS::closedir (dir); + return count; +#endif /* ACE_WIN32 */ + } + + int + parse_args (int argc, ACE_TCHAR *argv[]) + { + ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("t:")); + int c = 0; + + while ((c = get_opt ()) != EOF) + { + switch (c) + { + case 't': + if (Proactor_Test_Backend::parse_type (get_opt.opt_arg (), proactor_type) == 0) + break; + return -1; + default: + return -1; + } + } + + return 0; + } + + int + run_accept_contract_test (ACE_Proactor &proactor) + { + ACE_SOCK_Acceptor listen_socket; + ACE_INET_Addr listen_addr ((u_short) 0, ACE_LOCALHOST); + + if (listen_socket.open (listen_addr, 1) != 0) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("listen_socket.open")), + -1); + } + + if (listen_socket.get_local_addr (listen_addr) != 0) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("listen_socket.get_local_addr")), + -1); + } + + Accept_Handler handler; + ACE_Asynch_Accept acceptor; + if (acceptor.open (handler, listen_socket.get_handle (), 0, &proactor) != 0) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("ACE_Asynch_Accept::open")), + -1); + } + + ACE_Message_Block mb (1024); + if (acceptor.accept (mb, 0, ACE_INVALID_HANDLE, 0, 0, ACE_SIGRTMIN, AF_INET) != 0) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("ACE_Asynch_Accept::accept")), + -1); + } + + ACE_Time_Value zero = ACE_Time_Value::zero; + const int empty_poll = proactor.handle_events (zero); + if (empty_poll != 0) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("Expected empty zero-timeout poll to return 0; got %d\n"), + empty_poll)); + return -1; + } + + ACE_SOCK_Connector sock_connector; + ACE_SOCK_Stream client_stream; + if (sock_connector.connect (client_stream, listen_addr) != 0) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("connector.connect")), + -1); + } + + const ACE_Time_Value deadline = ACE_OS::gettimeofday () + ACE_Time_Value (5); + while (!handler.done_ && ACE_OS::gettimeofday () < deadline) + { + ACE_Time_Value poll_timeout = ACE_Time_Value::zero; + const int result = proactor.handle_events (poll_timeout); + if (result == -1) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("ACE_Proactor::handle_events")), + -1); + } + + if (!handler.done_) + ACE_OS::sleep (ACE_Time_Value (0, 1000)); + } + + if (!handler.done_) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("Timed out waiting for accept completion\n"))); + return -1; + } + + if (!handler.success_) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("Accept completion failed with error %u\n"), + handler.error_)); + return -1; + } + + if (handler.accept_handle_ == ACE_INVALID_HANDLE) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("Accept completion returned invalid accept handle\n"))); + return -1; + } + + if (handler.bytes_transferred_ != 0) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("Accept completion bytes_transferred=%B; expected 0\n"), + handler.bytes_transferred_)); + return -1; + } + + ACE_OS::closesocket (handler.accept_handle_); + client_stream.close (); + listen_socket.close (); + return 0; + } + + int + run_accept_cancel_test (ACE_Proactor &proactor) + { + ACE_SOCK_Acceptor listen_socket; + ACE_INET_Addr listen_addr ((u_short) 0, ACE_LOCALHOST); + + if (listen_socket.open (listen_addr, 1) != 0) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("listen_socket.open")), + -1); + } + + Accept_Handler handler; + ACE_Asynch_Accept acceptor; + if (acceptor.open (handler, listen_socket.get_handle (), 0, &proactor) != 0) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("ACE_Asynch_Accept::open")), + -1); + } + + ACE_Message_Block mb (1024); + if (acceptor.accept (mb, 0, ACE_INVALID_HANDLE, 0, 0, ACE_SIGRTMIN, AF_INET) != 0) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("ACE_Asynch_Accept::accept")), + -1); + } + + const int cancel_result = acceptor.cancel (); + if (cancel_result != 0) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("accept cancel returned %d; expected 0\n"), + cancel_result)); + return -1; + } + + const ACE_Time_Value deadline = ACE_OS::gettimeofday () + ACE_Time_Value (5); + while (!handler.done_ && ACE_OS::gettimeofday () < deadline) + { + ACE_Time_Value wait_time (0, 10000); + const int result = proactor.handle_events (wait_time); + if (result == -1) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("ACE_Proactor::handle_events")), + -1); + } + } + + if (!handler.done_) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("Timed out waiting for canceled accept completion\n"))); + return -1; + } + + if (handler.success_) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("Canceled accept unexpectedly succeeded\n"))); + return -1; + } + + const u_long expected_cancel_error = +#if defined (ACE_WIN32) + ERROR_OPERATION_ABORTED +#else + ECANCELED +#endif /* ACE_WIN32 */ + ; + + if (handler.error_ != expected_cancel_error) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("Canceled accept error=%u; expected %u\n"), + handler.error_, + expected_cancel_error)); + return -1; + } + + if (handler.bytes_transferred_ != 0) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("Canceled accept bytes_transferred=%B; expected 0\n"), + handler.bytes_transferred_)); + return -1; + } + + if (handler.accept_handle_ != ACE_INVALID_HANDLE) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("Canceled accept returned unexpected handle %d\n"), + handler.accept_handle_)); + ACE_OS::closesocket (handler.accept_handle_); + return -1; + } + + listen_socket.close (); + return 0; + } + + int + run_connect_failure_cleanup_test (ACE_Proactor &proactor) + { + ACE_SOCK_Acceptor busy_local_socket; + ACE_INET_Addr busy_local_addr ((u_short) 0, ACE_LOCALHOST); + if (busy_local_socket.open (busy_local_addr, 1) != 0) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("busy_local_socket.open")), + -1); + } + + if (busy_local_socket.get_local_addr (busy_local_addr) != 0) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("busy_local_socket.get_local_addr")), + -1); + } + + ACE_SOCK_Acceptor remote_socket; + ACE_INET_Addr remote_addr ((u_short) 0, ACE_LOCALHOST); + if (remote_socket.open (remote_addr, 1) != 0) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("remote_socket.open")), + -1); + } + + if (remote_socket.get_local_addr (remote_addr) != 0) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("remote_socket.get_local_addr")), + -1); + } + + Connect_Handler handler; + ACE_Asynch_Connect connector; + if (connector.open (handler, ACE_INVALID_HANDLE, 0, &proactor) != 0) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("ACE_Asynch_Connect::open")), + -1); + } + + const size_t fd_count_before = count_open_fds (); + + for (int i = 0; i < 32; ++i) + { + handler.done_ = false; + handler.success_ = false; + handler.connect_handle_ = ACE_INVALID_HANDLE; + handler.error_ = 0; + errno = 0; + const int result = + connector.connect (ACE_INVALID_HANDLE, remote_addr, busy_local_addr, 0, 0); + + if (result == 0) + { + const ACE_Time_Value deadline = ACE_OS::gettimeofday () + ACE_Time_Value (5); + while (!handler.done_ && ACE_OS::gettimeofday () < deadline) + { + ACE_Time_Value wait_time (0, 10000); + const int handle_result = proactor.handle_events (wait_time); + if (handle_result == -1) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("ACE_Proactor::handle_events")), + -1); + } + } + + if (!handler.done_) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("connect failure did not complete on iteration %d\n"), + i)); + return -1; + } + + if (handler.success_) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("connect failure unexpectedly succeeded on iteration %d\n"), + i)); + return -1; + } + } + else if (result != -1) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("connect failure returned unexpected rc=%d on iteration %d\n"), + result, + i)); + return -1; + } + else if (errno == 0) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("connect failure cleanup test did not set errno on iteration %d\n"), + i)); + return -1; + } + } + + const size_t fd_count_after = count_open_fds (); + if (fd_count_before != fd_count_after) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("connect failure leaked fds: before=%B after=%B\n"), + fd_count_before, + fd_count_after)); + return -1; + } + + remote_socket.close (); + busy_local_socket.close (); + return 0; + } + + int + run_transmit_file_contract_test (ACE_Proactor &proactor) + { +#if defined (ACE_WIN32) + ACE_UNUSED_ARG (proactor); + ACE_DEBUG ((LM_INFO, + ACE_TEXT ("Skipping transmit_file contract on Windows; ") + ACE_TEXT ("this test harness uses non-overlapped stream handles.\n"))); + return 0; +#endif /* ACE_WIN32 */ + + ACE_SOCK_Acceptor listen_socket; + ACE_INET_Addr listen_addr ((u_short) 0, ACE_LOCALHOST); + if (listen_socket.open (listen_addr, 1) != 0) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("listen_socket.open")), + -1); + } + + if (listen_socket.get_local_addr (listen_addr) != 0) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("listen_socket.get_local_addr")), + -1); + } + + ACE_SOCK_Connector connector; + ACE_SOCK_Stream client_stream; + if (connector.connect (client_stream, listen_addr) != 0) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("connector.connect")), + -1); + } + + ACE_SOCK_Stream server_stream; + if (listen_socket.accept (server_stream) != 0) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("listen_socket.accept")), + -1); + } + + ACE_FILE_Connector file_connector; + ACE_FILE_IO file; + if (file_connector.connect (file, ACE_sap_any_cast (ACE_FILE_Addr &)) != 0) + { + server_stream.close (); + client_stream.close (); + listen_socket.close (); + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("ACE_FILE_Connector::connect")), + -1); + } + + ACE_FILE_Addr tmp_addr; + file.get_local_addr (tmp_addr); + if (ACE_OS::write (file.get_handle (), "u", 1) != 1) + { + file.remove (); + server_stream.close (); + client_stream.close (); + listen_socket.close (); + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("write")), + -1); + } + + Transmit_Handler handler; + ACE_Asynch_Transmit_File transmit_file; + if (transmit_file.open (handler, server_stream.get_handle (), 0, &proactor) != 0) + { + file.remove (); + server_stream.close (); + client_stream.close (); + listen_socket.close (); + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("ACE_Asynch_Transmit_File::open")), + -1); + } + + errno = 0; + const int result = + transmit_file.transmit_file (file.get_handle (), 0, 1, 0, 0, 0, 0, 0); + if (proactor_type == Proactor_Test_Backend::BACKEND_URING) + { + if (result != -1 || errno != ENOTSUP) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("transmit_file result=%d errno=%d; expected -1/ENOTSUP\n"), + result, + errno)); + file.remove (); + server_stream.close (); + client_stream.close (); + listen_socket.close (); + return -1; + } + } + else + { + if (result != 0) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("POSIX transmit_file returned %d errno=%d; expected 0\n"), + result, + errno)); + file.remove (); + server_stream.close (); + client_stream.close (); + listen_socket.close (); + return -1; + } + + const ACE_Time_Value deadline = ACE_OS::gettimeofday () + ACE_Time_Value (5); + while (!handler.done_ && ACE_OS::gettimeofday () < deadline) + { + ACE_Time_Value wait_time (0, 10000); + const int handle_result = proactor.handle_events (wait_time); + if (handle_result == -1) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("ACE_Proactor::handle_events")), + -1); + } + } + + if (!handler.done_ || !handler.success_ || handler.bytes_transferred_ == 0) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("POSIX transmit_file completion invalid: done=%d success=%d bytes=%B error=%u\n"), + handler.done_, + handler.success_, + handler.bytes_transferred_, + handler.error_)); + file.remove (); + server_stream.close (); + client_stream.close (); + listen_socket.close (); + return -1; + } + + char received = '\0'; + const ssize_t recv_result = + ACE_OS::recv (client_stream.get_handle (), &received, 1, 0); + if (recv_result != 1 || received != 'u') + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("POSIX transmit_file recv_result=%d byte=%c; expected 1/'u'\n"), + static_cast (recv_result), + received)); + file.remove (); + server_stream.close (); + client_stream.close (); + listen_socket.close (); + return -1; + } + } + + file.remove (); + server_stream.close (); + client_stream.close (); + listen_socket.close (); + return 0; + } +} + +int +run_main (int argc, ACE_TCHAR *argv[]) +{ + ACE_START_TEST (ACE_TEXT ("Proactor_Contract_Test")); + + if (parse_args (argc, argv) != 0) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("Usage: %s [-t ]\n"), + argv[0])); + ACE_END_TEST; + return -1; + } + + ACE_Proactor *proactor_ptr = 0; + if (Proactor_Test_Backend::create_proactor (proactor_type, + 128, + proactor_ptr, + false) != 0) + { + ACE_END_TEST; + return -1; + } + ACE_Proactor &proactor = *proactor_ptr; + + int status = 0; + if (run_accept_contract_test (proactor) != 0) + status = -1; + else if (run_accept_cancel_test (proactor) != 0) + status = -1; + else if (run_connect_failure_cleanup_test (proactor) != 0) + status = -1; + else if (run_transmit_file_contract_test (proactor) != 0) + status = -1; + + delete proactor_ptr; + ACE_END_TEST; + return status; +} + +#else + +int +run_main (int, ACE_TCHAR *[]) +{ + ACE_START_TEST (ACE_TEXT ("Proactor_Contract_Test")); + ACE_DEBUG ((LM_INFO, + ACE_TEXT ("Asynchronous IO is unsupported.\n") + ACE_TEXT ("Proactor_Contract_Test will not be run.\n"))); + ACE_END_TEST; + return 0; +} + +#endif /* ACE_HAS_WIN32_OVERLAPPED_IO || ACE_HAS_AIO_CALLS */ diff --git a/ACE/tests/Proactor_File_Test.cpp b/ACE/tests/Proactor_File_Test.cpp index 0181d114995d1..fbaebe9a9a0b6 100644 --- a/ACE/tests/Proactor_File_Test.cpp +++ b/ACE/tests/Proactor_File_Test.cpp @@ -14,7 +14,7 @@ #if defined (ACE_HAS_WIN32_OVERLAPPED_IO) || defined (ACE_HAS_AIO_CALLS) // This only works on Win32 platforms and on Unix platforms - // supporting POSIX aio calls. + // supporting POSIX aio calls or io_uring. ////////////////////////////////////////////////////////////////// @@ -37,6 +37,8 @@ #include "ace/Proactor.h" #include "ace/Asynch_Connector.h" #include "ace/Time_Value.h" +#include "ace/Get_Opt.h" +#include "Proactor_Test_Backend.h" // How long are our fake serial I/O frames? @@ -353,10 +355,35 @@ FileIOHandler::handle_time_out(const ACE_Time_Value & /*tv*/, const void * /*act int -run_main(int /*argc*/, ACE_TCHAR * /*argv*/[]) +run_main(int argc, ACE_TCHAR *argv[]) { + ACE_Proactor *proactor = 0; + Proactor_Test_Backend::Type backend = Proactor_Test_Backend::BACKEND_DEFAULT; + ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("t:")); + int c = 0; + while ((c = get_opt ()) != EOF) + { + switch (c) + { + case 't': + if (Proactor_Test_Backend::parse_type (get_opt.opt_arg (), backend) == 0) + break; + Proactor_Test_Backend::print_type_usage (argv[0]); + return -1; + default: + Proactor_Test_Backend::print_type_usage (argv[0]); + return -1; + } + } + ACE_START_TEST (ACE_TEXT ("Proactor_File_Test")); + if (Proactor_Test_Backend::create_proactor (backend, 128, proactor, true) != 0) + { + ACE_END_TEST; + return -1; + } + int rc = 0; FileIOHandler fileIOHandler; @@ -380,6 +407,7 @@ run_main(int /*argc*/, ACE_TCHAR * /*argv*/[]) ACE_Proactor::instance()->proactor_run_event_loop(); } + ACE_Proactor::close_singleton (); ACE_END_TEST; return rc; diff --git a/ACE/tests/Proactor_Scatter_Gather_Test.cpp b/ACE/tests/Proactor_Scatter_Gather_Test.cpp index d0e75e84e25e2..d6ba6ae03870c 100644 --- a/ACE/tests/Proactor_Scatter_Gather_Test.cpp +++ b/ACE/tests/Proactor_Scatter_Gather_Test.cpp @@ -44,6 +44,8 @@ #include "ace/SOCK_Connector.h" +#include "Proactor_Test_Backend.h" + // For the Acceptor/Connector handlers maintenance lists static const int SENDERS = 1; static const int RECEIVERS = 2; @@ -62,6 +64,7 @@ static const ACE_TCHAR *output_file = ACE_TEXT("output"); static int client_only = 0; static int server_only = 0; static size_t chunk_size = 0; +static Proactor_Test_Backend::Type backend = Proactor_Test_Backend::BACKEND_DEFAULT; enum { @@ -869,7 +872,11 @@ Writer::handle_write_file (const ACE_Asynch_Write_File::Result &result) if (0 == this->receiver_count_ && 0 == this->io_count_) { - ACE_TEST_ASSERT (0 == this->odd_chain_ && 0 == this->even_chain_); + if (0 != this->odd_chain_ || 0 != this->even_chain_) + { + this->initiate_write_file (); + return; + } ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Writer::handle_write_file") @@ -1328,7 +1335,7 @@ 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")); + ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("f:csh:p:t:u")); int c; while ((c = get_opt ()) != EOF) @@ -1352,6 +1359,10 @@ parse_args (int argc, ACE_TCHAR *argv[]) case 'p': port = ACE_OS::atoi (get_opt.opt_arg ()); break; + case 't': + if (Proactor_Test_Backend::parse_type (get_opt.opt_arg (), backend) != 0) + return print_usage (argc, argv); + break; case 'u': default: return print_usage (argc, argv); @@ -1369,6 +1380,13 @@ run_main (int argc, ACE_TCHAR *argv[]) if (::parse_args (argc, argv) == -1) return -1; + ACE_Proactor *proactor = 0; + if (Proactor_Test_Backend::create_proactor (backend, 128, proactor, true) != 0) + { + ACE_END_TEST; + return -1; + } + chunk_size = ACE_OS::getpagesize (); if (client_only) diff --git a/ACE/tests/Proactor_Stress_Test.cpp b/ACE/tests/Proactor_Stress_Test.cpp new file mode 100644 index 0000000000000..0e16bfd2c0ffe --- /dev/null +++ b/ACE/tests/Proactor_Stress_Test.cpp @@ -0,0 +1,340 @@ +// ============================================================================ +/** + * @file Proactor_Stress_Test.cpp + * + * Stress coverage for recursive timer-driven dispatch patterns across + * selectable ACE Proactor backends. + */ +// ============================================================================ + +#include "test_config.h" + +#if defined (ACE_HAS_THREADS) && (defined (ACE_HAS_WIN32_OVERLAPPED_IO) || defined (ACE_HAS_AIO_CALLS)) + +#include "ace/Condition_Thread_Mutex.h" +#include "ace/Get_Opt.h" +#include "ace/OS_NS_sys_time.h" +#include "ace/Proactor.h" +#include "ace/Task.h" +#include "ace/Thread_Mutex.h" + +#include "Proactor_Test_Backend.h" + +namespace +{ + class Proactor_Task : public ACE_Task + { + public: + Proactor_Task () + : proactor_ (0) + { + } + + ~Proactor_Task () + { + this->stop (); + } + + int start (int thread_count, + Proactor_Test_Backend::Type backend, + size_t max_aio_operations) + { + if (this->proactor_ != 0) + return -1; + + if (Proactor_Test_Backend::create_proactor (backend, + max_aio_operations, + this->proactor_, + true) != 0) + return -1; + + return this->activate (THR_NEW_LWP | THR_JOINABLE, thread_count); + } + + int stop () + { + ACE_Proactor *proactor = this->proactor_; + if (proactor == 0) + return 0; + + proactor->proactor_end_event_loop (); + this->wait (); + ACE_Proactor::close_singleton (); + this->proactor_ = 0; + return 0; + } + + virtual int svc (void) + { + return ACE_Proactor::instance ()->proactor_run_event_loop (); + } + + private: + ACE_Proactor *proactor_; + }; + + class Recursive_Dispatch_Handler : public ACE_Handler + { + public: + Recursive_Dispatch_Handler (ACE_Proactor &proactor, + size_t dispatch_scale, + size_t target_count) + : proactor_ (proactor) + , lock_ () + , target_reached_ (lock_) + , idle_ (lock_) + , dispatch_scale_ (dispatch_scale) + , target_count_ (target_count) + , call_count_ (0) + , pending_ (0) + , schedule_failures_ (0) + , target_seen_ (false) + { + } + + int start (size_t initial_events) + { + for (size_t index = 0; index < initial_events; ++index) + { + if (this->schedule_one () != 0) + return -1; + } + return 0; + } + + void stop_dispatching () + { + ACE_GUARD (ACE_Thread_Mutex, guard, this->lock_); + this->dispatch_scale_ = 0; + if (this->pending_ == 0) + this->idle_.broadcast (); + } + + bool wait_for_target (const ACE_Time_Value &max_wait) + { + const ACE_Time_Value deadline = ACE_OS::gettimeofday () + max_wait; + ACE_GUARD_RETURN (ACE_Thread_Mutex, guard, this->lock_, false); + while (!this->target_seen_) + { + if (this->target_reached_.wait (&deadline) == -1) + return this->target_seen_; + } + return true; + } + + bool wait_for_idle (const ACE_Time_Value &max_wait) + { + const ACE_Time_Value deadline = ACE_OS::gettimeofday () + max_wait; + ACE_GUARD_RETURN (ACE_Thread_Mutex, guard, this->lock_, false); + while (this->pending_ != 0) + { + if (this->idle_.wait (&deadline) == -1) + return this->pending_ == 0; + } + return true; + } + + size_t call_count () const + { + ACE_GUARD_RETURN (ACE_Thread_Mutex, guard, const_cast (this->lock_), 0); + return this->call_count_; + } + + size_t schedule_failures () const + { + ACE_GUARD_RETURN (ACE_Thread_Mutex, guard, const_cast (this->lock_), 0); + return this->schedule_failures_; + } + + virtual void handle_time_out (const ACE_Time_Value &, const void *) + { + size_t schedule_count = 0; + { + ACE_GUARD (ACE_Thread_Mutex, guard, this->lock_); + if (this->pending_ > 0) + --this->pending_; + + ++this->call_count_; + if (!this->target_seen_ && this->call_count_ >= this->target_count_) + { + this->target_seen_ = true; + this->target_reached_.broadcast (); + } + + schedule_count = this->dispatch_scale_; + if (schedule_count == 0 && this->pending_ == 0) + this->idle_.broadcast (); + } + + for (size_t index = 0; index < schedule_count; ++index) + { + if (this->schedule_one () != 0) + break; + } + } + + private: + int schedule_one () + { + long timer_id = this->proactor_.schedule_timer (*this, + 0, + ACE_Time_Value::zero); + ACE_GUARD_RETURN (ACE_Thread_Mutex, guard, this->lock_, -1); + if (timer_id == -1) + { + ++this->schedule_failures_; + return -1; + } + + ++this->pending_; + return 0; + } + + ACE_Proactor &proactor_; + mutable ACE_Thread_Mutex lock_; + ACE_Condition_Thread_Mutex target_reached_; + ACE_Condition_Thread_Mutex idle_; + size_t dispatch_scale_; + size_t target_count_; + size_t call_count_; + size_t pending_; + size_t schedule_failures_; + bool target_seen_; + }; + + int print_usage (ACE_TCHAR *argv0) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("Usage: %s [-t ]\n"), + argv0)); + return Proactor_Test_Backend::print_type_usage (argv0); + } + + int run_recursive_test (Proactor_Test_Backend::Type backend, + bool immediate_shutdown) + { + Proactor_Task task; + if (task.start (8, backend, 512) != 0) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("Failed to start proactor task for backend %s\n"), + Proactor_Test_Backend::name (backend)), + -1); + } + + Recursive_Dispatch_Handler handler (*ACE_Proactor::instance (), 2, 100000); + if (handler.start (2) != 0) + { + task.stop (); + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("Failed to seed recursive dispatch for backend %s\n"), + Proactor_Test_Backend::name (backend)), + -1); + } + + if (!handler.wait_for_target (ACE_Time_Value (30))) + { + task.stop (); + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("Timed out waiting for target count on backend %s\n"), + Proactor_Test_Backend::name (backend)), + -1); + } + + handler.stop_dispatching (); + + if (!immediate_shutdown && !handler.wait_for_idle (ACE_Time_Value (10))) + { + task.stop (); + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("Timed out waiting for idle state on backend %s\n"), + Proactor_Test_Backend::name (backend)), + -1); + } + + task.stop (); + + if (handler.call_count () < 100000) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("Expected at least 100000 callbacks for backend %s; got %u\n"), + Proactor_Test_Backend::name (backend), + static_cast (handler.call_count ())), + -1); + } + + if (!immediate_shutdown && handler.schedule_failures () != 0) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("Unexpected timer scheduling failures for backend %s: %u\n"), + Proactor_Test_Backend::name (backend), + static_cast (handler.schedule_failures ())), + -1); + } + + return 0; + } +} + +int +run_main (int argc, ACE_TCHAR *argv[]) +{ + Proactor_Test_Backend::Type backend = Proactor_Test_Backend::BACKEND_DEFAULT; + ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("t:u")); + int c = 0; + int parse_failed = 0; + + while ((c = get_opt ()) != EOF) + { + switch (c) + { + case 't': + if (Proactor_Test_Backend::parse_type (get_opt.opt_arg (), backend) == 0) + break; + parse_failed = 1; + break; + case 'u': + default: + parse_failed = 1; + break; + } + + if (parse_failed) + break; + } + + ACE_START_TEST (ACE_TEXT ("Proactor_Stress_Test")); + + if (parse_failed) + { + print_usage (argv[0]); + ACE_END_TEST; + return -1; + } + + int status = 0; + if (run_recursive_test (backend, false) != 0) + status = -1; + else if (run_recursive_test (backend, true) != 0) + status = -1; + + ACE_END_TEST; + return status; +} + +#else + +int +run_main (int, ACE_TCHAR *[]) +{ + ACE_START_TEST (ACE_TEXT ("Proactor_Stress_Test")); + + ACE_DEBUG ((LM_INFO, + ACE_TEXT ("Asynchronous IO is unsupported.\n") + ACE_TEXT ("Proactor_Stress_Test will not be run.\n"))); + + ACE_END_TEST; + return 0; +} + +#endif /* ACE_HAS_THREADS && async io support */ diff --git a/ACE/tests/Proactor_Test.cpp b/ACE/tests/Proactor_Test.cpp index 6424635ae5246..ff6ea0b77035c 100644 --- a/ACE/tests/Proactor_Test.cpp +++ b/ACE/tests/Proactor_Test.cpp @@ -42,23 +42,18 @@ #include "ace/Atomic_Op.h" #include "ace/Synch_Traits.h" -#if defined (ACE_WIN32) - -# 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 /* ACE_WIN32 */ - #include "Proactor_Test.h" +#include "Proactor_Test_Backend.h" // Proactor Type (UNIX only, Win32 ignored) -typedef enum { DEFAULT = 0, AIOCB, SIG, SUN, CB } ProactorType; +typedef Proactor_Test_Backend::Type ProactorType; +static const ProactorType DEFAULT = Proactor_Test_Backend::BACKEND_DEFAULT; +static const ProactorType AIOCB = Proactor_Test_Backend::BACKEND_AIOCB; +static const ProactorType SIG = Proactor_Test_Backend::BACKEND_SIG; +static const ProactorType SUN = Proactor_Test_Backend::BACKEND_SUN; +static const ProactorType CB = Proactor_Test_Backend::BACKEND_CB; +static const ProactorType URING = Proactor_Test_Backend::BACKEND_URING; static ProactorType proactor_type = DEFAULT; // POSIX : > 0 max number aio operations proactor, @@ -202,80 +197,10 @@ MyTask::create_proactor (ProactorType type_proactor, size_t max_op) -1); ACE_TEST_ASSERT (this->proactor_ == 0); - -#if defined (ACE_WIN32) - - 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(ACE_HAS_BROKEN_SIGEVENT_STRUCT) - 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 /* !ACE_HAS_BROKEN_SIGEVENT_STRUCT */ - - default: - ACE_DEBUG ((LM_DEBUG, - ACE_TEXT ("(%t) Create Proactor Type = DEFAULT\n"))); - break; - } - -#endif /* ACE_WIN32 */ - - // 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; + return Proactor_Test_Backend::create_proactor (type_proactor, + max_op, + this->proactor_, + true); } int @@ -707,7 +632,10 @@ Server::~Server (void) this->tester_->server_done (this); if (this->handle_ != ACE_INVALID_HANDLE) - ACE_OS::closesocket (this->handle_); + { + ACE_OS::shutdown (this->handle_, ACE_SHUTDOWN_WRITE); + ACE_OS::closesocket (this->handle_); + } this->id_ = -1; this->handle_= ACE_INVALID_HANDLE; @@ -1547,7 +1475,8 @@ Client::handle_write_stream (const ACE_Asynch_Write_Stream::Result &result) if (result.error () == ERROR_OPERATION_ABORTED) prio = LM_DEBUG; #else - if (result.error () == ECANCELED) + if (result.error () == ECANCELED || + result.error () == EPIPE) prio = LM_DEBUG; #endif /* ACE_WIN32 */ else @@ -1673,7 +1602,8 @@ Client::handle_read_stream (const ACE_Asynch_Read_Stream::Result &result) if (result.error () == ERROR_OPERATION_ABORTED) prio = LM_DEBUG; #else - if (result.error () == ECANCELED) + if (result.error () == ECANCELED || + result.error () == ECONNRESET) prio = LM_DEBUG; #endif /* ACE_WIN32 */ else @@ -1726,6 +1656,7 @@ print_usage (int /* argc */, ACE_TCHAR *argv[]) ACE_TEXT ("\n i SIG") ACE_TEXT ("\n c CB") ACE_TEXT ("\n s SUN") + ACE_TEXT ("\n u URING") ACE_TEXT ("\n d default") ACE_TEXT ("\n-d ") ACE_TEXT ("\n-h for Client mode") @@ -1750,34 +1681,7 @@ print_usage (int /* argc */, ACE_TCHAR *argv[]) 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 (ACE_HAS_BROKEN_SIGEVENT_STRUCT) - case 'C': - proactor_type = CB; - return 1; -#endif /* !ACE_HAS_BROKEN_SIGEVENT_STRUCT */ - default: - break; - } - return 0; + return Proactor_Test_Backend::parse_type (ptype, proactor_type) == 0; } static int diff --git a/ACE/tests/Proactor_Test_Backend.h b/ACE/tests/Proactor_Test_Backend.h new file mode 100644 index 0000000000000..bc3c3b546d554 --- /dev/null +++ b/ACE/tests/Proactor_Test_Backend.h @@ -0,0 +1,278 @@ +// ============================================================================ +/** + * @file Proactor_Test_Backend.h + * + * Shared backend selection support for ACE Proactor tests. + */ +// ============================================================================ + +#ifndef ACE_TESTS_PROACTOR_TEST_BACKEND_H +#define ACE_TESTS_PROACTOR_TEST_BACKEND_H + +#include "ace/Init_ACE.h" +#include "ace/Log_Msg.h" +#include "test_config.h" + +#if defined (ACE_HAS_WIN32_OVERLAPPED_IO) || defined (ACE_HAS_AIO_CALLS) + +#include "ace/Get_Opt.h" +#include "ace/Proactor.h" +#include "ace/OS_NS_ctype.h" +#include "ace/OS_NS_string.h" + +#if defined (ACE_WIN32) +# include "ace/WIN32_Proactor.h" +#endif /* ACE_WIN32 */ + +#if defined (ACE_HAS_AIO_CALLS) +# include "ace/POSIX_Proactor.h" +# include "ace/POSIX_CB_Proactor.h" +# include "ace/SUN_Proactor.h" +#endif /* ACE_HAS_AIO_CALLS */ + +#if defined (ACE_HAS_AIO_CALLS) && defined (ACE_HAS_IO_URING) +# include "ace/Uring_Proactor.h" +#endif /* ACE_HAS_AIO_CALLS && ACE_HAS_IO_URING */ + +namespace Proactor_Test_Backend +{ + enum Type + { + BACKEND_DEFAULT = 0, + BACKEND_WIN32, + BACKEND_AIOCB, + BACKEND_SIG, + BACKEND_SUN, + BACKEND_CB, + BACKEND_URING + }; + + inline const ACE_TCHAR * + name (Type type) + { + switch (type) + { + case BACKEND_WIN32: + return ACE_TEXT ("win32"); + case BACKEND_AIOCB: + return ACE_TEXT ("aiocb"); + case BACKEND_SIG: + return ACE_TEXT ("sig"); + case BACKEND_SUN: + return ACE_TEXT ("sun"); + case BACKEND_CB: + return ACE_TEXT ("cb"); + case BACKEND_URING: + return ACE_TEXT ("uring"); + case BACKEND_DEFAULT: + default: + return ACE_TEXT ("default"); + } + } + + inline int + parse_type (const ACE_TCHAR *arg, Type &type) + { + if (arg == 0 || arg[0] == 0) + return -1; + + ACE_TCHAR folded[32]; + size_t index = 0; + for (; index + 1 < sizeof (folded) / sizeof (folded[0]) && arg[index] != 0; ++index) + folded[index] = static_cast (ACE_OS::ace_tolower (arg[index])); + folded[index] = 0; + + if (ACE_OS::strcmp (folded, ACE_TEXT ("d")) == 0 + || ACE_OS::strcmp (folded, ACE_TEXT ("default")) == 0) + { + type = BACKEND_DEFAULT; + return 0; + } + if (ACE_OS::strcmp (folded, ACE_TEXT ("w")) == 0 + || ACE_OS::strcmp (folded, ACE_TEXT ("win32")) == 0) + { + type = BACKEND_WIN32; + return 0; + } + if (ACE_OS::strcmp (folded, ACE_TEXT ("a")) == 0 + || ACE_OS::strcmp (folded, ACE_TEXT ("aiocb")) == 0 + || ACE_OS::strcmp (folded, ACE_TEXT ("posix_aiocb")) == 0) + { + type = BACKEND_AIOCB; + return 0; + } + if (ACE_OS::strcmp (folded, ACE_TEXT ("i")) == 0 + || ACE_OS::strcmp (folded, ACE_TEXT ("sig")) == 0 + || ACE_OS::strcmp (folded, ACE_TEXT ("posix_sig")) == 0) + { + type = BACKEND_SIG; + return 0; + } + if (ACE_OS::strcmp (folded, ACE_TEXT ("s")) == 0 + || ACE_OS::strcmp (folded, ACE_TEXT ("sun")) == 0) + { + type = BACKEND_SUN; + return 0; + } + if (ACE_OS::strcmp (folded, ACE_TEXT ("c")) == 0 + || ACE_OS::strcmp (folded, ACE_TEXT ("cb")) == 0 + || ACE_OS::strcmp (folded, ACE_TEXT ("posix_cb")) == 0) + { + type = BACKEND_CB; + return 0; + } + if (ACE_OS::strcmp (folded, ACE_TEXT ("u")) == 0 + || ACE_OS::strcmp (folded, ACE_TEXT ("uring")) == 0) + { + type = BACKEND_URING; + return 0; + } + + return -1; + } + + inline int + print_type_usage (ACE_TCHAR *argv0) + { + const ACE_TCHAR *sun_backend = +#if defined (sun) + ACE_TEXT ("\n s sun") +#else + ACE_TEXT ("") +#endif /* sun */ + ; + + const ACE_TCHAR *uring_backend = +#if defined (ACE_HAS_AIO_CALLS) && defined (ACE_HAS_IO_URING) + ACE_TEXT ("\n u uring") +#else + ACE_TEXT ("") +#endif /* ACE_HAS_AIO_CALLS && ACE_HAS_IO_URING */ + ; + + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("%s") + ACE_TEXT ("\n-t :") + ACE_TEXT ("\n d default") + ACE_TEXT ("\n w win32") + ACE_TEXT ("\n a aiocb / posix_aiocb") + ACE_TEXT ("\n i sig / posix_sig") + ACE_TEXT ("\n c cb / posix_cb") + ACE_TEXT ("%s") + ACE_TEXT ("%s") + ACE_TEXT ("\n"), + argv0, + sun_backend, + uring_backend)); + return -1; + } + + inline int + unsupported (Type type) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("Requested proactor backend '%s' is unavailable in this build.\n"), + name (type))); + return -1; + } + + inline int + create_impl (Type type, + size_t max_aio_operations, + ACE_Proactor_Impl *&implementation) + { + implementation = 0; + + switch (type) + { + case BACKEND_DEFAULT: + return 0; + + case BACKEND_WIN32: +#if defined (ACE_WIN32) && defined (ACE_HAS_WIN32_OVERLAPPED_IO) + ACE_NEW_RETURN (implementation, + ACE_WIN32_Proactor, + -1); + return 0; +#else + return unsupported (type); +#endif /* ACE_WIN32 && ACE_HAS_WIN32_OVERLAPPED_IO */ + + case BACKEND_AIOCB: +#if defined (ACE_HAS_AIO_CALLS) + ACE_NEW_RETURN (implementation, + ACE_POSIX_AIOCB_Proactor (max_aio_operations), + -1); + return 0; +#else + return unsupported (type); +#endif /* ACE_HAS_AIO_CALLS */ + + case BACKEND_SIG: +#if defined (ACE_HAS_AIO_CALLS) && defined (ACE_HAS_POSIX_REALTIME_SIGNALS) + ACE_NEW_RETURN (implementation, + ACE_POSIX_SIG_Proactor (max_aio_operations), + -1); + return 0; +#else + return unsupported (type); +#endif /* ACE_HAS_AIO_CALLS && ACE_HAS_POSIX_REALTIME_SIGNALS */ + + case BACKEND_SUN: +#if defined (ACE_HAS_AIO_CALLS) && defined (sun) + ACE_NEW_RETURN (implementation, + ACE_SUN_Proactor (max_aio_operations), + -1); + return 0; +#else + return unsupported (type); +#endif /* ACE_HAS_AIO_CALLS && sun */ + + case BACKEND_CB: +#if defined (ACE_HAS_AIO_CALLS) && !defined (ACE_HAS_BROKEN_SIGEVENT_STRUCT) + ACE_NEW_RETURN (implementation, + ACE_POSIX_CB_Proactor (max_aio_operations), + -1); + return 0; +#else + return unsupported (type); +#endif /* ACE_HAS_AIO_CALLS && !ACE_HAS_BROKEN_SIGEVENT_STRUCT */ + + case BACKEND_URING: +#if defined (ACE_HAS_AIO_CALLS) && defined (ACE_HAS_IO_URING) + ACE_NEW_RETURN (implementation, + ACE_Uring_Proactor (max_aio_operations), + -1); + return 0; +#else + return unsupported (type); +#endif /* ACE_HAS_AIO_CALLS && ACE_HAS_IO_URING */ + } + + return -1; + } + + inline int + create_proactor (Type type, + size_t max_aio_operations, + ACE_Proactor *&proactor, + bool install_singleton = true) + { + ACE_Proactor_Impl *implementation = 0; + if (create_impl (type, max_aio_operations, implementation) != 0) + return -1; + + ACE_NEW_RETURN (proactor, + ACE_Proactor (implementation, 1), + -1); + + if (install_singleton) + ACE_Proactor::instance (proactor, 1); + + return 0; + } +} + +#endif /* ACE_HAS_WIN32_OVERLAPPED_IO || ACE_HAS_AIO_CALLS */ + +#endif /* ACE_TESTS_PROACTOR_TEST_BACKEND_H */ diff --git a/ACE/tests/Proactor_Test_IPV6.cpp b/ACE/tests/Proactor_Test_IPV6.cpp index 341c604c30d97..d7bf4a2eaa53e 100644 --- a/ACE/tests/Proactor_Test_IPV6.cpp +++ b/ACE/tests/Proactor_Test_IPV6.cpp @@ -56,10 +56,17 @@ #endif /* defined (ACE_HAS_WIN32_OVERLAPPED_IO) */ #include "Proactor_Test.h" +#include "Proactor_Test_Backend.h" // Proactor Type (UNIX only, Win32 ignored) -typedef enum { DEFAULT = 0, AIOCB, SIG, SUN, CB } ProactorType; +typedef Proactor_Test_Backend::Type ProactorType; +static const ProactorType DEFAULT = Proactor_Test_Backend::BACKEND_DEFAULT; +static const ProactorType AIOCB = Proactor_Test_Backend::BACKEND_AIOCB; +static const ProactorType SIG = Proactor_Test_Backend::BACKEND_SIG; +static const ProactorType SUN = Proactor_Test_Backend::BACKEND_SUN; +static const ProactorType CB = Proactor_Test_Backend::BACKEND_CB; +static const ProactorType URING = Proactor_Test_Backend::BACKEND_URING; static ProactorType proactor_type = DEFAULT; // POSIX : > 0 max number aio operations proactor, @@ -203,80 +210,10 @@ MyTask::create_proactor (ProactorType type_proactor, size_t max_op) -1); ACE_TEST_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(ACE_HAS_BROKEN_SIGEVENT_STRUCT) - 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 /* !ACE_HAS_BROKEN_SIGEVENT_STRUCT */ - - 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; + return Proactor_Test_Backend::create_proactor (type_proactor, + max_op, + this->proactor_, + true); } int @@ -708,7 +645,10 @@ Server::~Server (void) this->tester_->server_done (this); if (this->handle_ != ACE_INVALID_HANDLE) - ACE_OS::closesocket (this->handle_); + { + ACE_OS::shutdown (this->handle_, ACE_SHUTDOWN_WRITE); + ACE_OS::closesocket (this->handle_); + } this->id_ = -1; this->handle_= ACE_INVALID_HANDLE; @@ -1587,7 +1527,8 @@ Client::handle_write_stream (const ACE_Asynch_Write_Stream::Result &result) if (result.error () == ERROR_OPERATION_ABORTED) prio = LM_DEBUG; #else - if (result.error () == ECANCELED) + if (result.error () == ECANCELED || + result.error () == EPIPE) prio = LM_DEBUG; #endif /* ACE_WIN32 */ else @@ -1713,7 +1654,8 @@ Client::handle_read_stream (const ACE_Asynch_Read_Stream::Result &result) if (result.error () == ERROR_OPERATION_ABORTED) prio = LM_DEBUG; #else - if (result.error () == ECANCELED) + if (result.error () == ECANCELED || + result.error () == ECONNRESET) prio = LM_DEBUG; #endif /* ACE_WIN32 */ else @@ -1790,34 +1732,7 @@ print_usage (int /* argc */, ACE_TCHAR *argv[]) 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 (ACE_HAS_BROKEN_SIGEVENT_STRUCT) - case 'C': - proactor_type = CB; - return 1; -#endif /* !ACE_HAS_BROKEN_SIGEVENT_STRUCT */ - default: - break; - } - return 0; + return Proactor_Test_Backend::parse_type (ptype, proactor_type) == 0; } static int diff --git a/ACE/tests/Proactor_Timer_Test.cpp b/ACE/tests/Proactor_Timer_Test.cpp index e13b01b9ff476..206048a03cd4f 100644 --- a/ACE/tests/Proactor_Timer_Test.cpp +++ b/ACE/tests/Proactor_Timer_Test.cpp @@ -13,20 +13,21 @@ */ //============================================================================= - #include "test_config.h" #include "ace/Trace.h" #if defined (ACE_HAS_WIN32_OVERLAPPED_IO) || defined (ACE_HAS_AIO_CALLS) // This only works on Win32 platforms and on Unix platforms - // supporting POSIX aio calls. + // supporting POSIX aio calls or io_uring. #include "ace/OS_NS_unistd.h" +#include "ace/OS_NS_string.h" #include "ace/Proactor.h" #include "ace/High_Res_Timer.h" #include "ace/Asynch_IO.h" #include "ace/Timer_Heap.h" #include "ace/Auto_Ptr.h" +#include "Proactor_Test_Backend.h" static int done = 0; static size_t counter = 0; @@ -283,14 +284,44 @@ test_cancel_repeat_timer (void) } -// If any command line arg is given, run the test with high res timer -// queue. Else run it normally. +// If any command line arg is given (other than -t u), run the test with +// high res timer queue. Else run it normally. int -run_main (int argc, ACE_TCHAR *[]) +run_main (int argc, ACE_TCHAR *argv[]) { + ACE_Proactor *proactor = 0; + Proactor_Test_Backend::Type backend = Proactor_Test_Backend::BACKEND_DEFAULT; + ACE_START_TEST (ACE_TEXT ("Proactor_Timer_Test")); - if (argc > 1) + // Determine whether to run with high-res timer queue. Ignore the + // backend selection arguments so they don't accidentally trigger + // this branch. + bool use_hires = false; + for (int i = 1; i < argc; ++i) + { + if (ACE_OS::strcmp (argv[i], ACE_TEXT ("-t")) == 0) + { + if (i + 1 >= argc + || Proactor_Test_Backend::parse_type (argv[i + 1], backend) != 0) + { + Proactor_Test_Backend::print_type_usage (argv[0]); + ACE_END_TEST; + return -1; + } + ++i; // skip the type argument + continue; + } + use_hires = true; + } + + if (Proactor_Test_Backend::create_proactor (backend, 128, proactor, true) != 0) + { + ACE_END_TEST; + return -1; + } + + if (use_hires) { ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Running with high-res timer queue\n"))); @@ -310,7 +341,7 @@ run_main (int argc, ACE_TCHAR *[]) // code ... typedef ACE_Timer_Heap_T Timer_Queue; - auto_ptr tq(new Timer_Queue); + ACE_Auto_Ptr tq(new Timer_Queue); // ... notice how the policy is in the derived timer queue type. // The abstract timer queue does not have a time policy ... tq->set_time_policy(&ACE_High_Res_Timer::gettimeofday_hr); @@ -335,6 +366,7 @@ run_main (int argc, ACE_TCHAR *[]) test_cancel_repeat_timer (); + ACE_Proactor::close_singleton (); ACE_END_TEST; return 0; } diff --git a/ACE/tests/Proactor_UDP_Test.cpp b/ACE/tests/Proactor_UDP_Test.cpp index bb0ea4863cb7a..a3d19f8cf3db0 100644 --- a/ACE/tests/Proactor_UDP_Test.cpp +++ b/ACE/tests/Proactor_UDP_Test.cpp @@ -51,8 +51,16 @@ #endif /* ACE_WIN32 */ +#include "Proactor_Test_Backend.h" + // Proactor Type (UNIX only, Win32 ignored) -typedef enum { DEFAULT = 0, AIOCB, SIG, SUN, CB } ProactorType; +typedef Proactor_Test_Backend::Type ProactorType; +static const ProactorType DEFAULT = Proactor_Test_Backend::BACKEND_DEFAULT; +static const ProactorType AIOCB = Proactor_Test_Backend::BACKEND_AIOCB; +static const ProactorType SIG = Proactor_Test_Backend::BACKEND_SIG; +static const ProactorType SUN = Proactor_Test_Backend::BACKEND_SUN; +static const ProactorType CB = Proactor_Test_Backend::BACKEND_CB; +static const ProactorType URING = Proactor_Test_Backend::BACKEND_URING; static ProactorType proactor_type = DEFAULT; // POSIX : > 0 max number aio operations proactor, @@ -196,80 +204,10 @@ MyTask::create_proactor (ProactorType type_proactor, size_t max_op) -1); ACE_TEST_ASSERT (this->proactor_ == 0); - -#if defined (ACE_WIN32) - - 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(ACE_HAS_BROKEN_SIGEVENT_STRUCT) - 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 /* !ACE_HAS_BROKEN_SIGEVENT_STRUCT */ - - default: - ACE_DEBUG ((LM_DEBUG, - ACE_TEXT ("(%t) Create Proactor Type = DEFAULT\n"))); - break; - } - -#endif /* ACE_WIN32 */ - - // 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; + return Proactor_Test_Backend::create_proactor (type_proactor, + max_op, + this->proactor_, + true); } int @@ -2016,34 +1954,7 @@ print_usage (int /* argc */, ACE_TCHAR *argv[]) 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 (ACE_HAS_BROKEN_SIGEVENT_STRUCT) - case 'C': - proactor_type = CB; - return 1; -#endif /* !ACE_HAS_BROKEN_SIGEVENT_STRUCT */ - default: - break; - } - return 0; + return Proactor_Test_Backend::parse_type (ptype, proactor_type) == 0; } static int diff --git a/ACE/tests/run_test.lst b/ACE/tests/run_test.lst index 00a1c3cb4e31f..ea1a70b7f22a5 100644 --- a/ACE/tests/run_test.lst +++ b/ACE/tests/run_test.lst @@ -186,7 +186,9 @@ Priority_Buffer_Test Priority_Reactor_Test: !ACE_FOR_TAO Priority_Task_Test Proactor_File_Test: !VxWorks !LynxOS !nsk !ACE_FOR_TAO !BAD_AIO +Proactor_Contract_Test: !VxWorks !LynxOS !nsk !ACE_FOR_TAO !BAD_AIO Proactor_Scatter_Gather_Test: !VxWorks !nsk !ACE_FOR_TAO +Proactor_Stress_Test: !VxWorks !LynxOS !nsk !ACE_FOR_TAO !BAD_AIO Proactor_Test: !VxWorks !LynxOS !nsk !ACE_FOR_TAO !BAD_AIO Proactor_Timer_Test: !VxWorks !nsk !ACE_FOR_TAO Proactor_UDP_Test: !VxWorks !LynxOS !nsk !ACE_FOR_TAO !BAD_AIO diff --git a/ACE/tests/tests.mpc b/ACE/tests/tests.mpc index 747face2cf474..c1d4483459efd 100644 --- a/ACE/tests/tests.mpc +++ b/ACE/tests/tests.mpc @@ -1304,6 +1304,14 @@ project(Proactor Scatter Gather Test) : acetest { } } +project(Proactor Stress Test) : acetest { + avoids += ace_for_tao + exename = Proactor_Stress_Test + Source_Files { + Proactor_Stress_Test.cpp + } +} + project(Proactor Test) : acetest { avoids += ace_for_tao exename = Proactor_Test @@ -1336,6 +1344,14 @@ project(Proactor UDP Test) : acetest { } } +project(Proactor Contract Test) : acetest { + avoids += ace_for_tao + exename = Proactor_Contract_Test + Source_Files { + Proactor_Contract_Test.cpp + } +} + project(Process Manual Event Test) : acetest { exename = Process_Manual_Event_Test Source_Files {