#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <pthread.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/time.h>
#include "fi.h"
#include "fi_osd.h"
#include "fi_file.h"
#include "rdma/fi_errno.h"
#include "rdma/providers/fi_log.h"
int fi_fd_nonblock(int fd)
{
long flags = 0;
flags = fcntl(fd, F_GETFL);
if (flags < 0) {
return -errno;
}
if(fcntl(fd, F_SETFL, flags | O_NONBLOCK))
return -errno;
return 0;
}
int fi_wait_cond(pthread_cond_t *cond, pthread_mutex_t *mut, int timeout_ms)
{
uint64_t t;
struct timespec ts;
if (timeout_ms < 0)
return pthread_cond_wait(cond, mut);
t = fi_gettime_ms() + timeout_ms;
ts.tv_sec = t / 1000;
ts.tv_nsec = (t % 1000) * 1000000;
return pthread_cond_timedwait(cond, mut, &ts);
}
int ofi_shm_map(struct util_shm *shm, const char *name, size_t size,
int readonly, void **mapped)
{
char *fname = 0;
int i, ret = FI_SUCCESS;
int flags = O_RDWR | (readonly ? 0 : O_CREAT);
struct stat mapstat;
*mapped = MAP_FAILED;
memset(shm, 0, sizeof(*shm));
fname = calloc(1, strlen(name) + 2);
if (!fname)
return -FI_ENOMEM;
strcpy(fname, "/");
strcat(fname, name);
shm->name = fname;
for (i = 0; i < strlen(fname); i++) {
if (fname[i] == ' ')
fname[i] = '_';
}
FI_DBG(&core_prov, FI_LOG_CORE,
"Creating shm segment :%s (size: %lu)\n", fname, size);
shm->shared_fd = shm_open(fname, flags, S_IRUSR | S_IWUSR);
if (shm->shared_fd < 0) {
FI_WARN(&core_prov, FI_LOG_CORE, "shm_open failed\n");
ret = -FI_EINVAL;
goto failed;
}
if (fstat(shm->shared_fd, &mapstat)) {
FI_WARN(&core_prov, FI_LOG_CORE, "failed to do fstat: %s\n",
strerror(errno));
ret = -FI_EINVAL;
goto failed;
}
if (mapstat.st_size == 0) {
if (ftruncate(shm->shared_fd, size)) {
FI_WARN(&core_prov, FI_LOG_CORE,
"ftruncate failed: %s\n", strerror(errno));
ret = -FI_EINVAL;
goto failed;
}
} else if (mapstat.st_size < size) {
FI_WARN(&core_prov, FI_LOG_CORE, "shm file too small\n");
ret = -FI_EINVAL;
goto failed;
}
shm->ptr = mmap(NULL, size, PROT_READ | PROT_WRITE,
MAP_SHARED, shm->shared_fd, 0);
if (shm->ptr == MAP_FAILED) {
FI_WARN(&core_prov, FI_LOG_CORE,
"mmap failed: %s\n", strerror(errno));
ret = -FI_EINVAL;
goto failed;
}
*mapped = shm->ptr;
shm->size = size;
return ret;
failed:
if (shm->shared_fd >= 0) {
close(shm->shared_fd);
shm_unlink(fname);
}
if (fname)
free(fname);
memset(shm, 0, sizeof(*shm));
return ret;
}
int ofi_shm_unmap(struct util_shm* shm)
{
if (shm->ptr && shm->ptr != MAP_FAILED) {
if (munmap(shm->ptr, shm->size)) {
FI_WARN(&core_prov, FI_LOG_CORE,
"munmap failed: %s\n", strerror(errno));
}
}
if (shm->shared_fd)
close(shm->shared_fd);
if (shm->name) {
shm_unlink(shm->name);
free((void*)shm->name);
}
memset(shm, 0, sizeof(*shm));
return FI_SUCCESS;
}
int fi_read_file(const char *dir, const char *file, char *buf, size_t size)
{
char *path;
int fd, len;
if (asprintf(&path, "%s/%s", dir, file) < 0)
return -1;
fd = open(path, O_RDONLY);
if (fd < 0) {
free(path);
return -1;
}
len = read(fd, buf, size);
close(fd);
free(path);
if (len > 0 && buf[len - 1] == '\n')
buf[--len] = '\0';
return len;
}