close问题。。

资源管理器还真难写。。
accept出来的句柄一close就会问题。出什么问题也看不懂。。
就是客户端再连一个就会被挂起。。

不把accept出来的句柄close的话,还能多接受几个客户端,但超过10几个就会崩溃。。。

都搞晕了。。。
不知道这个多线程资源管理器有什么问题。。


int my_io_open (resmgr_context_t *ctp, io_open_t *io,
RESMGR_HANDLE_T *h, void *v)
{
	int ret;
	io_socket_extra_t *ext = v;
                int fd;
 
 
	ret = iofunc_open_default(ctp,io,h,v);
	if (ret != 0) {
		printf("fail default open for pid:%d,coid:%d, strerror:%s\n", ctp->info.pid, ctp->info.coid,strerror(errno));
		return ret;
	}
	fd = my_open(,ext->type, ext->protocol);
               	if (fd != 0) {
		printf("fail my open for pid:%d,coid:%d, strerror:%s\n", ctp->info.pid, ctp->info.coid,strerror(errno));
		return ret;
	}
                my_fd_map(fd, ctp->info.pid, ctp->info.coid);
	return _RESMGR_ERRNO(EOK);
}


int my_io_openfd(resmgr_context_t *ctp, io_openfd_t *msg, RESMGR_OCB_T *ocb)
{
	int listen_fd;
	int child_fd;
	int len;
	int ret;
	struct sockaddr_in *addr;
	int type;


	switch (msg->i.xtype) {
	case _IO_OPENFD_ACCEPT:
		listen_fd = my_lookup_fd(ctp->info.pid, ctp->info.coid); 
		if (listen_fd < 0) {
			printf("Can't find socket for pid:%d,coid:%d\n", ctp->info.pid, ctp->info.coid);
			return _RESMGR_ERRNO(EBADF);
		}
		ret = iofunc_openfd(ctp, msg, ocb, ocb->attr);
		if (ret != EOK) {
			printf("iofunc_openfd ret:%d,str:%s\n",ret,strerror(errno));
			return _RESMGR_ERRNO(ret);
		}
		len = ctp->msg_max_size - ((char *)msg - (char *)ctp->msg);
		addr    = (struct sockaddr_in *)msg;
		iofunc_attr_unlock(ocb->attr);
		child_fd = my_accept(listen_fd, addr, &len);
		printf("my_accept return child_fd:%d, strerror:%s.\n", child_fd, strerror(errno));
		iofunc_attr_lock(ocb->attr);
		_RESMGR_STATUS(ctp, len);
                                my_fd_map(child_fd, ctp->info.pid, ctp->info.coid);
		return _RESMGR_ERRNO(errno);
	}
	return _RESMGR_ERRNO(EINVAL);
}


int
my_io_close(resmgr_context_t *ctp, void *msg, RESMGR_OCB_T *ocb)
{
	int i;
	iofunc_notify_t **notify;
	int type, handle;
	int ret;

	fd = my_lookup_fd(ctp->info.pid, ctp->info.coid);
	if (ret < 0) {
		printf("Can't find socket for pid:%d,coid:%d\n", ctp->info.pid, ctp->info.coid);
		return _RESMGR_ERRNO(EBADF);
	}
	my_notify_remove(ctp, fd);
 	my_close_fd(fd);
	iofunc_close_ocb(ctp, ocb, ocb->attr);
	return 0;
}


