1/*
2 * Copyright 2003-2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7#include "DebugSupport.h"
8
9#include <errno.h>
10#include <fcntl.h>
11#include <stdarg.h>
12#include <stdio.h>
13#include <string.h>
14#include <unistd.h>
15
16#include <OS.h>
17
18
19/*!
20	\file Debug.cpp
21	\brief Defines debug output function with printf() signature printing
22		   into a file.
23
24	\note The initialization is not thread safe!
25*/
26
27
28// locking support
29static int32 init_counter = 0;
30static sem_id dbg_printf_sem = -1;
31static thread_id dbg_printf_thread = -1;
32static int dbg_printf_nesting = 0;
33
34
35#if DEBUG_PRINT
36static int out = -1;
37#endif
38
39
40status_t
41init_debugging()
42{
43	status_t error = B_OK;
44	if (init_counter++ == 0) {
45		// open the file
46		#if DEBUG_PRINT
47			out = open(DEBUG_PRINT_FILE, O_RDWR | O_CREAT | O_TRUNC);
48			if (out < 0) {
49				error = errno;
50				init_counter--;
51			}
52		#endif	// DEBUG_PRINT
53		// 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(__i386__) && 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