#define fastlock_destroy(lock) pthread_mutex_destroy(lock)
#define fastlock_acquire(lock) pthread_mutex_lock(lock)
#define fastlock_release(lock) pthread_mutex_unlock(lock)
+
+typedef struct { pthread_mutex_t mut; int val; } atomic_t;
+static inline int atomic_inc(atomic_t *atomic)
+{
+ int v;
+
+ pthread_mutex_lock(&atomic->mut);
+ v = ++(atomic->val);
+ pthread_mutex_unlock(&atomic->mut);
+ return v;
+}
+static inline int atomic_dec(atomic_t *atomic)
+{
+ int v;
+
+ pthread_mutex_lock(&atomic->mut);
+ v = --(atomic->val);
+ pthread_mutex_unlock(&atomic->mut);
+ return v;
+}
+static inline void atomic_init(atomic_t *atomic)
+{
+ pthread_mutex_init(&atomic->mut, NULL);
+ atomic->val = 0;
+}
#else
typedef struct {
sem_t sem;
if (__sync_sub_and_fetch(&lock->cnt, 1) > 0)
sem_post(&lock->sem);
}
+
+typedef struct { volatile int val; } atomic_t;
+#define atomic_inc(v) (__sync_add_and_fetch(&(v)->val, 1))
+#define atomic_dec(v) (__sync_sub_and_fetch(&(v)->val, 1))
+#define atomic_init(v) ((v)->val = 0)
#endif /* DEFINE_ATOMICS */
+#define atomic_get(v) ((v)->val)
+#define atomic_set(v, s) ((v)->val = s)
int ucma_max_qpsize(struct rdma_cm_id *id);
int ucma_complete(struct rdma_cm_id *id);
int (*getsockopt)(int socket, int level, int optname,
void *optval, socklen_t *optlen);
int (*fcntl)(int socket, int cmd, ... /* arg */);
+ int (*dup2)(int oldfd, int newfd);
};
static struct socket_calls real;
struct fd_info {
enum fd_type type;
int fd;
+ struct fd_info *dupfdi;
+ atomic_t refcnt;
};
static int fd_open(void)
goto err1;
}
+ atomic_init(&fdi->refcnt);
+ atomic_set(&fdi->refcnt, 1);
pthread_mutex_lock(&mut);
ret = idm_set(&idm, index, fdi);
pthread_mutex_unlock(&mut);
real.setsockopt = dlsym(RTLD_NEXT, "setsockopt");
real.getsockopt = dlsym(RTLD_NEXT, "getsockopt");
real.fcntl = dlsym(RTLD_NEXT, "fcntl");
+ real.dup2 = dlsym(RTLD_NEXT, "dup2");
rs.socket = dlsym(RTLD_DEFAULT, "rsocket");
rs.bind = dlsym(RTLD_DEFAULT, "rbind");
return ret;
}
+/*
+ * dup2 is not thread safe
+ */
int dup2(int oldfd, int newfd)
{
- int fd;
- return (fd_get(oldfd, &fd) == fd_rsocket) ?
- : dup2(oldfd, newfd);
+ struct fd_info *oldfdi, *newfdi;
+ int ret;
+
+ oldfdi = idm_lookup(&idm, oldfd);
+ newfdi = idm_lookup(&idm, newfd);
+ if (newfdi) {
+ /* newfd cannot have been dup'ed directly */
+ if (atomic_get(&newfdi->refcnt) > 1)
+ return ERR(EBUSY);
+ close(newfd);
+ }
+
+ ret = real.dup2(oldfd, newfd);
+ if (!oldfdi || ret != newfd)
+ return ret;
+
+ newfdi = calloc(1, sizeof *fdi);
+ if (!newfdi) {
+ close(newfd);
+ return ERR(ENOMEM);
+ }
+
+ pthread_mutex_lock(&mut);
+ 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;
+ atomic_init(&newfdi->refcnt);
+ atomic_set(&newfdi->refcnt, 1);
+ atomic_inc(&oldfdi->refcnt);
+ return newfd;
}