int main( int argc, char **argv )
{
	resmgr_connect_funcs_t ConnectFuncs;
	resmgr_io_funcs_t IoFuncs;
	iofunc_attr_t IoFuncAttr;
	thread_pool_attr_t pool_attr;
	thread_pool_t *tpp;
	resmgr_attr_t resmgr_attr;
	dispatch_t *dpp;
	dispatch_context_t *ctp, *ctp_ret;
	int resmgr_id;


	dpp = dispatch_create();
	if( dpp == NULL )
	{
		fprintf( stderr, "dispatch_create() failed: %s\n", strerror( errno ) );
		return EXIT_FAILURE;
	}
	memset( &resmgr_attr, 0, sizeof( resmgr_attr ) );
	resmgr_attr.nparts_max = 5;
	resmgr_attr.msg_max_size = 2048;
	/* Setup the default I/O functions to handle open/read/write/... */
	iofunc_func_init( _RESMGR_CONNECT_NFUNCS, &ConnectFuncs,
	_RESMGR_IO_NFUNCS, &IoFuncs );
	ConnectFuncs.open = my_io_open;
	IoFuncs.read = my_io_read;
	IoFuncs.write = my_io_write;
	IoFuncs.close_ocb = my_io_close;
	IoFuncs.devctl = my_io_devctl;
	IoFuncs.openfd = my_io_openfd;
	IoFuncs.notify = my_io_notify;
	/* Setup the attribute for the entry in the filesystem */
	iofunc_attr_init( &IoFuncAttr, S_IFNAM | 0666, 0, 0 );
	printf("hello\n");
	resmgr_id = resmgr_attach( dpp, &resmgr_attr, "/dev/socket/4", _FTYPE_SOCKET, _RESMGR_FLAG_SELF,
			&ConnectFuncs, &IoFuncs, &IoFuncAttr );
	if( resmgr_id == -1 )
	{
		fprintf( stderr, "resmgr_attach() failed: %s\n", strerror( errno ) );
		return EXIT_FAILURE;
	}

	/* initialize thread pool attributes */
	memset(&pool_attr, 0, sizeof pool_attr);
	pool_attr.handle = dpp;
	pool_attr.context_alloc = dispatch_context_alloc;
	pool_attr.block_func = dispatch_block;
	pool_attr.unblock_func = dispatch_unblock;
	pool_attr.handler_func = dispatch_handler;
	pool_attr.context_free = dispatch_context_free;
	pool_attr.lo_water = 2;
	pool_attr.hi_water = 10;
	pool_attr.increment = 1;
	pool_attr.maximum = 50;
	/* allocate a thread pool handle */
	if((tpp = thread_pool_create(&pool_attr,
	POOL_FLAG_EXIT_SELF)) == NULL) {
	return EXIT_FAILURE;
	}
	/* start the threads, will not return */
	thread_pool_start(tpp);

}

经常会有err:No such process,而且这个错误是在进入我的消息处理前就有了。。read、write、notify、accept都会出现。。

客户端使用recv读取数据时,返回值都是正确的,但是buf里的内容有时候却是错误的。。。


int my_io_read (resmgr_context_t *ctp, io_read_t *msg, RESMGR_OCB_T *ocb)
{
	int ret;
	int sockid;
	struct msghdr mh;
	int flags;
	iov_t iov;

	sockid = my_lookup_fd(ctp->info.pid,ctp->info.coid);
	if (sockid < 0) {
		return -1;
	}
	printf("enter recv:%d.str:%s\n",errno,strerror(errno));  //有时候这里已经有no such process的错误了。。。
	switch(msg->i.xtype) {
	case _IO_XTYPE_TCPIP:/*recv、recvfrom*/
	{
		io_sock_recvfrom_t *recvp = (io_sock_recvfrom_t *)msg;

		flags = recvp->i.flags;
		mh.msg_control = NULL;
		mh.msg_controllen = 0;
		mh.msg_name = recvp->i.addrlen ? (void *)((char *)&recvp->o + sizeof recvp->o) : NULL;
		mh.msg_namelen = recvp->i.addrlen;
		mh.msg_iov = &iov;
		iov.iov_base = ((char *)&recvp->o + sizeof recvp->o) + recvp->i.addrlen;
		iov.iov_len = recvp->i.read.nbytes;
	}
		break;
	case _IO_XTYPE_TCPIP_MSG:/*recvmsg*/
	{
		struct iovec iov;
		io_sock_recvmsg_t *recvp = (io_sock_recvmsg_t *)msg;
                      //to be completed:
	}
		break;
	default:
		printf("come into default\n");
		break;
	}
                iofunc_attr_unlock(ocb->attr);
	iov.iov_len = my_recv(sockid,iov.iov_base,iov.iov_len,0);
	printf("my_recv ret:%d,errno:%d,%s,str:%s\n",iov.iov_len,errno,iov.iov_base,strerror(errno));
	iofunc_attr_lock(ocb->attr);
	_IO_SET_READ_NBYTES(ctp, iov.iov_len);
	if (iov.iov_len < 0) {
		return _RESMGR_ERRNO(errno);
	} else
		return _RESMGR_NPARTS(3);
}

