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) 2000 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: trccirc.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 <kernel/func.h>
#include <kernel/mem.h>
#include <kernel/log.h>

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

#include <fs/fs.h>

#include <unistd.h>
#include <fcntl.h>
#include <limits.h>

/* Well... this file is very similar to trcfixed.c! */

typedef struct TAGcircular_queue_t {
  /*+ size of the queue +*/
  int         size;
  /*+ index of the next insertion into the queue +*/
  int         index;
  /*+ index of the next item to write (if online_tracer activated) +*/
  int         windex;
  /*+ number of events lost (if online_tracer activated) +*/
  long        hoops;
  /*+ filename of the trace file +*/
  char        *filename;
  /*+ flags from flags field of the initialization struct +*/
  int         flags;
  /*+ some internal models have needed of extra parameters +*/
  void        *dummy;
  /*+ unique number that identify the queue +*/
  int         uniq;
 
  /*+ events table +*/
  trc_event_t table[0];  
} circular_queue_t;

static int mustgodown=0;

static TASK online_tracer(circular_queue_t *queue)
{
  char pathname[PATH_MAX];
  int handle;
  int index;

  if (queue->filename==NULL) trc_create_name("cir",queue->uniq,pathname);
  else trc_create_name(queue->filename,0,pathname);

  if (wait_for_fs_initialization()) {
    printk(KERN_NOTICE "tracer online task not running");
    goto BADEND;
  }
   
  handle=open(pathname,O_CREAT|O_TRUNC|O_WRONLY);
  if (handle==-1) {
    printk(KERN_NOTICE "tracer file %s not created!",pathname);
    goto BADEND;
  }
 
  for (;;) {
    while (queue->index!=queue->windex) {
      index=queue->index;
      if (index<queue->windex) {
        write(handle,
              queue->table+queue->windex,
              (queue->size-queue->windex)*sizeof(trc_event_t)
              );
        queue->windex=0;
        continue;
      }
      write(handle,
            queue->table+queue->windex,
            (index-queue->windex)*sizeof(trc_event_t)
            );
      queue->windex=index;
    }
    if (mustgodown) break;
   
    task_endcycle();
  }
 
  close(handle);
  printk(KERN_NOTICE "tracer file %s created!",pathname);

  if (queue->hoops)
    printk(KERN_NOTICE "tracer: %li event lost into %s",queue->hoops,pathname);

  resume_fs_shutdown();
  return NULL;

BADEND:
  resume_fs_shutdown();
 
  /*Why this? for a little bug on the task_makefree() routine */
  for (;;) {
    if (mustgodown) break;
    task_endcycle();
  }
 
  return NULL;  
}

static trc_event_t *circular_get2(circular_queue_t *queue)
{
  if (queue->index==queue->size-1) {
    if (queue->windex==0) {
      queue->hoops++;
      return NULL;
    }
    queue->index=0;
    return &queue->table[queue->size-1];
  }  
  if (queue->index+1==queue->windex) {
    queue->hoops++;
    return NULL;
  }
  return &queue->table[queue->index++];
}

static trc_event_t *circular_get1(circular_queue_t *queue)
{
  if (queue->index==queue->size-1) {
    queue->index=0;
    return &queue->table[queue->size-1];
  }
  return &queue->table[queue->index++];
}

static int circular_post(circular_queue_t *queue)
{
  return 0;
}

struct create_args {
  long             period;
  long             slice;
  circular_queue_t *queue;
};


/* to remove!!! */
/*
static void circular_create_postponed(void *foo)
{
  struct create_args *ptr=(struct create_args *)foo;
  SOFT_TASK_MODEL model;
  PID pid;

  printk(KERN_DEBUG "postponed create: START");
 
  soft_task_default_model(model);
  soft_task_def_system(model);
  soft_task_def_notrace(model);
  soft_task_def_periodic(model);
  soft_task_def_period(model,ptr->period);
  soft_task_def_met(model,ptr->slice);
  soft_task_def_wcet(model,ptr->slice);
  soft_task_def_arg(model,ptr->queue);

  printk(KERN_DEBUG "postponed create: A");
 
  kern_free(foo,sizeof(struct create_args));

  printk(KERN_DEBUG "postponed create: B");
           
  pid=task_create("trcCirc",online_tracer,&model,NULL);
  if (pid==-1) {
    printk(KERN_ERR "can't start tracer online circular trace task");
  } else {
    printk(KERN_DEBUG "postponed create: C1");
    task_activate(pid);
    printk(KERN_DEBUG "postponed create: C2");
    suspend_fs_shutdown();
    printk(KERN_DEBUG "postponed create: C3");
  }

  printk(KERN_DEBUG "postponed create: END");
}
*/


