struct fd_info {
enum fd_type type;
int fd;
- struct fd_info *dupfdi;
+ int dupfd;
atomic_t refcnt;
};
goto err1;
}
+ fdi->dupfd = -1;
atomic_init(&fdi->refcnt);
atomic_set(&fdi->refcnt, 1);
pthread_mutex_lock(&mut);
int close(int socket)
{
- int fd;
+ struct fd_info *fdi;
+
init_preload();
- return (fd_close(socket, &fd) == fd_rsocket) ? rclose(fd) : real.close(fd);
+ fdi = idm_lookup(&idm, socket);
+ if (!fdi)
+ return real.close(socket);
+
+ if (fdi->dupfd != -1) {
+ ret = close(fdi->dupfd);
+ if (ret)
+ return ret;
+ }
+
+ if (atomic_dec(&fdi->refcnt))
+ return 0;
+
+ idm_clear(&idm, socket);
+ real.close(socket);
+ ret = (fdi->type == fd_rsocket) ? rclose(fdi->fd) : real.close(fdi->fd);
+ free(fdi);
+ return ret;
}
int getpeername(int socket, struct sockaddr *addr, socklen_t *addrlen)
idm_set(&idm, newfd, newfdi);
pthread_mutex_unlock(&mut);
- if (oldfdi->dupfdi)
- oldfdi = oldfdi->dupfdi;
newfdi->fd = oldfdi->fd;
newfdi->type = oldfdi->type;
- newfdi->dupfdi = oldfdi;
+ if (oldfdi->dupfd != -1) {
+ newfdi->dupfd = oldfdi->dupfd;
+ oldfdi = idm_lookup(&idm, oldfdi->dupfd);
+ } else {
+ newfdi->dupfd = oldfd;
+ }
atomic_init(&newfdi->refcnt);
atomic_set(&newfdi->refcnt, 1);
atomic_inc(&oldfdi->refcnt);