Пример #1
0
MORDOR_UNITTEST(SSLStream, basic)
{
    WorkerPool pool;
    std::pair<Stream::ptr, Stream::ptr> pipes = pipeStream();

    SSLStream::ptr sslserver(new SSLStream(pipes.first, false));
    SSLStream::ptr sslclient(new SSLStream(pipes.second, true));

    pool.schedule(boost::bind(&accept, sslserver));
    sslclient->connect();
    pool.dispatch();

    Stream::ptr server = sslserver, client = sslclient;

    char buf[6];
    buf[5] = '\0';
    client->write("hello");
    client->flush(false);
    MORDOR_TEST_ASSERT_EQUAL(server->read(buf, 5), 5u);
    MORDOR_TEST_ASSERT_EQUAL((const char *)buf, "hello");
    server->write("world");
    server->flush(false);
    MORDOR_TEST_ASSERT_EQUAL(client->read(buf, 5), 5u);
    MORDOR_TEST_ASSERT_EQUAL((const char *)buf, "world");
}
Пример #2
0
MORDOR_UNITTEST(SSLStream, duplexStress)
{
    WorkerPool pool;
    // Force more fiber context switches by having a smaller buffer
    std::pair<Stream::ptr, Stream::ptr> pipes = pipeStream(1024);

    SSLStream::ptr sslserver(new SSLStream(pipes.first, false));
    SSLStream::ptr sslclient(new SSLStream(pipes.second, true));

    pool.schedule(boost::bind(&accept, sslserver));
    sslclient->connect();
    pool.dispatch();

    // Transfer 1 MB
    long long toTransfer = 1024 * 1024;
    std::vector<boost::function<void ()> > dgs;
    bool complete1 = false, complete2 = false, complete3 = false, complete4 = false;
    dgs.push_back(boost::bind(&writeLotsaData, sslserver, toTransfer, boost::ref(complete1)));
    dgs.push_back(boost::bind(&readLotsaData, sslserver, toTransfer, boost::ref(complete2)));
    dgs.push_back(boost::bind(&writeLotsaData, sslclient, toTransfer, boost::ref(complete3)));
    dgs.push_back(boost::bind(&readLotsaData, sslclient, toTransfer, boost::ref(complete4)));
    parallel_do(dgs);
    MORDOR_ASSERT(complete1);
    MORDOR_ASSERT(complete2);
    MORDOR_ASSERT(complete3);
    MORDOR_ASSERT(complete4);
}
Пример #3
0
int main()
{
    WorkerPool workers;

    for (int i = 0; i != 100; ++i)
    {
        workers.schedule([=]{ usleep(10); }, 0);
    }

    for (int i = 0; i != 50; ++i)
    {
        workers.schedule([=]{ usleep(10); }, 1);
    }

    for (int i = 0; i != 40; ++i)
    {
        workers.schedule([=]{ usleep(10); }, 2);
    }

    for (int i = 0; i != 10; ++i)
    {
        workers.schedule([=]{ usleep(10); }, 3);
    }
    
    sleep(1);
    quit = true;
}
Пример #4
0
// Just calling stop should still clear all pending work
MORDOR_UNITTEST(Scheduler, hijackStopOnScheduled)
{
    Fiber::ptr doNothingFiber(new Fiber(&doNothing));
    WorkerPool pool;
    MORDOR_TEST_ASSERT_EQUAL(Scheduler::getThis(), &pool);
    pool.schedule(doNothingFiber);
    MORDOR_TEST_ASSERT_EQUAL(doNothingFiber->state(), Fiber::INIT);
    pool.stop();
    MORDOR_TEST_ASSERT_EQUAL(doNothingFiber->state(), Fiber::TERM);
}
Пример #5
0
MORDOR_UNITTEST(PipeStream, closeOnBlockingReader)
{
    std::pair<Stream::ptr, Stream::ptr> pipe = pipeStream();
    WorkerPool pool;
    int sequence = 1;

    pool.schedule(Fiber::ptr(new Fiber(boost::bind(&closeOnBlockingReader,
                                       pipe.first, boost::ref(sequence)))));

    Buffer output;
    MORDOR_TEST_ASSERT_EQUAL(pipe.second->read(output, 10), 0u);
    MORDOR_TEST_ASSERT_EQUAL(++sequence, 4);
}
Пример #6
0
MORDOR_UNITTEST(PipeStream, closeOnBlockingWriter)
{
    std::pair<Stream::ptr, Stream::ptr> pipe = pipeStream(5);
    WorkerPool pool;
    int sequence = 1;

    pool.schedule(Fiber::ptr(new Fiber(boost::bind(&closeOnBlockingWriter, pipe.first,
                                       boost::ref(sequence)))));

    MORDOR_TEST_ASSERT_EQUAL(pipe.second->write("hello"), 5u);
    MORDOR_TEST_ASSERT_EQUAL(++sequence, 2);
    MORDOR_TEST_ASSERT_EXCEPTION(pipe.second->write("world"), BrokenPipeException);
    MORDOR_TEST_ASSERT_EQUAL(++sequence, 5);
}
Пример #7
0
MORDOR_UNITTEST(PipeStream, blockingRead)
{
    std::pair<Stream::ptr, Stream::ptr> pipe = pipeStream(5);
    WorkerPool pool;
    int sequence = 1;

    pool.schedule(Fiber::ptr(new Fiber(boost::bind(&blockingRead, pipe.second,
                                       boost::ref(sequence)))));

    Buffer output;
    MORDOR_TEST_ASSERT_EQUAL(pipe.first->read(output, 10), 5u);
    MORDOR_TEST_ASSERT_EQUAL(++sequence, 4);
    MORDOR_TEST_ASSERT(output == "hello");
}
Пример #8
0
MORDOR_UNITTEST(PipeStream, cancelOnBlockingWriter)
{
    std::pair<Stream::ptr, Stream::ptr> pipe = pipeStream(5);
    WorkerPool pool;
    int sequence = 1;

    pool.schedule(Fiber::ptr(new Fiber(boost::bind(&cancelOnBlockingWriter, pipe.first,
                                       boost::ref(sequence)))));
    Scheduler::yield();
    MORDOR_TEST_ASSERT_EQUAL(++sequence, 3);
    pipe.first->cancelWrite();
    pool.dispatch();
    MORDOR_TEST_ASSERT_EQUAL(++sequence, 5);
}
Пример #9
0
MORDOR_UNITTEST(PipeStream, cancelOnBlockingReader)
{
    std::pair<Stream::ptr, Stream::ptr> pipe = pipeStream();
    WorkerPool pool;
    int sequence = 1;

    pool.schedule(Fiber::ptr(new Fiber(boost::bind(&cancelOnBlockingReader,
                                       pipe.first, boost::ref(sequence)))));

    Buffer output;
    MORDOR_TEST_ASSERT_EXCEPTION(pipe.first->read(output, 10), OperationAbortedException);
    MORDOR_TEST_ASSERT_EQUAL(++sequence, 4);
    MORDOR_TEST_ASSERT_EXCEPTION(pipe.first->read(output, 10), OperationAbortedException);
}
Пример #10
0
// Similar to above, but after the scheduler has stopped, yielding
// to it again should implicitly restart it
MORDOR_UNITTEST(Scheduler, hijackMultipleDispatch)
{
    Fiber::ptr doNothingFiber(new Fiber(&doNothing));
    WorkerPool pool;
    MORDOR_TEST_ASSERT_EQUAL(Scheduler::getThis(), &pool);
    pool.schedule(doNothingFiber);
    MORDOR_TEST_ASSERT_EQUAL(doNothingFiber->state(), Fiber::INIT);
    pool.dispatch();
    MORDOR_TEST_ASSERT_EQUAL(doNothingFiber->state(), Fiber::TERM);
    doNothingFiber->reset();
    pool.schedule(doNothingFiber);
    MORDOR_TEST_ASSERT_EQUAL(doNothingFiber->state(), Fiber::INIT);
    pool.dispatch();
    MORDOR_TEST_ASSERT_EQUAL(doNothingFiber->state(), Fiber::TERM);
}
Пример #11
0
MORDOR_UNITTEST(PipeStream, destructOnBlockingReader)
{
    std::pair<Stream::ptr, Stream::ptr> pipe = pipeStream();
    WorkerPool pool;
    int sequence = 1;

    Fiber::ptr f = Fiber::ptr(new Fiber(boost::bind(&destructOnBlockingReader,
                                        boost::weak_ptr<Stream>(pipe.first), boost::ref(sequence))));
    f->call();
    pipe.first.reset();
    pool.schedule(f);

    Buffer output;
    MORDOR_TEST_ASSERT_EXCEPTION(pipe.second->read(output, 10), BrokenPipeException);
    MORDOR_TEST_ASSERT_EQUAL(++sequence, 4);
}
Пример #12
0
MORDOR_UNITTEST(PipeStream, destructOnBlockingWriter)
{
    std::pair<Stream::ptr, Stream::ptr> pipe = pipeStream(5);
    WorkerPool pool;
    int sequence = 1;

    Fiber::ptr f = Fiber::ptr(new Fiber(boost::bind(&destructOnBlockingWriter,
                                        boost::weak_ptr<Stream>(pipe.first), boost::ref(sequence))));
    f->call();
    pipe.first.reset();
    pool.schedule(f);

    MORDOR_TEST_ASSERT_EQUAL(pipe.second->write("hello"), 5u);
    MORDOR_TEST_ASSERT_EQUAL(++sequence, 2);
    MORDOR_TEST_ASSERT_EXCEPTION(pipe.second->write("world"), BrokenPipeException);
    MORDOR_TEST_ASSERT_EQUAL(++sequence, 5);
}
Пример #13
0
int main(int argc, char const *argv[])
{
	WorkerPool wp;
	std::cerr << "pool created\n";
	wp.waitallready();
	std::cerr << "pool ready\n";
	Scheduler s(argc == 3 ? 0: &wp,argv[1]);

	int q = 0;

	s << 1 << [&] {
		{lockio x; std::cerr << "i1A " << q << "\n"; }
		q = 1;
		usleep(10000);
		{lockio x; std::cerr << "i1B " << q << "\n"; }
	}	;

	s << 2 << [&] {
		{lockio x; std::cerr << "i2A " << q << "\n"; }
		q = 2;
		usleep(20000);
		{lockio x; std::cerr << "i2B " << q << "\n"; }
	}	;

	s << 3 <<  [&] {
		{lockio x; std::cerr << "i3A " << q << "\n"; }
		q = 3;
		usleep(30000);
		{lockio x; std::cerr << "i3B " << q << "\n"; }
	}	;

	// 
	s << 4 <<  [&] (int from, int to) {
		{lockio x; std::cerr << "i4A " << q <<  " range " << from << "-" << to << "\n"; }
		q = 4;
		usleep(30000);
		{lockio x; std::cerr << "i4B " << q << " range " << from << "-" << to <<  "\n"; }
	}	;


	std::cerr << "before run\n";
	s.run();
	std::cerr << "after run\n";
	return 0;
}
Пример #14
0
MORDOR_UNITTEST(SSLStream, forceDuplex)
{
    WorkerPool pool;
    std::pair<Stream::ptr, Stream::ptr> pipes = pipeStream();

    SSLStream::ptr sslserver(new SSLStream(pipes.first, false));
    SSLStream::ptr sslclient(new SSLStream(pipes.second, true));

    Stream::ptr server = sslserver, client = sslclient;

    int sequence = 0;
    pool.schedule(boost::bind(&accept, sslserver));
    sslclient->connect();
    pool.dispatch();

    pool.schedule(boost::bind(&readWorld, client,
        boost::ref(sequence)));
    pool.dispatch();
    MORDOR_TEST_ASSERT_EQUAL(++sequence, 2);
    // Read is pending
    client->write("hello");
    client->flush(false);
    pool.dispatch();
    server->write("world");
    server->flush(false);
    pool.dispatch();
    MORDOR_TEST_ASSERT_EQUAL(++sequence, 4);
}
Пример #15
0
MORDOR_UNITTEST(PipeStream, basicInFibers)
{
    std::pair<Stream::ptr, Stream::ptr> pipe = pipeStream();
    // pool must destruct before pipe, because when pool destructs it
    // waits for the other fiber to complete, which has a weak ref
    // to pipe.second; if pipe.second is gone, it will throw an
    // exception that we don't want
    WorkerPool pool;
    int sequence = 1;

    pool.schedule(Fiber::ptr(new Fiber(boost::bind(&basicInFibers, pipe.first, boost::ref(sequence)))));

    Buffer read;
    MORDOR_TEST_ASSERT_EQUAL(pipe.second->read(read, 10), 1u);
    MORDOR_TEST_ASSERT(read == "a");
    ++sequence;
    MORDOR_TEST_ASSERT_EQUAL(sequence, 2);
    MORDOR_TEST_ASSERT_EQUAL(pipe.second->read(read, 10), 0u);
}
Пример #16
0
void run(int argc, char **argv){
	ready_list_t ready_list;
	ready_list_t ready_list_2;
	ready_list_t::iterator it;
	const Fdevents::events_t *events;
	Server serv(ssdb);

	Fdevents select;
	select.set(serv_link->fd(), FDEVENT_IN, 0, serv_link);
	select.set(serv.reader->fd(), FDEVENT_IN, 0, serv.reader);
	select.set(serv.writer->fd(), FDEVENT_IN, 0, serv.writer);
	
	int link_count = 0;
	while(!quit){
		bool write_pending = false;
		ready_list.clear();
		ready_list_2.clear();
		
		if(write_pending || !ready_list.empty()){
			// give links that are not in ready_list a chance
			events = select.wait(0);
		}else{
			events = select.wait(50);
		}
		if(events == NULL){
			log_fatal("events.wait error: %s", strerror(errno));
			break;
		}
		for(int i=0; i<(int)events->size(); i++){
			const Fdevent *fde = events->at(i);
			if(fde->data.ptr == serv_link){
				Link *link = serv_link->accept();
				if(link == NULL){
					log_error("accept fail!");
					continue;
				}
				link_count ++;
				log_info("new link from %s:%d, fd: %d, link_count: %d",
					link->remote_ip, link->remote_port, link->fd(), link_count);
				
				link->nodelay();
				link->noblock();
				link->create_time = millitime();
				link->active_time = link->create_time;
				select.set(link->fd(), FDEVENT_IN, 1, link);
			}else if(fde->data.ptr == serv.reader || fde->data.ptr == serv.writer){
				WorkerPool<Server::ProcWorker, ProcJob> *worker = (WorkerPool<Server::ProcWorker, ProcJob> *)fde->data.ptr;
				ProcJob job;
				if(worker->pop(&job) == 0){
					log_fatal("reading result from workers error!");
					exit(0);
				}
				if(proc_result(job, select, ready_list_2) == PROC_ERROR){
					link_count --;
				}
			}else{
				Link *link = (Link *)fde->data.ptr;
				// 不能同时监听读和写事件, 只能监听其中一个
				if(fde->events & FDEVENT_ERR){
					log_info("fd: %d error, delete link", link->fd());
					link_count --;
					select.del(link->fd());
					delete link;
				}else if(fde->events & FDEVENT_IN){
					int len = link->read();
					//log_trace("fd: %d read: %d", link->fd(), len);
					if(len <= 0){
						log_info("fd: %d, read: %d, delete link", link->fd(), len);
						link_count --;
						select.del(link->fd());
						delete link;
					}else{
						ready_list.push_back(link);
					}
				}else if(fde->events & FDEVENT_OUT){
					int len = link->write();
					//log_trace("fd: %d write: %d", link->fd(), len);
					if(len <= 0){
						log_info("fd: %d, write: %d, delete link", link->fd(), len);
						link_count --;
						select.del(link->fd());
						delete link;
					}else if(link->output->empty()){
						//log_trace("delete %d from select.out", link->fd());
						select.clr(link->fd(), FDEVENT_OUT);
						if(!link->input->empty()){
							ready_list.push_back(link);
						}else{
							//log_trace("add %d to select.in", link->fd());
							select.set(link->fd(), FDEVENT_IN, 1, link);
						}
					}else{
						write_pending = true;
					}
				}
			}
		}

		for(it = ready_list.begin(); it != ready_list.end(); it ++){
			Link *link = *it;

			const Request *req = link->recv();
			if(req == NULL){
				log_warn("fd: %d, link parse error, delete link", link->fd());
				link_count --;
				select.del(link->fd());
				delete link;
				continue;
			}
			if(req->empty()){
				if(!select.isset(link->fd(), FDEVENT_IN)){
					//log_trace("add %d to select.in", link->fd());
					select.set(link->fd(), FDEVENT_IN, 1, link);
				}
				continue;
			}
			
			link->active_time = millitime();

			ProcJob job;
			job.link = link;
			serv.proc(&job);
			if(job.result == PROC_THREAD){
				select.del(link->fd());
				continue;
			}
			if(job.result == PROC_BACKEND){
				select.del(link->fd());
				link_count --;
				continue;
			}
			
			if(proc_result(job, select, ready_list_2) == PROC_ERROR){
				link_count --;
			}
		} // end foreach ready link
		ready_list.swap(ready_list_2);
	}
}
Пример #17
0
MORDOR_UNITTEST(Scheduler, tolerantException)
{
    WorkerPool pool;
    pool.schedule(throwException);
    MORDOR_TEST_ASSERT_ANY_EXCEPTION(pool.stop());
}
Пример #18
0
// Start can be called multiple times without consequence
MORDOR_UNITTEST(Scheduler, idempotentStartHijack)
{
    WorkerPool pool;
    pool.start();
    pool.start();
}
Пример #19
0
// When hijacking the calling thread, you can stop() from anywhere within
// it
MORDOR_UNITTEST(Scheduler, stopScheduledHijack)
{
    WorkerPool pool;
    pool.schedule(boost::bind(&Scheduler::stop, &pool));
    pool.dispatch();
}