/*
* convenient.h
*
* A few convenience macros and routines..
* Mostly for kernel-space usage, some for user-space as well.
*
* Author: Kaiwan N Billimoria <kaiwan@kaiwantech.com>
* (c) Kaiwan NB, kaiwanTECH
* GPL / LGPL
*
*/
#ifndef __CONVENIENT_H__
#define __CONVENIENT_H__
#include <asm/param.h> /* HZ */
#include <linux/sched.h>
#ifdef __KERNEL__
#include <linux/ratelimit.h>
/*
*** Note: PLEASE READ this documentation: ***
We can reduce the load, and increase readability, by using the trace_printk
instead of printk. To see the o/p do:
# cat /sys/kernel/debug/tracing/trace
If we insist on using the regular printk, lets at least rate-limit it.
For the programmers' convenience, this too is programatically controlled
(by an integer var USE_RATELIMITING [default: On]).
*** Kernel module authors Note: ***
To use the trace_printk(), pl #define the symbol USE_FTRACE_PRINT in your Makefile:
EXTRA_CFLAGS += -DUSE_FTRACE_PRINT
If you do not do this, we will use the usual printk() .
To view :
printk's : dmesg
trace_printk's : cat /sys/kernel/debug/tracing/trace
Default: printk
*/
// keep this defined to use the FTRACE-style trace_printk(), else will use regular printk()
//#define USE_FTRACE_PRINT
//#undef USE_FTRACE_PRINT
#ifdef USE_FTRACE_PRINT
#define DBGPRINT(string, args...) \
trace_printk(string, ##args);
#else
#define DBGPRINT(string, args...) do { \
int USE_RATELIMITING=0; \
/* Not supposed to use printk_ratelimit() now.. */ \
if (USE_RATELIMITING) { \
printk_ratelimited (KERN_INFO pr_fmt(string), ##args); \
} \
else \
pr_info (pr_fmt(string), ##args); \
} while (0)
#endif
/*------------------------ MSG, QP ------------------------------------*/
#ifdef DEBUG
#ifdef __KERNEL__
#define MSG(string, args...) do { \
DBGPRINT("%s:%d : " string, __FUNCTION__, __LINE__, ##args); \
} while (0)
#else
#define MSG(string, args...) do { \
fprintf(stderr, "%s:%d : " string, __FUNCTION__, __LINE__, ##args); \
} while (0)
#endif
#ifdef __KERNEL__
#define MSG_SHORT(string, args...) do { \
DBGPRINT(string, ##args); \
} while (0)
#else
#define MSG_SHORT(string, args...) do { \
fprintf(stderr, string, ##args); \
} while (0)
#endif
// QP = Quick Print
#define QP MSG("\n")
#ifdef __KERNEL__
#define QPDS do { \
MSG("\n"); \
dump_stack(); \
} while(0)
#endif
#ifdef __KERNEL__
#define HexDump(from_addr, len) \
print_hex_dump_bytes (" ", DUMP_PREFIX_ADDRESS, from_addr, len);
#endif
#else
#define MSG(string, args...)
#define MSG_SHORT(string, args...)
#define QP
#define QPDS
#endif
/*------------------------ PRINT_CTX ---------------------------------*/
/*
An interesting way to print the context info:
If USE_FTRACE_PRINT is On, it implies we'll use trace_printk(), else the vanilla
printk().
If we are using trace_printk(), we will automatically get output in the ftrace
latency format (see below):
* The Ftrace 'latency-format' :
_-----=> irqs-off [d]
/ _----=> need-resched [N]
| / _---=> hardirq/softirq [H|h|s] H=>both h && s
|| / _--=> preempt-depth [#]
||| /
CPU TASK/PID |||| DURATION FUNCTION CALLS
| | | |||| | | | | | |
However, if we're _not_ using ftrace trace_printk(), then we'll _emulate_ the same
with the printk() !
(Of course, without the 'Duration' and 'Function Calls' fields).
*/
#include <linux/sched.h>
#include <linux/interrupt.h>
#ifndef USE_FTRACE_PRINT // 'normal' printk(), lets emulate ftrace latency format
#define PRINT_CTX() do { \
char sep='|', intr='.'; \
\
if (in_interrupt()) { \
if (in_irq() && in_softirq()) \
intr='H'; \
else if (in_irq()) \
intr='h'; \
else if (in_softirq()) \
intr='s'; \
} \
else \
intr='.'; \
\
DBGPRINT( \
"PRINT_CTX:: [%03d]%c%s%c:%d %c " \
"%c%c%c%u " \
"\n" \
, smp_processor_id(), \
(!current->mm?'[':' '), current->comm, (!current->mm?']':' '), current->pid, sep, \
(irqs_disabled()?'d':'.'), \
(need_resched()?'N':'.'), \
intr, \
(preempt_count() && 0xff) \
); \
} while (0)
#else // using ftrace trace_prink() internally
#define PRINT_CTX() do { \
DBGPRINT("PRINT_CTX:: [cpu %02d]%s:%d\n", smp_processor_id(), __func__, current->pid); \
if (!in_interrupt()) { \
DBGPRINT(" in process context:%c%s%c:%d\n", \
(!current->mm?'[':' '), current->comm, (!current->mm?']':' '), current->pid); \
} else { \
DBGPRINT(" in interrupt context: in_interrupt:%3s. in_irq:%3s. in_softirq:%3s. " \
"in_serving_softirq:%3s. preempt_count=0x%x\n", \
(in_interrupt()?"yes":"no"), (in_irq()?"yes":"no"), (in_softirq()?"yes":"no"), \
(in_serving_softirq()?"yes":"no"), (preempt_count() && 0xff)); \
} \
} while (0)
#endif
#endif // end ifdef __KERNEL__ at the top
/*------------------------ assert ---------------------------------------
* Hey you, careful!
* Using assertions is great *but* pl be aware of traps & pitfalls:
* http://b...content-available-to-author-only...r.org/archives/1096
*
* The closest equivalent perhaps, to assert() in the kernel are the BUG()
* or BUG_ON() and WARN() or WARN_ON() macros. Using BUG*() is _only_ for those
* cases where recovery is impossible. WARN*() is usally considered a better
* option. Pl see <asm-generic/bug.h> for details.
*
* Here, we just trivially emit a noisy [trace_]printk() to "warn" the dev/user.
*/
#ifdef __KERNEL__
#define assert(expr) do { \
if (!(expr)) { \
DBGPRINT("********** Assertion [%s] failed! : %s:%s:%d **********\n", \
#expr, __FILE__, __func__, __LINE__); \
} \
} while(0)
#endif
/*------------------------ DELAY_LOOP --------------------------------*/
static inline void beep(int what)
{
#ifdef __KERNEL__
DBGPRINT("%c", (char)what);
#else
(void)printf("%c", (char)what
); #endif
}
/*
* DELAY_LOOP macro
* @val : ASCII value to print
* @loop_count : times to loop around
*/
#define DELAY_LOOP(val,loop_count) \
{ \
int c=0, m;\
unsigned int for_index,inner_index; \
\
for(for_index=0;for_index<loop_count;for_index++) { \
beep((val)); \
c++;\
for(inner_index=0;inner_index<HZ*1000*8;inner_index++) \
for(m=0;m<50;m++); \
} \
/*printf("c=%d\n",c);*/\
}
/*------------------------------------------------------------------------*/
#ifdef __KERNEL__
/*------------ DELAY_SEC -------------------------*
* Delays execution for n seconds.
* MUST be called from process context.
*------------------------------------------------*/
#define DELAY_SEC(val) \
{ \
if (!in_interrupt()) { \
set_current_state (TASK_INTERRUPTIBLE); \
schedule_timeout (val * HZ); \
} \
}
#endif
/* Get time difference between two struct timeval's
* Credits: Arkaitz Jimenez
* http://stackoverflow.com/questions/1444428/time-stamp-in-the-c-programming-language
*/
static int timeval_subtract(struct timeval *result, struct timeval *x,
struct timeval *y);
/* Subtract the `struct timeval' values X and Y,
storing the result in RESULT.
Return 1 if the difference is negative, otherwise 0. */
__attribute__ ((unused))
int timeval_subtract(struct timeval *result, struct timeval *x,
struct timeval *y)
{
/* Perform the carry for the later subtraction by updating y. */
if (x->tv_usec < y->tv_usec) {
int nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1;
y->tv_usec -= 1000000 * nsec;
y->tv_sec += nsec;
}
if (x->tv_usec - y->tv_usec > 1000000) {
int nsec = (x->tv_usec - y->tv_usec) / 1000000;
y->tv_usec += 1000000 * nsec;
y->tv_sec -= nsec;
}
/* Compute the time remaining to wait.
tv_usec is certainly positive. */
result->tv_sec = x->tv_sec - y->tv_sec;
result->tv_usec = x->tv_usec - y->tv_usec;
/* Return 1 if result is negative. */
return x->tv_sec < y->tv_sec;
}
/*
* Converts decimal to binary.
* Credits: vegaseat. URL: http://w...content-available-to-author-only...b.com/software-development/c/code/216349
* accepts a decimal integer and returns a binary coded string
*
* @decimal : decimal value to convert to binary (IN)
* @binary : the binary result as a string (OUT)
*
*/
__attribute__ ((unused))
static void dec2bin(long decimal, char *binary)
{
int k = 0, n = 0;
int neg_flag = 0;
int remain;
/*
gcc 4.6.3 : we get the warning:
"warning: variable ‘old_decimal’ set but not used [-Wunused-but-set-variable]"
To get rid of this warning, have #ifdef'd the test... -kaiwan.
Keep one of the following below (wrt TESTMODE); comment out the other.
UN-defining by default.
*/
//#define TESTMODE
#undef TESTMODE
#ifdef TESTMODE
int old_decimal; // for test
#endif
char temp[80];
// take care of negative input
if (decimal < 0) {
decimal = -decimal;
neg_flag = 1;
}
do {
#ifdef TESTMODE
old_decimal = decimal; // for test
#endif
remain = decimal % 2;
// whittle down the decimal number
decimal = decimal / 2;
// this is a test to show the action
#ifdef TESTMODE
printf("%d/2 = %d remainder = %d\n", old_decimal
, decimal
, remain);
#endif
// converts digit 0 or 1 to character '0' or '1'
temp[k++] = remain + '0';
} while (decimal > 0);
if (neg_flag)
temp[k++] = '-'; // add - sign
else
temp[k++] = ' '; // space
// reverse the spelling
while (k >= 0)
binary[n++] = temp[--k];
binary[n - 1] = 0; // end with NULL
}
#ifndef __KERNEL__
#define MSG(string, args...) do { \
fprintf(stderr, "%s:%d : " string, __FUNCTION__, __LINE__, ##args); \
} while (0)
#define MSG_SHORT(string, args...) do { \
fprintf(stderr, string, ##args); \
} while (0)
#define QP MSG("\n")
/* Verbose printf ... */
#define VP(verbose, str, args...) \
do { \
if (verbose) \
printf(str, ##args); \
} while (0)
static inline int err_exit(char *prg, char *err, int exitcode)
{
char err_str[512];
snprintf(err_str
, 511, "%s: %s", prg
, err
); } // err_exit()
#endif
#endif