static int circular_create(trc_queue_t *queue, TRC_CIRCULAR_PARMS *args)
{
  TRC_CIRCULAR_PARMS defaultargs;
  circular_queue_t *ptr;

  if (args==NULL) {
    trc_circular_default_parms(defaultargs);
    args=&defaultargs;
  }
 
  ptr=(circular_queue_t*)kern_alloc(sizeof(circular_queue_t)+
                                    sizeof(trc_event_t)*args->size);
  if (ptr==NULL) return -1;

  queue->get=(trc_event_t*(*)(void*))circular_get1;
  queue->post=(int(*)(void*))circular_post;
  queue->data=ptr;
 
  ptr->size=args->size;
  ptr->windex=ptr->index=0;
  ptr->hoops=0;
  ptr->filename=args->filename;
  ptr->flags=args->flags;
  ptr->dummy=NULL;
 
  if (args->flags&TRC_CIRCULAR_ONLINETASK) {
    struct create_args *p;
    p=kern_alloc(sizeof(struct create_args));
    if (p==NULL) {
      printk(KERN_ERR "can't create tracer online circular trace task");
      return -1;
    }
    queue->get=(trc_event_t*(*)(void*))circular_get2;
    ptr->dummy=p;
   
    p->period=args->period;
    p->slice=args->slice;
    p->queue=ptr;
    //sys_atrunlevel(circular_create_postponed,(void*)p,RUNLEVEL_INIT);    
  }
 
  return 0;
}

static int circular_activate(circular_queue_t *queue, int uniq)
{
  queue->uniq=uniq;

  if (queue->flags&TRC_CIRCULAR_ONLINETASK) {
   
    struct create_args *ptr=(struct create_args *)queue->dummy;
    SOFT_TASK_MODEL model;
    PID pid;

    printk(KERN_DEBUG "postponed create: START");
   
    soft_task_default_model(model);
    soft_task_def_system(model);
    soft_task_def_notrace(model);
    soft_task_def_periodic(model);
    soft_task_def_period(model,ptr->period);
    soft_task_def_met(model,ptr->slice);
    soft_task_def_wcet(model,ptr->slice);
    soft_task_def_arg(model,ptr->queue);

    printk(KERN_DEBUG "postponed create: A");
 
    kern_free(queue->dummy,sizeof(struct create_args));

    printk(KERN_DEBUG "postponed create: B");
           
    pid=task_create("trcCirc",online_tracer,&model,NULL);
    if (pid==-1) {
      printk(KERN_ERR "can't start tracer online circular trace task");
    } else {
      printk(KERN_DEBUG "postponed create: C1");
      suspend_fs_shutdown();
      printk(KERN_DEBUG "postponed create: C2");      
      task_activate(pid);
      printk(KERN_DEBUG "postponed create: C3");
    }

    printk(KERN_DEBUG "postponed create: END");    
  }
 
  return 0;
}

static TASK circular_shutdown(circular_queue_t *queue)
{
  char pathname[PATH_MAX];
  int h;
 
  if (queue->filename==NULL) trc_create_name("cir",queue->uniq,pathname);
  else trc_create_name(queue->filename,0,pathname);
 
  h=open(pathname,O_CREAT|O_TRUNC|O_WRONLY);
  if (h!=-1) {
    if (queue->index!=queue->size-1)
      write(h,
            queue->table+queue->index+1,
            (queue->size-queue->index-1)*sizeof(trc_event_t)
            );
    write(h,
          queue->table,
          queue->index*sizeof(trc_event_t)
          );
    close(h);
    printk(KERN_NOTICE "tracer file %s created!",pathname);
  }  else
    printk(KERN_NOTICE "tracer file %s NOT created!",pathname);
 
  resume_fs_shutdown();
  return NULL;
}

static int circular_terminate(circular_queue_t *queue)
{
  SOFT_TASK_MODEL model;
  PID pid;

  mustgodown=1;
  if (queue->flags&TRC_CIRCULAR_ONLINETASK) return 0;

  suspend_fs_shutdown();
 
  //nrt_task_default_model(model);
  //nrt_task_def_system(model);
  //nrt_task_def_arg(model,queue);

  soft_task_default_model(model);
  soft_task_def_system(model);
  soft_task_def_notrace(model);
  soft_task_def_periodic(model);
  soft_task_def_period(model,50000);
  soft_task_def_met(model,10000);
  soft_task_def_wcet(model,10000);
  soft_task_def_arg(model,queue);
 
  pid=task_create("ShutTrcCir",circular_shutdown,&model,NULL);
  if (pid==-1) {
    printk(KERN_ERR "can't start tracer shutdown task (circular)");
    return -1;
  } else
    task_activate(pid);

  return 0;
}

int trc_register_circular_queue(void)
{
  int res;
 
  res=trc_register_queuetype(TRC_CIRCULAR_QUEUE,
                             (int(*)(trc_queue_t*,void*))circular_create,
                             (int(*)(void*,int))circular_activate,
                             (int(*)(void*))circular_terminate
                             );
 
  if (res!=0) printk(KERN_WARNING "can't register tracer circular queue");
  return res;
}