read返回的内容错误估计是因为我用的多线程,又不加锁,不能直接让资源管理器返回,因为内容可能被别的线程改掉。。

我没试过,不过我有个疑问。在my_io_open()里,你用my_fd_map()把fd和ctp->info.pid/ctp->info.coid映射到一起,在my_io_openfd()里,你用my_lookup_fd()把这个fd做为listen_fd再找出来,是吗?

我感觉在这两个函数里的 ctp->info.coid 应该是不一样的,你可以打印一下试试。

my_io_read()里,如果进来的xtype什么也不是的话,iov好象没初始化?就算是 recv/recvfrom进来的,最后的那个 return _RESMGR_NPARTS(3); 似乎也不对。

在这两个函数里的 ctp->info.coid 确实是不一样的,那个lookup需要使用
msg->i.info.pid, msg->i.info.coid 这两个来找到listen_fd。

现在我的问题是openfd之后得到的connect关闭时,系统就会出问题。。
资源管理器的listen_fd无法正常工作。

非openfd得到的connect直接关闭就没有问题。

猜测可能是iofunc_openfd新建的连接与listen_fd对应的连接有所关联,不能直接使用iofunc_close_ocb关闭openfd得到的连接,否则会影响到listen_fd。。
但是不知道这两者的关联该怎么解除。

我该怎么去删除openfd得到的连接呢?

对,但是,在my_accept()返回child_fd后,你应该用ctp->info.pid, ctp->info.coid来map它;这样才能保证在close时,你会close这个child_fd,而不是别的值。

你可以把listen_fd, child_fd, my_io_close()时找到的fd都打出来确认一下,看看你每次关掉的fd是不是正确。

openfd()的连接与listen_fd的连接应该是没有什么别的关系的。

嗯,我是使用ctp->info.pid, ctp->info.coid来map它的,
对于fd内部的操作,这个是可以确保没有问题的,除了notify,其它与资源管理器框架基本没有关联了。

现在没有使用iofunc_openfd,而是学着iofunc_openfd里面构造相应的参数调用iofunc_open_default,不再与listen的句柄对应的ocb产生关联,close就没问题了。

所以现在就是不懂在资源管理器内部,iofunc_openfd会把listen的ocb与accept产生的ocb进行什么样的关联? 为什么close会导致listen的资源出问题?

资源管理器就是个黑匣子,实现起来真痛苦。

一进入io_openfd,errno就不为0,已经是No such process了,不知道为什么。

还有照上面的close处理,进入iofunc_close_ocb函数前没有errno,出来后就是Invalid argument,iofunc_close_ocb恒返回OK,就是说errno没有意义?不知道为什么errno会变成这个Invalid argument。

close改完后,可以accept,close连接。
但是有5个客户端连接上来后,进程就挂掉了,
前4个都跑得好好的,第5个一来就挂。
异常是SIGSEGV Segmentation violation.

资源管理器的源码,都在C库里,这个以前在F27上开源的。如果你有C库源码,可以编译相关函数链到你的程序里,这样就可以从头Debug了。

errno的值只在出错时有效,函数不出错时,errno可以是任意值。

SIGSEGV是使用了非法内存,除去常见原因外,多线程同步不好也会出这个错,debug一下就能找到原因。

汗,系统有问题,free一个某些特定的地址就会死掉。因为我简单测试时,固定到5个连接时会死,因为第5个连接会分配到特定的地址,然后free就死了。
我先申请一段内存,避开那个特定的地址,结果都没问题了。真是晕。
操作系统是虚拟机上的6.4.1。。。

说实话,我怀疑这个是系统问题。

free()时出错(有时也会在malloc时SIGSEGV),通常是因为Heap里的链接指针被冲乱了所致。而Heap里的指针会乱,一般是因为你的程序有内存处理问题。double free()啊,malloc来的内存使用时越界啊,都有可能造成这种错。

你的办法,很可能回避了出错针所在的内存块,但如果是我猜测的那样,那么连接更多,或多次连接、关闭什么的,早晚会出问题。最好是现在能发现解决,(现在至少你能保证每5次连接就出错)要是到了以后”每隔二、三天会crash一次“的时候,就更难找了。:slight_smile: