1/*
2 * Copyright 2003-2006, Haiku.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		IngoWeinhold <bonefish@cs.tu-berlin.de>
7 */
8
9#include "Debug.h"
10
11#include <errno.h>
12#include <fcntl.h>
13#include <stdarg.h>
14#include <stdio.h>
15#include <string.h>
16#include <unistd.h>
17
18#include <OS.h>
19
20/*!
21	\file Debug.cpp
22	\brief Defines debug output function with printf() signature printing
23		   into a file.
24
25	\note The initialization is not thread safe!
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#if DEBUG_PRINT
35static int out = -1;
36#endif
37
38// init_debugging
39status_t
40init_debugging()
41{
42	status_t error = B_OK;
43	if (init_counter++ == 0) {
44		// open the file
45		#if DEBUG_PRINT
46			out = open(DEBUG_PRINT_FILE, O_RDWR | O_CREAT | O_TRUNC);
47			if (out < 0) {
48				error = errno;
49				init_counter--;
50			}
51		#endif	// DEBUG_PRINT
52		// allocate the semaphore
53		if (error == B_OK) {
54			dbg_printf_sem = create_sem(1, "dbg_printf");
55			if (dbg_printf_sem < 0)
56				error = dbg_printf_sem;
57		}
58		if (error == B_OK) {
59			#if DEBUG
60				__out("##################################################\n");
61			#endif
62		} else
63			exit_debugging();
64	}
65	return error;
66}
67
68// exit_debugging
69status_t
70exit_debugging()
71{
72	status_t error = B_OK;
73	if (--init_counter == 0) {
74		#if DEBUG_PRINT
75			close(out);
76			out = -1;
77		#endif	// DEBUG_PRINT
78		delete_sem(dbg_printf_sem);
79	} else
80		error = B_NO_INIT;
81	return error;
82}
83
84// dbg_printf_lock
85static inline
86bool
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// dbg_printf_unlock
100static inline
101void
102dbg_printf_unlock()
103{
104	thread_id thread = find_thread(NULL);
105	if (thread != dbg_printf_thread)
106		return;
107	dbg_printf_nesting--;
108	if (dbg_printf_nesting == 0) {
109		dbg_printf_thread = -1;
110		release_sem(dbg_printf_sem);
111	}
112}
113
114// dbg_printf_begin
115void
116dbg_printf_begin()
117{
118	dbg_printf_lock();
119}
120
121// dbg_printf_end
122void
123dbg_printf_end()
124{
125	dbg_printf_unlock();
126}
127
128#if DEBUG_PRINT
129
130// dbg_printf
131void
132dbg_printf(const char *format,...)
133{
134	if (!dbg_printf_lock())
135		return;
136	char buffer[1024];
137	va_list args;
138	va_start(args, format);
139	// no vsnprintf() on PPC and in kernel
140	#if defined(__i386__) && USER
141		vsnprintf(buffer, sizeof(buffer) - 1, format, args);
142	#else
143		vsprintf(buffer, format, args);
144	#endif
145	va_end(args);
146	buffer[sizeof(buffer) - 1] = '\0';
147	write(out, buffer, strlen(buffer));
148	dbg_printf_unlock();
149}
150
151#endif	// DEBUG_PRINT
152