aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--erts/emulator/drivers/common/efile_drv.c569
-rw-r--r--erts/preloaded/ebin/prim_file.beambin39536 -> 46840 bytes
-rw-r--r--erts/preloaded/src/prim_file.erl600
-rw-r--r--lib/kernel/src/file.erl149
-rw-r--r--lib/kernel/src/file_io_server.erl15
-rw-r--r--lib/kernel/src/file_server.erl106
-rw-r--r--lib/kernel/test/prim_file_SUITE.erl108
7 files changed, 1061 insertions, 486 deletions
diff --git a/erts/emulator/drivers/common/efile_drv.c b/erts/emulator/drivers/common/efile_drv.c
index a251b064da..b72f95792c 100644
--- a/erts/emulator/drivers/common/efile_drv.c
+++ b/erts/emulator/drivers/common/efile_drv.c
@@ -112,6 +112,8 @@
#include "erl_threads.h"
#include "zlib.h"
#include "gzio.h"
+#define DTRACE_DRIVER_SKIP_FUNC_DECLARATIONS
+#include "dtrace-wrapper.h"
#include <ctype.h>
#include <sys/types.h>
@@ -119,6 +121,40 @@ void erl_exit(int n, char *fmt, ...);
static ErlDrvSysInfo sys_info;
+/* For explanation of this var, see comment for same var in erl_async.c */
+static unsigned gcc_optimizer_hack = 0;
+
+#ifdef HAVE_DTRACE
+
+#define DTRACE_INVOKE_SETUP(op) \
+ do { DTRACE3(efile_drv_int_entry, d->sched_i1, d->sched_i2, op); } while (0)
+#define DTRACE_INVOKE_SETUP_BY_NAME(op) \
+ struct t_data *d = (struct t_data *) data ; \
+ DTRACE_INVOKE_SETUP(op)
+#define DTRACE_INVOKE_RETURN(op) \
+ do { DTRACE3(efile_drv_int_return, d->sched_i1, d->sched_i2, \
+ op); } while (0) ; gcc_optimizer_hack++ ;
+
+/* Assign human-friendlier id numbers to scheduler & I/O worker threads */
+int dt_driver_idnum = 0;
+int dt_driver_io_worker_base = 5000;
+erts_mtx_t dt_driver_mutex;
+pthread_key_t dt_driver_key;
+
+typedef struct {
+ int thread_num;
+ Uint64 tag;
+} dt_private;
+
+dt_private *get_dt_private(int);
+#else /* HAVE_DTRACE */
+typedef struct {
+} dt_private;
+
+#define DTRACE_INVOKE_SETUP(op) do {} while (0)
+#define DTRACE_INVOKE_SETUP_BY_NAME(op) do {} while (0)
+#define DTRACE_INVOKE_RETURN(op) do {} while (0)
+#endif /* HAVE_DTRACE */
/* #define TRACE 1 */
#ifdef TRACE
@@ -289,6 +325,10 @@ typedef struct {
ErlDrvPDL q_mtx; /* Mutex for the driver queue, known by the emulator. Also used for
mutual exclusion when accessing field(s) below. */
size_t write_buffered;
+#ifdef HAVE_DTRACE
+ int idnum; /* Unique ID # for this driver thread/desc */
+ char port_str[DTRACE_TERM_BUF_SIZE];
+#endif
} file_descriptor;
@@ -386,6 +426,13 @@ struct t_data
void (*free)(void *);
int again;
int reply;
+#ifdef HAVE_DTRACE
+ int sched_i1;
+ Uint64 sched_i2;
+ char sched_utag[128+1];
+#else
+ char sched_utag[1];
+#endif
int result_ok;
Efile_error errInfo;
int flags;
@@ -458,8 +505,6 @@ struct t_data
char b[1];
};
-
-
#define EF_ALLOC(S) driver_alloc((S))
#define EF_REALLOC(P, S) driver_realloc((P), (S))
#define EF_SAFE_ALLOC(S) ef_safe_alloc((S))
@@ -488,7 +533,7 @@ static void *ef_safe_realloc(void *op, Uint s)
* ErlIOVec manipulation functions.
*/
-/* char EV_CHAR(ErlIOVec *ev, int p, int q) */
+/* char EV_CHAR_P(ErlIOVec *ev, int p, int q) */
#define EV_CHAR_P(ev, p, q) \
(((char *)(ev)->iov[(q)].iov_base) + (p))
@@ -683,6 +728,11 @@ file_init(void)
: 0);
driver_system_info(&sys_info, sizeof(ErlDrvSysInfo));
+#ifdef HAVE_DTRACE
+ erts_mtx_init(&dt_driver_mutex, "efile_drv dtrace mutex");
+ pthread_key_create(&dt_driver_key, NULL);
+#endif /* HAVE_DTRACE */
+
return 0;
}
@@ -722,6 +772,10 @@ file_start(ErlDrvPort port, char* command)
desc->write_error = 0;
MUTEX_INIT(desc->q_mtx, port); /* Refc is one, referenced by emulator now */
desc->write_buffered = 0;
+#ifdef HAVE_DTRACE
+ dtrace_drvport_str(port, desc->port_str);
+ get_dt_private(0); /* throw away return value */
+#endif /* HAVE_DTRACE */
return (ErlDrvData) desc;
}
@@ -741,8 +795,10 @@ static void do_close(int flags, SWord fd) {
static void invoke_close(void *data)
{
struct t_data *d = (struct t_data *) data;
+ DTRACE_INVOKE_SETUP(FILE_CLOSE);
d->again = 0;
do_close(d->flags, d->fd);
+ DTRACE_INVOKE_RETURN(FILE_CLOSE);
}
/*********************************************************************
@@ -972,49 +1028,63 @@ static void invoke_name(void *data, int (*f)(Efile_error *, char *))
static void invoke_mkdir(void *data)
{
+ DTRACE_INVOKE_SETUP_BY_NAME(FILE_MKDIR);
invoke_name(data, efile_mkdir);
+ DTRACE_INVOKE_RETURN(FILE_MKDIR);
}
static void invoke_rmdir(void *data)
{
+ DTRACE_INVOKE_SETUP_BY_NAME(FILE_RMDIR);
invoke_name(data, efile_rmdir);
+ DTRACE_INVOKE_RETURN(FILE_RMDIR);
}
static void invoke_delete_file(void *data)
{
+ DTRACE_INVOKE_SETUP_BY_NAME(FILE_DELETE);
invoke_name(data, efile_delete_file);
+ DTRACE_INVOKE_RETURN(FILE_DELETE);
}
static void invoke_chdir(void *data)
{
+ DTRACE_INVOKE_SETUP_BY_NAME(FILE_CHDIR);
invoke_name(data, efile_chdir);
+ DTRACE_INVOKE_RETURN(FILE_CHDIR);
}
static void invoke_fdatasync(void *data)
{
struct t_data *d = (struct t_data *) data;
int fd = (int) d->fd;
+ DTRACE_INVOKE_SETUP(FILE_FDATASYNC);
d->again = 0;
d->result_ok = efile_fdatasync(&d->errInfo, fd);
+ DTRACE_INVOKE_RETURN(FILE_FDATASYNC);
}
static void invoke_fsync(void *data)
{
struct t_data *d = (struct t_data *) data;
int fd = (int) d->fd;
+ DTRACE_INVOKE_SETUP(FILE_FSYNC);
d->again = 0;
d->result_ok = efile_fsync(&d->errInfo, fd);
+ DTRACE_INVOKE_RETURN(FILE_FSYNC);
}
static void invoke_truncate(void *data)
{
struct t_data *d = (struct t_data *) data;
int fd = (int) d->fd;
+ DTRACE_INVOKE_SETUP(FILE_TRUNCATE);
d->again = 0;
d->result_ok = efile_truncate_file(&d->errInfo, &fd, d->flags);
+ DTRACE_INVOKE_RETURN(FILE_TRUNCATE);
}
static void invoke_read(void *data)
@@ -1022,6 +1092,7 @@ static void invoke_read(void *data)
struct t_data *d = (struct t_data *) data;
int status, segment;
size_t size, read_size;
+ DTRACE_INVOKE_SETUP(FILE_READ);
segment = d->again && d->c.read.bin_size >= 2*FILE_SEGMENT_READ;
if (segment) {
@@ -1056,6 +1127,7 @@ static void invoke_read(void *data)
} else {
d->again = 0;
}
+ DTRACE_INVOKE_RETURN(FILE_READ);
}
static void free_read(void *data)
@@ -1072,6 +1144,7 @@ static void invoke_read_line(void *data)
int status;
size_t read_size;
int local_loop = (d->again == 0);
+ DTRACE_INVOKE_SETUP(FILE_READ_LINE);
do {
size_t size = (d->c.read_line.binp)->orig_size -
@@ -1163,6 +1236,7 @@ static void invoke_read_line(void *data)
break;
}
} while (local_loop);
+ DTRACE_INVOKE_RETURN(FILE_READ_LINE);
}
static void free_read_line(void *data)
@@ -1178,6 +1252,7 @@ static void invoke_read_file(void *data)
struct t_data *d = (struct t_data *) data;
size_t read_size;
int chop;
+ DTRACE_INVOKE_SETUP(FILE_READ_FILE);
if (! d->c.read_file.binp) { /* First invocation only */
int fd;
@@ -1214,12 +1289,14 @@ static void invoke_read_file(void *data)
&read_size);
if (d->result_ok) {
d->c.read_file.offset += read_size;
- if (chop) return; /* again */
+ if (chop) goto chop_done; /* again */
}
close:
efile_closefile((int) d->fd);
done:
d->again = 0;
+ chop_done:
+ DTRACE_INVOKE_RETURN(FILE_READ_FILE);
}
static void free_read_file(void *data)
@@ -1239,6 +1316,7 @@ static void invoke_preadv(void *data)
ErlIOVec *ev = &c->eiov;
size_t bytes_read_so_far = 0;
unsigned char *p = (unsigned char *)ev->iov[0].iov_base + 4+4+8*c->cnt;
+ DTRACE_INVOKE_SETUP(FILE_PREADV);
while (c->cnt < c->n) {
size_t read_size = ev->iov[1 + c->cnt].iov_len - c->size;
@@ -1260,7 +1338,7 @@ static void invoke_preadv(void *data)
bytes_read_so_far += bytes_read;
if (chop && bytes_read == read_size) {
c->size += bytes_read;
- return;
+ goto done;
}
ASSERT(bytes_read <= read_size);
ev->iov[1 + c->cnt].iov_len = bytes_read + c->size;
@@ -1271,7 +1349,7 @@ static void invoke_preadv(void *data)
if (d->again
&& bytes_read_so_far >= FILE_SEGMENT_READ
&& c->cnt < c->n) {
- return;
+ goto done;
}
} else {
/* In case of a read error, ev->size will not be correct,
@@ -1282,6 +1360,8 @@ static void invoke_preadv(void *data)
}
}
d->again = 0;
+ done:
+ DTRACE_INVOKE_RETURN(FILE_PREADV);
}
static void free_preadv(void *data) {
@@ -1303,6 +1383,7 @@ static void invoke_ipread(void *data)
size_t bytes_read = 0;
char buf[2*sizeof(Uint32)];
Uint32 offset, size;
+ DTRACE_INVOKE_SETUP(FILE_IPREAD);
/* Read indirection header */
if (! efile_pread(&d->errInfo, (int) d->fd, c->offsets[0],
@@ -1341,14 +1422,17 @@ static void invoke_ipread(void *data)
/* Read data block */
d->invoke = invoke_preadv;
invoke_preadv(data);
+ DTRACE_INVOKE_RETURN(FILE_IPREAD);
return;
error:
d->result_ok = 0;
d->again = 0;
+ DTRACE_INVOKE_RETURN(FILE_IPREAD);
return;
done:
d->result_ok = !0;
d->again = 0;
+ DTRACE_INVOKE_RETURN(FILE_IPREAD);
}
/* invoke_writev and invoke_pwritev are the only thread functions that
@@ -1371,6 +1455,7 @@ static void invoke_writev(void *data) {
size_t size;
size_t p;
int segment;
+ DTRACE_INVOKE_SETUP(FILE_WRITE);
segment = d->again && d->c.writev.size >= 2*FILE_SEGMENT_WRITE;
if (segment) {
@@ -1444,6 +1529,7 @@ static void invoke_writev(void *data) {
TRACE_F(("w%lu", (unsigned long)size));
}
+ DTRACE_INVOKE_RETURN(FILE_WRITE);
}
static void free_writev(void *data) {
@@ -1457,34 +1543,40 @@ static void free_writev(void *data) {
static void invoke_pwd(void *data)
{
struct t_data *d = (struct t_data *) data;
+ DTRACE_INVOKE_SETUP(FILE_PWD);
d->again = 0;
d->result_ok = efile_getdcwd(&d->errInfo,d->drive, d->b+1,
RESBUFSIZE-1);
+ DTRACE_INVOKE_RETURN(FILE_PWD);
}
static void invoke_readlink(void *data)
{
struct t_data *d = (struct t_data *) data;
char resbuf[RESBUFSIZE]; /* Result buffer. */
+ DTRACE_INVOKE_SETUP(FILE_READLINK);
d->again = 0;
d->result_ok = efile_readlink(&d->errInfo, d->b, resbuf+1,
RESBUFSIZE-1);
if (d->result_ok != 0)
FILENAME_COPY((char *) d->b + 1, resbuf+1);
+ DTRACE_INVOKE_RETURN(FILE_READLINK);
}
static void invoke_altname(void *data)
{
struct t_data *d = (struct t_data *) data;
char resbuf[RESBUFSIZE]; /* Result buffer. */
+ DTRACE_INVOKE_SETUP(FILE_ALTNAME);
d->again = 0;
d->result_ok = efile_altname(&d->errInfo, d->b, resbuf+1,
RESBUFSIZE-1);
if (d->result_ok != 0)
FILENAME_COPY((char *) d->b + 1, resbuf+1);
+ DTRACE_INVOKE_RETURN(FILE_ALTNAME);
}
static void invoke_pwritev(void *data) {
@@ -1497,6 +1589,7 @@ static void invoke_pwritev(void *data) {
size_t p;
int segment;
size_t size, write_size;
+ DTRACE_INVOKE_SETUP(FILE_PWRITEV);
segment = d->again && c->size >= 2*FILE_SEGMENT_WRITE;
if (segment) {
@@ -1576,6 +1669,7 @@ static void invoke_pwritev(void *data) {
}
done:
EF_FREE(iov); /* Free our copy of the vector, nothing to restore */
+ DTRACE_INVOKE_RETURN(FILE_PWRITEV);
}
static void free_pwritev(void *data) {
@@ -1591,9 +1685,14 @@ static void invoke_flstat(void *data)
{
struct t_data *d = (struct t_data *) data;
+ DTRACE3(efile_drv_int_entry, d->sched_i1, d->sched_i2,
+ d->command == FILE_LSTAT ? FILE_LSTAT : FILE_FSTAT);
d->again = 0;
d->result_ok = efile_fileinfo(&d->errInfo, &d->info,
d->b, d->command == FILE_LSTAT);
+ DTRACE3(efile_drv_int_entry, d->sched_i1, d->sched_i2,
+ d->command == FILE_LSTAT ? FILE_LSTAT : FILE_FSTAT);
+ gcc_optimizer_hack++;
}
static void invoke_link(void *data)
@@ -1601,10 +1700,12 @@ static void invoke_link(void *data)
struct t_data *d = (struct t_data *) data;
char *name = d->b;
char *new_name;
+ DTRACE_INVOKE_SETUP(FILE_LINK);
d->again = 0;
new_name = name+FILENAME_BYTELEN(name)+FILENAME_CHARSIZE;
d->result_ok = efile_link(&d->errInfo, name, new_name);
+ DTRACE_INVOKE_RETURN(FILE_LINK);
}
static void invoke_symlink(void *data)
@@ -1612,10 +1713,12 @@ static void invoke_symlink(void *data)
struct t_data *d = (struct t_data *) data;
char *name = d->b;
char *new_name;
+ DTRACE_INVOKE_SETUP(FILE_SYMLINK);
d->again = 0;
new_name = name+FILENAME_BYTELEN(name)+FILENAME_CHARSIZE;
d->result_ok = efile_symlink(&d->errInfo, name, new_name);
+ DTRACE_INVOKE_RETURN(FILE_SYMLINK);
}
static void invoke_rename(void *data)
@@ -1623,24 +1726,29 @@ static void invoke_rename(void *data)
struct t_data *d = (struct t_data *) data;
char *name = d->b;
char *new_name;
+ DTRACE_INVOKE_SETUP(FILE_RENAME);
d->again = 0;
new_name = name+FILENAME_BYTELEN(name)+FILENAME_CHARSIZE;
d->result_ok = efile_rename(&d->errInfo, name, new_name);
+ DTRACE_INVOKE_RETURN(FILE_RENAME);
}
static void invoke_write_info(void *data)
{
struct t_data *d = (struct t_data *) data;
+ DTRACE_INVOKE_SETUP(FILE_WRITE_INFO);
d->again = 0;
d->result_ok = efile_write_info(&d->errInfo, &d->info, d->b);
+ DTRACE_INVOKE_RETURN(FILE_WRITE_INFO);
}
static void invoke_lseek(void *data)
{
struct t_data *d = (struct t_data *) data;
int status;
+ DTRACE_INVOKE_SETUP(FILE_LSEEK);
d->again = 0;
if (d->flags & EFILE_COMPRESSED) {
@@ -1665,6 +1773,7 @@ static void invoke_lseek(void *data)
&d->c.lseek.location);
}
d->result_ok = status;
+ DTRACE_INVOKE_RETURN(FILE_LSEEK);
}
static void invoke_readdir(void *data)
@@ -1675,6 +1784,7 @@ static void invoke_readdir(void *data)
size_t n = 0, total = 0;
struct t_readdir_buf *b = NULL;
int res = 0;
+ DTRACE_INVOKE_SETUP(FILE_READDIR);
d->again = 0;
d->errInfo.posix_errno = 0;
@@ -1710,13 +1820,14 @@ static void invoke_readdir(void *data)
} while(res);
d->result_ok = (d->errInfo.posix_errno == 0);
+ DTRACE_INVOKE_RETURN(FILE_READDIR);
}
static void invoke_open(void *data)
{
struct t_data *d = (struct t_data *) data;
-
int status = 1; /* Status of open call. */
+ DTRACE_INVOKE_SETUP(FILE_OPEN);
d->again = 0;
if ((d->flags & EFILE_COMPRESSED) == 0) {
@@ -1749,6 +1860,7 @@ static void invoke_open(void *data)
}
d->result_ok = status;
+ DTRACE_INVOKE_RETURN(FILE_OPEN);
}
static void invoke_fadvise(void *data)
@@ -1758,9 +1870,11 @@ static void invoke_fadvise(void *data)
off_t offset = (off_t) d->c.fadvise.offset;
off_t length = (off_t) d->c.fadvise.length;
int advise = (int) d->c.fadvise.advise;
+ DTRACE_INVOKE_SETUP(FILE_FADVISE);
d->again = 0;
d->result_ok = efile_fadvise(&d->errInfo, fd, offset, length, advise);
+ DTRACE_INVOKE_RETURN(FILE_FADVISE);
}
#ifdef HAVE_SENDFILE
@@ -1841,6 +1955,7 @@ static void free_readdir(void *data)
{
struct t_data *d = (struct t_data *) data;
struct t_readdir_buf *b1 = d->c.read_dir.first_buf;
+
while (b1) {
struct t_readdir_buf *b2 = b1;
b1 = b1->next;
@@ -1909,12 +2024,13 @@ static void cq_execute(file_descriptor *desc) {
DRIVER_ASYNC(d->level, desc, d->invoke, void_ptr=d, d->free);
}
-static int async_write(file_descriptor *desc, int *errp,
- int reply, Uint32 reply_size) {
+static struct t_data *async_write(file_descriptor *desc, int *errp,
+ int reply, Uint32 reply_size,
+ Sint64 *dt_i1, Sint64 *dt_i2, Sint64 *dt_i3) {
struct t_data *d;
if (! (d = EF_ALLOC(sizeof(struct t_data) - 1))) {
if (errp) *errp = ENOMEM;
- return -1;
+ return NULL;
}
TRACE_F(("w%lu", (unsigned long)desc->write_buffered));
d->command = FILE_WRITE;
@@ -1923,6 +2039,11 @@ static int async_write(file_descriptor *desc, int *errp,
d->c.writev.port = desc->port;
d->c.writev.q_mtx = desc->q_mtx;
d->c.writev.size = desc->write_buffered;
+ if (dt_i1 != NULL) {
+ *dt_i1 = d->fd;
+ *dt_i2 = d->flags;
+ *dt_i3 = d->c.writev.size;
+ }
d->reply = reply;
d->c.writev.free_size = 0;
d->c.writev.reply_size = reply_size;
@@ -1931,18 +2052,41 @@ static int async_write(file_descriptor *desc, int *errp,
d->level = 1;
cq_enq(desc, d);
desc->write_buffered = 0;
- return 0;
+ return d;
}
-static int flush_write(file_descriptor *desc, int *errp) {
- int result;
+static int flush_write(file_descriptor *desc, int *errp,
+ dt_private *dt_priv, char *dt_utag) {
+ int result = 0;
+ Sint64 dt_i1 = 0, dt_i2 = 0, dt_i3 = 0;
+ struct t_data *d = NULL;
+
MUTEX_LOCK(desc->q_mtx);
if (desc->write_buffered > 0) {
- result = async_write(desc, errp, 0, 0);
- } else {
- result = 0;
+ if ((d = async_write(desc, errp, 0, 0,
+ &dt_i1, &dt_i2, &dt_i3)) == NULL) {
+ result = -1;
+ }
}
MUTEX_UNLOCK(desc->q_mtx);
+#ifdef HAVE_DTRACE
+ if (d != NULL) {
+ d->sched_i1 = dt_priv->thread_num;
+ d->sched_i2 = dt_priv->tag;
+ d->sched_utag[0] = '\0';
+ if (dt_utag != NULL) {
+ if (dt_utag[0] == '\0') {
+ dt_utag = NULL;
+ } else {
+ strncpy(d->sched_utag, dt_utag, sizeof(d->sched_utag) - 1);
+ d->sched_utag[sizeof(d->sched_utag) - 1] = '\0';
+ }
+ }
+ DTRACE11(efile_drv_entry, dt_priv->thread_num, dt_priv->tag++,
+ dt_utag, FILE_WRITE,
+ NULL, NULL, dt_i1, dt_i2, dt_i3, 0, desc->port_str);
+ }
+#endif /* HAVE_DTRACE */
return result;
}
@@ -1955,9 +2099,10 @@ static int check_write_error(file_descriptor *desc, int *errp) {
return 0;
}
-static int flush_write_check_error(file_descriptor *desc, int *errp) {
+static int flush_write_check_error(file_descriptor *desc, int *errp,
+ dt_private *dt_priv, char *dt_utag) {
int r;
- if ( (r = flush_write(desc, errp)) != 0) {
+ if ( (r = flush_write(desc, errp, dt_priv, dt_utag)) != 0) {
check_write_error(desc, NULL);
return r;
} else {
@@ -1965,12 +2110,13 @@ static int flush_write_check_error(file_descriptor *desc, int *errp) {
}
}
-static int async_lseek(file_descriptor *desc, int *errp, int reply,
- Sint64 offset, int origin) {
+static struct t_data *async_lseek(file_descriptor *desc, int *errp, int reply,
+ Sint64 offset, int origin,
+ Sint64 *dt_i1, Sint64 *dt_i2, Sint64 *dt_i3) {
struct t_data *d;
if (! (d = EF_ALLOC(sizeof(struct t_data)))) {
*errp = ENOMEM;
- return -1;
+ return NULL;
}
d->flags = desc->flags;
d->fd = desc->fd;
@@ -1978,11 +2124,16 @@ static int async_lseek(file_descriptor *desc, int *errp, int reply,
d->reply = reply;
d->c.lseek.offset = offset;
d->c.lseek.origin = origin;
+ if (dt_i1 != NULL) {
+ *dt_i1 = d->fd;
+ *dt_i2 = d->c.lseek.offset;
+ *dt_i3 = d->c.lseek.origin;
+ }
d->invoke = invoke_lseek;
d->free = free_data;
d->level = 1;
cq_enq(desc, d);
- return 0;
+ return d;
}
static void flush_read(file_descriptor *desc) {
@@ -1994,18 +2145,37 @@ static void flush_read(file_descriptor *desc) {
}
}
-static int lseek_flush_read(file_descriptor *desc, int *errp) {
+static int lseek_flush_read(file_descriptor *desc, int *errp,
+ dt_private *dt_priv, char *dt_utag) {
int r = 0;
size_t read_size = desc->read_size;
+ Sint64 dt_i1 = 0, dt_i2 = 0, dt_i3 = 0;
+ struct t_data *d;
+
+ flush_read(desc);
if (read_size != 0) {
- flush_read(desc);
- if ((r = async_lseek(desc, errp, 0,
- -((ssize_t)read_size), EFILE_SEEK_CUR))
- < 0) {
- return r;
- }
- } else {
- flush_read(desc);
+ if ((d = async_lseek(desc, errp, 0,
+ -((ssize_t)read_size), EFILE_SEEK_CUR,
+ &dt_i1, &dt_i2, &dt_i3)) == NULL) {
+ r = -1;
+ } else {
+#ifdef HAVE_DTRACE
+ d->sched_i1 = dt_priv->thread_num;
+ d->sched_i2 = dt_priv->tag;
+ d->sched_utag[0] = '\0';
+ if (dt_utag != NULL) {
+ if (dt_utag[0] == '\0') {
+ dt_utag = NULL;
+ } else {
+ strncpy(d->sched_utag, dt_utag, sizeof(d->sched_utag) - 1);
+ d->sched_utag[sizeof(d->sched_utag) - 1] = '\0';
+ }
+ }
+ DTRACE11(efile_drv_entry, dt_priv->thread_num, dt_priv->tag++,
+ dt_utag, FILE_LSEEK,
+ NULL, NULL, dt_i1, dt_i2, dt_i3, 0, desc->port_str);
+#endif /* HAVE_DTRACE */
+ }
}
return r;
}
@@ -2022,11 +2192,23 @@ file_async_ready(ErlDrvData e, ErlDrvThreadData data)
struct t_data *d = (struct t_data *) data;
char header[5]; /* result code + count */
char resbuf[RESBUFSIZE]; /* Result buffer. */
-
+#ifdef HAVE_DTRACE
+ int sched_i1 = d->sched_i1, sched_i2 = d->sched_i2, command = d->command,
+ result_ok = d->result_ok,
+ posix_errno = d->result_ok ? 0 : d->errInfo.posix_errno;
+ DTRACE_CHARBUF(sched_utag, 128+1);
+
+ sched_utag[0] = '\0';
+ if (DTRACE_ENABLED(efile_drv_return)) {
+ strncpy(sched_utag, d->sched_utag, sizeof(sched_utag) - 1);
+ sched_utag[sizeof(sched_utag) - 1] = '\0';
+ }
+#endif /* HAVE_DTRACE */
TRACE_C('r');
if (try_again(desc, d)) {
+ /* DTRACE TODO: what kind of probe makes sense here? */
return;
}
@@ -2224,6 +2406,9 @@ file_async_ready(ErlDrvData e, ErlDrvThreadData data)
if (d->reply) {
TRACE_C('K');
reply_ok(desc);
+#ifdef HAVE_DTRACE
+ result_ok = 1;
+#endif
}
free_data(data);
break;
@@ -2279,6 +2464,8 @@ file_async_ready(ErlDrvData e, ErlDrvThreadData data)
default:
abort();
}
+ DTRACE6(efile_drv_return, sched_i1, sched_i2, sched_utag,
+ command, result_ok, posix_errno);
if (desc->write_buffered != 0 && desc->timer_state == timer_idle) {
desc->timer_state = timer_write;
driver_set_timer(desc->port, desc->write_delay);
@@ -2301,7 +2488,11 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count)
char* name; /* Points to the filename in buf. */
int command;
struct t_data *d = NULL;
-
+ char *dt_utag = NULL, *dt_s1 = NULL, *dt_s2 = NULL;
+ Sint64 dt_i1 = 0, dt_i2 = 0, dt_i3 = 0, dt_i4 = 0;
+#ifdef HAVE_DTRACE
+ dt_private *dt_priv = get_dt_private(0);
+#endif /* HAVE_DTRACE */
TRACE_C('o');
@@ -2316,6 +2507,8 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count)
d = EF_SAFE_ALLOC(sizeof(struct t_data) - 1 + FILENAME_BYTELEN(name) + FILENAME_CHARSIZE);
FILENAME_COPY(d->b, name);
+ dt_s1 = d->b;
+ dt_utag = name + strlen(d->b) + 1;
d->command = command;
d->invoke = invoke_mkdir;
d->free = free_data;
@@ -2327,6 +2520,8 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count)
d = EF_SAFE_ALLOC(sizeof(struct t_data) - 1 + FILENAME_BYTELEN(name) + FILENAME_CHARSIZE);
FILENAME_COPY(d->b, name);
+ dt_s1 = d->b;
+ dt_utag = name + strlen(d->b) + 1;
d->command = command;
d->invoke = invoke_rmdir;
d->free = free_data;
@@ -2338,6 +2533,8 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count)
d = EF_SAFE_ALLOC(sizeof(struct t_data) - 1 + FILENAME_BYTELEN(name) + FILENAME_CHARSIZE);
FILENAME_COPY(d->b, name);
+ dt_s1 = d->b;
+ dt_utag = name + strlen(d->b) + 1;
d->command = command;
d->invoke = invoke_delete_file;
d->free = free_data;
@@ -2354,7 +2551,10 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count)
+ FILENAME_BYTELEN(new_name) + FILENAME_CHARSIZE);
FILENAME_COPY(d->b, name);
+ dt_s1 = d->b;
FILENAME_COPY(d->b + namelen, new_name);
+ dt_s2 = d->b + namelen;
+ dt_utag = buf + namelen + strlen(dt_s2) + 1;
d->flags = desc->flags;
d->fd = fd;
d->command = command;
@@ -2368,6 +2568,8 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count)
d = EF_SAFE_ALLOC(sizeof(struct t_data) - 1 + FILENAME_BYTELEN(name) + FILENAME_CHARSIZE);
FILENAME_COPY(d->b, name);
+ dt_s1 = d->b;
+ dt_utag = name + strlen(d->b) + 1;
d->command = command;
d->invoke = invoke_chdir;
d->free = free_data;
@@ -2379,6 +2581,7 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count)
d = EF_SAFE_ALLOC(sizeof(struct t_data) - 1 + RESBUFSIZE + 1);
d->drive = *(uchar*)buf;
+ dt_utag = buf + 1;
d->command = command;
d->invoke = invoke_pwd;
d->free = free_data;
@@ -2394,6 +2597,8 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count)
FILENAME_CHARSIZE);
FILENAME_COPY(d->b, name);
+ dt_s1 = d->b;
+ dt_utag = name + strlen(d->b) + 1;
d->dir_handle = NULL;
d->command = command;
d->invoke = invoke_readdir;
@@ -2418,6 +2623,9 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count)
dir_handle = NULL;
resbuf[0] = FILE_RESP_LFNAME;
+ dt_s1 = name;
+ dt_utag = name + strlen(dt_s1) + 1;
+
/* Fill the buffer with multiple directory listings before sending it to the
* receiving process. READDIR_CHUNKS is minimum number of files sent to the
* receiver.
@@ -2451,6 +2659,11 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count)
reply_error(desc, &errInfo);
return;
}
+#ifdef HAVE_DTRACE
+ DTRACE11(efile_drv_entry, dt_priv->thread_num, dt_priv->tag++,
+ dt_utag, command, name, dt_s2,
+ dt_i1, dt_i2, dt_i3, dt_i4, desc->port_str);
+#endif
TRACE_C('R');
driver_output2(desc->port, resbuf, 1, NULL, 0);
return;
@@ -2461,8 +2674,11 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count)
FILENAME_CHARSIZE);
d->flags = get_int32((uchar*)buf);
+ dt_i1 = d->flags;
name = buf+4;
FILENAME_COPY(d->b, name);
+ dt_s1 = d->b;
+ dt_utag = name + strlen(d->b) + 1;
d->command = command;
d->invoke = invoke_open;
d->free = free_data;
@@ -2474,7 +2690,9 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count)
{
d = EF_SAFE_ALLOC(sizeof(struct t_data));
+ dt_utag = name;
d->fd = fd;
+ dt_i1 = fd;
d->command = command;
d->invoke = invoke_fdatasync;
d->free = free_data;
@@ -2486,7 +2704,9 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count)
{
d = EF_SAFE_ALLOC(sizeof(struct t_data));
+ dt_utag = name;
d->fd = fd;
+ dt_i1 = fd;
d->command = command;
d->invoke = invoke_fsync;
d->free = free_data;
@@ -2502,7 +2722,13 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count)
FILENAME_CHARSIZE);
FILENAME_COPY(d->b, name);
+ dt_utag = name + strlen(d->b) + 1;
d->fd = fd;
+ if (command == FILE_LSTAT) {
+ dt_s1 = d->b;
+ } else {
+ dt_i1 = fd;
+ }
d->command = command;
d->invoke = invoke_flstat;
d->free = free_data;
@@ -2514,8 +2740,11 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count)
{
d = EF_SAFE_ALLOC(sizeof(struct t_data));
+ dt_utag = name;
d->flags = desc->flags;
d->fd = fd;
+ dt_i1 = fd;
+ dt_i2 = d->flags;
d->command = command;
d->invoke = invoke_truncate;
d->free = free_data;
@@ -2529,13 +2758,18 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count)
+ FILENAME_BYTELEN(buf + 9*4) + FILENAME_CHARSIZE);
d->info.mode = get_int32(buf + 0 * 4);
+ dt_i1 = d->info.mode;
d->info.uid = get_int32(buf + 1 * 4);
+ dt_i2 = d->info.uid;
d->info.gid = get_int32(buf + 2 * 4);
+ dt_i3 = d->info.gid;
d->info.accessTime = (time_t)((Sint64)get_int64(buf + 3 * 4));
d->info.modifyTime = (time_t)((Sint64)get_int64(buf + 5 * 4));
d->info.cTime = (time_t)((Sint64)get_int64(buf + 7 * 4));
FILENAME_COPY(d->b, buf + 9*4);
+ dt_s1 = d->b;
+ dt_utag = buf + 9 * 4 + strlen(d->b) + 1;
d->command = command;
d->invoke = invoke_write_info;
d->free = free_data;
@@ -2548,6 +2782,8 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count)
d = EF_SAFE_ALLOC(sizeof(struct t_data) - 1 + RESBUFSIZE + 1);
FILENAME_COPY(d->b, name);
+ dt_s1 = d->b;
+ dt_utag = name + strlen(d->b) + 1;
d->command = command;
d->invoke = invoke_readlink;
d->free = free_data;
@@ -2559,6 +2795,8 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count)
{
d = EF_SAFE_ALLOC(sizeof(struct t_data) - 1 + RESBUFSIZE + 1);
FILENAME_COPY(d->b, name);
+ dt_s1 = d->b;
+ dt_utag = name + strlen(d->b) + 1;
d->command = command;
d->invoke = invoke_altname;
d->free = free_data;
@@ -2578,7 +2816,10 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count)
+ FILENAME_BYTELEN(new_name) + FILENAME_CHARSIZE);
FILENAME_COPY(d->b, name);
+ dt_s1 = d->b;
FILENAME_COPY(d->b + namelen, new_name);
+ dt_s2 = d->b + namelen;
+ dt_utag = buf + namelen + strlen(dt_s2) + 1;
d->flags = desc->flags;
d->fd = fd;
d->command = command;
@@ -2599,7 +2840,10 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count)
+ FILENAME_BYTELEN(new_name) + FILENAME_CHARSIZE);
FILENAME_COPY(d->b, name);
+ dt_s1 = d->b;
FILENAME_COPY(d->b + namelen, new_name);
+ dt_s2 = d->b + namelen;
+ dt_utag = buf + namelen + strlen(dt_s2) + 1;
d->flags = desc->flags;
d->fd = fd;
d->command = command;
@@ -2614,13 +2858,18 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count)
d = EF_SAFE_ALLOC(sizeof(struct t_data));
d->fd = fd;
+ dt_i1 = d->fd;
d->command = command;
d->invoke = invoke_fadvise;
d->free = free_data;
d->level = 2;
d->c.fadvise.offset = get_int64((uchar*) buf);
+ dt_i2 = d->c.fadvise.offset;
d->c.fadvise.length = get_int64(((uchar*) buf) + sizeof(Sint64));
+ dt_i3 = d->c.fadvise.length;
d->c.fadvise.advise = get_int32(((uchar*) buf) + 2 * sizeof(Sint64));
+ dt_i4 = d->c.fadvise.advise;
+ dt_utag = buf + 3 * sizeof(Sint64);
goto done;
}
@@ -2634,6 +2883,22 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count)
done:
if (d) {
+#ifdef HAVE_DTRACE
+ d->sched_i1 = dt_priv->thread_num;
+ d->sched_i2 = dt_priv->tag;
+ d->sched_utag[0] = '\0';
+ if (dt_utag != NULL) {
+ if (dt_utag[0] == '\0') {
+ dt_utag = NULL;
+ } else {
+ strncpy(d->sched_utag, dt_utag, sizeof(d->sched_utag) - 1);
+ d->sched_utag[sizeof(d->sched_utag) - 1] = '\0';
+ }
+ }
+ DTRACE11(efile_drv_entry, dt_priv->thread_num, dt_priv->tag++,
+ dt_utag, command, dt_s1, dt_s2,
+ dt_i1, dt_i2, dt_i3, dt_i4, desc->port_str);
+#endif
cq_enq(desc, d);
}
}
@@ -2647,6 +2912,11 @@ file_flush(ErlDrvData e) {
#ifdef DEBUG
int r;
#endif
+#ifdef HAVE_DTRACE
+ dt_private *dt_priv = get_dt_private(dt_driver_io_worker_base);
+#else
+ dt_private *dt_priv = NULL;
+#endif
TRACE_C('f');
@@ -2657,7 +2927,8 @@ file_flush(ErlDrvData e) {
#ifdef DEBUG
r =
#endif
- flush_write(desc, NULL);
+ flush_write(desc, NULL, dt_priv,
+ (desc->d == NULL) ? NULL : desc->d->sched_utag);
/* Only possible reason for bad return value is ENOMEM, and
* there is nobody to tell...
*/
@@ -2699,6 +2970,11 @@ static void
file_timeout(ErlDrvData e) {
file_descriptor *desc = (file_descriptor *)e;
enum e_timer timer_state = desc->timer_state;
+#ifdef HAVE_DTRACE
+ dt_private *dt_priv = get_dt_private(dt_driver_io_worker_base);
+#else
+ dt_private *dt_priv = NULL;
+#endif
TRACE_C('t');
@@ -2716,7 +2992,8 @@ file_timeout(ErlDrvData e) {
#ifdef DEBUG
int r =
#endif
- flush_write(desc, NULL);
+ flush_write(desc, NULL, dt_priv,
+ (desc->d == NULL) ? NULL : desc->d->sched_utag);
/* Only possible reason for bad return value is ENOMEM, and
* there is nobody to tell...
*/
@@ -2737,7 +3014,14 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) {
char command;
int p, q;
int err;
-
+ struct t_data *d = NULL;
+ Sint64 dt_i1 = 0, dt_i2 = 0, dt_i3 = 0, dt_i4 = 0;
+ char *dt_utag = NULL, *dt_s1 = NULL;
+#ifdef HAVE_DTRACE
+ dt_private *dt_priv = get_dt_private(dt_driver_io_worker_base);
+#else
+ dt_private *dt_priv = NULL;
+#endif
TRACE_C('v');
p = 0; q = 1;
@@ -2756,25 +3040,22 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) {
switch (command) {
case FILE_CLOSE: {
+ dt_utag = EV_CHAR_P(ev, p, q);
flush_read(desc);
- if (flush_write_check_error(desc, &err) < 0) {
+ if (flush_write_check_error(desc, &err, dt_priv, dt_utag) < 0) {
reply_posix_error(desc, err);
goto done;
}
- if (ev->size != 1) {
- /* Wrong command length */
- reply_posix_error(desc, EINVAL);
- goto done;
- }
if (desc->fd != FILE_FD_INVALID) {
- struct t_data *d;
if (! (d = EF_ALLOC(sizeof(struct t_data)))) {
reply_posix_error(desc, ENOMEM);
} else {
d->command = command;
d->reply = !0;
d->fd = desc->fd;
+ dt_i1 = d->fd;
d->flags = desc->flags;
+ dt_i2 = d->flags;
d->invoke = invoke_close;
d->free = free_data;
d->level = 2;
@@ -2790,8 +3071,15 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) {
case FILE_READ: {
Uint32 sizeH, sizeL;
size_t size, alloc_size;
- struct t_data *d;
- if (flush_write_check_error(desc, &err) < 0) {
+
+ if (!EV_GET_UINT32(ev, &sizeH, &p, &q)
+ || !EV_GET_UINT32(ev, &sizeL, &p, &q)) {
+ /* Wrong buffer length to contain the read count */
+ reply_posix_error(desc, EINVAL);
+ goto done;
+ }
+ dt_utag = EV_CHAR_P(ev, p, q);
+ if (flush_write_check_error(desc, &err, dt_priv, dt_utag) < 0) {
reply_posix_error(desc, err);
goto done;
}
@@ -2799,19 +3087,12 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) {
if (desc->read_bufsize == 0 && desc->read_binp != NULL && desc->read_size > 0) {
/* We have allocated a buffer for line mode but should not really have a
read-ahead buffer... */
- if (lseek_flush_read(desc, &err) < 0) {
+ if (lseek_flush_read(desc, &err, dt_priv) < 0) {
reply_posix_error(desc, err);
goto done;
}
}
#endif
- if (ev->size != 1+8
- || !EV_GET_UINT32(ev, &sizeH, &p, &q)
- || !EV_GET_UINT32(ev, &sizeL, &p, &q)) {
- /* Wrong buffer length to contain the read count */
- reply_posix_error(desc, EINVAL);
- goto done;
- }
#if SIZEOF_SIZE_T == 4
if (sizeH != 0) {
reply_posix_error(desc, EINVAL);
@@ -2882,11 +3163,14 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) {
d->command = command;
d->reply = !0;
d->fd = desc->fd;
+ dt_i1 = d->fd;
d->flags = desc->flags;
+ dt_i2 = d->flags;
d->c.read.binp = desc->read_binp;
d->c.read.bin_offset = desc->read_offset + desc->read_size;
d->c.read.bin_size = desc->read_binp->orig_size - d->c.read.bin_offset;
d->c.read.size = size;
+ dt_i3 = d->c.read.size;
driver_binary_inc_refc(d->c.read.binp);
d->invoke = invoke_read;
d->free = free_read;
@@ -2904,12 +3188,12 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) {
* allocated binary + dealing with offsets and lengts are done in file_async ready
* for this OP.
*/
- struct t_data *d;
- if (flush_write_check_error(desc, &err) < 0) {
+ dt_utag = EV_CHAR_P(ev, p, q);
+ if (flush_write_check_error(desc, &err, dt_priv, dt_utag) < 0) {
reply_posix_error(desc, err);
goto done;
}
- if (ev->size != 1) {
+ if (ev->size != 1+strlen(dt_utag)+1) {
/* Wrong command length */
reply_posix_error(desc, EINVAL);
goto done;
@@ -2961,13 +3245,17 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) {
d->command = command;
d->reply = !0;
d->fd = desc->fd;
+ dt_i1 = d->fd;
d->flags = desc->flags;
+ dt_i2 = d->flags;
d->c.read_line.binp = desc->read_binp;
d->c.read_line.read_offset = desc->read_offset;
d->c.read_line.read_size = desc->read_size;
+ dt_i3 = d->c.read_line.read_offset;
#if !ALWAYS_READ_LINE_AHEAD
d->c.read_line.read_ahead = (desc->read_bufsize > 0);
#endif
+ dt_i4 = d->c.read_line.read_ahead;
driver_binary_inc_refc(d->c.read.binp);
d->invoke = invoke_read_line;
d->free = free_read_line;
@@ -2977,7 +3265,21 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) {
case FILE_WRITE: {
ErlDrvSizeT skip = 1;
ErlDrvSizeT size = ev->size - skip;
- if (lseek_flush_read(desc, &err) < 0) {
+
+ dt_utag = EV_CHAR_P(ev, p, q);
+ skip += strlen(dt_utag) + 1;
+ size = ev->size - skip;
+ /*
+ * Interesting dependency on using port # for key to async
+ * I/O worker pool thread: lseek_flush_read() can enqueue a
+ * lseek() op. If that lseek() were scheduled on a different
+ * thread than the write that we'll enqueue later in this case,
+ * then Bad Things could happen. This DTrace work is probably
+ * well worthwhile to get a sense of how often there's head-of-
+ * line blocking/unfairness during busy file I/O because of the
+ * mapping of port #/key -> thread.
+ */
+ if (lseek_flush_read(desc, &err, dt_priv, dt_utag) < 0) {
reply_posix_error(desc, err);
goto done;
}
@@ -3004,7 +3306,8 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) {
driver_set_timer(desc->port, desc->write_delay);
}
} else {
- if (async_write(desc, &err, !0, size) != 0) {
+ if ((d = async_write(desc, &err, !0, size,
+ &dt_i1, &dt_i2, &dt_i3)) == NULL) {
MUTEX_UNLOCK(desc->q_mtx);
reply_posix_error(desc, err);
goto done;
@@ -3017,19 +3320,25 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) {
case FILE_PWRITEV: {
Uint32 i, j, n;
size_t total;
- struct t_data *d;
- if (lseek_flush_read(desc, &err) < 0) {
- reply_Uint_posix_error(desc, 0, err);
+ char tmp;
+ int dt_utag_bytes = 1;
+
+ dt_utag = EV_CHAR_P(ev, p, q);
+ while (EV_GET_CHAR(ev, &tmp, &p, &q) && tmp != '\0') {
+ dt_utag_bytes++;
+ }
+ if (ev->size < 1+4+dt_utag_bytes
+ || !EV_GET_UINT32(ev, &n, &p, &q)) {
+ /* Buffer too short to contain even the number of pos/size specs */
+ reply_Uint_posix_error(desc, 0, EINVAL);
goto done;
}
- if (flush_write_check_error(desc, &err) < 0) {
+ if (lseek_flush_read(desc, &err, dt_priv, dt_utag) < 0) {
reply_Uint_posix_error(desc, 0, err);
goto done;
}
- if (ev->size < 1+4
- || !EV_GET_UINT32(ev, &n, &p, &q)) {
- /* Buffer too short to contain even the number of pos/size specs */
- reply_Uint_posix_error(desc, 0, EINVAL);
+ if (flush_write_check_error(desc, &err, dt_priv, dt_utag) < 0) {
+ reply_Uint_posix_error(desc, 0, err);
goto done;
}
if (n == 0) {
@@ -3041,7 +3350,7 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) {
}
goto done;
}
- if (ev->size < 1+4+8*(2*n)) {
+ if (ev->size < 1+4+8*(2*n)+dt_utag_bytes) {
/* Buffer too short to contain even the pos/size specs */
reply_Uint_posix_error(desc, 0, EINVAL);
goto done;
@@ -3055,7 +3364,9 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) {
d->command = command;
d->reply = !0;
d->fd = desc->fd;
+ dt_i1 = d->fd;
d->flags = desc->flags;
+ dt_i2 = d->flags;
d->c.pwritev.port = desc->port;
d->c.pwritev.q_mtx = desc->q_mtx;
d->c.pwritev.n = n;
@@ -3093,13 +3404,14 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) {
}
}
d->c.pwritev.size = total;
+ dt_i3 = d->c.pwritev.size;
d->c.pwritev.free_size = 0;
if (j == 0) {
/* Trivial case - nothing to write */
EF_FREE(d);
reply_Uint(desc, 0);
} else {
- ErlDrvSizeT skip = 1 + 4 + 8*(2*n);
+ ErlDrvSizeT skip = 1 + 4 + 8 * (2*n) + dt_utag_bytes;
if (skip + total != ev->size) {
/* Actual amount of data does not match
* total of all pos/size specs
@@ -3123,24 +3435,30 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) {
case FILE_PREADV: {
register void * void_ptr;
Uint32 i, n;
- struct t_data *d;
ErlIOVec *res_ev;
- if (lseek_flush_read(desc, &err) < 0) {
+ char tmp;
+ int dt_utag_bytes = 1;
+
+ dt_utag = EV_CHAR_P(ev, p, q);
+ while (EV_GET_CHAR(ev, &tmp, &p, &q) && tmp != '\0') {
+ dt_utag_bytes++;
+ }
+ if (lseek_flush_read(desc, &err, dt_priv, dt_utag) < 0) {
reply_posix_error(desc, err);
goto done;
}
- if (flush_write_check_error(desc, &err) < 0) {
+ if (flush_write_check_error(desc, &err, dt_priv, dt_utag) < 0) {
reply_posix_error(desc, err);
goto done;
}
- if (ev->size < 1+8
+ if (ev->size < 1+8+dt_utag_bytes
|| !EV_GET_UINT32(ev, &n, &p, &q)
|| !EV_GET_UINT32(ev, &n, &p, &q)) {
/* Buffer too short to contain even the number of pos/size specs */
reply_posix_error(desc, EINVAL);
goto done;
}
- if (ev->size != 1+8+8*(2*n)) {
+ if (ev->size < 1+8+8*(2*n)+dt_utag_bytes) {
/* Buffer wrong length to contain the pos/size specs */
reply_posix_error(desc, EINVAL);
goto done;
@@ -3159,7 +3477,9 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) {
d->command = command;
d->reply = !0;
d->fd = desc->fd;
+ dt_i1 = d->fd;
d->flags = desc->flags;
+ dt_i2 = d->flags;
d->c.preadv.n = n;
d->c.preadv.cnt = 0;
d->c.preadv.size = 0;
@@ -3187,6 +3507,7 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) {
#else
size = ((size_t)sizeH<<32) | sizeL;
#endif
+ dt_i3 += size;
if (! (res_ev->binv[i] = driver_alloc_binary(size))) {
reply_posix_error(desc, ENOMEM);
break;
@@ -3233,31 +3554,33 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) {
} goto done; /* case FILE_PREADV: */
case FILE_LSEEK: {
- Sint64 offset; /* Offset for seek */
+ Sint64 offset; /* Offset for seek */
Uint32 origin; /* Origin of seek. */
- if (lseek_flush_read(desc, &err) < 0) {
- reply_posix_error(desc, err);
+
+ if (ev->size < 1+8+4
+ || !EV_GET_UINT64(ev, &offset, &p, &q)
+ || !EV_GET_UINT32(ev, &origin, &p, &q)) {
+ /* Wrong length of buffer to contain offset and origin */
+ reply_posix_error(desc, EINVAL);
goto done;
}
- if (flush_write_check_error(desc, &err) < 0) {
+ dt_utag = EV_CHAR_P(ev, p, q);
+ if (lseek_flush_read(desc, &err, dt_priv, dt_utag) < 0) {
reply_posix_error(desc, err);
goto done;
}
- if (ev->size != 1+8+4
- || !EV_GET_UINT64(ev, &offset, &p, &q)
- || !EV_GET_UINT32(ev, &origin, &p, &q)) {
- /* Wrong length of buffer to contain offset and origin */
- reply_posix_error(desc, EINVAL);
+ if (flush_write_check_error(desc, &err, dt_priv, dt_utag) < 0) {
+ reply_posix_error(desc, err);
goto done;
}
- if (async_lseek(desc, &err, !0, offset, origin) < 0) {
+ if ((d = async_lseek(desc, &err, !0, offset, origin,
+ &dt_i1, &dt_i2, &dt_i3)) == NULL) {
reply_posix_error(desc, err);
goto done;
}
} goto done;
case FILE_READ_FILE: {
- struct t_data *d;
char *filename;
if (ev->size < 1+1) {
/* Buffer contains empty name */
@@ -3279,6 +3602,8 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) {
d->reply = !0;
/* Copy name */
FILENAME_COPY(d->b, filename);
+ dt_s1 = d->b;
+ dt_utag = filename + strlen(d->b) + 1;
d->c.read_file.binp = NULL;
d->invoke = invoke_read_file;
d->free = free_read_file;
@@ -3298,7 +3623,6 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) {
char mode;
Sint64 hdr_offset;
Uint32 max_size;
- struct t_data *d;
ErlIOVec *res_ev;
int vsize;
if (! EV_GET_CHAR(ev, &mode, &p, &q)) {
@@ -3310,14 +3634,6 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) {
reply_posix_error(desc, EINVAL);
goto done;
}
- if (lseek_flush_read(desc, &err) < 0) {
- reply_posix_error(desc, err);
- goto done;
- }
- if (flush_write_check_error(desc, &err) < 0) {
- reply_posix_error(desc, err);
- goto done;
- }
if (ev->size < 1+1+8+4
|| !EV_GET_UINT64(ev, &hdr_offset, &p, &q)
|| !EV_GET_UINT32(ev, &max_size, &p, &q)) {
@@ -3326,6 +3642,15 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) {
reply_posix_error(desc, EINVAL);
goto done;
}
+ dt_utag = EV_CHAR_P(ev, p, q);
+ if (lseek_flush_read(desc, &err, dt_priv, dt_utag) < 0) {
+ reply_posix_error(desc, err);
+ goto done;
+ }
+ if (flush_write_check_error(desc, &err, dt_priv, dt_utag) < 0) {
+ reply_posix_error(desc, err);
+ goto done;
+ }
/* Create the thread data structure with the contained ErlIOVec
* and corresponding binaries for the response
*/
@@ -3339,9 +3664,13 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) {
d->command = command;
d->reply = !0;
d->fd = desc->fd;
+ dt_i1 = d->fd;
d->flags = desc->flags;
+ dt_i2 = d->flags;
d->c.preadv.offsets[0] = hdr_offset;
+ dt_i3 = d->c.preadv.offsets[0];
d->c.preadv.size = max_size;
+ dt_i4 = d->c.preadv.size;
res_ev = &d->c.preadv.eiov;
/* XXX possible alignment problems here for weird machines */
res_ev->iov = void_ptr = d + 1;
@@ -3356,16 +3685,19 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) {
case FILE_SETOPT: {
char opt;
+
if (ev->size < 1+1
|| !EV_GET_CHAR(ev, &opt, &p, &q)) {
/* Buffer too short to contain even the option type */
reply_posix_error(desc, EINVAL);
goto done;
}
+ dt_i1 = opt;
+ dt_utag = EV_CHAR_P(ev, p, q);
switch (opt) {
case FILE_OPT_DELAYED_WRITE: {
Uint32 sizeH, sizeL, delayH, delayL;
- if (ev->size != 1+1+4*sizeof(Uint32)
+ if (ev->size != 1+1+4*sizeof(Uint32)+strlen(dt_utag)+1
|| !EV_GET_UINT32(ev, &sizeH, &p, &q)
|| !EV_GET_UINT32(ev, &sizeL, &p, &q)
|| !EV_GET_UINT32(ev, &delayH, &p, &q)
@@ -3392,12 +3724,13 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) {
#else
desc->write_delay = ((unsigned long)delayH << 32) | delayL;
#endif
+ dt_i2 = desc->write_delay;
TRACE_C('K');
reply_ok(desc);
} goto done;
case FILE_OPT_READ_AHEAD: {
Uint32 sizeH, sizeL;
- if (ev->size != 1+1+2*sizeof(Uint32)
+ if (ev->size != 1+1+2*sizeof(Uint32)+strlen(dt_utag)+1
|| !EV_GET_UINT32(ev, &sizeH, &p, &q)
|| !EV_GET_UINT32(ev, &sizeL, &p, &q)) {
/* Buffer has wrong length to contain the option values */
@@ -3413,6 +3746,7 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) {
#else
desc->read_bufsize = ((size_t)sizeH << 32) | sizeL;
#endif
+ dt_i2 = desc->read_bufsize;
TRACE_C('K');
reply_ok(desc);
} goto done;
@@ -3499,11 +3833,11 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) {
} /* switch(command) */
- if (lseek_flush_read(desc, &err) < 0) {
+ if (lseek_flush_read(desc, &err, dt_priv, dt_utag) < 0) {
reply_posix_error(desc, err);
goto done;
}
- if (flush_write_check_error(desc, &err) < 0) {
+ if (flush_write_check_error(desc, &err, dt_priv, dt_utag) < 0) {
reply_posix_error(desc, err);
goto done;
} else {
@@ -3521,5 +3855,46 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) {
}
done:
+ if (d != NULL) {
+#ifdef HAVE_DTRACE
+ /*
+ * If d == NULL, then either:
+ * 1). There was an error of some sort, or
+ * 2). The command given to us is actually implemented
+ * by file_output() instead.
+ *
+ * Case #1 is probably a TODO item, perhaps?
+ * Case #2 we definitely don't want to activate a probe.
+ */
+ d->sched_i1 = dt_priv->thread_num;
+ d->sched_i2 = dt_priv->tag;
+ d->sched_utag[0] = '\0';
+ if (dt_utag != NULL) {
+ strncpy(d->sched_utag, dt_utag, sizeof(d->sched_utag) - 1);
+ d->sched_utag[sizeof(d->sched_utag) - 1] = '\0';
+ }
+ DTRACE11(efile_drv_entry, dt_priv->thread_num, dt_priv->tag++,
+ dt_utag, command, dt_s1, NULL, dt_i1, dt_i2, dt_i3, dt_i4,
+ desc->port_str);
+#endif
+ }
cq_execute(desc);
}
+
+#ifdef HAVE_DTRACE
+dt_private *
+get_dt_private(int base)
+{
+ dt_private *dt_priv = (dt_private *) pthread_getspecific(dt_driver_key);
+
+ if (dt_priv == NULL) {
+ dt_priv = EF_SAFE_ALLOC(sizeof(dt_private));
+ erts_mtx_lock(&dt_driver_mutex);
+ dt_priv->thread_num = (base + dt_driver_idnum++);
+ erts_mtx_unlock(&dt_driver_mutex);
+ dt_priv->tag = 0;
+ pthread_setspecific(dt_driver_key, dt_priv);
+ }
+ return dt_priv;
+}
+#endif /* HAVE_DTRACE */
diff --git a/erts/preloaded/ebin/prim_file.beam b/erts/preloaded/ebin/prim_file.beam
index 87e80aae9b..9d6c47ffc1 100644
--- a/erts/preloaded/ebin/prim_file.beam
+++ b/erts/preloaded/ebin/prim_file.beam
Binary files differ
diff --git a/erts/preloaded/src/prim_file.erl b/erts/preloaded/src/prim_file.erl
index 36cbe329e8..5c9cad3a2c 100644
--- a/erts/preloaded/src/prim_file.erl
+++ b/erts/preloaded/src/prim_file.erl
@@ -25,39 +25,59 @@
%%% Interface towards a single file's contents. Uses ?FD_DRV.
%% Generic file contents operations
--export([open/2, close/1, datasync/1, sync/1, advise/4, position/2, truncate/1,
- write/2, pwrite/2, pwrite/3, read/2, read_line/1, pread/2, pread/3,
- copy/3, sendfile/10]).
+
+-export([
+ open/2, open/3,
+ close/1, close/2,
+ datasync/1, datasync/2,
+ sync/1, sync/2,
+ advise/4, advise/5,
+ position/2, position/3,
+ truncate/1, truncate/2,
+ write/2, write/3,
+ pwrite/2, pwrite/3, pwrite/4,
+ read/2, read/3,
+ read_line/1, read_line/2,
+ pread/2, pread/3, pread/4,
+ copy/3, copy/4,
+ sendfile/10
+ ]).
%% Specialized file operations
--export([open/1, open/3]).
--export([read_file/1, read_file/2, write_file/2]).
--export([ipread_s32bu_p32bu/3]).
+-export([open/1]).
+-export([read_file/1, read_file/2, read_file/3, write_file/2, write_file/3]).
+-export([ipread_s32bu_p32bu/3, ipread_s32bu_p32bu/4]).
%%% Interface towards file system and metadata. Uses ?DRV.
%% Takes an optional port (opens a ?DRV port per default) as first argument.
--export([get_cwd/0, get_cwd/1, get_cwd/2,
- set_cwd/1, set_cwd/2,
- delete/1, delete/2,
- rename/2, rename/3,
- make_dir/1, make_dir/2,
- del_dir/1, del_dir/2,
- read_file_info/1, read_file_info/2, read_file_info/3,
- altname/1, altname/2,
- write_file_info/2, write_file_info/3, write_file_info/4,
- make_link/2, make_link/3,
- make_symlink/2, make_symlink/3,
- read_link/1, read_link/2,
- read_link_info/1, read_link_info/2, read_link_info/3,
- list_dir/1, list_dir/2]).
+
+-export([
+ get_cwd/0, get_cwd/1, get_cwd/3,
+ set_cwd/1, set_cwd/3,
+ delete/1, delete/2, delete/3,
+ rename/2, rename/3, rename/4,
+ make_dir/1, make_dir/3,
+ del_dir/1, del_dir/3,
+ read_file_info/1, read_file_info/2, read_file_info/3, read_file_info/4,
+ altname/1, altname/3,
+ write_file_info/2, write_file_info/4, write_file_info/5,
+ make_link/2, make_link/3, make_link/4,
+ make_symlink/2, make_symlink/3, make_symlink/4,
+ read_link/1, read_link/3,
+ read_link_info/1, read_link_info/2, read_link_info/3, read_link_info/4,
+ list_dir/1, list_dir/3
+ ]).
%% How to start and stop the ?DRV port.
-export([start/0, stop/1]).
%% Debug exports
--export([open_int/4, open_mode/1, open_mode/4]).
+-export([open_int/4, open_int/5, open_mode/1, open_mode/4]).
+
+%% For DTrace/Systemtap tracing
+-export([get_dtrace_utag/0]).
%%%-----------------------------------------------------------------
%%% Includes and defines
@@ -155,30 +175,21 @@
%%% Supposed to be called by applications through module file.
-%% Opens a file using the driver port Port. Returns {error, Reason}
-%% | {ok, FileDescriptor}
-open(Port, File, ModeList) when is_port(Port),
- (is_list(File) orelse is_binary(File)),
- is_list(ModeList) ->
- case open_mode(ModeList) of
- {Mode, _Portopts, _Setopts} ->
- open_int(Port, File, Mode, []);
- Reason ->
- {error, Reason}
- end;
-open(_,_,_) ->
- {error, badarg}.
-
%% Opens a file. Returns {error, Reason} | {ok, FileDescriptor}.
-open(File, ModeList) when (is_list(File) orelse is_binary(File)),
- is_list(ModeList) ->
+open(File, ModeList) ->
+ open(File, ModeList, get_dtrace_utag()).
+
+open(File, ModeList, DTraceUtag)
+ when (is_list(File) orelse is_binary(File)),
+ is_list(ModeList),
+ (is_list(DTraceUtag) orelse is_binary(DTraceUtag)) ->
case open_mode(ModeList) of
{Mode, Portopts, Setopts} ->
- open_int({?FD_DRV, Portopts},File, Mode, Setopts);
+ open_int({?FD_DRV, Portopts}, File, Mode, Setopts, DTraceUtag);
Reason ->
{error, Reason}
end;
-open(_, _) ->
+open(_, _, _) ->
{error, badarg}.
%% Opens a port that can be used for open/3 or read_file/2.
@@ -193,29 +204,34 @@ open(Portopts) when is_list(Portopts) ->
open(_) ->
{error, badarg}.
-open_int({Driver, Portopts}, File, Mode, Setopts) ->
+open_int(Arg, File, Mode, Setopts) ->
+ open_int(Arg, File, Mode, Setopts, get_dtrace_utag()).
+
+open_int({Driver, Portopts}, File, Mode, Setopts, DTraceUtag) ->
+ %% TODO: add DTraceUtag to drv_open()?
case drv_open(Driver, Portopts) of
{ok, Port} ->
- open_int(Port, File, Mode, Setopts);
+ open_int(Port, File, Mode, Setopts, DTraceUtag);
{error, _} = Error ->
Error
end;
-open_int(Port, File, Mode, Setopts) ->
+open_int(Port, File, Mode, Setopts, DTraceUtag) ->
M = Mode band ?EFILE_MODE_MASK,
- case drv_command(Port, [<<?FILE_OPEN, M:32>>, pathname(File)]) of
+ case drv_command(Port, [<<?FILE_OPEN, M:32>>,
+ pathname(File), enc_utag(DTraceUtag)]) of
{ok, Number} ->
- open_int_setopts(Port, Number, Setopts);
+ open_int_setopts(Port, Number, Setopts, DTraceUtag);
Error ->
drv_close(Port),
Error
end.
-open_int_setopts(Port, Number, []) ->
+open_int_setopts(Port, Number, [], _DTraceUtag) ->
{ok, #file_descriptor{module = ?MODULE, data = {Port, Number}}};
-open_int_setopts(Port, Number, [Cmd | Tail]) ->
- case drv_command(Port, Cmd) of
+open_int_setopts(Port, Number, [Cmd | Tail], DTraceUtag) ->
+ case drv_command(Port, [Cmd, enc_utag(DTraceUtag)]) of
ok ->
- open_int_setopts(Port, Number, Tail);
+ open_int_setopts(Port, Number, Tail, DTraceUtag);
Error ->
drv_close(Port),
Error
@@ -225,50 +241,64 @@ open_int_setopts(Port, Number, [Cmd | Tail]) ->
%% Returns ok.
-close(#file_descriptor{module = ?MODULE, data = {Port, _}}) ->
- case drv_command(Port, <<?FILE_CLOSE>>) of
+close(Arg) ->
+ close(Arg, get_dtrace_utag()).
+
+close(#file_descriptor{module = ?MODULE, data = {Port, _}}, DTraceUtag)
+ when (is_list(DTraceUtag) orelse is_binary(DTraceUtag)) ->
+ case drv_command(Port, [<<?FILE_CLOSE>>, enc_utag(DTraceUtag)]) of
ok ->
drv_close(Port);
Error ->
Error
end;
%% Closes a port opened with open/1.
-close(Port) when is_port(Port) ->
+close(Port, _DTraceUtag) when is_port(Port) ->
drv_close(Port).
--define(ADVISE(Offs, Len, Adv),
+-define(ADVISE(Offs, Len, Adv, BUtag),
<<?FILE_ADVISE, Offs:64/signed, Len:64/signed,
- Adv:32/signed>>).
+ Adv:32/signed, BUtag/binary>>).
%% Returns {error, Reason} | ok.
+advise(FD, Offset, Length, Advise) ->
+ advise(FD, Offset, Length, Advise, get_dtrace_utag()).
+
advise(#file_descriptor{module = ?MODULE, data = {Port, _}},
- Offset, Length, Advise) ->
+ Offset, Length, Advise, DTraceUtag)
+ when (is_list(DTraceUtag) orelse is_binary(DTraceUtag)) ->
+ BUtag = term_to_binary(enc_utag(DTraceUtag)),
case Advise of
normal ->
- Cmd = ?ADVISE(Offset, Length, ?POSIX_FADV_NORMAL),
+ Cmd = ?ADVISE(Offset, Length, ?POSIX_FADV_NORMAL, BUtag),
drv_command(Port, Cmd);
random ->
- Cmd = ?ADVISE(Offset, Length, ?POSIX_FADV_RANDOM),
+ Cmd = ?ADVISE(Offset, Length, ?POSIX_FADV_RANDOM, BUtag),
drv_command(Port, Cmd);
sequential ->
- Cmd = ?ADVISE(Offset, Length, ?POSIX_FADV_SEQUENTIAL),
+ Cmd = ?ADVISE(Offset, Length, ?POSIX_FADV_SEQUENTIAL, BUtag),
drv_command(Port, Cmd);
will_need ->
- Cmd = ?ADVISE(Offset, Length, ?POSIX_FADV_WILLNEED),
+ Cmd = ?ADVISE(Offset, Length, ?POSIX_FADV_WILLNEED, BUtag),
drv_command(Port, Cmd);
dont_need ->
- Cmd = ?ADVISE(Offset, Length, ?POSIX_FADV_DONTNEED),
+ Cmd = ?ADVISE(Offset, Length, ?POSIX_FADV_DONTNEED, BUtag),
drv_command(Port, Cmd);
no_reuse ->
- Cmd = ?ADVISE(Offset, Length, ?POSIX_FADV_NOREUSE),
+ Cmd = ?ADVISE(Offset, Length, ?POSIX_FADV_NOREUSE, BUtag),
drv_command(Port, Cmd);
_ ->
{error, einval}
end.
%% Returns {error, Reason} | ok.
-write(#file_descriptor{module = ?MODULE, data = {Port, _}}, Bytes) ->
- case drv_command(Port, [?FILE_WRITE,Bytes]) of
+write(Desc, Bytes) ->
+ write(Desc, Bytes, get_dtrace_utag()).
+
+write(#file_descriptor{module = ?MODULE, data = {Port, _}}, Bytes, DTraceUtag)
+ when (is_list(DTraceUtag) orelse is_binary(DTraceUtag)) ->
+ %% This is rare case where DTraceUtag is not at end of command list.
+ case drv_command(Port, [?FILE_WRITE,enc_utag(DTraceUtag),Bytes]) of
{ok, _Size} ->
ok;
Error ->
@@ -278,39 +308,40 @@ write(#file_descriptor{module = ?MODULE, data = {Port, _}}, Bytes) ->
%% Returns ok | {error, {WrittenCount, Reason}}
pwrite(#file_descriptor{module = ?MODULE, data = {Port, _}}, L)
when is_list(L) ->
- pwrite_int(Port, L, 0, [], []).
+ pwrite_int(Port, L, 0, [], [], get_dtrace_utag()).
-pwrite_int(_, [], 0, [], []) ->
+pwrite_int(_, [], 0, [], [], _DTraceUtag) ->
ok;
-pwrite_int(Port, [], N, Spec, Data) ->
- Header = list_to_binary([<<?FILE_PWRITEV, N:32>> | reverse(Spec)]),
+pwrite_int(Port, [], N, Spec, Data, DTraceUtag) ->
+ Header = list_to_binary([<<?FILE_PWRITEV>>, enc_utag(DTraceUtag),
+ <<N:32>>, reverse(Spec)]),
case drv_command_raw(Port, [Header | reverse(Data)]) of
{ok, _Size} ->
ok;
Error ->
Error
end;
-pwrite_int(Port, [{Offs, Bytes} | T], N, Spec, Data)
+pwrite_int(Port, [{Offs, Bytes} | T], N, Spec, Data, DTraceUtag)
when is_integer(Offs) ->
if
-(?LARGEFILESIZE) =< Offs, Offs < ?LARGEFILESIZE ->
- pwrite_int(Port, T, N, Spec, Data, Offs, Bytes);
+ pwrite_int(Port, T, N, Spec, Data, Offs, Bytes, DTraceUtag);
true ->
{error, einval}
end;
-pwrite_int(_, [_|_], _N, _Spec, _Data) ->
+pwrite_int(_, [_|_], _N, _Spec, _Data, _DTraceUtag) ->
{error, badarg}.
-pwrite_int(Port, T, N, Spec, Data, Offs, Bin)
+pwrite_int(Port, T, N, Spec, Data, Offs, Bin, DTraceUtag)
when is_binary(Bin) ->
Size = byte_size(Bin),
pwrite_int(Port, T, N+1,
[<<Offs:64/signed, Size:64>> | Spec],
- [Bin | Data]);
-pwrite_int(Port, T, N, Spec, Data, Offs, Bytes) ->
+ [Bin | Data], DTraceUtag);
+pwrite_int(Port, T, N, Spec, Data, Offs, Bytes, DTraceUtag) ->
try list_to_binary(Bytes) of
Bin ->
- pwrite_int(Port, T, N, Spec, Data, Offs, Bin)
+ pwrite_int(Port, T, N, Spec, Data, Offs, Bin, DTraceUtag)
catch
error:Reason ->
{error, Reason}
@@ -319,11 +350,28 @@ pwrite_int(Port, T, N, Spec, Data, Offs, Bytes) ->
%% Returns {error, Reason} | ok.
-pwrite(#file_descriptor{module = ?MODULE, data = {Port, _}}, Offs, Bytes)
+pwrite(#file_descriptor{module = ?MODULE, data = {Port, _}}, L, DTraceUtag)
+ when is_list(L),
+ (is_list(DTraceUtag) orelse is_binary(DTraceUtag)) ->
+ pwrite_int(Port, L, 0, [], [], DTraceUtag);
+
+pwrite(#file_descriptor{module = ?MODULE, data = {Port, _}}, Offs, Bytes)
when is_integer(Offs) ->
+ pwrite_int2(Port, Offs, Bytes, get_dtrace_utag());
+pwrite(#file_descriptor{module = ?MODULE}, _, _) ->
+ {error, badarg}.
+
+pwrite(#file_descriptor{module = ?MODULE, data = {Port, _}}, Offs, Bytes, DTraceUtag)
+ when is_integer(Offs),
+ (is_list(DTraceUtag) orelse is_binary(DTraceUtag)) ->
+ pwrite_int2(Port, Offs, Bytes, DTraceUtag);
+pwrite(#file_descriptor{module = ?MODULE}, _, _, _DTraceUtag) ->
+ {error, badarg}.
+
+pwrite_int2(Port, Offs, Bytes, DTraceUtag) ->
if
-(?LARGEFILESIZE) =< Offs, Offs < ?LARGEFILESIZE ->
- case pwrite_int(Port, [], 0, [], [], Offs, Bytes) of
+ case pwrite_int(Port, [], 0, [], [], Offs, Bytes, DTraceUtag) of
{error, {_, Reason}} ->
{error, Reason};
Result ->
@@ -331,22 +379,30 @@ pwrite(#file_descriptor{module = ?MODULE, data = {Port, _}}, Offs, Bytes)
end;
true ->
{error, einval}
- end;
-pwrite(#file_descriptor{module = ?MODULE}, _, _) ->
- {error, badarg}.
-
+ end.
%% Returns {error, Reason} | ok.
-datasync(#file_descriptor{module = ?MODULE, data = {Port, _}}) ->
- drv_command(Port, [?FILE_FDATASYNC]).
+datasync(FD) ->
+ datasync(FD, get_dtrace_utag()).
+
+datasync(#file_descriptor{module = ?MODULE, data = {Port, _}}, DTraceUtag)
+ when (is_list(DTraceUtag) orelse is_binary(DTraceUtag)) ->
+ drv_command(Port, [?FILE_FDATASYNC, enc_utag(DTraceUtag)]).
%% Returns {error, Reason} | ok.
-sync(#file_descriptor{module = ?MODULE, data = {Port, _}}) ->
- drv_command(Port, [?FILE_FSYNC]).
+sync(FD) ->
+ sync(FD, get_dtrace_utag()).
+
+sync(#file_descriptor{module = ?MODULE, data = {Port, _}}, DTraceUtag)
+ when (is_list(DTraceUtag) orelse is_binary(DTraceUtag)) ->
+ drv_command(Port, [?FILE_FSYNC, enc_utag(DTraceUtag)]).
%% Returns {ok, Data} | eof | {error, Reason}.
-read_line(#file_descriptor{module = ?MODULE, data = {Port, _}}) ->
- case drv_command(Port, <<?FILE_READ_LINE>>) of
+read_line(FD) ->
+ read_line(FD, get_dtrace_utag()).
+
+read_line(#file_descriptor{module = ?MODULE, data = {Port, _}}, DTraceUtag) ->
+ case drv_command(Port, [<<?FILE_READ_LINE>>, enc_utag(DTraceUtag)]) of
{ok, {0, _Data}} ->
eof;
{ok, {_Size, Data}} ->
@@ -366,11 +422,17 @@ read_line(#file_descriptor{module = ?MODULE, data = {Port, _}}) ->
end.
%% Returns {ok, Data} | eof | {error, Reason}.
-read(#file_descriptor{module = ?MODULE, data = {Port, _}}, Size)
- when is_integer(Size), 0 =< Size ->
+read(FD, Size) ->
+ read(FD, Size, get_dtrace_utag()).
+
+read(#file_descriptor{module = ?MODULE, data = {Port, _}}, Size, DTraceUtag)
+ when is_integer(Size),
+ 0 =< Size,
+ (is_list(DTraceUtag) orelse is_binary(DTraceUtag)) ->
if
Size < ?LARGEFILESIZE ->
- case drv_command(Port, <<?FILE_READ, Size:64>>) of
+ case drv_command(Port, [<<?FILE_READ, Size:64>>,
+ enc_utag(DTraceUtag)]) of
{ok, {0, _Data}} when Size =/= 0 ->
eof;
{ok, {_Size, Data}} ->
@@ -379,7 +441,8 @@ read(#file_descriptor{module = ?MODULE, data = {Port, _}}, Size)
%% Garbage collecting here might help if
%% the current processes have some old binaries left.
erlang:garbage_collect(),
- case drv_command(Port, <<?FILE_READ, Size:64>>) of
+ case drv_command(Port, [<<?FILE_READ, Size:64>>,
+ enc_utag(DTraceUtag)]) of
{ok, {0, _Data}} when Size =/= 0 ->
eof;
{ok, {_Size, Data}} ->
@@ -397,35 +460,43 @@ read(#file_descriptor{module = ?MODULE, data = {Port, _}}, Size)
%% Returns {ok, [Data|eof, ...]} | {error, Reason}
pread(#file_descriptor{module = ?MODULE, data = {Port, _}}, L)
when is_list(L) ->
- pread_int(Port, L, 0, []).
+ pread_int(Port, L, 0, [], get_dtrace_utag()).
-pread_int(_, [], 0, []) ->
+pread_int(_, [], 0, [], _DTraceUtag) ->
{ok, []};
-pread_int(Port, [], N, Spec) ->
- drv_command(Port, [<<?FILE_PREADV, 0:32, N:32>> | reverse(Spec)]);
-pread_int(Port, [{Offs, Size} | T], N, Spec)
+pread_int(Port, [], N, Spec, DTraceUtag) ->
+ drv_command(Port, [<<?FILE_PREADV>>, enc_utag(DTraceUtag),
+ <<0:32, N:32>>, reverse(Spec)]);
+pread_int(Port, [{Offs, Size} | T], N, Spec, DTraceUtag)
when is_integer(Offs), is_integer(Size), 0 =< Size ->
if
-(?LARGEFILESIZE) =< Offs, Offs < ?LARGEFILESIZE,
Size < ?LARGEFILESIZE ->
- pread_int(Port, T, N+1, [<<Offs:64/signed, Size:64>> | Spec]);
+ pread_int(Port, T, N+1, [<<Offs:64/signed, Size:64>> | Spec],
+ DTraceUtag);
true ->
{error, einval}
end;
-pread_int(_, [_|_], _N, _Spec) ->
+pread_int(_, [_|_], _N, _Spec, _DTraceUtag) ->
{error, badarg}.
-
-
%% Returns {ok, Data} | eof | {error, Reason}.
-pread(#file_descriptor{module = ?MODULE, data = {Port, _}}, Offs, Size)
+pread(#file_descriptor{module = ?MODULE, data = {Port, _}}, L, DTraceUtag)
+ when is_list(L),
+ (is_list(DTraceUtag) orelse is_binary(DTraceUtag)) ->
+ pread_int(Port, L, 0, [], get_dtrace_utag());
+pread(FD, Offs, Size)
when is_integer(Offs), is_integer(Size), 0 =< Size ->
+ pread(FD, Offs, Size, get_dtrace_utag()).
+
+pread(#file_descriptor{module = ?MODULE, data = {Port, _}}, Offs, Size, DTraceUtag)
+ when (is_list(DTraceUtag) orelse is_binary(DTraceUtag)) ->
if
-(?LARGEFILESIZE) =< Offs, Offs < ?LARGEFILESIZE,
Size < ?LARGEFILESIZE ->
case drv_command(Port,
- <<?FILE_PREADV, 0:32, 1:32,
- Offs:64/signed, Size:64>>) of
+ [<<?FILE_PREADV>>, enc_utag(DTraceUtag),
+ <<0:32, 1:32, Offs:64/signed, Size:64>>]) of
{ok, [eof]} ->
eof;
{ok, [Data]} ->
@@ -436,17 +507,22 @@ pread(#file_descriptor{module = ?MODULE, data = {Port, _}}, Offs, Size)
true ->
{error, einval}
end;
-pread(#file_descriptor{module = ?MODULE, data = {_, _}}, _, _) ->
+pread(_, _, _, _) ->
{error, badarg}.
%% Returns {ok, Position} | {error, Reason}.
-position(#file_descriptor{module = ?MODULE, data = {Port, _}}, At) ->
+position(FD, At) ->
+ position(FD, At, get_dtrace_utag()).
+
+position(#file_descriptor{module = ?MODULE, data = {Port, _}}, At, DTraceUtag)
+ when (is_list(DTraceUtag) orelse is_binary(DTraceUtag)) ->
case lseek_position(At) of
{Offs, Whence}
when -(?LARGEFILESIZE) =< Offs, Offs < ?LARGEFILESIZE ->
- drv_command(Port, <<?FILE_LSEEK, Offs:64/signed, Whence:32>>);
+ drv_command(Port, [<<?FILE_LSEEK, Offs:64/signed, Whence:32>>,
+ enc_utag(DTraceUtag)]);
{_, _} ->
{error, einval};
Reason ->
@@ -454,63 +530,89 @@ position(#file_descriptor{module = ?MODULE, data = {Port, _}}, At) ->
end.
%% Returns {error, Reaseon} | ok.
-truncate(#file_descriptor{module = ?MODULE, data = {Port, _}}) ->
- drv_command(Port, <<?FILE_TRUNCATE>>).
+truncate(FD) ->
+ truncate(FD, get_dtrace_utag()).
+
+truncate(#file_descriptor{module = ?MODULE, data = {Port, _}}, DTraceUtag)
+ when (is_list(DTraceUtag) orelse is_binary(DTraceUtag)) ->
+ drv_command(Port, [<<?FILE_TRUNCATE>>, enc_utag(DTraceUtag)]).
%% Returns {error, Reason} | {ok, BytesCopied}
+copy(Source, Dest, Length) ->
+ copy(Source, Dest, Length, get_dtrace_utag()).
+
copy(#file_descriptor{module = ?MODULE} = Source,
#file_descriptor{module = ?MODULE} = Dest,
- Length)
+ Length, DTraceUtag)
when is_integer(Length), Length >= 0;
- is_atom(Length) ->
+ is_atom(Length),
+ (is_list(DTraceUtag) orelse is_binary(DTraceUtag)) ->
%% XXX Should be moved down to the driver for optimization.
- file:copy_opened(Source, Dest, Length).
+ file:copy_opened(Source, Dest, Length, DTraceUtag).
+
+ipread_s32bu_p32bu(FD, Offs, Arg) ->
+ ipread_s32bu_p32bu(FD, Offs, Arg, get_dtrace_utag()).
ipread_s32bu_p32bu(#file_descriptor{module = ?MODULE,
data = {_, _}} = Handle,
Offs,
- Infinity) when is_atom(Infinity) ->
+ Infinity,
+ DTraceUtag)
+ when is_atom(Infinity),
+ (is_list(DTraceUtag) orelse is_binary(DTraceUtag)) ->
ipread_s32bu_p32bu(Handle, Offs, (1 bsl 31)-1);
ipread_s32bu_p32bu(#file_descriptor{module = ?MODULE, data = {Port, _}},
Offs,
- MaxSize)
- when is_integer(Offs), is_integer(MaxSize) ->
+ MaxSize,
+ DTraceUtag)
+ when is_integer(Offs),
+ is_integer(MaxSize),
+ (is_list(DTraceUtag) orelse is_binary(DTraceUtag)) ->
if
-(?LARGEFILESIZE) =< Offs, Offs < ?LARGEFILESIZE,
0 =< MaxSize, MaxSize < (1 bsl 31) ->
- drv_command(Port, <<?FILE_IPREAD, ?IPREAD_S32BU_P32BU,
- Offs:64, MaxSize:32>>);
+ drv_command(Port, [<<?FILE_IPREAD, ?IPREAD_S32BU_P32BU,
+ Offs:64, MaxSize:32>>, enc_utag(DTraceUtag)]);
true ->
{error, einval}
end;
ipread_s32bu_p32bu(#file_descriptor{module = ?MODULE, data = {_, _}},
_Offs,
- _MaxSize) ->
+ _MaxSize,
+ _DTraceUtag) ->
{error, badarg}.
%% Returns {ok, Contents} | {error, Reason}
read_file(File) when (is_list(File) orelse is_binary(File)) ->
+ read_file(File, get_dtrace_utag());
+read_file(_) ->
+ {error, badarg}.
+
+read_file(File, DTraceUtag)
+ when (is_list(File) orelse is_binary(File)),
+ (is_list(DTraceUtag) orelse is_binary(DTraceUtag))->
case drv_open(?FD_DRV, [binary]) of
{ok, Port} ->
- Result = read_file(Port, File),
+ Result = read_file(Port, File, DTraceUtag),
close(Port),
Result;
{error, _} = Error ->
Error
end;
-read_file(_) ->
+read_file(_, _) ->
{error, badarg}.
%% Takes a Port opened with open/1.
-read_file(Port, File) when is_port(Port),
+read_file(Port, File, DTraceUtag) when is_port(Port),
(is_list(File) orelse is_binary(File)) ->
- Cmd = [?FILE_READ_FILE | pathname(File)],
+ Cmd = [?FILE_READ_FILE |
+ list_to_binary([pathname(File), enc_utag(DTraceUtag)])],
case drv_command(Port, Cmd) of
{error, enomem} ->
%% It could possibly help to do a
@@ -522,22 +624,30 @@ read_file(Port, File) when is_port(Port),
Result ->
Result
end;
-read_file(_,_) ->
+read_file(_,_,_) ->
{error, badarg}.
%% Returns {error, Reason} | ok.
-write_file(File, Bin) when (is_list(File) orelse is_binary(File)) ->
+write_file(File, Bin) ->
+ write_file(File, Bin, get_dtrace_utag()).
+
+write_file(File, Bin, DTraceUtag)
+ when (is_list(File) orelse is_binary(File)),
+ (is_list(DTraceUtag) orelse is_binary(DTraceUtag)) ->
+ OldUtag = put(dtrace_utag, DTraceUtag), % TODO: API?
case open(File, [binary, write]) of
{ok, Handle} ->
Result = write(Handle, Bin),
close(Handle),
+ put(dtrace_utag, OldUtag),
Result;
Error ->
+ put(dtrace_utag, OldUtag),
Error
end;
-write_file(_, _) ->
+write_file(_, _, _) ->
{error, badarg}.
@@ -601,54 +711,56 @@ stop(Port) when is_port(Port) ->
-%% get_cwd/{0,1,2}
+%% get_cwd/{0,1,3}
get_cwd() ->
- get_cwd_int(0).
+ get_cwd_int(0, get_dtrace_utag()).
get_cwd(Port) when is_port(Port) ->
- get_cwd_int(Port, 0);
+ get_cwd_int(Port, 0, get_dtrace_utag());
get_cwd([]) ->
- get_cwd_int(0);
+ get_cwd_int(0, get_dtrace_utag());
get_cwd([Letter, $: | _]) when $a =< Letter, Letter =< $z ->
- get_cwd_int(Letter - $a + 1);
+ get_cwd_int(Letter - $a + 1, get_dtrace_utag());
get_cwd([Letter, $: | _]) when $A =< Letter, Letter =< $Z ->
- get_cwd_int(Letter - $A + 1);
+ get_cwd_int(Letter - $A + 1, get_dtrace_utag());
get_cwd([_|_]) ->
{error, einval};
get_cwd(_) ->
{error, badarg}.
-get_cwd(Port, []) when is_port(Port) ->
- get_cwd_int(Port, 0);
-get_cwd(Port, [Letter, $: | _])
+get_cwd(Port, [], DTraceUtag) when is_port(Port) ->
+ get_cwd_int(Port, 0, DTraceUtag);
+get_cwd(Port, no_drive, DTraceUtag) when is_port(Port) ->
+ get_cwd_int(Port, 0, DTraceUtag);
+get_cwd(Port, [Letter, $: | _], DTraceUtag)
when is_port(Port), $a =< Letter, Letter =< $z ->
- get_cwd_int(Port, Letter - $a + 1);
-get_cwd(Port, [Letter, $: | _])
+ get_cwd_int(Port, Letter - $a + 1, DTraceUtag);
+get_cwd(Port, [Letter, $: | _], DTraceUtag)
when is_port(Port), $A =< Letter, Letter =< $Z ->
- get_cwd_int(Port, Letter - $A + 1);
-get_cwd(Port, [_|_]) when is_port(Port) ->
+ get_cwd_int(Port, Letter - $A + 1, DTraceUtag);
+get_cwd(Port, [_|_], _DTraceUtag) when is_port(Port) ->
{error, einval};
-get_cwd(_, _) ->
+get_cwd(_, _, _DTraceUtag) ->
{error, badarg}.
-get_cwd_int(Drive) ->
- get_cwd_int({?DRV, [binary]}, Drive).
+get_cwd_int(Drive, DTraceUtag) ->
+ get_cwd_int({?DRV, [binary]}, Drive, DTraceUtag).
-get_cwd_int(Port, Drive) ->
- drv_command(Port, <<?FILE_PWD, Drive>>).
+get_cwd_int(Port, Drive, DTraceUtag) ->
+ drv_command(Port, list_to_binary([?FILE_PWD, Drive, enc_utag(DTraceUtag)])).
-%% set_cwd/{1,2}
+%% set_cwd/{1,3}
set_cwd(Dir) ->
- set_cwd_int({?DRV, [binary]}, Dir).
+ set_cwd_int({?DRV, [binary]}, Dir, get_dtrace_utag()).
-set_cwd(Port, Dir) when is_port(Port) ->
- set_cwd_int(Port, Dir).
+set_cwd(Port, Dir, DTraceUtag) when is_port(Port) ->
+ set_cwd_int(Port, Dir, DTraceUtag).
-set_cwd_int(Port, Dir0) ->
+set_cwd_int(Port, Dir0, DTraceUtag) ->
Dir =
(catch
case os:type() of
@@ -658,7 +770,7 @@ set_cwd_int(Port, Dir0) ->
%% must call get_cwd from here and use
%% absname/2, since
%% absname/1 uses file:get_cwd ...
- case get_cwd_int(Port, 0) of
+ case get_cwd_int(Port, 0, "") of
{ok, AbsPath} ->
filename:absname(Dir0, AbsPath);
_Badcwd ->
@@ -669,78 +781,86 @@ set_cwd_int(Port, Dir0) ->
end),
%% Dir is now either a string or an EXIT tuple.
%% An EXIT tuple will fail in the following catch.
- drv_command(Port, [?FILE_CHDIR, pathname(Dir)]).
+ drv_command(Port, [?FILE_CHDIR, pathname(Dir), enc_utag(DTraceUtag)]).
-%% delete/{1,2}
+%% delete/{1,2,3}
delete(File) ->
- delete_int({?DRV, [binary]}, File).
+ delete_int({?DRV, [binary]}, File, get_dtrace_utag()).
delete(Port, File) when is_port(Port) ->
- delete_int(Port, File).
+ delete_int(Port, File, get_dtrace_utag()).
+
+delete(Port, File, DTraceUtag) when is_port(Port) ->
+ delete_int(Port, File, DTraceUtag).
-delete_int(Port, File) ->
- drv_command(Port, [?FILE_DELETE, pathname(File)]).
+delete_int(Port, File, DTraceUtag) ->
+ drv_command(Port, [?FILE_DELETE, pathname(File), enc_utag(DTraceUtag)]).
-%% rename/{2,3}
+%% rename/{2,3,4}
rename(From, To) ->
- rename_int({?DRV, [binary]}, From, To).
+ rename_int({?DRV, [binary]}, From, To, get_dtrace_utag()).
rename(Port, From, To) when is_port(Port) ->
- rename_int(Port, From, To).
+ rename_int(Port, From, To, get_dtrace_utag()).
+
+rename(Port, From, To, DTraceUtag) when is_port(Port) ->
+ rename_int(Port, From, To, DTraceUtag).
-rename_int(Port, From, To) ->
- drv_command(Port, [?FILE_RENAME, pathname(From), pathname(To)]).
+rename_int(Port, From, To, DTraceUtag) ->
+ drv_command(Port, [?FILE_RENAME, pathname(From), pathname(To),
+ enc_utag(DTraceUtag)]).
-%% make_dir/{1,2}
+%% make_dir/{1,3}
make_dir(Dir) ->
- make_dir_int({?DRV, [binary]}, Dir).
+ make_dir_int({?DRV, [binary]}, Dir, get_dtrace_utag()).
-make_dir(Port, Dir) when is_port(Port) ->
- make_dir_int(Port, Dir).
+make_dir(Port, Dir, DTraceUtag) when is_port(Port) ->
+ make_dir_int(Port, Dir, DTraceUtag).
-make_dir_int(Port, Dir) ->
- drv_command(Port, [?FILE_MKDIR, pathname(Dir)]).
+make_dir_int(Port, Dir, DTraceUtag) ->
+ drv_command(Port, [?FILE_MKDIR, pathname(Dir), enc_utag(DTraceUtag)]).
-%% del_dir/{1,2}
+%% del_dir/{1,3}
del_dir(Dir) ->
- del_dir_int({?DRV, [binary]}, Dir).
+ del_dir_int({?DRV, [binary]}, Dir, get_dtrace_utag()).
-del_dir(Port, Dir) when is_port(Port) ->
- del_dir_int(Port, Dir).
+del_dir(Port, Dir, DTraceUtag) when is_port(Port) ->
+ del_dir_int(Port, Dir, DTraceUtag).
-del_dir_int(Port, Dir) ->
- drv_command(Port, [?FILE_RMDIR, pathname(Dir)]).
+del_dir_int(Port, Dir, DTraceUtag) ->
+ drv_command(Port, [?FILE_RMDIR, pathname(Dir), enc_utag(DTraceUtag)]).
-
-
-%% read_file_info/{1,2,3}
+%% read_file_info/{1,2,3,4}
read_file_info(File) ->
- read_file_info_int({?DRV, [binary]}, File, local).
+ read_file_info_int({?DRV, [binary]}, File, local, get_dtrace_utag()).
read_file_info(Port, File) when is_port(Port) ->
- read_file_info_int(Port, File, local);
+ read_file_info_int(Port, File, local, get_dtrace_utag());
read_file_info(File, Opts) ->
- read_file_info_int({?DRV, [binary]}, File, plgv(time, Opts, local)).
+ read_file_info_int({?DRV, [binary]}, File, plgv(time, Opts, local), get_dtrace_utag()).
-read_file_info(Port, File, Opts) when is_port(Port) ->
- read_file_info_int(Port, File, plgv(time, Opts, local)).
+read_file_info(Port, File, Opts) when is_port(Port), is_list(Opts) ->
+ read_file_info_int(Port, File, plgv(time, Opts, local), get_dtrace_utag()).
-read_file_info_int(Port, File, TimeType) ->
+read_file_info(Port, File, Opts, DTraceUtag) when is_port(Port) ->
+ read_file_info_int(Port, File, plgv(time, Opts, local), DTraceUtag).
+
+read_file_info_int(Port, File, TimeType, DTraceUtag) ->
try
- case drv_command(Port, [?FILE_FSTAT, pathname(File)]) of
+ case drv_command(Port, [?FILE_FSTAT, pathname(File), enc_utag(DTraceUtag)]) of
{ok, FI} -> {ok, FI#file_info{
ctime = from_seconds(FI#file_info.ctime, TimeType),
mtime = from_seconds(FI#file_info.mtime, TimeType),
@@ -752,30 +872,33 @@ read_file_info_int(Port, File, TimeType) ->
error:_ -> {error, badarg}
end.
-
-%% altname/{1,2}
+%% altname/{1,3}
altname(File) ->
- altname_int({?DRV, [binary]}, File).
+ altname_int({?DRV, [binary]}, File, get_dtrace_utag()).
-altname(Port, File) when is_port(Port) ->
- altname_int(Port, File).
+altname(Port, File, DTraceUtag) when is_port(Port) ->
+ altname_int(Port, File, DTraceUtag).
-altname_int(Port, File) ->
- drv_command(Port, [?FILE_ALTNAME, pathname(File)]).
+altname_int(Port, File, DTraceUtag) ->
+ drv_command(Port, [?FILE_ALTNAME, pathname(File), enc_utag(DTraceUtag)]).
-%% write_file_info/{2,3,4}
+
+%% write_file_info/{2,3,4,5}
write_file_info(File, Info) ->
- write_file_info_int({?DRV, [binary]}, File, Info, local).
+ write_file_info_int({?DRV, [binary]}, File, Info, local, get_dtrace_utag()).
write_file_info(Port, File, Info) when is_port(Port) ->
- write_file_info_int(Port, File, Info, local);
+ write_file_info_int(Port, File, Info, local, get_dtrace_utag());
write_file_info(File, Info, Opts) ->
- write_file_info_int({?DRV, [binary]}, File, Info, plgv(time, Opts, local)).
+ write_file_info_int({?DRV, [binary]}, File, Info, plgv(time, Opts, local), get_dtrace_utag()).
write_file_info(Port, File, Info, Opts) when is_port(Port) ->
- write_file_info_int(Port, File, Info, plgv(time, Opts, local)).
+ write_file_info_int(Port, File, Info, plgv(time, Opts, local), get_dtrace_utag()).
+
+write_file_info(Port, File, Info, Opts, DTraceUtag) when is_port(Port) ->
+ write_file_info_int(Port, File, Info, plgv(time, Opts, local), DTraceUtag).
write_file_info_int(Port, File,
#file_info{mode=Mode,
@@ -784,7 +907,8 @@ write_file_info_int(Port, File,
atime=Atime0,
mtime=Mtime0,
ctime=Ctime0},
- TimeType) ->
+ TimeType,
+ DTraceUtag) ->
% Atime and/or Mtime might be undefined
% - use localtime() for atime, if atime is undefined
@@ -803,12 +927,13 @@ write_file_info_int(Port, File,
int_to_int64bytes(to_seconds(Atime, TimeType)),
int_to_int64bytes(to_seconds(Mtime, TimeType)),
int_to_int64bytes(to_seconds(Ctime, TimeType)),
- pathname(File)])
+ pathname(File),
+ enc_utag(DTraceUtag)
+ ])
catch
error:_ -> {error, badarg}
end.
-
file_info_validate_atime(Atime, _) when Atime =/= undefined -> Atime;
file_info_validate_atime(undefined, local) -> erlang:localtime();
file_info_validate_atime(undefined, universal) -> erlang:universaltime();
@@ -820,63 +945,72 @@ file_info_validate_mtime(Mtime, _) -> Mtime.
file_info_validate_ctime(undefined, Mtime) -> Mtime;
file_info_validate_ctime(Ctime, _) -> Ctime.
-%% make_link/{2,3}
+%% make_link/{2,3,4}
make_link(Old, New) ->
- make_link_int({?DRV, [binary]}, Old, New).
+ make_link_int({?DRV, [binary]}, Old, New, get_dtrace_utag()).
make_link(Port, Old, New) when is_port(Port) ->
- make_link_int(Port, Old, New).
+ make_link_int(Port, Old, New, get_dtrace_utag()).
-make_link_int(Port, Old, New) ->
- drv_command(Port, [?FILE_LINK, pathname(Old), pathname(New)]).
+make_link(Port, Old, New, DTraceUtag) when is_port(Port) ->
+ make_link_int(Port, Old, New, DTraceUtag).
+make_link_int(Port, Old, New, DTraceUtag) ->
+ drv_command(Port, [?FILE_LINK, pathname(Old), pathname(New),
+ enc_utag(DTraceUtag)]).
-%% make_symlink/{2,3}
+
+%% make_symlink/{2,3,4}
make_symlink(Old, New) ->
- make_symlink_int({?DRV, [binary]}, Old, New).
+ make_symlink_int({?DRV, [binary]}, Old, New, get_dtrace_utag()).
make_symlink(Port, Old, New) when is_port(Port) ->
- make_symlink_int(Port, Old, New).
+ make_symlink_int(Port, Old, New, get_dtrace_utag()).
+
+make_symlink(Port, Old, New, DTraceUtag) when is_port(Port) ->
+ make_symlink_int(Port, Old, New, DTraceUtag).
-make_symlink_int(Port, Old, New) ->
- drv_command(Port, [?FILE_SYMLINK, pathname(Old), pathname(New)]).
+make_symlink_int(Port, Old, New, DTraceUtag) ->
+ drv_command(Port, [?FILE_SYMLINK, pathname(Old), pathname(New),
+ enc_utag(DTraceUtag)]).
-%% read_link/{2,3}
+%% read_link/{1,3}
read_link(Link) ->
- read_link_int({?DRV, [binary]}, Link).
+ read_link_int({?DRV, [binary]}, Link, get_dtrace_utag()).
-read_link(Port, Link) when is_port(Port) ->
- read_link_int(Port, Link).
+read_link(Port, Link, DTraceUtag) when is_port(Port) ->
+ read_link_int(Port, Link, DTraceUtag).
-read_link_int(Port, Link) ->
- drv_command(Port, [?FILE_READLINK, pathname(Link)]).
+read_link_int(Port, Link, DTraceUtag) ->
+ drv_command(Port, [?FILE_READLINK, pathname(Link), enc_utag(DTraceUtag)]).
-%% read_link_info/{2,3}
+%% read_link_info/{1,2,3,4}
read_link_info(Link) ->
- read_link_info_int({?DRV, [binary]}, Link, local).
+ read_link_info_int({?DRV, [binary]}, Link, local, get_dtrace_utag()).
read_link_info(Port, Link) when is_port(Port) ->
- read_link_info_int(Port, Link, local);
-
+ read_link_info_int(Port, Link, local, get_dtrace_utag());
read_link_info(Link, Opts) ->
- read_link_info_int({?DRV, [binary]}, Link, plgv(time, Opts, local)).
+ read_link_info_int({?DRV, [binary]}, Link, plgv(time, Opts, local), get_dtrace_utag()).
read_link_info(Port, Link, Opts) when is_port(Port) ->
- read_link_info_int(Port, Link, plgv(time, Opts, local)).
+ read_link_info_int(Port, Link, plgv(time, Opts, local), get_dtrace_utag()).
+read_link_info(Port, Link, Opts, DTraceUtag) when is_port(Port) ->
+ read_link_info_int(Port, Link, plgv(time, Opts, local), DTraceUtag).
-read_link_info_int(Port, Link, TimeType) ->
+read_link_info_int(Port, Link, TimeType, DTraceUtag) ->
try
- case drv_command(Port, [?FILE_LSTAT, pathname(Link)]) of
+ case drv_command(Port, [?FILE_LSTAT, pathname(Link), enc_utag(DTraceUtag)]) of
{ok, FI} -> {ok, FI#file_info{
ctime = from_seconds(FI#file_info.ctime, TimeType),
mtime = from_seconds(FI#file_info.mtime, TimeType),
@@ -888,16 +1022,16 @@ read_link_info_int(Port, Link, TimeType) ->
error:_ -> {error, badarg}
end.
-%% list_dir/{1,2}
+%% list_dir/{1,3}
list_dir(Dir) ->
- list_dir_int({?DRV, [binary]}, Dir).
+ list_dir_int({?DRV, [binary]}, Dir, get_dtrace_utag()).
-list_dir(Port, Dir) when is_port(Port) ->
- list_dir_int(Port, Dir).
+list_dir(Port, Dir, DTraceUtag) when is_port(Port) ->
+ list_dir_int(Port, Dir, DTraceUtag).
-list_dir_int(Port, Dir) ->
- drv_command(Port, [?FILE_READDIR, pathname(Dir)], []).
+list_dir_int(Port, Dir, DTraceUtag) ->
+ drv_command(Port, [?FILE_READDIR, pathname(Dir), enc_utag(DTraceUtag)], []).
@@ -1335,7 +1469,6 @@ reverse(L, T) -> lists:reverse(L, T).
pathname(File) ->
(catch prim_file:internal_name2native(File)).
-
%% proplist:get_value/3
plgv(K, [{K, V}|_], _) -> V;
plgv(K, [_|KVs], D) -> plgv(K, KVs, D);
@@ -1359,3 +1492,20 @@ to_seconds({_,_} = Datetime, universal) ->
erlang:universaltime_to_posixtime(Datetime);
to_seconds({_,_} = Datetime, local) ->
erlang:universaltime_to_posixtime(erlang:localtime_to_universaltime(Datetime)).
+
+%% TODO: Duplicate code!
+get_dtrace_utag() ->
+ case get(dtrace_utag) of
+ X when is_list(X) ->
+ X;
+ _ ->
+ ""
+ end.
+
+%% TODO: Measure if it's worth checking (re:run()?) for NUL byte first?
+enc_utag([0|Cs]) ->
+ enc_utag(Cs);
+enc_utag([C|Cs]) ->
+ [C|enc_utag(Cs)];
+enc_utag([]) ->
+ [0].
diff --git a/lib/kernel/src/file.erl b/lib/kernel/src/file.erl
index 4028dd4f0b..a2e0d261ee 100644
--- a/lib/kernel/src/file.erl
+++ b/lib/kernel/src/file.erl
@@ -39,7 +39,7 @@
-export([ipread_s32bu_p32bu/3]).
%% Generic file contents.
-export([open/2, close/1, advise/4,
- read/2, write/2,
+ read/2, write/2,
pread/2, pread/3, pwrite/2, pwrite/3,
read_line/1,
position/2, truncate/1, datasync/1, sync/1,
@@ -62,7 +62,7 @@
%% Internal export to prim_file and ram_file until they implement
%% an efficient copy themselves.
--export([copy_opened/3]).
+-export([copy_opened/4]).
-export([ipread_s32bu_p32bu_int/3]).
@@ -166,7 +166,7 @@ pid2name(Pid) when is_pid(Pid) ->
Reason :: posix().
get_cwd() ->
- call(get_cwd, []).
+ call(get_cwd, [no_drive, get_dtrace_utag()]).
-spec get_cwd(Drive) -> {ok, Dir} | {error, Reason} when
Drive :: string(),
@@ -174,21 +174,21 @@ get_cwd() ->
Reason :: posix() | badarg.
get_cwd(Drive) ->
- check_and_call(get_cwd, [file_name(Drive)]).
+ check_and_call(get_cwd, [file_name(Drive), get_dtrace_utag()]).
-spec set_cwd(Dir) -> ok | {error, Reason} when
Dir :: name(),
Reason :: posix() | badarg.
set_cwd(Dirname) ->
- check_and_call(set_cwd, [file_name(Dirname)]).
+ check_and_call(set_cwd, [file_name(Dirname), get_dtrace_utag()]).
-spec delete(Filename) -> ok | {error, Reason} when
Filename :: name(),
Reason :: posix() | badarg.
delete(Name) ->
- check_and_call(delete, [file_name(Name)]).
+ check_and_call(delete, [file_name(Name), get_dtrace_utag()]).
-spec rename(Source, Destination) -> ok | {error, Reason} when
Source :: name(),
@@ -196,21 +196,21 @@ delete(Name) ->
Reason :: posix() | badarg.
rename(From, To) ->
- check_and_call(rename, [file_name(From), file_name(To)]).
+ check_and_call(rename, [file_name(From), file_name(To), get_dtrace_utag()]).
-spec make_dir(Dir) -> ok | {error, Reason} when
Dir :: name(),
Reason :: posix() | badarg.
make_dir(Name) ->
- check_and_call(make_dir, [file_name(Name)]).
+ check_and_call(make_dir, [file_name(Name), get_dtrace_utag()]).
-spec del_dir(Dir) -> ok | {error, Reason} when
Dir :: name(),
Reason :: posix() | badarg.
del_dir(Name) ->
- check_and_call(del_dir, [file_name(Name)]).
+ check_and_call(del_dir, [file_name(Name), get_dtrace_utag()]).
-spec read_file_info(Filename) -> {ok, FileInfo} | {error, Reason} when
Filename :: name(),
@@ -218,7 +218,7 @@ del_dir(Name) ->
Reason :: posix() | badarg.
read_file_info(Name) ->
- check_and_call(read_file_info, [file_name(Name)]).
+ check_and_call(read_file_info, [file_name(Name), get_dtrace_utag()]).
-spec read_file_info(Filename, Opts) -> {ok, FileInfo} | {error, Reason} when
Filename :: name(),
@@ -232,7 +232,7 @@ read_file_info(Name, Opts) when is_list(Opts) ->
-spec altname(Name :: name()) -> any().
altname(Name) ->
- check_and_call(altname, [file_name(Name)]).
+ check_and_call(altname, [file_name(Name), get_dtrace_utag()]).
-spec read_link_info(Name) -> {ok, FileInfo} | {error, Reason} when
Name :: name(),
@@ -240,7 +240,7 @@ altname(Name) ->
Reason :: posix() | badarg.
read_link_info(Name) ->
- check_and_call(read_link_info, [file_name(Name)]).
+ check_and_call(read_link_info, [file_name(Name), get_dtrace_utag()]).
-spec read_link_info(Name, Opts) -> {ok, FileInfo} | {error, Reason} when
Name :: name(),
@@ -258,7 +258,7 @@ read_link_info(Name, Opts) when is_list(Opts) ->
Reason :: posix() | badarg.
read_link(Name) ->
- check_and_call(read_link, [file_name(Name)]).
+ check_and_call(read_link, [file_name(Name), get_dtrace_utag()]).
-spec write_file_info(Filename, FileInfo) -> ok | {error, Reason} when
Filename :: name(),
@@ -266,7 +266,7 @@ read_link(Name) ->
Reason :: posix() | badarg.
write_file_info(Name, Info = #file_info{}) ->
- check_and_call(write_file_info, [file_name(Name), Info]).
+ check_and_call(write_file_info, [file_name(Name), Info, get_dtrace_utag()]).
-spec write_file_info(Filename, FileInfo, Opts) -> ok | {error, Reason} when
Filename :: name(),
@@ -283,7 +283,7 @@ write_file_info(Name, Info = #file_info{}, Opts) when is_list(Opts) ->
Reason :: posix() | badarg.
list_dir(Name) ->
- check_and_call(list_dir, [file_name(Name)]).
+ check_and_call(list_dir, [file_name(Name), get_dtrace_utag()]).
-spec read_file(Filename) -> {ok, Binary} | {error, Reason} when
Filename :: name(),
@@ -291,7 +291,7 @@ list_dir(Name) ->
Reason :: posix() | badarg | terminated | system_limit.
read_file(Name) ->
- check_and_call(read_file, [file_name(Name)]).
+ check_and_call(read_file, [file_name(Name), get_dtrace_utag()]).
-spec make_link(Existing, New) -> ok | {error, Reason} when
Existing :: name(),
@@ -299,7 +299,7 @@ read_file(Name) ->
Reason :: posix() | badarg.
make_link(Old, New) ->
- check_and_call(make_link, [file_name(Old), file_name(New)]).
+ check_and_call(make_link, [file_name(Old), file_name(New), get_dtrace_utag()]).
-spec make_symlink(Existing, New) -> ok | {error, Reason} when
Existing :: name(),
@@ -307,7 +307,7 @@ make_link(Old, New) ->
Reason :: posix() | badarg.
make_symlink(Old, New) ->
- check_and_call(make_symlink, [file_name(Old), file_name(New)]).
+ check_and_call(make_symlink, [file_name(Old), file_name(New), get_dtrace_utag()]).
-spec write_file(Filename, Bytes) -> ok | {error, Reason} when
Filename :: name(),
@@ -315,7 +315,7 @@ make_symlink(Old, New) ->
Reason :: posix() | badarg | terminated | system_limit.
write_file(Name, Bin) ->
- check_and_call(write_file, [file_name(Name), make_binary(Bin)]).
+ check_and_call(write_file, [file_name(Name), make_binary(Bin), get_dtrace_utag()]).
%% This whole operation should be moved to the file_server and prim_file
%% when it is time to change file server protocol again.
@@ -367,7 +367,7 @@ raw_write_file_info(Name, #file_info{} = Info) ->
case check_args(Args) of
ok ->
[FileName] = Args,
- ?PRIM_FILE:write_file_info(FileName, Info);
+ ?PRIM_FILE:write_file_info(FileName, Info, get_dtrace_utag());
Error ->
Error
end.
@@ -400,7 +400,7 @@ open(Item, ModeList) when is_list(ModeList) ->
[FileName | _] = Args,
%% We rely on the returned Handle (in {ok, Handle})
%% being a pid() or a #file_descriptor{}
- ?PRIM_FILE:open(FileName, ModeList);
+ ?PRIM_FILE:open(FileName, ModeList, get_dtrace_utag());
Error ->
Error
end
@@ -421,7 +421,7 @@ open(Item, ModeList) when is_list(ModeList) ->
case check_args(Args) of
ok ->
[FileName | _] = Args,
- call(open, [FileName, ModeList]);
+ call(open, [FileName, ModeList, get_dtrace_utag()]);
Error ->
Error
end
@@ -466,7 +466,10 @@ close(_) ->
advise(File, Offset, Length, Advise) when is_pid(File) ->
R = file_request(File, {advise, Offset, Length, Advise}),
wait_file_reply(File, R);
+advise(#file_descriptor{module = prim_file = Module} = Handle, Offset, Length, Advise) ->
+ Module:advise(Handle, Offset, Length, Advise, get_dtrace_utag());
advise(#file_descriptor{module = Module} = Handle, Offset, Length, Advise) ->
+ %% DTrace TODO: ram_file and other file drivers not yet DTrace'ified.
Module:advise(Handle, Offset, Length, Advise);
advise(_, _, _, _) ->
{error, badarg}.
@@ -477,17 +480,25 @@ advise(_, _, _, _) ->
Data :: string() | binary(),
Reason :: posix() | badarg | terminated.
-read(File, Sz) when (is_pid(File) orelse is_atom(File)), is_integer(Sz), Sz >= 0 ->
+read(File, Sz) ->
+ read(File, Sz, get_dtrace_utag()).
+
+read(File, Sz, _DTraceUtag)
+ when (is_pid(File) orelse is_atom(File)), is_integer(Sz), Sz >= 0 ->
case io:request(File, {get_chars, '', Sz}) of
Data when is_list(Data); is_binary(Data) ->
{ok, Data};
Other ->
Other
end;
-read(#file_descriptor{module = Module} = Handle, Sz)
+read(#file_descriptor{module = prim_file = Module} = Handle, Sz, DTraceUtag)
+ when is_integer(Sz), Sz >= 0 ->
+ Module:read(Handle, Sz, DTraceUtag);
+read(#file_descriptor{module = Module} = Handle, Sz, _DTraceUtag)
when is_integer(Sz), Sz >= 0 ->
+ %% DTrace TODO: ram_file and other file drivers not yet DTrace'ified.
Module:read(Handle, Sz);
-read(_, _) ->
+read(_, _, _) ->
{error, badarg}.
-spec read_line(IoDevice) -> {ok, Data} | eof | {error, Reason} when
@@ -502,7 +513,10 @@ read_line(File) when (is_pid(File) orelse is_atom(File)) ->
Other ->
Other
end;
+read_line(#file_descriptor{module = prim_file = Module} = Handle) ->
+ Module:read_line(Handle, get_dtrace_utag());
read_line(#file_descriptor{module = Module} = Handle) ->
+ %% DTrace TODO: ram_file and other file drivers not yet DTrace'ified.
Module:read_line(Handle);
read_line(_) ->
{error, badarg}.
@@ -516,7 +530,10 @@ read_line(_) ->
pread(File, L) when is_pid(File), is_list(L) ->
pread_int(File, L, []);
+pread(#file_descriptor{module = prim_file = Module} = Handle, L) when is_list(L) ->
+ Module:pread(Handle, L, get_dtrace_utag());
pread(#file_descriptor{module = Module} = Handle, L) when is_list(L) ->
+ %% DTrace TODO: ram_file and other file drivers not yet DTrace'ified.
Module:pread(Handle, L);
pread(_, _) ->
{error, badarg}.
@@ -548,6 +565,7 @@ pread(File, At, Sz) when is_pid(File), is_integer(Sz), Sz >= 0 ->
wait_file_reply(File, R);
pread(#file_descriptor{module = Module} = Handle, Offs, Sz)
when is_integer(Sz), Sz >= 0 ->
+ %% DTrace TODO: ram_file and other file drivers not yet DTrace'ified.
Module:pread(Handle, Offs, Sz);
pread(_, _, _) ->
{error, badarg}.
@@ -557,16 +575,22 @@ pread(_, _, _) ->
Bytes :: iodata(),
Reason :: posix() | badarg | terminated.
-write(File, Bytes) when (is_pid(File) orelse is_atom(File)) ->
+write(File, Bytes) ->
+ write(File, Bytes, get_dtrace_utag()).
+
+write(File, Bytes, _DTraceUtag) when (is_pid(File) orelse is_atom(File)) ->
case make_binary(Bytes) of
Bin when is_binary(Bin) ->
io:request(File, {put_chars,Bin});
Error ->
Error
end;
-write(#file_descriptor{module = Module} = Handle, Bytes) ->
+write(#file_descriptor{module = prim_file = Module} = Handle, Bytes, DTraceUtag) ->
+ Module:write(Handle, Bytes, DTraceUtag);
+write(#file_descriptor{module = Module} = Handle, Bytes, _DTraceUtag) ->
+ %% DTrace TODO: ram_file and other file drivers not yet DTrace'ified.
Module:write(Handle, Bytes);
-write(_, _) ->
+write(_, _, _) ->
{error, badarg}.
-spec pwrite(IoDevice, LocBytes) -> ok | {error, {N, Reason}} when
@@ -577,7 +601,10 @@ write(_, _) ->
pwrite(File, L) when is_pid(File), is_list(L) ->
pwrite_int(File, L, 0);
+pwrite(#file_descriptor{module = prim_file = Module} = Handle, L) when is_list(L) ->
+ Module:pwrite(Handle, L, get_dtrace_utag());
pwrite(#file_descriptor{module = Module} = Handle, L) when is_list(L) ->
+ %% DTrace TODO: ram_file and other file drivers not yet DTrace'ified.
Module:pwrite(Handle, L);
pwrite(_, _) ->
{error, badarg}.
@@ -604,6 +631,7 @@ pwrite(File, At, Bytes) when is_pid(File) ->
R = file_request(File, {pwrite, At, Bytes}),
wait_file_reply(File, R);
pwrite(#file_descriptor{module = Module} = Handle, Offs, Bytes) ->
+ %% DTrace TODO: ram_file and other file drivers not yet DTrace'ified.
Module:pwrite(Handle, Offs, Bytes);
pwrite(_, _, _) ->
{error, badarg}.
@@ -615,7 +643,10 @@ pwrite(_, _, _) ->
datasync(File) when is_pid(File) ->
R = file_request(File, datasync),
wait_file_reply(File, R);
+datasync(#file_descriptor{module = prim_file = Module} = Handle) ->
+ Module:datasync(Handle, get_dtrace_utag());
datasync(#file_descriptor{module = Module} = Handle) ->
+ %% DTrace TODO: ram_file and other file drivers not yet DTrace'ified.
Module:datasync(Handle);
datasync(_) ->
{error, badarg}.
@@ -627,7 +658,10 @@ datasync(_) ->
sync(File) when is_pid(File) ->
R = file_request(File, sync),
wait_file_reply(File, R);
+sync(#file_descriptor{module = prim_file = Module} = Handle) ->
+ Module:sync(Handle, get_dtrace_utag());
sync(#file_descriptor{module = Module} = Handle) ->
+ %% DTrace TODO: ram_file and other file drivers not yet DTrace'ified.
Module:sync(Handle);
sync(_) ->
{error, badarg}.
@@ -641,7 +675,10 @@ sync(_) ->
position(File, At) when is_pid(File) ->
R = file_request(File, {position,At}),
wait_file_reply(File, R);
+position(#file_descriptor{module = prim_file = Module} = Handle, At) ->
+ Module:position(Handle, At, get_dtrace_utag());
position(#file_descriptor{module = Module} = Handle, At) ->
+ %% DTrace TODO: ram_file and other file drivers not yet DTrace'ified.
Module:position(Handle, At);
position(_, _) ->
{error, badarg}.
@@ -653,7 +690,10 @@ position(_, _) ->
truncate(File) when is_pid(File) ->
R = file_request(File, truncate),
wait_file_reply(File, R);
+truncate(#file_descriptor{module = prim_file = Module} = Handle) ->
+ Module:truncate(Handle, get_dtrace_utag());
truncate(#file_descriptor{module = Module} = Handle) ->
+ %% DTrace TODO: ram_file and other file drivers not yet DTrace'ified.
Module:truncate(Handle);
truncate(_) ->
{error, badarg}.
@@ -694,7 +734,7 @@ copy_int(Source, Dest, Length)
when is_pid(Source), is_pid(Dest);
is_pid(Source), is_record(Dest, file_descriptor);
is_record(Source, file_descriptor), is_pid(Dest) ->
- copy_opened_int(Source, Dest, Length, 0);
+ copy_opened_int(Source, Dest, Length, get_dtrace_utag());
%% Copy between open raw files, both handled by the same module
copy_int(#file_descriptor{module = Module} = Source,
#file_descriptor{module = Module} = Dest,
@@ -703,14 +743,14 @@ copy_int(#file_descriptor{module = Module} = Source,
%% Copy between open raw files of different modules
copy_int(#file_descriptor{} = Source,
#file_descriptor{} = Dest, Length) ->
- copy_opened_int(Source, Dest, Length, 0);
+ copy_opened_int(Source, Dest, Length, get_dtrace_utag());
%% Copy between filenames, let the server do the copy
copy_int({SourceName, SourceOpts}, {DestName, DestOpts}, Length)
when is_list(SourceOpts), is_list(DestOpts) ->
check_and_call(copy,
[file_name(SourceName), SourceOpts,
file_name(DestName), DestOpts,
- Length]);
+ Length, get_dtrace_utag()]);
%% Filename -> open file; must open Source and do client copy
copy_int({SourceName, SourceOpts}, Dest, Length)
when is_list(SourceOpts), is_pid(Dest);
@@ -721,7 +761,8 @@ copy_int({SourceName, SourceOpts}, Dest, Length)
Source ->
case open(Source, [read | SourceOpts]) of
{ok, Handle} ->
- Result = copy_opened_int(Handle, Dest, Length, 0),
+ Result = copy_opened_int(Handle, Dest, Length,
+ get_dtrace_utag()),
close(Handle),
Result;
{error, _} = Error ->
@@ -738,7 +779,8 @@ copy_int(Source, {DestName, DestOpts}, Length)
Dest ->
case open(Dest, [write | DestOpts]) of
{ok, Handle} ->
- Result = copy_opened_int(Source, Handle, Length, 0),
+ Result = copy_opened_int(Source, Handle, Length,
+ get_dtrace_utag()),
close(Handle),
Result;
{error, _} = Error ->
@@ -773,45 +815,46 @@ copy_int(Source, Dest, Length) ->
-copy_opened(Source, Dest, Length)
+copy_opened(Source, Dest, Length, DTraceUtag)
when is_integer(Length), Length >= 0;
is_atom(Length) ->
- copy_opened_int(Source, Dest, Length);
-copy_opened(_, _, _) ->
+ copy_opened_int(Source, Dest, Length, DTraceUtag);
+copy_opened(_, _, _, _) ->
{error, badarg}.
%% Here we know that Length is either an atom or an integer >= 0
%% (by the way, atoms > integers)
-copy_opened_int(Source, Dest, Length)
+copy_opened_int(Source, Dest, Length, DTraceUtag)
when is_pid(Source), is_pid(Dest) ->
- copy_opened_int(Source, Dest, Length, 0);
-copy_opened_int(Source, Dest, Length)
+ copy_opened_int(Source, Dest, Length, 0, DTraceUtag);
+copy_opened_int(Source, Dest, Length, DTraceUtag)
when is_pid(Source), is_record(Dest, file_descriptor) ->
- copy_opened_int(Source, Dest, Length, 0);
-copy_opened_int(Source, Dest, Length)
+ copy_opened_int(Source, Dest, Length, 0, DTraceUtag);
+copy_opened_int(Source, Dest, Length, DTraceUtag)
when is_record(Source, file_descriptor), is_pid(Dest) ->
- copy_opened_int(Source, Dest, Length, 0);
-copy_opened_int(Source, Dest, Length)
+ copy_opened_int(Source, Dest, Length, 0, DTraceUtag);
+copy_opened_int(Source, Dest, Length, DTraceUtag)
when is_record(Source, file_descriptor), is_record(Dest, file_descriptor) ->
- copy_opened_int(Source, Dest, Length, 0);
-copy_opened_int(_, _, _) ->
+ copy_opened_int(Source, Dest, Length, 0, DTraceUtag);
+copy_opened_int(_, _, _, _) ->
{error, badarg}.
%% Here we know that Source and Dest are handles to open files, Length is
%% as above, and Copied is an integer >= 0
%% Copy loop in client process
-copy_opened_int(_, _, Length, Copied) when Length =< 0 -> % atom() > integer()
+copy_opened_int(_, _, Length, Copied, _DTraceUtag)
+ when Length =< 0 -> % atom() > integer()
{ok, Copied};
-copy_opened_int(Source, Dest, Length, Copied) ->
+copy_opened_int(Source, Dest, Length, Copied, DTraceUtag) ->
N = if Length > 65536 -> 65536; true -> Length end, % atom() > integer() !
- case read(Source, N) of
+ case read(Source, N, DTraceUtag) of
{ok, Data} ->
M = if is_binary(Data) -> byte_size(Data);
is_list(Data) -> length(Data)
end,
- case write(Dest, Data) of
+ case write(Dest, Data, DTraceUtag) of
ok ->
if M < N ->
%% Got less than asked for - must be end of file
@@ -821,7 +864,8 @@ copy_opened_int(Source, Dest, Length, Copied) ->
NewLength = if is_atom(Length) -> Length;
true -> Length-M
end,
- copy_opened_int(Source, Dest, NewLength, Copied+M)
+ copy_opened_int(Source, Dest, NewLength, Copied+M,
+ DTraceUtag)
end;
{error, _} = Error ->
Error
@@ -841,6 +885,8 @@ copy_opened_int(Source, Dest, Length, Copied) ->
ipread_s32bu_p32bu(File, Pos, MaxSize) when is_pid(File) ->
ipread_s32bu_p32bu_int(File, Pos, MaxSize);
+ipread_s32bu_p32bu(#file_descriptor{module = prim_file = Module} = Handle, Pos, MaxSize) ->
+ Module:ipread_s32bu_p32bu(Handle, Pos, MaxSize, get_dtrace_utag());
ipread_s32bu_p32bu(#file_descriptor{module = Module} = Handle, Pos, MaxSize) ->
Module:ipread_s32bu_p32bu(Handle, Pos, MaxSize);
ipread_s32bu_p32bu(_, _, _) ->
@@ -1456,3 +1502,6 @@ wait_file_reply(From, Ref) ->
%% receive {'EXIT', From, _} -> ok after 0 -> ok end,
{error, terminated}
end.
+
+get_dtrace_utag() ->
+ prim_file:get_dtrace_utag().
diff --git a/lib/kernel/src/file_io_server.erl b/lib/kernel/src/file_io_server.erl
index 14da9c1a55..cc0343031b 100644
--- a/lib/kernel/src/file_io_server.erl
+++ b/lib/kernel/src/file_io_server.erl
@@ -21,7 +21,7 @@
%% A simple file server for io to one file instance per server instance.
-export([format_error/1]).
--export([start/3, start_link/3]).
+-export([start/4, start_link/4]).
-export([count_and_find/3]).
@@ -43,18 +43,18 @@ format_error({_Line, Mod, Reason}) ->
format_error(ErrorId) ->
erl_posix_msg:message(ErrorId).
-start(Owner, FileName, ModeList)
+start(Owner, FileName, ModeList, DTraceUtag)
when is_pid(Owner), (is_list(FileName) orelse is_binary(FileName)), is_list(ModeList) ->
- do_start(spawn, Owner, FileName, ModeList).
+ do_start(spawn, Owner, FileName, ModeList, DTraceUtag).
-start_link(Owner, FileName, ModeList)
+start_link(Owner, FileName, ModeList, DTraceUtag)
when is_pid(Owner), (is_list(FileName) orelse is_binary(FileName)), is_list(ModeList) ->
- do_start(spawn_link, Owner, FileName, ModeList).
+ do_start(spawn_link, Owner, FileName, ModeList, DTraceUtag).
%%%-----------------------------------------------------------------
%%% Server starter, dispatcher and helpers
-do_start(Spawn, Owner, FileName, ModeList) ->
+do_start(Spawn, Owner, FileName, ModeList, DTraceUtag) ->
Self = self(),
Ref = make_ref(),
Pid =
@@ -63,11 +63,12 @@ do_start(Spawn, Owner, FileName, ModeList) ->
%% process_flag(trap_exit, true),
case parse_options(ModeList) of
{ReadMode, UnicodeMode, Opts} ->
- case ?PRIM_FILE:open(FileName, Opts) of
+ case ?PRIM_FILE:open(FileName, Opts, DTraceUtag) of
{error, Reason} = Error ->
Self ! {Ref, Error},
exit(Reason);
{ok, Handle} ->
+ put(dtrace_utag, DTraceUtag), % TODO: API?
%% XXX must I handle R6 nodes here?
M = erlang:monitor(process, Owner),
Self ! {Ref, ok},
diff --git a/lib/kernel/src/file_server.erl b/lib/kernel/src/file_server.erl
index fc6cd823c9..c917819508 100644
--- a/lib/kernel/src/file_server.erl
+++ b/lib/kernel/src/file_server.erl
@@ -76,6 +76,7 @@ stop() ->
init([]) ->
process_flag(trap_exit, true),
+ put(dtrace_utag, atom_to_list(?FILE_SERVER)),
case ?PRIM_FILE:start() of
{ok, Handle} ->
ets:new(?FILE_IO_SERVER_TABLE, [named_table]),
@@ -99,9 +100,9 @@ init([]) ->
{'reply', 'eof' | 'ok' | {'error', term()} | {'ok', term()}, state()} |
{'stop', 'normal', 'stopped', state()}.
-handle_call({open, Name, ModeList}, {Pid, _Tag} = _From, Handle)
+handle_call({open, Name, ModeList, DTraceUtag}, {Pid, _Tag} = _From, Handle)
when is_list(ModeList) ->
- Child = ?FILE_IO_SERVER:start_link(Pid, Name, ModeList),
+ Child = ?FILE_IO_SERVER:start_link(Pid, Name, ModeList, DTraceUtag),
case Child of
{ok, P} when is_pid(P) ->
ets:insert(?FILE_IO_SERVER_TABLE, {P, Name});
@@ -110,87 +111,86 @@ handle_call({open, Name, ModeList}, {Pid, _Tag} = _From, Handle)
end,
{reply, Child, Handle};
-handle_call({open, _Name, _Mode}, _From, Handle) ->
+handle_call({open, _Name, _Mode, _DTraceUtag}, _From, Handle) ->
{reply, {error, einval}, Handle};
-handle_call({read_file, Name}, _From, Handle) ->
- {reply, ?PRIM_FILE:read_file(Name), Handle};
+handle_call({read_file, Name, DTraceUtag}, _From, Handle) ->
+ {reply, ?PRIM_FILE:read_file(Name, DTraceUtag), Handle};
-handle_call({write_file, Name, Bin}, _From, Handle) ->
- {reply, ?PRIM_FILE:write_file(Name, Bin), Handle};
+handle_call({write_file, Name, Bin, DTraceUtag}, _From, Handle) ->
+ {reply, ?PRIM_FILE:write_file(Name, Bin, DTraceUtag), Handle};
-handle_call({set_cwd, Name}, _From, Handle) ->
- {reply, ?PRIM_FILE:set_cwd(Handle, Name), Handle};
+handle_call({set_cwd, Name, DTraceUtag}, _From, Handle) ->
+ {reply, ?PRIM_FILE:set_cwd(Handle, Name, DTraceUtag), Handle};
-handle_call({delete, Name}, _From, Handle) ->
- {reply, ?PRIM_FILE:delete(Handle, Name), Handle};
+handle_call({delete, Name, DTraceUtag}, _From, Handle) ->
+ {reply, ?PRIM_FILE:delete(Handle, Name, DTraceUtag), Handle};
-handle_call({rename, Fr, To}, _From, Handle) ->
- {reply, ?PRIM_FILE:rename(Handle, Fr, To), Handle};
+handle_call({rename, Fr, To, DTraceUtag}, _From, Handle) ->
+ {reply, ?PRIM_FILE:rename(Handle, Fr, To, DTraceUtag), Handle};
-handle_call({make_dir, Name}, _From, Handle) ->
- {reply, ?PRIM_FILE:make_dir(Handle, Name), Handle};
+handle_call({make_dir, Name, DTraceUtag}, _From, Handle) ->
+ {reply, ?PRIM_FILE:make_dir(Handle, Name, DTraceUtag), Handle};
-handle_call({del_dir, Name}, _From, Handle) ->
- {reply, ?PRIM_FILE:del_dir(Handle, Name), Handle};
+handle_call({del_dir, Name, DTraceUtag}, _From, Handle) ->
+ {reply, ?PRIM_FILE:del_dir(Handle, Name, DTraceUtag), Handle};
-handle_call({list_dir, Name}, _From, Handle) ->
- {reply, ?PRIM_FILE:list_dir(Handle, Name), Handle};
+handle_call({list_dir, Name, DTraceUtag}, _From, Handle) ->
+ {reply, ?PRIM_FILE:list_dir(Handle, Name, DTraceUtag), Handle};
handle_call(get_cwd, _From, Handle) ->
- {reply, ?PRIM_FILE:get_cwd(Handle), Handle};
-handle_call({get_cwd}, _From, Handle) ->
- {reply, ?PRIM_FILE:get_cwd(Handle), Handle};
-handle_call({get_cwd, Name}, _From, Handle) ->
- {reply, ?PRIM_FILE:get_cwd(Handle, Name), Handle};
+ {reply, ?PRIM_FILE:get_cwd(Handle, no_drive, "TODO-fixme"), Handle};
+handle_call({get_cwd, no_drive, DTraceUtag}, _From, Handle) ->
+ {reply, ?PRIM_FILE:get_cwd(Handle, no_drive, DTraceUtag), Handle};
+handle_call({get_cwd, Name, DTraceUtag}, _From, Handle) ->
+ {reply, ?PRIM_FILE:get_cwd(Handle, Name, DTraceUtag), Handle};
-handle_call({read_file_info, Name}, _From, Handle) ->
- {reply, ?PRIM_FILE:read_file_info(Handle, Name), Handle};
+handle_call({read_file_info, Name, DTraceUtag}, _From, Handle) ->
+ {reply, ?PRIM_FILE:read_file_info(Handle, Name, DTraceUtag), Handle};
+handle_call({read_file_info, Name, Opts, DTraceUtag}, _From, Handle) ->
+ {reply, ?PRIM_FILE:read_file_info(Handle, Name, Opts, DTraceUtag), Handle};
-handle_call({read_file_info, Name, Opts}, _From, Handle) ->
- {reply, ?PRIM_FILE:read_file_info(Handle, Name, Opts), Handle};
+handle_call({altname, Name, DTraceUtag}, _From, Handle) ->
+ {reply, ?PRIM_FILE:altname(Handle, Name, DTraceUtag), Handle};
-handle_call({altname, Name}, _From, Handle) ->
- {reply, ?PRIM_FILE:altname(Handle, Name), Handle};
+handle_call({write_file_info, Name, Info, DTraceUtag}, _From, Handle) ->
+ {reply, ?PRIM_FILE:write_file_info(Handle, Name, Info, DTraceUtag), Handle};
+handle_call({write_file_info, Name, Info, Opts, DTraceUtag}, _From, Handle) ->
+ {reply, ?PRIM_FILE:write_file_info(Handle, Name, Info, Opts, DTraceUtag), Handle};
-handle_call({write_file_info, Name, Info}, _From, Handle) ->
- {reply, ?PRIM_FILE:write_file_info(Handle, Name, Info), Handle};
+handle_call({read_link_info, Name, DTraceUtag}, _From, Handle) ->
+ {reply, ?PRIM_FILE:read_link_info(Handle, Name, DTraceUtag), Handle};
+handle_call({read_link_info, Name, Opts, DTraceUtag}, _From, Handle) ->
+ {reply, ?PRIM_FILE:read_link_info(Handle, Name, Opts, DTraceUtag), Handle};
-handle_call({write_file_info, Name, Info, Opts}, _From, Handle) ->
- {reply, ?PRIM_FILE:write_file_info(Handle, Name, Info, Opts), Handle};
+handle_call({read_link, Name, DTraceUtag}, _From, Handle) ->
+ {reply, ?PRIM_FILE:read_link(Handle, Name, DTraceUtag), Handle};
-handle_call({read_link_info, Name}, _From, Handle) ->
- {reply, ?PRIM_FILE:read_link_info(Handle, Name), Handle};
+handle_call({make_link, Old, New, DTraceUtag}, _From, Handle) ->
+ {reply, ?PRIM_FILE:make_link(Handle, Old, New, DTraceUtag), Handle};
-handle_call({read_link_info, Name, Opts}, _From, Handle) ->
- {reply, ?PRIM_FILE:read_link_info(Handle, Name, Opts), Handle};
+handle_call({make_symlink, Old, New, DTraceUtag}, _From, Handle) ->
+ {reply, ?PRIM_FILE:make_symlink(Handle, Old, New, DTraceUtag), Handle};
-handle_call({read_link, Name}, _From, Handle) ->
- {reply, ?PRIM_FILE:read_link(Handle, Name), Handle};
-
-handle_call({make_link, Old, New}, _From, Handle) ->
- {reply, ?PRIM_FILE:make_link(Handle, Old, New), Handle};
-
-handle_call({make_symlink, Old, New}, _From, Handle) ->
- {reply, ?PRIM_FILE:make_symlink(Handle, Old, New), Handle};
-
-handle_call({copy, SourceName, SourceOpts, DestName, DestOpts, Length},
+handle_call({copy, SourceName, SourceOpts, DestName, DestOpts, Length, DTraceUtag},
_From, Handle) ->
Reply =
- case ?PRIM_FILE:open(SourceName, [read, binary | SourceOpts]) of
+ case ?PRIM_FILE:open(SourceName, [read, binary | SourceOpts],
+ DTraceUtag) of
{ok, Source} ->
SourceReply =
case ?PRIM_FILE:open(DestName,
- [write, binary | DestOpts]) of
+ [write, binary | DestOpts],
+ DTraceUtag) of
{ok, Dest} ->
DestReply =
- ?PRIM_FILE:copy(Source, Dest, Length),
- ?PRIM_FILE:close(Dest),
+ ?PRIM_FILE:copy(Source, Dest, Length, DTraceUtag),
+ ?PRIM_FILE:close(Dest, DTraceUtag),
DestReply;
{error, _} = Error ->
Error
end,
- ?PRIM_FILE:close(Source),
+ ?PRIM_FILE:close(Source, DTraceUtag),
SourceReply;
{error, _} = Error ->
Error
diff --git a/lib/kernel/test/prim_file_SUITE.erl b/lib/kernel/test/prim_file_SUITE.erl
index 3e2202922c..9575762b12 100644
--- a/lib/kernel/test/prim_file_SUITE.erl
+++ b/lib/kernel/test/prim_file_SUITE.erl
@@ -70,7 +70,7 @@
%% compile time.
-define(PRIM_FILE_call(F, H, A),
case H of
- [] -> apply(?PRIM_FILE, F, A);
+ [] -> apply(?PRIM_FILE, F, A -- ["utag"]);
_ -> apply(?PRIM_FILE, F, [H | A])
end).
@@ -255,31 +255,31 @@ make_del_dir(Config, Handle, Suffix) ->
?line NewDir = filename:join(RootDir,
atom_to_list(?MODULE)
++"_mk-dir"++Suffix),
- ?line ok = ?PRIM_FILE_call(make_dir, Handle, [NewDir]),
- ?line {error, eexist} = ?PRIM_FILE_call(make_dir, Handle, [NewDir]),
- ?line ok = ?PRIM_FILE_call(del_dir, Handle, [NewDir]),
- ?line {error, enoent} = ?PRIM_FILE_call(del_dir, Handle, [NewDir]),
+ ?line ok = ?PRIM_FILE_call(make_dir, Handle, [NewDir, "utag"]),
+ ?line {error, eexist} = ?PRIM_FILE_call(make_dir, Handle, [NewDir, "utag"]),
+ ?line ok = ?PRIM_FILE_call(del_dir, Handle, [NewDir, "utag"]),
+ ?line {error, enoent} = ?PRIM_FILE_call(del_dir, Handle, [NewDir, "utag"]),
% Make sure we are not in a directory directly under test_server
% as that would result in eacess errors when trying to delere '..',
% because there are processes having that directory as current.
- ?line ok = ?PRIM_FILE_call(make_dir, Handle, [NewDir]),
+ ?line ok = ?PRIM_FILE_call(make_dir, Handle, [NewDir, "utag"]),
?line {ok, CurrentDir} = ?PRIM_FILE_call(get_cwd, Handle, []),
- ?line ok = ?PRIM_FILE_call(set_cwd, Handle, [NewDir]),
+ ?line ok = ?PRIM_FILE_call(set_cwd, Handle, [NewDir, "utag"]),
try
%% Check that we get an error when trying to create...
%% a deep directory
?line NewDir2 = filename:join(RootDir,
atom_to_list(?MODULE)
++"_mk-dir-noexist/foo"),
- ?line {error, enoent} = ?PRIM_FILE_call(make_dir, Handle, [NewDir2]),
+ ?line {error, enoent} = ?PRIM_FILE_call(make_dir, Handle, [NewDir2, "utag"]),
%% a nameless directory
- ?line {error, enoent} = ?PRIM_FILE_call(make_dir, Handle, [""]),
+ ?line {error, enoent} = ?PRIM_FILE_call(make_dir, Handle, ["", "utag"]),
%% a directory with illegal name
- ?line {error, badarg} = ?PRIM_FILE_call(make_dir, Handle, ['mk-dir']),
+ ?line {error, badarg} = ?PRIM_FILE_call(make_dir, Handle, ['mk-dir', "utag"]),
%% a directory with illegal name, even if it's a (bad) list
- ?line {error, badarg} = ?PRIM_FILE_call(make_dir, Handle, [[1,2,3,{}]]),
+ ?line {error, badarg} = ?PRIM_FILE_call(make_dir, Handle, [[1,2,3,{}], "utag"]),
%% Maybe this isn't an error, exactly, but worth mentioning anyway:
%% ok = ?PRIM_FILE:make_dir([$f,$o,$o,0,$b,$a,$r])),
@@ -292,17 +292,17 @@ make_del_dir(Config, Handle, Suffix) ->
%% Try deleting some bad directories
%% Deleting the parent directory to the current, sounds dangerous, huh?
%% Don't worry ;-) the parent directory should never be empty, right?
- ?line case ?PRIM_FILE_call(del_dir, Handle, [".."]) of
+ ?line case ?PRIM_FILE_call(del_dir, Handle, ["..", "utag"]) of
{error, eexist} -> ok;
{error, eacces} -> ok; %OpenBSD
{error, einval} -> ok %FreeBSD
end,
- ?line {error, enoent} = ?PRIM_FILE_call(del_dir, Handle, [""]),
- ?line {error, badarg} = ?PRIM_FILE_call(del_dir, Handle, [[3,2,1,{}]]),
+ ?line {error, enoent} = ?PRIM_FILE_call(del_dir, Handle, ["", "utag"]),
+ ?line {error, badarg} = ?PRIM_FILE_call(del_dir, Handle, [[3,2,1,{}], "utag"]),
?line test_server:timetrap_cancel(Dog)
after
- ?line ok = ?PRIM_FILE_call(set_cwd, Handle, [CurrentDir])
+ ?line ok = ?PRIM_FILE_call(set_cwd, Handle, [CurrentDir, "utag"])
end,
ok.
@@ -324,7 +324,7 @@ cur_dir_0(Config, Handle) ->
%% Find out the current dir, and cd to it ;-)
?line {ok,BaseDir} = ?PRIM_FILE_call(get_cwd, Handle, []),
?line Dir1 = BaseDir ++ "", %% Check that it's a string
- ?line ok = ?PRIM_FILE_call(set_cwd, Handle, [Dir1]),
+ ?line ok = ?PRIM_FILE_call(set_cwd, Handle, [Dir1, "utag"]),
?line DirName = atom_to_list(?MODULE) ++
case Handle of
[] ->
@@ -336,40 +336,40 @@ cur_dir_0(Config, Handle) ->
%% Make a new dir, and cd to that
?line RootDir = ?config(priv_dir,Config),
?line NewDir = filename:join(RootDir, DirName),
- ?line ok = ?PRIM_FILE_call(make_dir, Handle, [NewDir]),
+ ?line ok = ?PRIM_FILE_call(make_dir, Handle, [NewDir, "utag"]),
?line io:format("cd to ~s",[NewDir]),
- ?line ok = ?PRIM_FILE_call(set_cwd, Handle, [NewDir]),
+ ?line ok = ?PRIM_FILE_call(set_cwd, Handle, [NewDir, "utag"]),
%% Create a file in the new current directory, and check that it
%% really is created there
?line UncommonName = "uncommon.fil",
?line {ok,Fd} = ?PRIM_FILE:open(UncommonName, [read, write]),
?line ok = ?PRIM_FILE:close(Fd),
- ?line {ok,NewDirFiles} = ?PRIM_FILE_call(list_dir, Handle, ["."]),
+ ?line {ok,NewDirFiles} = ?PRIM_FILE_call(list_dir, Handle, [".", "utag"]),
?line true = lists:member(UncommonName,NewDirFiles),
%% Delete the directory and return to the old current directory
%% and check that the created file isn't there (too!)
?line expect({error, einval}, {error, eacces}, {error, eexist},
- ?PRIM_FILE_call(del_dir, Handle, [NewDir])),
- ?line ?PRIM_FILE_call(delete, Handle, [UncommonName]),
- ?line {ok,[]} = ?PRIM_FILE_call(list_dir, Handle, ["."]),
- ?line ok = ?PRIM_FILE_call(set_cwd, Handle, [Dir1]),
+ ?PRIM_FILE_call(del_dir, Handle, [NewDir, "utag"])),
+ ?line ?PRIM_FILE_call(delete, Handle, [UncommonName, "utag"]),
+ ?line {ok,[]} = ?PRIM_FILE_call(list_dir, Handle, [".", "utag"]),
+ ?line ok = ?PRIM_FILE_call(set_cwd, Handle, [Dir1, "utag"]),
?line io:format("cd back to ~s",[Dir1]),
- ?line ok = ?PRIM_FILE_call(del_dir, Handle, [NewDir]),
- ?line {error, enoent} = ?PRIM_FILE_call(set_cwd, Handle, [NewDir]),
- ?line ok = ?PRIM_FILE_call(set_cwd, Handle, [Dir1]),
+ ?line ok = ?PRIM_FILE_call(del_dir, Handle, [NewDir, "utag"]),
+ ?line {error, enoent} = ?PRIM_FILE_call(set_cwd, Handle, [NewDir, "utag"]),
+ ?line ok = ?PRIM_FILE_call(set_cwd, Handle, [Dir1, "utag"]),
?line io:format("cd back to ~s",[Dir1]),
- ?line {ok,OldDirFiles} = ?PRIM_FILE_call(list_dir, Handle, ["."]),
+ ?line {ok,OldDirFiles} = ?PRIM_FILE_call(list_dir, Handle, [".", "utag"]),
?line false = lists:member(UncommonName,OldDirFiles),
%% Try doing some bad things
?line {error, badarg} =
- ?PRIM_FILE_call(set_cwd, Handle, [{foo,bar}]),
+ ?PRIM_FILE_call(set_cwd, Handle, [{foo,bar}, "utag"]),
?line {error, enoent} =
- ?PRIM_FILE_call(set_cwd, Handle, [""]),
+ ?PRIM_FILE_call(set_cwd, Handle, ["", "utag"]),
?line {error, enoent} =
- ?PRIM_FILE_call(set_cwd, Handle, [".......a......"]),
+ ?PRIM_FILE_call(set_cwd, Handle, [".......a......", "utag"]),
?line {ok,BaseDir} =
?PRIM_FILE_call(get_cwd, Handle, []), %% Still there?
@@ -405,10 +405,10 @@ cur_dir_1(Config, Handle) ->
?line case os:type() of
{unix, _} ->
?line {error, enotsup} =
- ?PRIM_FILE_call(get_cwd, Handle, ["d:"]);
+ ?PRIM_FILE_call(get_cwd, Handle, ["d:", "utag"]);
vxworks ->
?line {error, enotsup} =
- ?PRIM_FILE_call(get_cwd, Handle, ["d:"]);
+ ?PRIM_FILE_call(get_cwd, Handle, ["d:", "utag"]);
{win32, _} ->
win_cur_dir_1(Config, Handle)
end,
@@ -422,7 +422,7 @@ win_cur_dir_1(_Config, Handle) ->
%% and try to get current directory for that drive.
?line [Drive, $:|_] = BaseDir,
- ?line {ok, BaseDir} = ?PRIM_FILE_call(get_cwd, Handle, [[Drive, $:]]),
+ ?line {ok, BaseDir} = ?PRIM_FILE_call(get_cwd, Handle, [[Drive, $:], "utag"]),
io:format("BaseDir = ~s\n", [BaseDir]),
%% Unfortunately, there is no way to move away from the
@@ -1027,7 +1027,7 @@ file_write_file_info(Config, Handle, Suffix) ->
?line ok = ?PRIM_FILE:write_file(Name, "hello"),
?line Time = {{1997, 01, 02}, {12, 35, 42}},
?line Info = #file_info{mode=8#400, atime=Time, mtime=Time, ctime=Time},
- ?line ok = ?PRIM_FILE_call(write_file_info, Handle, [Name, Info]),
+ ?line ok = ?PRIM_FILE_call(write_file_info, Handle, [Name, Info, "utag"]),
%% Read back the times.
@@ -1050,12 +1050,12 @@ file_write_file_info(Config, Handle, Suffix) ->
%% Make the file writable again.
?line ?PRIM_FILE_call(write_file_info, Handle,
- [Name, #file_info{mode=8#600}]),
+ [Name, #file_info{mode=8#600}, "utag"]),
?line ok = ?PRIM_FILE:write_file(Name, "hello again"),
%% And unwritable.
?line ?PRIM_FILE_call(write_file_info, Handle,
- [Name, #file_info{mode=8#400}]),
+ [Name, #file_info{mode=8#400}, "utag"]),
?line {error, eacces} = ?PRIM_FILE:write_file(Name, "hello again"),
%% Write the times again.
@@ -1063,7 +1063,7 @@ file_write_file_info(Config, Handle, Suffix) ->
?line NewTime = {{1997, 02, 15}, {13, 18, 20}},
?line NewInfo = #file_info{atime=NewTime, mtime=NewTime, ctime=NewTime},
- ?line ok = ?PRIM_FILE_call(write_file_info, Handle, [Name, NewInfo]),
+ ?line ok = ?PRIM_FILE_call(write_file_info, Handle, [Name, NewInfo, "utag"]),
?line {ok, ActualInfo2} =
?PRIM_FILE_call(read_file_info, Handle, [Name]),
?line #file_info{atime=NewActAtime, mtime=NewTime,
@@ -1081,7 +1081,7 @@ file_write_file_info(Config, Handle, Suffix) ->
%% Make the file writeable again, so that we can remove the
%% test suites ... :-)
?line ?PRIM_FILE_call(write_file_info, Handle,
- [Name, #file_info{mode=8#600}]),
+ [Name, #file_info{mode=8#600}, "utag"]),
?line test_server:timetrap_cancel(Dog),
ok.
@@ -1390,11 +1390,11 @@ delete(Config, Handle, Suffix) ->
%% Check that the file is readable
?line {ok, Fd2} = ?PRIM_FILE:open(Name, [read]),
?line ok = ?PRIM_FILE:close(Fd2),
- ?line ok = ?PRIM_FILE_call(delete, Handle, [Name]),
+ ?line ok = ?PRIM_FILE_call(delete, Handle, [Name, "utag"]),
%% Check that the file is not readable anymore
?line {error, _} = ?PRIM_FILE:open(Name, [read]),
%% Try deleting a nonexistent file
- ?line {error, enoent} = ?PRIM_FILE_call(delete, Handle, [Name]),
+ ?line {error, enoent} = ?PRIM_FILE_call(delete, Handle, [Name, "utag"]),
?line test_server:timetrap_cancel(Dog),
ok.
@@ -1895,14 +1895,14 @@ make_link(Config, Handle, Suffix) ->
?line NewDir = filename:join(RootDir,
atom_to_list(?MODULE)
++"_make_link"++Suffix),
- ?line ok = ?PRIM_FILE_call(make_dir, Handle, [NewDir]),
+ ?line ok = ?PRIM_FILE_call(make_dir, Handle, [NewDir, "utag"]),
?line Name = filename:join(NewDir, "a_file"),
?line ok = ?PRIM_FILE:write_file(Name, "some contents\n"),
?line Alias = filename:join(NewDir, "an_alias"),
?line Result =
- case ?PRIM_FILE_call(make_link, Handle, [Name, Alias]) of
+ case ?PRIM_FILE_call(make_link, Handle, [Name, Alias, "utag"]) of
{error, enotsup} ->
{skipped, "Links not supported on this platform"};
ok ->
@@ -1913,12 +1913,12 @@ make_link(Config, Handle, Suffix) ->
%% since they are not used on symbolic links.
?line {ok, Info} =
- ?PRIM_FILE_call(read_link_info, Handle, [Name]),
+ ?PRIM_FILE_call(read_link_info, Handle, [Name, "utag"]),
?line {ok, Info} =
- ?PRIM_FILE_call(read_link_info, Handle, [Alias]),
+ ?PRIM_FILE_call(read_link_info, Handle, [Alias, "utag"]),
?line #file_info{links = 2, type = regular} = Info,
?line {error, eexist} =
- ?PRIM_FILE_call(make_link, Handle, [Name, Alias]),
+ ?PRIM_FILE_call(make_link, Handle, [Name, Alias, "utag"]),
ok
end,
@@ -1956,30 +1956,30 @@ symlinks(Config, Handle, Suffix) ->
?line NewDir = filename:join(RootDir,
atom_to_list(?MODULE)
++"_make_symlink"++Suffix),
- ?line ok = ?PRIM_FILE_call(make_dir, Handle, [NewDir]),
+ ?line ok = ?PRIM_FILE_call(make_dir, Handle, [NewDir, "utag"]),
?line Name = filename:join(NewDir, "a_plain_file"),
?line ok = ?PRIM_FILE:write_file(Name, "some stupid content\n"),
?line Alias = filename:join(NewDir, "a_symlink_alias"),
?line Result =
- case ?PRIM_FILE_call(make_symlink, Handle, [Name, Alias]) of
+ case ?PRIM_FILE_call(make_symlink, Handle, [Name, Alias, "utag"]) of
{error, enotsup} ->
{skipped, "Links not supported on this platform"};
ok ->
?line {ok, Info1} =
- ?PRIM_FILE_call(read_file_info, Handle, [Name]),
+ ?PRIM_FILE_call(read_file_info, Handle, [Name, "utag"]),
?line {ok, Info1} =
- ?PRIM_FILE_call(read_file_info, Handle, [Alias]),
+ ?PRIM_FILE_call(read_file_info, Handle, [Alias, "utag"]),
?line {ok, Info1} =
- ?PRIM_FILE_call(read_link_info, Handle, [Name]),
+ ?PRIM_FILE_call(read_link_info, Handle, [Name, "utag"]),
?line #file_info{links = 1, type = regular} = Info1,
?line {ok, Info2} =
- ?PRIM_FILE_call(read_link_info, Handle, [Alias]),
+ ?PRIM_FILE_call(read_link_info, Handle, [Alias, "utag"]),
?line #file_info{links=1, type=symlink} = Info2,
?line {ok, Name} =
- ?PRIM_FILE_call(read_link, Handle, [Alias]),
+ ?PRIM_FILE_call(read_link, Handle, [Alias, "utag"]),
ok
end,
@@ -2003,7 +2003,7 @@ list_dir_limit(Config) when is_list(Config) ->
?line NewDir = filename:join(RootDir,
atom_to_list(?MODULE)++"_list_dir_limit"),
?line {ok, Handle1} = ?PRIM_FILE:start(),
- ?line ok = ?PRIM_FILE_call(make_dir, Handle1, [NewDir]),
+ ?line ok = ?PRIM_FILE_call(make_dir, Handle1, [NewDir, "utag"]),
Ref = erlang:start_timer(MaxTime*1000, self(), []),
?line Result = list_dir_limit_loop(NewDir, Handle1, Ref, MaxNumber, 0),
?line Time = case erlang:cancel_timer(Ref) of
@@ -2054,7 +2054,7 @@ list_dir_limit_loop(Dir, Handle, Ref, N, Cnt) ->
end.
list_dir_check(Dir, Handle, Cnt) ->
- case ?PRIM_FILE:list_dir(Handle, Dir) of
+ case ?PRIM_FILE:list_dir(Handle, Dir, "utag") of
{ok, ListDir} ->
case length(ListDir) of
Cnt ->