FUSE: we now process only one opendir command at a time

This commit is contained in:
Laxmikant Rashinkar 2013-09-24 17:19:10 -07:00
parent 1a6483f0ab
commit 379685bfca
6 changed files with 553 additions and 83 deletions

View File

@ -8,7 +8,8 @@ EXTRA_DIST = \
drdynvc.h \
rail.h \
sound.h \
xcommon.h
xcommon.h \
mlog.h
EXTRA_DEFINES =
EXTRA_INCLUDES =
@ -51,7 +52,8 @@ xrdp_chansrv_SOURCES = \
xcommon.c \
drdynvc.c \
chansrv_fuse.c \
irp.c
irp.c \
fifo.c
xrdp_chansrv_LDFLAGS = \
$(EXTRA_FLAGS)

View File

@ -102,6 +102,7 @@ void xfuse_devredir_cb_file_close(void *vp) {}
#include "os_calls.h"
#include "chansrv_fuse.h"
#include "list.h"
#include "fifo.h"
#define min(x, y) ((x) < (y) ? (x) : (y))
@ -223,6 +224,16 @@ struct dir_info
int index;
};
/* queue FUSE opendir commands so we run only one at a time */
struct opendir_req
{
fuse_req_t req;
fuse_ino_t ino;
struct fuse_file_info *fi;
};
FIFO g_fifo_opendir;
static struct list *g_req_list = 0;
static struct xrdp_fs g_xrdp_fs; /* an inst of xrdp file system */
static char *g_mount_point = 0; /* our FUSE mount point */
@ -338,19 +349,22 @@ static void xfuse_cb_create(fuse_req_t req, fuse_ino_t parent,
static void xfuse_cb_fsync(fuse_req_t req, fuse_ino_t ino, int datasync,
struct fuse_file_info *fi);
/* clipboard calls */
int clipboard_request_file_data(int stream_id, int lindex, int offset,
int request_bytes);
static void xfuse_cb_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
int to_set, struct fuse_file_info *fi);
static void xfuse_cb_opendir(fuse_req_t req, fuse_ino_t ino,
struct fuse_file_info *fi);
static int xfuse_proc_opendir_req(fuse_req_t req, fuse_ino_t ino,
struct fuse_file_info *fi);
static void xfuse_cb_releasedir(fuse_req_t req, fuse_ino_t ino,
struct fuse_file_info *fi);
/* clipboard calls */
int clipboard_request_file_data(int stream_id, int lindex, int offset,
int request_bytes);
/* misc calls */
static void xfuse_mark_as_stale(int pinode);
static void xfuse_delete_stale_entries(int pinode);
@ -403,6 +417,9 @@ int xfuse_init()
if (xfuse_init_xrdp_fs())
return -1;
/* setup FIFOs */
fifo_init(&g_fifo_opendir, 30);
/* setup FUSE callbacks */
g_memset(&g_xfuse_ops, 0, sizeof(g_xfuse_ops));
g_xfuse_ops.lookup = xfuse_cb_lookup;
@ -424,6 +441,8 @@ int xfuse_init()
fuse_opt_add_arg(&args, "xrdp-chansrv");
fuse_opt_add_arg(&args, g_fuse_root_path);
//fuse_opt_add_arg(&args, "-s"); /* single threaded mode */
//fuse_opt_add_arg(&args, "-d"); /* debug mode */
if (xfuse_init_lib(&args))
{
@ -444,6 +463,7 @@ int xfuse_init()
int xfuse_deinit()
{
xfuse_deinit_xrdp_fs();
fifo_deinit(&g_fifo_opendir);
if (g_ch != 0)
{
@ -901,12 +921,11 @@ static int xfuse_deinit_xrdp_fs()
static int xfuse_is_inode_valid(int ino)
{
/* our lowest ino is FIRST_INODE */
if (ino < FIRST_INODE)
/* is ino present in our table? */
if ((ino < FIRST_INODE) || (ino >= g_xrdp_fs.next_node))
return 0;
/* is ino present in our table? */
if (ino >= g_xrdp_fs.next_node)
if (g_xrdp_fs.inode_table[ino] == NULL)
return 0;
return 1;
@ -989,6 +1008,11 @@ static void xfuse_dump_fs()
log_debug("found %d entries", g_xrdp_fs.num_entries - FIRST_INODE);
#if 0
log_debug("not dumping xrdp fs");
return;
#endif
for (i = FIRST_INODE; i < g_xrdp_fs.num_entries; i++)
{
if ((xinode = g_xrdp_fs.inode_table[i]) == NULL)
@ -1229,6 +1253,9 @@ static int xfuse_delete_file_with_xinode(XRDP_INODE *xinode)
if ((xinode == NULL) || (xinode->mode & S_IFDIR))
return -1;
log_always("deleting: inode=%d name=%s", xinode->inode, xinode->name);
log_debug("deleting: inode=%d name=%s", xinode->inode, xinode->name);
g_xrdp_fs.inode_table[xinode->parent_inode]->nentries--;
g_xrdp_fs.inode_table[xinode->inode] = NULL;
free(xinode);
@ -1281,6 +1308,12 @@ static int xfuse_recursive_delete_dir_with_xinode(XRDP_INODE *xinode)
if ((xinode == NULL) || (xinode->mode & S_IFREG))
return -1;
log_always("recursively deleting dir with inode=%d name=%s",
xinode->inode, xinode->name);
log_debug("recursively deleting dir with inode=%d name=%s",
xinode->inode, xinode->name);
for (i = FIRST_INODE; i < g_xrdp_fs.num_entries; i++)
{
if ((xip = g_xrdp_fs.inode_table[i]) == NULL)
@ -1342,60 +1375,6 @@ static void xfuse_update_xrdpfs_size()
g_xrdp_fs.inode_table = vp;
}
/* LK_TODO do we still need this function */
#if 0
static void xfuse_enum_dir(fuse_req_t req, fuse_ino_t ino, size_t size,
off_t off, struct fuse_file_info *fi)
{
XRDP_INODE *xinode;
XRDP_INODE *xinode1;
struct dirbuf b;
int first_time = 1;
int i;
memset(&b, 0, sizeof(struct dirbuf));
for (i = FIRST_INODE; i < g_xrdp_fs.num_entries; i++)
{
if ((xinode = g_xrdp_fs.inode_table[i]) == NULL)
continue;
/* match parent inode */
if (xinode->parent_inode != ino)
continue;
if (first_time)
{
first_time = 0;
if (ino == 1)
{
xfuse_dirbuf_add(req, &b, ".", 1);
xfuse_dirbuf_add(req, &b, "..", 1);
}
else
{
xinode1 = g_xrdp_fs.inode_table[ino];
xfuse_dirbuf_add(req, &b, ".", ino);
xfuse_dirbuf_add(req, &b, "..", xinode1->parent_inode);
}
}
xfuse_dirbuf_add(req, &b, xinode->name, xinode->inode);
}
if (!first_time)
{
if (off < b.size)
fuse_reply_buf(req, b.p + off, min(b.size - off, size));
else
fuse_reply_buf(req, NULL, 0);
}
if (b.p)
free(b.p);
}
#endif
/******************************************************************************
** **
** callbacks for devredir **
@ -1464,8 +1443,9 @@ void xfuse_devredir_cb_enum_dir(void *vp, struct xrdp_inode *xinode)
void xfuse_devredir_cb_enum_dir_done(void *vp, tui32 IoStatus)
{
XFUSE_INFO *fip;
struct dir_info *di;
XFUSE_INFO *fip;
struct dir_info *di;
struct opendir_req *odreq;
log_debug("vp=%p IoStatus=0x%x", vp, IoStatus);
@ -1473,7 +1453,7 @@ void xfuse_devredir_cb_enum_dir_done(void *vp, tui32 IoStatus)
if (fip == NULL)
{
log_debug("fip is NULL");
return;
goto done;
}
if (IoStatus != 0)
@ -1506,6 +1486,22 @@ done:
if (fip)
free(fip);
/* remove current request */
g_free(fifo_remove(&g_fifo_opendir));
while (1)
{
/* process next request */
odreq = fifo_peek(&g_fifo_opendir);
if (!odreq)
return;
if (xfuse_proc_opendir_req(odreq->req, odreq->ino, odreq->fi))
g_free(fifo_remove(&g_fifo_opendir)); /* req failed */
else
break; /* req has been queued */
}
}
void xfuse_devredir_cb_open_file(void *vp, tui32 IoStatus, tui32 DeviceId,
@ -1903,15 +1899,19 @@ static void xfuse_cb_getattr(fuse_req_t req, fuse_ino_t ino,
}
xino = g_xrdp_fs.inode_table[ino];
if (!xino)
{
log_debug("****** invalid ino=%d", (int) ino);
fuse_reply_err(req, EBADF);
return;
}
memset(&stbuf, 0, sizeof(stbuf));
stbuf.st_ino = ino;
stbuf.st_mode = xino->mode;
stbuf.st_nlink = xino->nlink;
stbuf.st_size = xino->size;
fuse_reply_attr(req, &stbuf, 1.0);
log_debug("exiting");
}
/**
@ -1977,8 +1977,7 @@ static void xfuse_cb_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
int i;
int first_time;
log_debug("req=%p inode=%d name=%s size=%d offset=%d", req, ino,
g_xrdp_fs.inode_table[ino]->name, size, off);
log_debug("req=%p inode=%d size=%d offset=%d", req, ino, size, off);
/* do we have a valid inode? */
if (!xfuse_is_inode_valid(ino))
@ -2014,6 +2013,12 @@ static void xfuse_cb_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
{
first_time = 0;
ti = g_xrdp_fs.inode_table[ino];
if (!ti)
{
log_debug("****** g_xrdp_fs.inode_table[%d] is NULL", ino);
fuse_reply_buf(req, NULL, 0);
return;
}
xfuse_dirbuf_add1(req, &b, ".", ino);
xfuse_dirbuf_add1(req, &b, "..", ti->parent_inode);
}
@ -2451,6 +2456,12 @@ static void xfuse_cb_open(fuse_req_t req, fuse_ino_t ino,
/* if ino points to a dir, fail the open request */
xinode = g_xrdp_fs.inode_table[ino];
if (!xinode)
{
log_debug("****** g_xrdp_fs.inode_table[%d] is NULL", ino);
fuse_reply_err(req, EBADF);
return;
}
if (xinode->mode & S_IFDIR)
{
log_debug("reading a dir not allowed!");
@ -2491,8 +2502,6 @@ static void xfuse_cb_open(fuse_req_t req, fuse_ino_t ino,
fip->name[1023] = 0;
fip->reply_type = RT_FUSE_REPLY_OPEN;
/* LK_TODO need to handle open permissions */
/* we want path minus 'root node of the share' */
if ((cptr = strchr(full_path, '/')) == NULL)
{
@ -2532,6 +2541,12 @@ static void xfuse_cb_release(fuse_req_t req, fuse_ino_t ino, struct
}
XRDP_INODE *xinode = g_xrdp_fs.inode_table[ino];
if (!xinode)
{
log_debug("****** g_xrdp_fs.inode_table[%d] is NULL", ino);
fuse_reply_err(req, 0);
return;
}
if (xinode->is_loc_resource)
{
/* specified file is a local resource */
@ -2748,7 +2763,12 @@ static void xfuse_cb_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
return;
}
xinode = g_xrdp_fs.inode_table[ino];
if ((xinode = g_xrdp_fs.inode_table[ino]) == NULL)
{
log_debug("g_xrdp_fs.inode_table[%d] is NULL", ino);
fuse_reply_err(req, EBADF);
return;
}
if (to_set & FUSE_SET_ATTR_MODE)
{
@ -2813,8 +2833,39 @@ static void xfuse_cb_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
fuse_reply_attr(req, &st, 1.0); /* LK_TODO just faking for now */
}
/**
* Get dir listing
*****************************************************************************/
static void xfuse_cb_opendir(fuse_req_t req, fuse_ino_t ino,
struct fuse_file_info *fi)
{
struct opendir_req *odreq;
/* save request */
odreq = malloc(sizeof(struct opendir_req));
odreq->req = req;
odreq->ino = ino;
odreq->fi = fi;
if (fifo_is_empty(&g_fifo_opendir))
{
fifo_insert(&g_fifo_opendir, odreq);
xfuse_proc_opendir_req(req, ino, fi);
}
else
{
/* place req in FIFO; xfuse_devredir_cb_enum_dir_done() will handle it */
fifo_insert(&g_fifo_opendir, odreq);
}
}
/**
* Process the next opendir req
*
* @return 0 of the request was sent for remote lookup, -1 otherwise
*****************************************************************************/
static int xfuse_proc_opendir_req(fuse_req_t req, fuse_ino_t ino,
struct fuse_file_info *fi)
{
struct dir_info *di;
XRDP_INODE *xinode;
@ -2823,19 +2874,26 @@ static void xfuse_cb_opendir(fuse_req_t req, fuse_ino_t ino,
char full_path[4096];
char *cptr;
log_debug("inode=%d name=%s", ino, g_xrdp_fs.inode_table[ino]->name);
log_debug("inode=%d", ino);
if (!xfuse_is_inode_valid(ino))
{
log_error("inode %d is not valid", ino);
fuse_reply_err(req, EBADF);
return;
g_free(fifo_remove(&g_fifo_opendir));
return -1;
}
if (ino == 1)
goto done; /* special case; enumerate top level dir */
xinode = g_xrdp_fs.inode_table[ino];
if ((xinode = g_xrdp_fs.inode_table[ino]) == NULL)
{
log_debug("g_xrdp_fs.inode_table[%d] is NULL", ino);
fuse_reply_err(req, EBADF);
g_free(fifo_remove(&g_fifo_opendir));
return -1;
}
if (xinode->is_loc_resource)
goto done;
@ -2846,7 +2904,8 @@ static void xfuse_cb_opendir(fuse_req_t req, fuse_ino_t ino,
if (xinode->is_synced)
{
xfuse_enum_dir(req, ino, size, off, fi);
return;
g_free(fifo_remove(&g_fifo_opendir));
return -1;
}
else
{
@ -2867,7 +2926,8 @@ do_remote_lookup:
{
log_error("system out of memory");
fuse_reply_err(req, ENOMEM);
return;
g_free(fifo_remove(&g_fifo_opendir));
return -1;
}
fip->req = req;
@ -2900,7 +2960,7 @@ do_remote_lookup:
}
}
return;
return 0;
done:
@ -2908,6 +2968,8 @@ done:
di->index = FIRST_INODE;
fi->fh = (long) di;
fuse_reply_open(req, fi);
g_free(fifo_remove(&g_fifo_opendir));
return -1;
}
/**

View File

@ -68,7 +68,7 @@
#define log_info(_params...) \
{ \
if (LOG_INFO <= LOG_LEVEL) \
if (LOG_INFO <= LOG_LEVEL) \
{ \
g_write("[%10.10u]: DEV_REDIR %s: %d : ", \
g_time3(), __func__, __LINE__); \
@ -78,7 +78,7 @@
#define log_debug(_params...) \
{ \
if (LOG_DEBUG <= LOG_LEVEL) \
if (LOG_DEBUG <= LOG_LEVEL) \
{ \
g_write("[%10.10u]: DEV_REDIR %s: %d : ", \
g_time3(), __func__, __LINE__); \
@ -1101,7 +1101,11 @@ dev_redir_file_open(void *fusep, tui32 device_id, char *path,
#if 1
/* without the 0x00000010 rdesktop opens files in */
/* O_RDONLY instead of O_RDWR mode */
DesiredAccess = DA_FILE_READ_DATA | DA_FILE_WRITE_DATA | DA_SYNCHRONIZE | 0x00000010;
if (mode & O_RDWR)
DesiredAccess = DA_FILE_READ_DATA | DA_FILE_WRITE_DATA | DA_SYNCHRONIZE | 0x00000010;
else
DesiredAccess = DA_FILE_READ_DATA | DA_SYNCHRONIZE;
CreateOptions = CO_FILE_SYNCHRONOUS_IO_NONALERT;
CreateDisposition = CD_FILE_OPEN; // WAS 1
#else

255
sesman/chansrv/fifo.c Normal file
View File

@ -0,0 +1,255 @@
/**
* xrdp: A Remote Desktop Protocol server.
*
* Copyright (C) Laxmikant Rashinkar 2013 LK.Rashinkar@gmail.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* FIFO implementation to store a pointer to a user struct */
/* module based logging */
#define MODULE_NAME "FIFO "
#define LOCAL_DEBUG
#include "fifo.h"
#include "mlog.h"
/**
* Initialize a FIFO that grows as required
*
* @param fp pointer to a FIFO
* @param num_entries initial size
*
* @return 0 on success, -1 on failure
*****************************************************************************/
int
fifo_init(FIFO* fp, int num_entries)
{
log_debug_high("entered");
/* validate params */
if (!fp)
{
log_debug_high("invalid parameters");
return -1;
}
if (num_entries < 1)
num_entries = 10;
fp->rd_ptr = 0;
fp->wr_ptr = 0;
fp->user_data = (long *) g_malloc(sizeof(long) * num_entries);
if (fp->user_data)
{
fp->entries = num_entries;
log_debug_low("FIFO created; rd_ptr=%d wr_ptr=%d entries=%d",
fp->rd_ptr, fp->wr_ptr, fp->entries);
return 0;
}
else
{
log_error("FIFO create error; system out of memory");
fp->entries = 0;
return -1;
}
}
/**
* Deinit FIFO and release resources
*
* @param fp FIFO to deinit
*
* @return 0 on success, -1 on error
*****************************************************************************/
int
fifo_deinit(FIFO* fp)
{
log_debug_high("entered");
if (!fp)
{
log_debug_high("FIFO is null");
return -1;
}
if (fp->user_data)
{
g_free(fp->user_data);
fp->user_data = 0;
}
fp->rd_ptr = 0;
fp->wr_ptr = 0;
fp->entries = 0;
}
/**
* Check if FIFO is empty
*
* @param fp FIFO
*
* @return 1 if FIFO is empty, 0 otherwise
*****************************************************************************/
int
fifo_is_empty(FIFO* fp)
{
log_debug_high("entered");
if (!fp)
{
log_debug_high("FIFO is null");
return 0;
}
return (fp->rd_ptr == fp->wr_ptr) ? 1 : 0;
}
/**
* Insert an item at the end
*
* @param fp FIFO
* @param data data to insert into FIFO
*
* @param 0 on success, -1 on error
*****************************************************************************/
int
fifo_insert(FIFO* fp, void* data)
{
long* lp;
int next_val; /* next value for wr_ptr */
int i;
log_debug_high("entered");
if (!fp)
{
log_debug_high("FIFO is null");
return -1;
}
next_val = fp->wr_ptr + 1;
if (next_val >= fp->entries)
next_val = 0;
if (next_val == fp->rd_ptr)
{
/* FIFO is full, expand it by 10 entries */
lp = (long *) g_malloc(sizeof(long) * (fp->entries + 10));
if (!lp)
{
log_debug_low("FIFO full; cannot expand, no memory");
return -1;
}
log_debug_low("FIFO full, expanding by 10 entries");
/* copy old data new location */
for (i = 0; i < (fp->entries - 1); i++)
{
lp[i] = fp->user_data[fp->rd_ptr++];
if (fp->rd_ptr >= fp->entries)
fp->rd_ptr = 0;
}
/* update pointers */
fp->rd_ptr = 0;
fp->wr_ptr = fp->entries - 1;
next_val = fp->entries;
fp->entries += 10;
/* free old data */
g_free(fp->user_data);
fp->user_data = lp;
}
log_debug_low("inserting data at index %d", fp->wr_ptr);
fp->user_data[fp->wr_ptr] = (long) data;
fp->wr_ptr = next_val;
return 0;
}
/**
* Remove an item from the head
*
* @param fp FIFO
*
* @param data on success, NULL on error
*****************************************************************************/
void*
fifo_remove(FIFO* fp)
{
long data;
log_debug_high("entered");
if (!fp)
{
log_debug_high("FIFO is null");
return 0;
}
if (fp->rd_ptr == fp->wr_ptr)
{
log_debug_high("FIFO is empty");
return 0;
}
log_debug_low("removing data at index %d", fp->rd_ptr);
data = fp->user_data[fp->rd_ptr++];
if (fp->rd_ptr >= fp->entries)
{
log_debug_high("FIFO rd_ptr wrapped around");
fp->rd_ptr = 0;
}
return (void *) data;
}
/**
* Return item from head, but do not remove it
*
* @param fp FIFO
*
* @param data on success, NULL on error
*****************************************************************************/
void*
fifo_peek(FIFO* fp)
{
long data;
log_debug_high("entered\n");
if (!fp)
{
log_debug_high("FIFO is null\n");
return 0;
}
if (fp->rd_ptr == fp->wr_ptr)
{
log_debug_high("FIFO is empty\n");
return 0;
}
log_debug_low("peeking data at index %d\n", fp->rd_ptr);
return (void *) fp->user_data[fp->rd_ptr];
}

35
sesman/chansrv/fifo.h Normal file
View File

@ -0,0 +1,35 @@
/**
* xrdp: A Remote Desktop Protocol server.
*
* Copyright (C) Laxmikant Rashinkar 2013 LK.Rashinkar@gmail.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* FIFO implementation to store a pointer to a user struct */
typedef struct fifo
{
long* user_data;
int rd_ptr;
int wr_ptr;
int entries;
} FIFO;
int fifo_init(FIFO* fp, int num_entries);
int fifo_deinit(FIFO* fp);
int fifo_is_empty(FIFO* fp);
int fifo_insert(FIFO* fp, void* data);
void* fifo_remove(FIFO* fp);
void* fifo_peek(FIFO* fp);

112
sesman/chansrv/mlog.h Normal file
View File

@ -0,0 +1,112 @@
/**
* xrdp: A Remote Desktop Protocol server.
*
* Copyright (C) Laxmikant Rashinkar 2013 LK.Rashinkar@gmail.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* module based logging */
#ifndef _MLOG_H
#define _MLOG_H
/*
* Note1: to enable debug messages, in your .c file, #define LOCAL_DEBUG
* BEFORE including this file
*
* Note2: in your .c file, #define MODULE_NAME, 8 chars long, to print each
* log entry with your module name
*/
#define LOG_ERROR 0
#define LOG_INFO 1
#define LOG_DEBUG_LOW 2
#define LOG_DEBUG_HIGH 3
#define LOG_LEVEL LOG_ERROR
/*
* print always
*/
#define log_error(_params...) \
do \
{ \
g_write("[%10.10u]: %s %s: %d: ERROR: ", g_time3(), \
MODULE_NAME, __func__, __LINE__); \
g_writeln (_params); \
} \
while(0)
#define log_always(_params...) \
do \
{ \
g_write("[%10.10u]: %s %s: %d: ALWAYS: ", g_time3(), \
MODULE_NAME, __func__, __LINE__); \
g_writeln (_params); \
} \
while(0)
/*
* print conditionally
*/
#ifdef LOCAL_DEBUG
#define log_info(_params...) \
do \
{ \
if (LOG_INFO <= LOG_LEVEL) \
{ \
g_write("[%10.10u]: %s %s: %d: INFO: ", g_time3(), \
MODULE_NAME, __func__, __LINE__); \
g_writeln (_params); \
} \
} \
while(0)
#else
#define log_info(_params...)
#endif
#ifdef LOCAL_DEBUG
#define log_debug_low(_params...) \
do \
{ \
if (LOG_DEBUG_LOW <= LOG_LEVEL) \
{ \
g_write("[%10.10u]: %s %s: %d: DEBUG: ", g_time3(), \
MODULE_NAME, __func__, __LINE__); \
g_writeln (_params); \
} \
} \
while(0)
#else
#define log_debug_low(_params...)
#endif
#ifdef LOCAL_DEBUG
#define log_debug_high(_params...) \
do \
{ \
if (LOG_DEBUG_HIGH <= LOG_LEVEL) \
{ \
g_write("[%10.10u]: %s %s: %d: DEBUG: ", g_time3(), \
MODULE_NAME, __func__, __LINE__); \
g_writeln (_params); \
} \
} \
while(0)
#else
#define log_debug_high(_params...)
#endif
#endif /* #ifndef _MLOG_H */