Subversion Repositories shark

Rev

Rev 2 | Blame | Compare with Previous | Last modification | View Log | RSS feed

/*
 * Project: S.Ha.R.K.
 *
 * Coordinators:
 *   Giorgio Buttazzo    <giorgio@sssup.it>
 *   Paolo Gai           <pj@gandalf.sssup.it>
 *
 * Authors     :
 *   Paolo Gai           <pj@gandalf.sssup.it>
 *   Massimiliano Giorgi <massy@gandalf.sssup.it>
 *   Luca Abeni          <luca@gandalf.sssup.it>
 *   (see the web pages for full authors list)
 *
 * ReTiS Lab (Scuola Superiore S.Anna - Pisa - Italy)
 *
 * http://www.sssup.it
 * http://retis.sssup.it
 * http://shark.sssup.it
 */


/*
 * Copyright (C) 1999 Massimiliano Giorgi
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This 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 program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */


/*
 * CVS :        $Id: trace.c,v 1.1.1.1 2002-03-29 14:12:52 pj Exp $
 *
 * File:        $File$
 * Revision:    $Revision: 1.1.1.1 $
 * Last update: $Date: 2002-03-29 14:12:52 $
 */


#include <ll/sys/types.h>
#include <ll/stdlib.h>
#include <ll/string.h>

#include <kernel/func.h>
#include <kernel/trace.h>

#include <trace/types.h>
#include <trace/trace.h>
#include <trace/queues.h>

#include <bits/limits.h>

#define TRC_MAXQUEUES 5

/*
 *
 */


static char basepath[PATH_MAX];

void trc_create_name(char *basename, int uniq, char *pathname)
{
  if (uniq) sprintf(pathname,"%s/%s%i",basepath,basename,uniq);
  else      sprintf(pathname,"%s/%s",basepath,basename);
}

/*
 *
 */


#define FLAG_NOTRACE 0x01

typedef struct TAGtrc_evtinfo_t {
  trc_queue_t *queue;
  unsigned    flags;
} trc_evtinfo_t;

/* -- */

trc_evtinfo_t eventstable[TRC_NUMEVENTS];

int (*createqueue[TRC_QUEUETYPESNUMBER])(trc_queue_t *, void *);
int (*activatequeue[TRC_QUEUETYPESNUMBER])(void *,int);
int (*terminatequeue[TRC_QUEUETYPESNUMBER])(void *);

trc_queue_t queuetable[TRC_MAXQUEUES];
trc_queue_t queuesink;
int numqueues;

/* -- */

static trc_event_t *dummy_get(void *foo)
{  
  return NULL;
}

static int dummy_post(void *foo)
{
  return 0;
}

static int dummy_createqueue(trc_queue_t *queue, void *unused)
{
  queue->get=dummy_get;
  queue->post=dummy_post;
  queue->data=NULL;
  return 0;
}

static int dummy_terminatequeue(void *unused)
{
  return 0;
}

static int dummy_activatequeue(void *unused, int unused2)
{
  return 0;
}

/* -- */

int trc_register_queuetype(int queuetype,
                           int(*creat)(trc_queue_t *, void *),
                           int(*activate)(void *,int),
                           int(*term)(void *))
{
  if (queuetype<0||queuetype>=TRC_QUEUETYPESNUMBER) return -1;
  createqueue[queuetype]=creat;
  activatequeue[queuetype]=activate;
  terminatequeue[queuetype]=term;
  return 0;
}

int trc_create_queue(int queuetype, void *args)
{
  int res;

  if (createqueue[queuetype]==dummy_createqueue) return -1;
  if (numqueues==TRC_MAXQUEUES) return -1;
  res=createqueue[queuetype](&queuetable[numqueues],args);
  if (res) return -1;
  queuetable[numqueues].type=queuetype;
  numqueues++;
  return numqueues-1;
}

/* -- */

static void (*old_logevent)(int event, void *ptr)=NULL;
static void internal_trc_logevent(int, void *ptr);

static void trc_end(void *unused)
{
  int i;
 
  printk(KERN_INFO "tracer shutdown...");
 
  /* suspend event logging */
  trc_suspend();

  /* for safety: send all events to the sink queue */
  for (i=0;i<TRC_NUMEVENTS;i++) {
    eventstable[i].queue=&queuesink;
    eventstable[i].flags|=FLAG_NOTRACE;
  }
 
  /* terminate all queues */
  for (i=0;i<numqueues;i++)
    terminatequeue[queuetable[i].type](queuetable[i].data);
}

static int internal_trc_resume(void);
static int internal_trc_suspend(void);

