| // Simple implementation of cprintf console output for the kernel, | 
 | // based on printfmt() and the kernel console's cputchar(). | 
 |  | 
 | #include <arch/arch.h> | 
 | #include <ros/common.h> | 
 |  | 
 | #include <atomic.h> | 
 | #include <stdio.h> | 
 | #include <stdarg.h> | 
 | #include <smp.h> | 
 | #include <kprof.h> | 
 | #include <init.h> | 
 |  | 
 | /* Recursive lock.  Would like to avoid spreading these in the kernel. */ | 
 | static spinlock_t output_lock = SPINLOCK_INITIALIZER_IRQSAVE; | 
 | static int output_lock_holder = -1;	/* core_id. */ | 
 | static int output_lock_count; | 
 |  | 
 | void print_lock(void) | 
 | { | 
 | 	if (output_lock_holder == core_id_early()) { | 
 | 		output_lock_count++; | 
 | 		return; | 
 | 	} | 
 | 	pcpui_var(core_id_early(), __lock_checking_enabled)--; | 
 | 	spin_lock_irqsave(&output_lock); | 
 | 	output_lock_holder = core_id_early(); | 
 | 	output_lock_count = 1; | 
 | } | 
 |  | 
 | void print_unlock(void) | 
 | { | 
 | 	output_lock_count--; | 
 | 	if (output_lock_count) | 
 | 		return; | 
 | 	output_lock_holder = -1; | 
 | 	spin_unlock_irqsave(&output_lock); | 
 | 	pcpui_var(core_id_early(), __lock_checking_enabled)++; | 
 | } | 
 |  | 
 | /* Regardless of where we are, unlock.  This is dangerous, and only used when | 
 |  * you know you will never unwind your stack, such as for a panic. */ | 
 | void print_unlock_force(void) | 
 | { | 
 | 	output_lock_holder = -1; | 
 | 	output_lock_count = 0; | 
 | 	spin_unlock_irqsave(&output_lock); | 
 | 	pcpui_var(core_id_early(), __lock_checking_enabled)++; | 
 | } | 
 |  | 
 | void putch(int ch, int **cnt) | 
 | { | 
 | 	cputchar(ch); | 
 | 	**cnt = **cnt + 1; | 
 | } | 
 |  | 
 | // buffered putch to (potentially) speed up printing. | 
 | // static buffer is safe because output_lock must be held. | 
 | // ch == -1 flushes the buffer. | 
 | void buffered_putch(int ch, int **cnt) | 
 | { | 
 | 	#define buffered_putch_bufsize 64 | 
 | 	static char buf[buffered_putch_bufsize]; | 
 | 	static int buflen = 0; | 
 |  | 
 | 	if(ch != -1) | 
 | 	{ | 
 | 		buf[buflen++] = ch; | 
 | 		**cnt = **cnt + 1; | 
 | 	} | 
 |  | 
 | 	if(ch == -1 || buflen == buffered_putch_bufsize) | 
 | 	{ | 
 | 		cputbuf(buf,buflen); | 
 | 		buflen = 0; | 
 | 	} | 
 | } | 
 |  | 
 | int vcprintf(const char *fmt, va_list ap) | 
 | { | 
 | 	int cnt = 0; | 
 | 	int *cntp = &cnt; | 
 | 	volatile int i; | 
 | 	va_list args; | 
 |  | 
 | 	print_lock(); | 
 |  | 
 | 	va_copy(args, ap); | 
 | 	trace_vprintk(fmt, args); | 
 | 	va_end(args); | 
 |  | 
 | 	// do the buffered printf | 
 | 	vprintfmt((void*)buffered_putch, (void*)&cntp, fmt, ap); | 
 |  | 
 | 	// write out remaining chars in the buffer | 
 | 	buffered_putch(-1,&cntp); | 
 |  | 
 | 	print_unlock(); | 
 |  | 
 | 	return cnt; | 
 | } | 
 |  | 
 | int cprintf(const char *fmt, ...) | 
 | { | 
 | 	va_list ap; | 
 | 	int cnt; | 
 |  | 
 | 	if (!fmt) | 
 | 		return 0; | 
 |  | 
 | 	va_start(ap, fmt); | 
 | 	cnt = vcprintf(fmt, ap); | 
 | 	va_end(ap); | 
 |  | 
 | 	return cnt; | 
 | } |