1351290Sdim/*
2351290Sdim * Copyright 2003-2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3351290Sdim * Distributed under the terms of the MIT License.
4351290Sdim */
5351290Sdim
6351290Sdim
7351290Sdim#include "DebugSupport.h"
8351290Sdim
9351290Sdim#include <errno.h>
10351290Sdim#include <fcntl.h>
11351290Sdim#include <stdarg.h>
12351290Sdim#include <stdio.h>
13351290Sdim#include <string.h>
14351290Sdim#include <unistd.h>
15351290Sdim
16351290Sdim#include <OS.h>
17351290Sdim
18351290Sdim
19351290Sdim/*!
20351290Sdim	\file DebugSupport.cpp
21351290Sdim	\brief Defines debug output function with printf() signature printing
22351290Sdim		   into a file.
23351290Sdim
24351290Sdim	\note The initialization is not thread safe!
25351290Sdim*/
26351290Sdim
27351290Sdim
28351290Sdim// locking support
29351290Sdimstatic int32 init_counter = 0;
30351290Sdimstatic sem_id dbg_printf_sem = -1;
31351290Sdimstatic thread_id dbg_printf_thread = -1;
32351290Sdimstatic int dbg_printf_nesting = 0;
33351290Sdim
34351290Sdim
35351290Sdim#if DEBUG_PRINT
36351290Sdimstatic int out = -1;
37351290Sdim#endif
38351290Sdim
39351290Sdim
40360784Sdimstatus_t
41360784Sdiminit_debugging()
42360784Sdim{
43360784Sdim	status_t error = B_OK;
44360784Sdim	if (init_counter++ == 0) {
45360784Sdim		// open the file
46360784Sdim		#if DEBUG_PRINT
47351290Sdim			out = open(DEBUG_PRINT_FILE, O_RDWR | O_CREAT | O_TRUNC);
48351290Sdim			if (out < 0) {
49351290Sdim				error = errno;
50351290Sdim				init_counter--;
51351290Sdim			}
52351290Sdim		#endif	// DEBUG_PRINT
53351290Sdim		// allocate the semaphore
54		if (error == B_OK) {
55			dbg_printf_sem = create_sem(1, "dbg_printf");
56			if (dbg_printf_sem < 0)
57				error = dbg_printf_sem;
58		}
59		if (error == B_OK) {
60			#if DEBUG
61				__out("##################################################\n");
62			#endif
63		} else
64			exit_debugging();
65	}
66	return error;
67}
68
69
70status_t
71exit_debugging()
72{
73	status_t error = B_OK;
74	if (--init_counter == 0) {
75		#if DEBUG_PRINT
76			close(out);
77			out = -1;
78		#endif	// DEBUG_PRINT
79		delete_sem(dbg_printf_sem);
80	} else
81		error = B_NO_INIT;
82	return error;
83}
84
85
86static inline bool
87dbg_printf_lock()
88{
89	thread_id thread = find_thread(NULL);
90	if (thread != dbg_printf_thread) {
91		if (acquire_sem(dbg_printf_sem) != B_OK)
92			return false;
93		dbg_printf_thread = thread;
94	}
95	dbg_printf_nesting++;
96	return true;
97}
98
99
100static inline void
101dbg_printf_unlock()
102{
103	thread_id thread = find_thread(NULL);
104	if (thread != dbg_printf_thread)
105		return;
106	dbg_printf_nesting--;
107	if (dbg_printf_nesting == 0) {
108		dbg_printf_thread = -1;
109		release_sem(dbg_printf_sem);
110	}
111}
112
113
114void
115dbg_printf_begin()
116{
117	dbg_printf_lock();
118}
119
120
121void
122dbg_printf_end()
123{
124	dbg_printf_unlock();
125}
126
127
128#if DEBUG_PRINT
129
130void
131dbg_printf(const char *format,...)
132{
133	if (!dbg_printf_lock())
134		return;
135	char buffer[1024];
136	va_list args;
137	va_start(args, format);
138	// no vsnprintf() on PPC and in kernel
139	#if defined(__INTEL__) && USER
140		vsnprintf(buffer, sizeof(buffer) - 1, format, args);
141	#else
142		vsprintf(buffer, format, args);
143	#endif
144	va_end(args);
145	buffer[sizeof(buffer) - 1] = '\0';
146	write(out, buffer, strlen(buffer));
147	dbg_printf_unlock();
148}
149
150#endif	// DEBUG_PRINT
151