int TRC_init_phase1(TRC_PARMS *parms)
{
  int i;
 
  printk(KERN_INFO "initializing tracer...");
 
  for (i=0;i<TRC_QUEUETYPESNUMBER;i++) {
    createqueue[i]=dummy_createqueue;
    terminatequeue[i]=dummy_terminatequeue;
  }
  dummy_createqueue(&queuesink,NULL);
  numqueues=0;
 
  for (i=0;i<TRC_NUMEVENTS;i++) {
    eventstable[i].queue=&queuesink;
    eventstable[i].flags=FLAG_NOTRACE;
  }
 
  i=sys_atrunlevel(trc_end,NULL,RUNLEVEL_SHUTDOWN);

  {
    TRC_PARMS m;
    trc_default_parms(m);
    if (parms==NULL) parms=&m;

    strncpy(basepath,parms->path,sizeof(basepath));
    basepath[sizeof(basepath)-1]='\0';
  }

  trc_suspend=internal_trc_suspend;
  trc_resume=internal_trc_resume;
   
  trc_resume();
  return 0;
}

int TRC_init_phase2(void)
{
  int i;
  for (i=0;i<numqueues;i++)
    activatequeue[queuetable[i].type](queuetable[i].data,i+1);
  return 0;
}

static int internal_trc_resume(void)
{
  SYS_FLAGS f;
  int ret=-1;
  f=kern_fsave();
  if (old_logevent==NULL) {  
    old_logevent=trc_logevent;
    trc_logevent=internal_trc_logevent;
    ret=0;
  }
  kern_frestore(f);
  return ret;
}

static int internal_trc_suspend(void)
{
  SYS_FLAGS f;
  int ret=-1;
  f=kern_fsave();
  if (old_logevent!=NULL) {    
    trc_logevent=old_logevent;
    old_logevent=NULL;
    ret=0;
  }
  kern_frestore(f);
  return 0;
}

static void internal_trc_logevent(int event, void *ptr)
{
  trc_event_t   *evt;
  trc_queue_t   *queue;
  SYS_FLAGS f;

  f=kern_fsave();

  if (eventstable[event].flags&FLAG_NOTRACE) {
    kern_frestore(f);
    return;
  }
  queue=eventstable[event].queue;
 
  evt=queue->get(queue->data);
  if (evt!=NULL) {
    evt->event=event;
    evt->time=ll_gettime(TIME_EXACT,NULL);
    memcpy(&evt->x,ptr,sizeof(trc_allevents_t));
    queue->post(queue->data);
  }
 
  kern_frestore(f);
}

/*
 *
 *
 *
 */


int classtable[TRC_NUMCLASSES+1]={
  TRC_F_TRACER,
  TRC_F_SYSTEM,
  TRC_F_USER,
  TRC_F_LL,
  TRC_F_SEM,
  TRC_F_LAST
};

#define checkevent(x)   if ((x)<0||(x)>=TRC_NUMEVENTS) return -1
#define checkqueue(x)   if ((x)<0||(x)>=numqueues) return -1
#define checkclass(x)   if ((x)<0||(x)>=TRC_NUMCLASSES) return -1

int trc_assign_event_to_queue(int event, int queue)
{
  checkevent(event);
  checkqueue(queue);
  eventstable[event].queue=&queuetable[queue];
  return 0;
}

int trc_assign_class_to_queue(int class, int queue)
{
  int i;
  checkqueue(queue);
  checkclass(class);
  for (i=classtable[class];i<classtable[class+1];i++)
    eventstable[i].queue=&queuetable[queue];
  return 0;
}

int trc_notrace_event(int event)
{
  checkevent(event);
  eventstable[event].flags|=FLAG_NOTRACE;
  return 0;
}

int trc_trace_event(int event)
{
  checkevent(event);
  eventstable[event].flags&=~FLAG_NOTRACE;
  return 0;
}

int trc_notrace_class(int class)
{
  int i;
  checkclass(class);
  for (i=classtable[class];i<classtable[class+1];i++)
    eventstable[i].flags|=FLAG_NOTRACE;
  return 0;
}

int trc_trace_class(int class)
{
  int i;
  checkclass(class);
  for (i=classtable[class];i<classtable[class+1];i++)
    eventstable[i].flags&=~FLAG_NOTRACE;
  return 0;
}


/* -- */

int TRC_init_phase1_standard(void)
{
  int qf,qc;
  int res;
 
  res=TRC_init_phase1(NULL);
  if (res) return res;

  res=trc_register_circular_queue();
  if (res) return res;
  res=trc_register_fixed_queue();
  if (res) return res;

  qc=trc_create_queue(TRC_CIRCULAR_QUEUE,NULL);
  qf=trc_create_queue(TRC_FIXED_QUEUE,NULL);
  if (qc==-1||qf==-1) return -97;

  res=trc_trace_class(TRC_CLASS_SYSTEM);
  if (res) return res;
  res=trc_assign_class_to_queue(TRC_CLASS_SYSTEM,qc);
  if (res) return res;

  return 0;
}

int TRC_init_phase2_standard(void)
{
  return TRC_init_phase2();
}