dlib C++ Library - linker_kernel_1.cpp

// Copyright (C) 2003 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_LINKER_KERNEL_1_CPp_
#define DLIB_LINKER_KERNEL_1_CPp_
#include "linker_kernel_1.h"
namespace dlib
{
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
 // member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
 
 linker::
 linker (
 ) :
 running(false),
 running_signaler(running_mutex),
 A(0),
 B(0),
 service_connection_running_signaler(service_connection_running_mutex)
 {
 }
// ----------------------------------------------------------------------------------------
 linker::
 linker (
 connection& a,
 connection& b
 ) :
 running(false),
 running_signaler(running_mutex),
 A(0),
 B(0),
 service_connection_running_signaler(service_connection_running_mutex)
 {
 link(a,b);
 }
// ----------------------------------------------------------------------------------------
 linker::
 ~linker (
 )
 {
 clear();
 }
// ----------------------------------------------------------------------------------------
 void linker::
 clear (
 )
 {
 // shutdown the connections
 cons_mutex.lock();
 if (A != 0 )
 {
 A->shutdown();
 A = 0;
 }
 if (B != 0)
 {
 B->shutdown();
 B = 0;
 }
 cons_mutex.unlock();
 
 // wait for the other threads to signal that they have ended
 running_mutex.lock();
 while (running == true)
 {
 running_signaler.wait();
 }
 running_mutex.unlock();
 }
// ----------------------------------------------------------------------------------------
 bool linker::
 is_running (
 ) const
 {
 running_mutex.lock();
 bool temp = running;
 running_mutex.unlock();
 return temp;
 }
// ----------------------------------------------------------------------------------------
 void linker::
 link (
 connection& a,
 connection& b
 )
 {
 // make sure requires clause is not broken
 DLIB_CASSERT( 
 this->is_running() == false ,
 "\tvoid linker::link"
 << "\n\tis_running() == " << this->is_running() 
 << "\n\tthis: " << this
 );
 running_mutex.lock();
 running = true;
 running_mutex.unlock();
 cons_mutex.lock();
 A = &a;
 B = &b;
 cons_mutex.unlock();
 
 service_connection_running_mutex.lock();
 service_connection_running = true;
 service_connection_running_mutex.unlock();
 service_connection_error_mutex.lock();
 service_connection_error = false;
 service_connection_error_mutex.unlock();
 // if we fail to make the thread
 if (!create_new_thread(service_connection,this))
 {
 a.shutdown();
 b.shutdown();
 service_connection_running_mutex.lock();
 service_connection_running = false;
 service_connection_running_mutex.unlock();
 cons_mutex.lock();
 A = 0;
 B = 0;
 cons_mutex.unlock(); 
 running_mutex.lock();
 running = false;
 running_mutex.unlock();
 throw dlib::thread_error (
 ECREATE_THREAD,
 "failed to make new thread in linker::link()"
 );
 }
 // forward data from a to b
 char buf[200];
 long status;
 bool error = false; // becomes true if one of the connections returns an error
 while (true)
 {
 status = a.read(buf,sizeof(buf));
 // if there was an error reading from the socket
 if (status == OTHER_ERROR)
 {
 error = true;
 break;
 }
 else if (status == SHUTDOWN)
 {
 b.shutdown();
 }
 if (status <= 0)
 {
 // if a has closed normally
 if (status == 0)
 b.shutdown_outgoing();
 break; 
 }
 status = b.write(buf,status);
 // if there was an error writing to the socket then break
 if (status == OTHER_ERROR)
 {
 error = true;
 break;
 }
 
 if (status <= 0)
 break; 
 }
 // if there was an error then shutdown both connections
 if (error)
 {
 a.shutdown();
 b.shutdown();
 }
 // wait for the other thread to end
 service_connection_running_mutex.lock();
 while(service_connection_running)
 {
 service_connection_running_signaler.wait();
 }
 service_connection_running_mutex.unlock();
 // make sure connections are shutdown
 a.shutdown();
 b.shutdown();
 // both threads have ended so the connections are no longer needed
 cons_mutex.lock();
 A = 0;
 B = 0;
 cons_mutex.unlock();
 // if service_connection terminated due to an error then set error to true
 service_connection_error_mutex.lock();
 if (service_connection_error)
 error = true;
 service_connection_error_mutex.unlock();
 // if we are ending because of an error
 if (error)
 {
 // signal that the link() function is ending
 running_mutex.lock();
 running = false;
 running_signaler.broadcast();
 running_mutex.unlock();
 // throw the exception for this error
 throw dlib::socket_error (
 ECONNECTION,
 "a connection returned an error in linker::link()"
 );
 
 }
 // signal that the link() function is ending
 running_mutex.lock();
 running = false;
 running_signaler.broadcast();
 running_mutex.unlock();
 }
// ----------------------------------------------------------------------------------------
 void linker::
 service_connection (
 void* param
 )
 {
 linker& p = *static_cast<linker*>(param);
 p.cons_mutex.lock();
 // if the connections are gone for whatever reason then return
 if (p.A == 0 || p.B == 0)
 {
 // signal that this function is ending
 p.service_connection_running_mutex.lock();
 p.service_connection_running = false;
 p.service_connection_running_signaler.broadcast();
 p.service_connection_running_mutex.unlock();
 return;
 }
 connection& a = *p.A;
 connection& b = *p.B;
 p.cons_mutex.unlock();
 // forward data from b to a
 char buf[200];
 long status;
 bool error = false;
 while (true)
 {
 status = b.read(buf,sizeof(buf));
 // if there was an error reading from the socket
 if (status == OTHER_ERROR)
 {
 error = true;
 break;
 }
 else if (status == SHUTDOWN)
 {
 a.shutdown();
 }
 if (status <= 0)
 {
 // if b has closed normally 
 if (status == 0)
 a.shutdown_outgoing();
 break; 
 }
 status = a.write(buf,status);
 // if there was an error writing to the socket then break
 if (status == OTHER_ERROR)
 {
 error = true;
 break;
 }
 
 if (status <= 0)
 break; 
 }
 // if there was an error then shutdown both connections
 if (error)
 {
 a.shutdown();
 b.shutdown();
 }
 // if there was an error then signal that
 if (error)
 {
 p.service_connection_error_mutex.lock();
 p.service_connection_error = true;
 p.service_connection_error_mutex.unlock();
 }
 // signal that this function is ending
 p.service_connection_running_mutex.lock();
 p.service_connection_running = false;
 p.service_connection_running_signaler.broadcast();
 p.service_connection_running_mutex.unlock();
 }
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_LINKER_KERNEL_1_CPp_

AltStyle によって変換されたページ (->オリジナル) /