xref: /haiku/src/apps/debugger/user_interface/report/ReportUserInterface.cpp (revision 5e7964b0a929555415798dea3373db9ac4611caa)
1 /*
2  * Copyright 2015-2016, Rene Gollent, rene@gollent.com.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include "ReportUserInterface.h"
8 
9 #include <stdio.h>
10 
11 #include <Entry.h>
12 #include <FindDirectory.h>
13 #include <Path.h>
14 
15 #include <AutoLocker.h>
16 
17 #include "MessageCodes.h"
18 #include "UiUtils.h"
19 
20 
21 ReportUserInterface::ReportUserInterface(thread_id targetThread,
22 	const char* reportPath)
23 	:
24 	fTeam(NULL),
25 	fListener(NULL),
26 	fTargetThread(targetThread),
27 	fReportPath(reportPath),
28 	fShowSemaphore(-1),
29 	fReportSemaphore(-1),
30 	fShown(false),
31 	fTerminating(false)
32 {
33 }
34 
35 
36 ReportUserInterface::~ReportUserInterface()
37 {
38 	if (fShowSemaphore >= 0)
39 		delete_sem(fShowSemaphore);
40 
41 	fTeam->RemoveListener(this);
42 }
43 
44 
45 const char*
46 ReportUserInterface::ID() const
47 {
48 	return "ReportUserInterface";
49 }
50 
51 
52 status_t
53 ReportUserInterface::Init(Team* team, UserInterfaceListener* listener)
54 {
55 	fShowSemaphore = create_sem(0, "show report");
56 	if (fShowSemaphore < 0)
57 		return fShowSemaphore;
58 
59 	fReportSemaphore = create_sem(0, "report generator wait");
60 	if (fReportSemaphore < 0)
61 		return fReportSemaphore;
62 
63 	fTeam = team;
64 	fListener = listener;
65 
66 	fTeam->AddListener(this);
67 
68 	return B_OK;
69 }
70 
71 
72 void
73 ReportUserInterface::Show()
74 {
75 	fShown = true;
76 	release_sem(fShowSemaphore);
77 }
78 
79 
80 void
81 ReportUserInterface::Terminate()
82 {
83 	fTerminating = true;
84 }
85 
86 
87 UserInterface*
88 ReportUserInterface::Clone() const
89 {
90 	// the report interface does not support cloning, since
91 	// it won't ever be asked to interactively restart.
92 	return NULL;
93 }
94 
95 
96 bool
97 ReportUserInterface::IsInteractive() const
98 {
99 	return false;
100 }
101 
102 
103 status_t
104 ReportUserInterface::LoadSettings(const TeamUiSettings* settings)
105 {
106 	return B_OK;
107 }
108 
109 
110 status_t
111 ReportUserInterface::SaveSettings(TeamUiSettings*& settings) const
112 {
113 	return B_OK;
114 }
115 
116 
117 void
118 ReportUserInterface::NotifyUser(const char* title, const char* message,
119 	user_notification_type type)
120 {
121 }
122 
123 
124 void
125 ReportUserInterface::NotifyBackgroundWorkStatus(const char* message)
126 {
127 }
128 
129 
130 int32
131 ReportUserInterface::SynchronouslyAskUser(const char* title,
132 	const char* message, const char* choice1, const char* choice2,
133 	const char* choice3)
134 {
135 	return -1;
136 }
137 
138 
139 status_t
140 ReportUserInterface::SynchronouslyAskUserForFile(entry_ref* _ref)
141 {
142 	return B_UNSUPPORTED;
143 }
144 
145 
146 void
147 ReportUserInterface::Run()
148 {
149 	// Wait for the Show() semaphore to be released.
150 	status_t error;
151 	do {
152 		error = acquire_sem(fShowSemaphore);
153 	} while (error == B_INTERRUPTED);
154 
155 	if (error != B_OK)
156 		return;
157 
158 	bool waitNeeded = false;
159 	if (fTargetThread > 0) {
160 		AutoLocker< ::Team> teamLocker(fTeam);
161 		::Thread* thread = fTeam->ThreadByID(fTargetThread);
162 		if (thread == NULL)
163 			waitNeeded = true;
164 		else if (thread->State() != THREAD_STATE_STOPPED) {
165 			waitNeeded = true;
166 			fListener->ThreadActionRequested(fTargetThread, MSG_THREAD_STOP);
167 		}
168 	}
169 
170 	if (waitNeeded) {
171 		do {
172 			error = acquire_sem(fShowSemaphore);
173 		} while (error == B_INTERRUPTED);
174 
175 		if (error != B_OK)
176 			return;
177 	}
178 
179 	entry_ref ref;
180 	if (fReportPath != NULL && fReportPath[0] == '/') {
181 		error = get_ref_for_path(fReportPath, &ref);
182 	} else {
183 		char filename[B_FILE_NAME_LENGTH];
184 		if (fReportPath != NULL)
185 			strlcpy(filename, fReportPath, sizeof(filename));
186 		else
187 			UiUtils::ReportNameForTeam(fTeam, filename, sizeof(filename));
188 
189 		BPath path;
190 		error = find_directory(B_DESKTOP_DIRECTORY, &path);
191 		if (error == B_OK)
192 			error = path.Append(filename);
193 		if (error == B_OK)
194 			error = get_ref_for_path(path.Path(), &ref);
195 	}
196 
197 	if (error != B_OK)
198 		printf("Unable to get ref for report path %s\n", strerror(error));
199 	else {
200 		fListener->DebugReportRequested(&ref);
201 
202 		do {
203 			error = acquire_sem(fReportSemaphore);
204 		} while (error == B_INTERRUPTED);
205 	}
206 
207 	fListener->UserInterfaceQuitRequested(
208 		UserInterfaceListener::QUIT_OPTION_ASK_KILL_TEAM);
209 }
210 
211 
212 void
213 ReportUserInterface::ThreadAdded(const Team::ThreadEvent& event)
214 {
215 	::Thread* thread = event.GetThread();
216 	if (thread->ID() != fTargetThread)
217 		return;
218 
219 	if (thread->State() != THREAD_STATE_STOPPED)
220 		fListener->ThreadActionRequested(thread->ID(), MSG_THREAD_STOP);
221 	else
222 		release_sem(fShowSemaphore);
223 }
224 
225 
226 void
227 ReportUserInterface::ThreadStateChanged(const Team::ThreadEvent& event)
228 {
229 	::Thread* thread = event.GetThread();
230 	if (thread->ID() != fTargetThread)
231 		return;
232 	else if (thread->State() == THREAD_STATE_STOPPED)
233 		release_sem(fShowSemaphore);
234 }
235 
236 
237 void
238 ReportUserInterface::DebugReportChanged(const Team::DebugReportEvent& event)
239 {
240 	if (event.GetFinalStatus() == B_OK)
241 		printf("Debug report saved to %s\n", event.GetReportPath());
242 	else {
243 		fprintf(stderr, "Failed to write debug report: %s\n", strerror(
244 				event.GetFinalStatus()));
245 	}
246 	release_sem(fReportSemaphore);
247 }
248