Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / sam-t2 / sam / include / vtracer_async_queue.h
/*
* ========== Copyright Header Begin ==========================================
*
* OpenSPARC T2 Processor File: vtracer_async_queue.h
* Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES.
*
* The above named program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License version 2 as published by the Free Software Foundation.
*
* The above named program is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
*
* ========== Copyright Header End ============================================
*/
////////////////////////////////////////////////////////////
//
// File: vtracer_async_queue.h
//
// Copyright (C) 2001-2006 Sun Microsystems, Inc.
// All rights reserved.
//
// re-entrant queue structure for devices to send dma's, strings etc to the tracer
// this is the interface between blaze, the vcpu and devices (not relevant to tracer)
// use dd if=/dev/random | od -XN 8 to get the random suffix
#ifndef _vtracer_async_queue_h_8b214547ac275755_
#define _vtracer_async_queue_h_8b214547ac275755_
class vtracer_async_queue_el {
public:
vtracer_async_queue_el(const union vtracer_async_data_u * arg_data) {
memcpy(&data, arg_data, sizeof(union vtracer_async_data_u));
next = NULL;
}
union vtracer_async_data_u data;
vtracer_async_queue_el * next;
}; // struct vtracer_async_queue_el
class vtracer_async_queue {
public:
vtracer_async_queue() {
mutex_init(&mu, NULL, NULL);
head = tail = NULL;
qsize = 0;
}
// for fast, non-locking "single reader" use
// example: if (trace_async_queue->getsize()) { dequeue(...); if (rtype_DMA) vtracer->dma(...); }
// this avoids the lock/unlock operations when the queue is empty, which is the common case
int getsize() {
return qsize;
}
// use dequeue() in conjunction with getsize() for fast single-reader use
// if multiple threads wish to dequeue, they must call mt_dequeue() instead of getsize() and dequeue()
// WARNING: precondition: head != NULL. must enforce by calling is_empty before calling dequeue
// WARNING: only one thread can "own" the queue - ie call is_empty() and dequeue().
void dequeue(vtracer_async_data_u * data) {
volatile vtracer_async_queue_el * el = head;
mutex_lock(&mu);
head = el->next;
if (head == NULL) tail = NULL;
qsize --;
mutex_unlock(&mu);
memcpy((void *) data, (void *) &el->data, sizeof(vtracer_async_data_u));
delete el;
} // void dequeue(int &iswrite, uint64_t &paddr, int64_t &nbytes)
// enqueue is called by (multiple) writer threads to add async records
void enqueue(vtracer_async_data_u * data) {
vtracer_async_queue_el * el = new vtracer_async_queue_el(data);
mutex_lock(&mu);
if (tail != NULL) {
tail->next = el;
} else {
head = el;
}
tail = el;
qsize ++;
mutex_unlock(&mu);
} // void enqueue(int iswrite, uint64_t paddr, int64_t nbytes)
// mt_dequeue atomically checks if the async queue is empty and dequeues the head if non-empty.
// Use it if multiple threads want to read out of the queue.
// Returns zero if queue was empty, positive otherwise. The number of records remaining is (return_value-1) or 0 if empty
//
// example: if (mt_dequeue(...)) if (dma) vtracer->dma(...); etc
int mt_dequeue(vtracer_async_data_u * data) {
mutex_lock(&mu);
int rv = qsize;
if (qsize) {
volatile vtracer_async_queue_el * el = head;
head = el->next;
if (head == NULL) tail = NULL;
qsize--;
memcpy((void *) data, (void *) &el->data, sizeof(vtracer_async_data_u));
delete el;
}
mutex_unlock(&mu);
return rv;
} // int mt_dequeue(vtracer_async_data_u * data)
private:
mutex_t mu;
volatile int qsize;
volatile vtracer_async_queue_el * head;
volatile vtracer_async_queue_el * tail;
}; // class vtracer_async_queue
// this is instantiated elsewhere in blaze initialization code
extern vtracer_async_queue * trace_async_queue;
#define TRACE_DMA(TD_iswrite, TD_nbytes, TD_pa, TD_devid) \
if (g_vcpu[g_vcpu_id_max]->config.trace_on) { \
vtracer_async_data_u ad = {0}; \
ad.dma.rtype = vtracer_async_data_u::rtype_DMA; \
ad.dma.iswrite = TD_iswrite; \
ad.dma.nbytes = TD_nbytes; \
ad.dma.pa = TD_pa; \
ad.dma.devid = TD_devid; \
trace_async_queue->enqueue(&ad); \
}
#endif // _vtracer_async_queue_h_8b214547ac275755_