1// Debug.cpp
2//
3// Copyright (c) 2003-2004, Ingo Weinhold (bonefish@cs.tu-berlin.de)
4//
5// Permission is hereby granted, free of charge, to any person obtaining a
6// copy of this software and associated documentation files (the "Software"),
7// to deal in the Software without restriction, including without limitation
8// the rights to use, copy, modify, merge, publish, distribute, sublicense,
9// and/or sell copies of the Software, and to permit persons to whom the
10// Software is furnished to do so, subject to the following conditions:
11//
12// The above copyright notice and this permission notice shall be included in
13// all copies or substantial portions of the Software.
14//
15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21// DEALINGS IN THE SOFTWARE.
22//
23// Except as contained in this notice, the name of a copyright holder shall
24// not be used in advertising or otherwise to promote the sale, use or other
25// dealings in this Software without prior written authorization of the
26// copyright holder.
27
28#include <errno.h>
29#include <fcntl.h>
30#include <stdarg.h>
31#include <stdio.h>
32#include <string.h>
33#include <unistd.h>
34
35#include <OS.h>
36
37#include "Debug.h"
38
39/*!
40	\file Debug.cpp
41	\brief Defines debug output function with printf() signature printing
42		   into a file.
43
44	\note The initialization is not thread safe!
45*/
46
47// locking support
48static int32 init_counter = 0;
49static sem_id dbg_printf_sem = -1;
50static thread_id dbg_printf_thread = -1;
51static int dbg_printf_nesting = 0;
52
53#if DEBUG_PRINT
54static int out = -1;
55#endif
56
57// init_debugging
58status_t
59init_debugging()
60{
61	status_t error = B_OK;
62	if (init_counter++ == 0) {
63		// open the file
64		#if DEBUG_PRINT
65			out = open(DEBUG_PRINT_FILE, O_RDWR | O_CREAT | O_TRUNC);
66			if (out < 0) {
67				error = errno;
68				init_counter--;
69			}
70		#endif	// DEBUG_PRINT
71		// allocate the semaphore
72		if (error == B_OK) {
73			dbg_printf_sem = create_sem(1, "dbg_printf");
74			if (dbg_printf_sem < 0)
75				error = dbg_printf_sem;
76		}
77		if (error == B_OK) {
78			#if DEBUG
79				__out("##################################################\n");
80			#endif
81		} else
82			exit_debugging();
83	}
84	return error;
85}
86
87// exit_debugging
88status_t
89exit_debugging()
90{
91	status_t error = B_OK;
92	if (--init_counter == 0) {
93		#if DEBUG_PRINT
94			close(out);
95			out = -1;
96		#endif	// DEBUG_PRINT
97		delete_sem(dbg_printf_sem);
98	} else
99		error = B_NO_INIT;
100	return error;
101}
102
103// dbg_printf_lock
104static inline
105bool
106dbg_printf_lock()
107{
108	thread_id thread = find_thread(NULL);
109	if (thread != dbg_printf_thread) {
110		if (acquire_sem(dbg_printf_sem) != B_OK)
111			return false;
112		dbg_printf_thread = thread;
113	}
114	dbg_printf_nesting++;
115	return true;
116}
117
118// dbg_printf_unlock
119static inline
120void
121dbg_printf_unlock()
122{
123	thread_id thread = find_thread(NULL);
124	if (thread != dbg_printf_thread)
125		return;
126	dbg_printf_nesting--;
127	if (dbg_printf_nesting == 0) {
128		dbg_printf_thread = -1;
129		release_sem(dbg_printf_sem);
130	}
131}
132
133// dbg_printf_begin
134void
135dbg_printf_begin()
136{
137	dbg_printf_lock();
138}
139
140// dbg_printf_end
141void
142dbg_printf_end()
143{
144	dbg_printf_unlock();
145}
146
147#if DEBUG_PRINT
148
149// dbg_printf
150void
151dbg_printf(const char *format,...)
152{
153	if (!dbg_printf_lock())
154		return;
155	char buffer[1024];
156	va_list args;
157	va_start(args, format);
158	// no vsnprintf() on PPC and in kernel
159	#if defined(__INTEL__) && USER
160		vsnprintf(buffer, sizeof(buffer) - 1, format, args);
161	#else
162		vsprintf(buffer, format, args);
163	#endif
164	va_end(args);
165	buffer[sizeof(buffer) - 1] = '\0';
166	write(out, buffer, strlen(buffer));
167	dbg_printf_unlock();
168}
169
170#endif	// DEBUG_PRINT
171