1/*
2 * Copyright (c) 1999-2000, Eric Moon.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions, and the following disclaimer.
11 *
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions, and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * 3. The name of the author may not be used to endorse or promote products
17 *    derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
27 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31
32// NodeSyncThread.cpp
33
34#include "NodeSyncThread.h"
35
36#include <cstring>
37
38#include <Debug.h>
39#include <MediaRoster.h>
40
41__USE_CORTEX_NAMESPACE
42
43// -------------------------------------------------------- //
44// *** dtor/ctors
45// -------------------------------------------------------- //
46
47NodeSyncThread::~NodeSyncThread() {
48	status_t err;
49
50	// clean up
51	if(m_thread) {
52		err = kill_thread(m_thread);
53		if(err < B_OK)
54			PRINT((
55				"! ~NodeSyncThread(): kill_thread(%" B_PRId32 "):\n"
56				"  %s\n",
57				m_thread,
58				strerror(err)));
59
60		// +++++ is a wait_for_thread() necessary?
61	}
62
63	if(m_port) {
64		err = delete_port(m_port);
65		if(err < B_OK)
66			PRINT((
67				"! ~NodeSyncThread(): delete_port(%" B_PRId32 "):\n"
68				"  %s\n",
69				m_port,
70				strerror(err)));
71	}
72
73	if(m_portBuffer)
74		delete [] m_portBuffer;
75	if(m_messenger)
76		delete m_messenger;
77}
78
79NodeSyncThread::NodeSyncThread(
80	const media_node&						node,
81	BMessenger*									messenger) :
82
83	m_node(node),
84	m_messenger(messenger),
85	m_syncInProgress(false),
86	m_thread(0),
87	m_port(0),
88	m_portBuffer(0),
89	m_portBufferSize(sizeof(_sync_op)) {
90
91	ASSERT(m_messenger);
92
93	m_portBuffer = new char[m_portBufferSize];
94
95	m_port = create_port(
96		m_portBufferSize * 16,
97		"NodeSyncThread___port");
98	ASSERT(m_port >= B_OK);
99
100	m_thread = spawn_thread(
101		&_Sync,
102		"NodeSyncThread",
103		B_DISPLAY_PRIORITY,
104		this);
105	ASSERT(m_thread >= B_OK);
106	resume_thread(m_thread);
107}
108
109// -------------------------------------------------------- //
110// *** operations
111// -------------------------------------------------------- //
112
113// trigger a sync operation: when 'perfTime' arrives
114// for the node, a M_SYNC_COMPLETE message with the given
115// position value will be sent,  unless the sync operation
116// times out, in which case M_TIMED_OUT will be sent.
117
118status_t NodeSyncThread::sync(
119	bigtime_t										perfTime,
120	bigtime_t										position,
121	bigtime_t										timeout) {
122
123	status_t err;
124
125	if(m_syncInProgress)
126		return B_NOT_ALLOWED;
127
128	_sync_op op = {perfTime, position, timeout};
129	err = write_port(
130		m_port,
131		M_TRIGGER,
132		&op,
133		sizeof(_sync_op));
134
135	return err;
136}
137
138// -------------------------------------------------------- //
139// *** guts
140// -------------------------------------------------------- //
141
142/*static*/
143status_t NodeSyncThread::_Sync(
144	void*												cookie) {
145	((NodeSyncThread*)cookie)->_sync();
146	return B_OK;
147}
148
149// THREAD BODY
150//
151void NodeSyncThread::_sync() {
152	ASSERT(m_port >= B_OK);
153	ASSERT(m_messenger);
154
155	bool done = false;
156	while(!done) {
157
158		// WAIT FOR A REQUEST
159		int32 code;
160		ssize_t readCount = read_port(
161			m_port,
162			&code,
163			m_portBuffer,
164			m_portBufferSize);
165
166		if(readCount < B_OK) {
167			PRINT((
168				"! NodeSyncThread::_sync(): read_port():\n"
169				"  %s\n",
170				strerror(readCount)));
171			continue;
172		}
173
174		if(code != M_TRIGGER) {
175			PRINT((
176				"! NodeSyncThread::sync(): unknown message code %" B_PRId32
177					"\n", code));
178			continue;
179		}
180
181		// SERVICE THE REQUEST
182		const _sync_op& op = *(_sync_op*)m_portBuffer;
183
184		// pre-fill the message
185		BMessage m(M_SYNC_COMPLETE);
186		m.AddInt32("nodeID", m_node.node);
187		m.AddInt64("perfTime", op.targetTime);
188		m.AddInt64("position", op.position);
189
190		// sync
191		status_t err = BMediaRoster::Roster()->SyncToNode(
192			m_node,
193			op.targetTime,
194			op.timeout);
195
196		// deliver reply
197		if(err < B_OK) {
198			m.what = M_SYNC_FAILED;
199			m.AddInt32("error", err);
200		}
201
202		err = m_messenger->SendMessage(&m);
203		if(err < B_OK) {
204			PRINT((
205				"! NodeSyncThread::_sync(): m_messenger->SendMessage():\n"
206				"  %s\n",
207				strerror(err)));
208		}
209	}
210}
211
212
213// END -- NodeSyncThread.cpp --
214