1// Debug.cpp
2//
3// Copyright (c) 2003, Ingo Weinhold (bonefish@cs.tu-berlin.de)
4//
5// This program is free software; you can redistribute it and/or modify
6// it under the terms of the GNU General Public License as published by
7// the Free Software Foundation; either version 2 of the License, or
8// (at your option) any later version.
9//
10// This program is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13// GNU General Public License for more details.
14//
15// You should have received a copy of the GNU General Public License
16// along with this program; if not, write to the Free Software
17// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18//
19// You can alternatively use *this file* under the terms of the the MIT
20// license included in this package.
21
22#include <errno.h>
23#include <fcntl.h>
24#include <stdarg.h>
25#include <stdio.h>
26#include <string.h>
27#include <unistd.h>
28
29#include <OS.h>
30
31#include "Debug.h"
32
33/*!
34	\file Debug.cpp
35	\brief Defines debug output function with printf() signature printing
36		   into a file.
37
38	\note The initialization is not thread safe!
39*/
40
41// no need to define it, if not used
42#if DEBUG_PRINT
43
44static int32 init_counter = 0;
45static int out = -1;
46static sem_id dbg_printf_sem = -1;
47static thread_id dbg_printf_thread = -1;
48static int dbg_printf_nesting = 0;
49
50// init_debugging
51status_t
52init_debugging()
53{
54	status_t error = B_OK;
55	if (init_counter++ == 0) {
56		// open the file
57		out = open(DEBUG_PRINT_FILE, O_RDWR | O_CREAT | O_TRUNC);
58		if (out < 0) {
59			error = errno;
60			init_counter--;
61		} else {
62			dbg_printf("##################################################\n");
63			dbg_printf_sem = create_sem(1, "dbg_printf");
64		}
65	}
66	return error;
67}
68
69// exit_debugging
70status_t
71exit_debugging()
72{
73	status_t error = B_OK;
74	if (out >= 0) {
75		if (--init_counter == 0) {
76			close(out);
77			out = -1;
78			delete_sem(dbg_printf_sem);
79		}
80	} else
81		error = B_NO_INIT;
82	return error;
83}
84
85// dbg_printf_lock
86static inline
87bool
88dbg_printf_lock()
89{
90	thread_id thread = find_thread(NULL);
91	if (thread != dbg_printf_thread) {
92		if (acquire_sem(dbg_printf_sem) != B_OK)
93			return false;
94		dbg_printf_thread = thread;
95	}
96	dbg_printf_nesting++;
97	return true;
98}
99
100// dbg_printf_unlock
101static inline
102void
103dbg_printf_unlock()
104{
105	thread_id thread = find_thread(NULL);
106	if (thread != dbg_printf_thread)
107		return;
108	dbg_printf_nesting--;
109	if (dbg_printf_nesting == 0) {
110		dbg_printf_thread = -1;
111		release_sem(dbg_printf_sem);
112	}
113}
114
115// dbg_printf
116void
117dbg_printf(const char *format,...)
118{
119	if (!dbg_printf_lock())
120		return;
121	char buffer[1024];
122	va_list args;
123	va_start(args, format);
124	// no vsnprintf() on PPC and in kernel
125	#if defined(__INTEL__) && USER
126		vsnprintf(buffer, sizeof(buffer) - 1, format, args);
127	#else
128		vsprintf(buffer, format, args);
129	#endif
130	va_end(args);
131	buffer[sizeof(buffer) - 1] = '\0';
132	write(out, buffer, strlen(buffer));
133	dbg_printf_unlock();
134}
135
136// dbg_printf_begin
137void
138dbg_printf_begin()
139{
140	dbg_printf_lock();
141}
142
143// dbg_printf_end
144void
145dbg_printf_end()
146{
147	dbg_printf_unlock();
148}
149
150#endif	// DEBUG_PRINT
151