Exemplo n.º 1
0
int aio_socket_destroy(aio_socket_t socket, aio_ondestroy ondestroy, void* param)
{
	struct epoll_context* ctx = (struct epoll_context*)socket;
	assert(ctx->ev.data.ptr == ctx);
	ctx->ondestroy = ondestroy;
	ctx->param = param;

	shutdown(ctx->socket, SHUT_RDWR);
//	close(sock); // can't close socket now, avoid socket reuse

	aio_socket_release(ctx); // shutdown will generate EPOLLHUP event
	return 0;
}
Exemplo n.º 2
0
int aio_socket_destroy(aio_socket_t socket, aio_ondestroy ondestroy, void* param)
{
	struct aio_context *ctx = (struct aio_context*)socket;
//	InterlockedExchange(&ctx->closed, 1);
	ctx->ondestroy = ondestroy;
	ctx->param = param;

	if(ctx->own)
	{
		closesocket(ctx->socket);
		ctx->socket = INVALID_SOCKET;
	}

	aio_socket_release(ctx);
	return 0;
}
Exemplo n.º 3
0
static void util_free(struct aio_context_action* aio)
{
	aio_socket_release(aio->context);

	// lock-free enqueue
	EnterCriticalSection(&s_locker);
	if(s_actions_count < s_cpu+1)
	{
		aio->next = s_actions;
		s_actions = aio;
		++s_actions_count;
		aio = NULL; // stop free
	}
	LeaveCriticalSection(&s_locker);

	if(aio)
		free(aio);
}
Exemplo n.º 4
0
int aio_socket_destroy(aio_socket_t socket)
{
	struct epoll_context* ctx = (struct epoll_context*)socket;
	assert(ctx->ev.data.ptr == ctx);

	if(0 != epoll_ctl(s_epoll, EPOLL_CTL_DEL, ctx->socket, &ctx->ev))
	{
		assert(EBADF == errno); // EBADF: socket close by user
//		return errno;
	}

	if(ctx->own && EBADF != errno)
	{
		shutdown(ctx->socket, SHUT_RDWR);
		close(ctx->socket);
	}

	ctx->socket = -1;

	aio_socket_release(ctx);
	return 0;
}
Exemplo n.º 5
0
int aio_socket_process(int timeout)
{
	int i, r;
	uint32_t userevent;
	struct epoll_context* ctx;
	struct epoll_event events[1];

	r = epoll_wait(s_epoll, events, 1, timeout);
	for(i = 0; i < r; i++)
	{
		// EPOLLERR: Error condition happened on the associated file descriptor
		// EPOLLHUP: Hang up happened on the associated file descriptor
		// EPOLLRDHUP: Stream socket peer closed connection, or shut down writing half of connection. 
		//			   (This flag is especially useful for writing simple code to detect peer shutdown when using Edge Triggered monitoring.) 
		int flags = EPOLLERR|EPOLLHUP;
#if defined(EPOLLRDHUP)
		flags |= EPOLLRDHUP;
#endif
		assert(events[i].data.ptr);
		ctx = (struct epoll_context*)events[i].data.ptr;
		assert(ctx->ref > 0);
		if(events[i].events & flags)
		{
			// save event
			pthread_spin_lock(&ctx->locker);
			userevent = ctx->ev.events;
			ctx->ev.events &= ~(EPOLLIN|EPOLLOUT);
			pthread_spin_unlock(&ctx->locker);

			// epoll oneshot don't need change event
			//if(userevent & (EPOLLIN|EPOLLOUT))
			//	epoll_ctl(s_epoll, EPOLL_CTL_MOD, ctx->socket, &ctx->ev); // endless loop

			// error
			if(EPOLLIN & userevent)
			{
				assert(ctx->read);
				ctx->read(ctx, 1, EPIPE); // EPOLLRDHUP ?
				aio_socket_release(ctx);
			}

			if(EPOLLOUT & userevent)
			{
				assert(ctx->write);
				ctx->write(ctx, 1, EPIPE); // EPOLLRDHUP ?
				aio_socket_release(ctx);
			}
		}
		else
		{
			// save event
			// 1. thread-1 current ctx->ev.events = EPOLLIN
			// 2. thread-2 user call aio_socket_send() set ctx->ev.events to EPOLLIN|EPOLLOUT
			// 3. switch thread-1 call ctx->write and decrement ctx->ref
			// 4. switch thread-2 aio_socket_send() epoll_ctl failed, then user set ctx->ev.events to EPOLLIN 
			// 5. thread-2 redo decrement ctx->ref (decrement twice, crash)

			// clear IN/OUT event
			pthread_spin_lock(&ctx->locker);
	
			// 1. thread-1 aio_socket_send() set ctx->ev.events to EPOLLOUT
			// 2. thread-2 epoll_wait -> events[i].events EPOLLOUT
			// 3. thread-1 aio_socket_recv() set ctx->ev.events to EPOLLOUT|EPOLLIN
			// 4. thread-1 epoll_wait -> events[i].events EPOLLOUT
			// 5. thread-1 set ctx->ev.events to EPOLLIN
			// 6. thread-2 check ctx->ev.events with EPOLLOUT failed
			//assert(events[i].events == (events[i].events & ctx->ev.events));

			events[i].events &= ctx->ev.events; // check events again(multi-thread condition)
			ctx->ev.events &= ~(events[i].events & (EPOLLIN | EPOLLOUT));
			if(ctx->ev.events & (EPOLLIN|EPOLLOUT))
				epoll_ctl(s_epoll, EPOLL_CTL_MOD, ctx->socket, &ctx->ev); // update epoll event(clear in/out cause EPOLLHUP)
			pthread_spin_unlock(&ctx->locker);

			//if(EPOLLRDHUP & events[i].events)
			//{
			//	// closed
			//	assert(EPOLLIN & events[i].events);
			//}

			if(EPOLLIN & events[i].events)
			{
				assert(ctx->read);
				ctx->read(ctx, 1, 0);
				aio_socket_release(ctx);
			}

			if(EPOLLOUT & events[i].events)
			{
				assert(ctx->write);
				ctx->write(ctx, 1, 0);
				aio_socket_release(ctx);
			}
		}
	}

	return r;
}
Exemplo n.º 6
0
int aio_socket_process(int timeout)
{
	int i, r;
	uint32_t userevent;
	struct epoll_context* ctx;
	struct epoll_event events[1];

	r = epoll_wait(s_epoll, events, 1, timeout);
	for(i = 0; i < r; i++)
	{
		assert(events[i].data.ptr);
		ctx = (struct epoll_context*)events[i].data.ptr;
		if(events[i].events & (EPOLLERR|EPOLLHUP))
		{
			// save event
			// 1. thread-1 current ctx->ev.events = EPOLLIN
			// 2. thread-2 user call aio_socket_send() set ctx->ev.events to EPOLLIN|EPOLLOUT
			// 3. switch thread-1 call ctx->write and decrement ctx->ref
			// 4. switch thread-2 aio_socket_send() epoll_ctl failed, then user set ctx->ev.events to EPOLLIN 
			// 5. thread-2 redo decrement ctx->ref (decrement twice, crash)
			pthread_spin_lock(&ctx->locker);
			userevent = ctx->ev.events;
			pthread_spin_unlock(&ctx->locker);

			// error
			if(EPOLLIN & userevent)
			{
				assert(ctx->read);
				ctx->read(ctx, 1, -1);
				aio_socket_release(ctx);
			}

			if(EPOLLOUT & userevent)
			{
				assert(ctx->write);
				ctx->write(ctx, 1, -1);
				aio_socket_release(ctx);
			}
		}
		else
		{
			// clear IN/OUT event
			pthread_spin_lock(&ctx->locker);
			assert(events[i].events == (events[i].events & ctx->ev.events));
			ctx->ev.events &= ~(events[i].events & (EPOLLIN|EPOLLOUT));
			pthread_spin_unlock(&ctx->locker);
			epoll_ctl(s_epoll, EPOLL_CTL_MOD, ctx->socket, &ctx->ev);

			if(EPOLLRDHUP & events[i].events)
			{
				// closed
				assert(EPOLLIN & events[i].events);
			}

			if(EPOLLIN & events[i].events)
			{
				assert(ctx->read);
				ctx->read(ctx, 1, 0);
				aio_socket_release(ctx);
			}

			if(EPOLLOUT & events[i].events)
			{
				assert(ctx->write);
				ctx->write(ctx, 1, 0);
				aio_socket_release(ctx);
			}
		}
	}

	return r;
}