segunda-feira, 1 de fevereiro de 2010

Fake kernel ..

This is the implementations of this and I know,
it's realy bad coded ..

files:
common.c -> common functions
scheduler.c -> scheduler functions
process.c -> process functions
filequeue.c -> queue functions
fakek.h -> where all stuff is declared
main.c -> the main program
Makefile -> the make file :P

/*
 * file: common.c
 */
#include <dirent.h>
#include <stdlib.h>
#include <string.h>

void *
xmalloc (size_t size)
{
  void * pool = malloc (size);
  if (pool == NULL)
 err (1, "xmalloc");
  return pool;
}

DIR *
xopendir (const char * dirname)
{
  DIR * dp = opendir (dirname);
  if (dp == NULL)
 err (1, "xopendir");
  return dp;
}

int 
xopen (const char * filename, int state, mode_t mode)
{
  int fd = open (filename, state, mode);
  if (fd == -1)
 err (1, "xopen\n");
  return fd;
}

char * 
create_filepath (const char * dir, const char * file)
{
  char * path = (char *) xmalloc ((size_t) strlen (dir) + strlen (file) +1);
  memset (path, 0, strlen (dir) + strlen (file) +1);
  strncpy (path, dir, strlen (dir));
  strncat (path, file, strlen (file));
  return path;
}

void xrename (const char * old, const char * new)
{
  int rval = rename (old, new);
  if (rval == -1)
 err (1, "xrename");
}


/*
 * file scheduler.c
 */
#include "fakek.h"


queue_type QBuffer;
const char * userdir = "./fstack/User/";
const char * sysdir = "./fstack/System/";
const char * rdir = "./fstack/Running/";  

/* Save function to queue process */
void 
Sched_writebuf (unsigned int pid, unsigned int state, unsigned int fork,
    unsigned int stopline, unsigned int spendtime,
    unsigned int priority, char * filename)
{
  /* Write here */
  QBuffer.proc.pid = pid;
  QBuffer.proc.state = state;
  QBuffer.proc.fork = fork;
  QBuffer.proc.stopline = stopline;
  QBuffer.proc.spendtime = spendtime;
  QBuffer.proc.priority = priority;
  //  QBuffer.proc.filename = (char *) xmalloc (strlen (filename) + 1);
  /* This will be freed with q_read() */
  strncpy (QBuffer.proc.filename, filename, strlen (filename));
  QBuffer.proc.filename [strlen (filename)] = '\0';
  /* Send to Queue, the q_write increments QSize */
  q_write (& QBuffer);
}
  

/* 
 * return a regular file entry 
 * consecutive calls return consecutive file entries 
 * it uses Scheddir poiter, that must be a non-NULL pointer
 * otherwise the behavior is undefined 
 */
struct dirent *
Sched_getrfile (DIR * dirp)
{
  struct dirent * entry_ptr;
  while (entry_ptr = readdir (dirp))
 if (entry_ptr->d_type & DT_REG)
   return entry_ptr;
  /* There is no regular files in this diretory */ 
  return NULL;
}


/* This is the scheduler itself */ 
void *
Scheduler_thread (void * unused)
{
  struct timespec time = { 0, 1000 };
  struct dirent * entry_ptr;
  int sys_switch;
  char * snew, * sold;
  DIR * tmpdir_ptr;
  /* While forever */
  while (1) {
 /* Search first for System process after User process */ 
 sys_switch = 0;
 while (1) {
   pthread_mutex_lock (&mutex);
   printf ("SCHEDULER LOOP START\n");
   /* open system dir */
   tmpdir_ptr = xopendir (sysdir);
   entry_ptr = Sched_getrfile (tmpdir_ptr);
   closedir (tmpdir_ptr);
   if (entry_ptr != NULL) {
  /* We got one system process */
  sys_switch++;
  pthread_mutex_unlock (&mutex);
  break;
   }
   /* open user dir */
   tmpdir_ptr = xopendir (userdir);
   entry_ptr = Sched_getrfile (tmpdir_ptr);
   closedir (tmpdir_ptr);
   if (entry_ptr != NULL) {
  /* We got one user process */
  pthread_mutex_unlock (&mutex);
  break;
   }
   /* There is no more process */
   sleep (1);
   printf ("SCHEDULER LOOP /* NO NEW PROCESS */\n");
   pthread_mutex_unlock (&mutex);
   /* Wait 1000 nanoseconds to search again */
   nanosleep (&time, NULL);
 } 
 pthread_mutex_lock (&mutex);
 sleep (1);
 printf ("\E[31mNew process arise: %s\n\E[0m", entry_ptr->d_name);
 sleep (1);
 if (sys_switch) {
   sold = create_filepath (sysdir, entry_ptr->d_name);
   snew = create_filepath (rdir, entry_ptr->d_name);
   printf ("\E[31mmoving %s -> %s\n\E[0m", sold, snew);
   sleep (1);
   rename (sold, snew);
   free (sold);
   free (snew);
   printf ("\E[31mScheduling system proc Pid:%d\n\E[0m", 10 + PidCounter);
   sleep (1);
   /* pid, state, fork, stopline, spendtime, priority, filename */
   Sched_writebuf (10 + PidCounter, 0, 0, 1, 0, 4, entry_ptr->d_name);
   PidCounter++;
   printf ("\E[31mQueueSize = %d\n\E[0m", QSize);
   sleep (1);
 }
 else {
   sold = create_filepath (userdir, entry_ptr->d_name);
   snew = create_filepath (rdir, entry_ptr->d_name);
   sleep (1);
   printf ("\E[31mmoving %s -> %s\n\E[0m", sold, snew);
   rename (sold, snew);
   free (sold);
   free (snew);
   sleep (1);
   printf ("\E[32mScheduling it Pid:%d\n\E[0m", 10 + PidCounter);
   /* pid, state, fork, stopline, spendtime, priority, filename */
   Sched_writebuf (10 + PidCounter, 0, 0, 1, 0, 1, entry_ptr->d_name);
   PidCounter++;
   sleep (1);
   printf ("\E[32mQueueSize = %d\n\E[0m", QSize);
 }
 sleep (1);
 printf ("SCHEDULER LOOP FINISH\n");
 pthread_mutex_unlock (&mutex);         
 nanosleep (&time, NULL);
  }
}

/*
 * file: process.c
 */
#define MAXPIDNUM 99
#define THREADMAXNANOTIME 1000
#include "fakek.h"

queue_type PBuffer;
pthread_mutex_t Proc_readbuf_mutex = PTHREAD_MUTEX_INITIALIZER;
unsigned int MaxTime;
unsigned int Elapsed = 0;
static char pid_array[MAXPIDNUM + 1];
const char * fdir = "./fstack/Finished/";


void * 
Timer_thread (void * unused)
{ 
  struct timespec ttime = {
 0, THREADMAXNANOTIME
  };
  int oldcancelstate;
  while (Elapsed < MaxTime) {
 nanosleep (&ttime, NULL);
 pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, &oldcancelstate);
 Elapsed++;
 pthread_setcancelstate (oldcancelstate, NULL);
  }
}

char
Proc_setline (int fd, unsigned int stopline)
{
  char ch = 0;
  signed int nbytes;
  unsigned int currentline = 1;
  while (currentline != stopline) {
 nbytes = read (fd, &ch, 1);
 if (nbytes == 0)
   return EOF;
 else if (nbytes == -1)
   err (1, "Proc_setline");
  
 if (ch == '\n')
   currentline++;
  }
}

char
Proc_readline (int fd)
{
  int rval;
  char line[7];
  if (PBuffer.proc.state != 0) 
 /* The process is waiting for other process */
 if (pid_array[PBuffer.proc.state] != 0) 
   /* that not occored yet */
   return 1;
  lseek (fd, 0, SEEK_SET);
  rval = Proc_setline (fd, PBuffer.proc.stopline);
  if (rval == EOF)
 return EOF;
  read (fd, line, 7);
  line[7] = '\0';
  printf ("\E[33m\tExecuting line %d (%s) from file %s\n\E[0m", 
    PBuffer.proc.stopline, line, PBuffer.proc.filename);
  if (strcmp (line, "wait") > 0) {
 /* wait found */
 int pid_to_wait;
 sscanf (line, "wait %d", &pid_to_wait);
 PBuffer.proc.state = pid_to_wait;
 /* This will be 0 again when the process
    `pid_to_wait' ends */
 pid_array[pid_to_wait] = PBuffer.proc.pid;
 PBuffer.proc.stopline++;
 return 1;
  } 
  else if (strcmp (line, "fork 00") == 0) {
 /* fork found */
 PBuffer.proc.stopline++;
 return 2;
  }
 PBuffer.proc.stopline++;
  return 0;
}
 
  
void *
Process_thread (void * unused)
{
  struct timespec process_time = { 0, 1000 };
  pthread_t timer_thread_id;
  int fd; 
  char rval, * old, * new;

 START_PROCESS: while (1) { 

 /* While Queue is empty, Wait */

 while (QSize == 0) 
   nanosleep (&process_time, NULL);

 pthread_mutex_lock (&mutex); 
 printf ("\tPROCESS LOOP START\n");
 sleep (1);
 /* Read a process from queue */
 q_read (&PBuffer);
 printf ("\E[35m\tTaked a process from queue pid:%d | filename %s\n\E[0m", 
   PBuffer.proc.pid, PBuffer.proc.filename);
 printf ("\E[34m\t QueueSize = %d\n", QSize);
 sleep (1);
 /* Start Timer according wiht priority */
 MaxTime = PBuffer.proc.priority;
 char * filename = create_filepath (rdir, PBuffer.proc.filename);
 printf ("\E[33m\topening file %s\n\E[0m", filename);
 fd = xopen (filename, O_RDONLY, 0);
 free (filename); 
 printf ("\E[35m\tStarting timer\n\E[0m");
 pthread_create (&timer_thread_id, NULL, &Timer_thread, NULL);
 /* Until EOF */
 while ((rval = Proc_readline(fd)) != EOF) {
   if (rval == 1) {
  /*
   * This process was set to wait for other process 
   * reshedule it util the wait process ends
   */
  pthread_cancel (timer_thread_id);
  pthread_join (timer_thread_id, NULL);
  close (fd);
  Elapsed = 0;
  printf ("\E[32m\tWaiting for pid:%d\n\E[0m", PBuffer.proc.state);
  Sched_writebuf (PBuffer.proc.pid, PBuffer.proc.state, PBuffer.proc.fork,
      PBuffer.proc.stopline, Elapsed * 1000, PBuffer.proc.priority, 
      PBuffer.proc.filename);
  printf ("\tPROCESS FINISH\n");
  sleep (1);
  pthread_mutex_unlock (&mutex);
  nanosleep (&process_time, NULL);
  goto START_PROCESS;
   }
   else if (rval == 2) {
  /* fork found */
  char * wholefname, * fname, pidchar[2], buf[100];
  int newfiled, nbytes;
  fname = create_filepath ("F", (PBuffer.proc.filename+1));
  wholefname = create_filepath (rdir, fname);
  /* Copy the file */
  printf ("\E[32m\tCopying file %s%s -> %s\n\E[0m", 
    rdir, PBuffer.proc.filename, wholefname);
  newfiled = xopen (wholefname, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
  lseek (fd, 1, SEEK_CUR);
  while ((nbytes = read (fd, buf, 100)) > 0)
   write (newfiled, buf, nbytes);
  if (nbytes == -1)
    errx (1, "read error");
  /* End of copy file */
  printf ("\E[32m\tFork found making a copy of process. Pid: %d\n\E[0m",
    PidCounter + 10);
  Sched_writebuf (PidCounter + 10, PBuffer.proc.state, 2, 1, 
      0, PBuffer.proc.priority, fname);
  free (fname);
  free (wholefname);
  PidCounter++;
  PBuffer.proc.fork = 1; /* this is the original one */
   }
   /* if Time Out, reschedule */
   else if (Elapsed == MaxTime) {
  pthread_join (timer_thread_id, NULL);
  printf ("\E[31m\tTime exceded at priority %d, rescheduling pid:%d %s\n\E[0m", 
    PBuffer.proc.priority, PBuffer.proc.pid, PBuffer.proc.filename);
  Sched_writebuf (PBuffer.proc.pid, PBuffer.proc.state, PBuffer.proc.fork,
      PBuffer.proc.stopline, Elapsed * 1000 + PBuffer.proc.spendtime
      , PBuffer.proc.priority, PBuffer.proc.filename);
  close (fd);
  Elapsed = 0;
  printf ("\tPROCESS FINISH\n");
  sleep (1);
  pthread_mutex_unlock (&mutex);
  nanosleep (&process_time, NULL);
  goto START_PROCESS;
   }
 }
 /* The curret process ends */
 close (fd);
 printf ("\E[31m\tEOF %s\n\E[0m", PBuffer.proc.filename);
 /* if was some other waiting for it .. release */
 if (pid_array[PBuffer.proc.pid] != 0) {
   printf ("\E[32m\tReleazing process pid:%d\n\E[0m", pid_array[PBuffer.proc.pid]);
   pid_array[PBuffer.proc.pid] = 0;
 }
 printf ("\E[31m\tTime expense %d nanoseconds at prioriry %d\n", 
   PBuffer.proc.spendtime + (1000 * Elapsed), PBuffer.proc.priority);
 pthread_cancel (timer_thread_id);
 pthread_join (timer_thread_id, NULL);
 Elapsed = 0;
 new = create_filepath (fdir, PBuffer.proc.filename);
 old = create_filepath (rdir, PBuffer.proc.filename);
 sleep (1);
 printf ("\E[32m\tmoving %s -> %s\n\E[0m", old, new);
 xrename (old, new);
 free (old);
 free (new);
 sleep (1);
 printf ("\tPROCESS LOOP FINISH\n");
 pthread_mutex_unlock (&mutex);
 nanosleep (&process_time, NULL);
  } 
}

/*
 * file: filequeue.c
 */
#include <err.h>
#include <stdlib.h>
#include <string.h>

#include "fakek.h"

/* Init Global variables */
queue_type * GFirst = NULL;
queue_type * GLast = NULL;
unsigned int QSize = 0;
unsigned int PidCounter = 0;

void *
q_write (queue_type * buf)
{
  queue_type * new = (queue_type *) malloc (sizeof (queue_type));
  if (new == NULL)
 errx (2, "q_write (malloc fail)");
  /* Set data */
  memcpy (new, buf, sizeof (queue_type));
  new->next = NULL;
  /* Set Globals */
  if (QSize == 0)
 GFirst = GLast = new;
  else {
 GLast->next = new;
 GLast = new;
  }
  QSize++;
}

void *
q_read (queue_type * buf)
{
  if (QSize < 1)
 errx (1, "Queue is empty, wrong q_read call");
  /* Save data */
  memcpy (buf, GFirst, sizeof (queue_type));
  /* Set Globals */
  queue_type * tmp = GFirst;
  GFirst = GFirst->next;
  /* Free the read data */
  free (tmp);
  /* Set the queue size need be last thing to do
  to avoid race conditions */
  QSize--;
}

void *
q_destroy (void)
{
  unsigned int released_items = 0;
  queue_type * tmp;
  while ((tmp = GFirst) != NULL) {
 GFirst = GFirst->next;
 free (tmp);
 released_items++;
  }
  GLast = NULL;
  QSize = 0;
  return (void *) released_items;
}

/*
 * file: fakek.h
 */
#ifndef FAKEK_H
#define FAKEK_H

#include <dirent.h>
#include <err.h>
#include <fcntl.h>
#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>


/*
 * Defined in filequeue.c
 */
typedef struct proc_strc {
  unsigned int pid;
  unsigned int state;
  unsigned int fork;
  unsigned int stopline;
  unsigned int spendtime;
  unsigned int priority;
  char filename[5];
} proc_type;

typedef struct queue_strc {
  proc_type proc;
  struct queue_strc * next;
} queue_type;

/* Global First and Last processs in Queue */
extern queue_type * GFirst;
extern queue_type * GLast;
/* Queue Size */
extern unsigned int QSize;

/* pid counter */
extern unsigned int PidCounter;

/* Fifo like functions */
extern void * q_write (queue_type *);
extern void * q_read (queue_type *);
extern void * q_destroy (void);


/*
 * Defined in common.c
 */
extern DIR * xopendir (const char *);
extern void * xmalloc (size_t);
extern int xopen (const char *, int, mode_t);
extern char * create_filepath (const char *, const char *);

/* 
 * Defined in scheduler.c
 */
extern const char * userdir;
extern const char * sysdir;
extern const char * rdir;
extern queue_type QBuffer;
extern void Sched_writebuf (unsigned int, unsigned int, unsigned int,
       unsigned int, unsigned int, unsigned int, char *);
extern struct dirent * Sched_getrfile (DIR *);
extern void * Scheduler_thread (void *);

/*
 * Defined int process.c 
 */
extern const char * fdir;
extern queue_type PBuffer;
extern unsigned int MaxTime;
extern unsigned int Elapsed;
extern void * Timer_thread (void *);
extern char Proc_setline (int, unsigned int);
extern char Proc_readline (int fd);
extern void * Process_thread (void *);
#endif 

/*
 * Defined in main 
 */
extern pthread_mutex_t mutex;


/*
 * file: main.c
 */
#include "fakek.h"
#include <pthread.h>

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

int
main (void)
{
  pthread_t Scheduler_id, Process_id;
  pthread_create (&Process_id, NULL, &Process_thread, NULL);  
  pthread_create (&Scheduler_id, NULL, &Scheduler_thread, NULL);
  pthread_join (Scheduler_id, NULL);
  pthread_join (Process_id, NULL);
  
  return 0;
}

fakek: main.c common.o filequeue.o process.o scheduler.o fakek.h
 gcc $(CFLAGS) -o fakek main.c common.o filequeue.o process.o scheduler.o fakek.h -lpthread
 mkdir -p ./fstack/System ./fstack/User ./fstack/Running ./fstack/Finished

common.o: common.c fakek.h
 gcc $(CFLAGS) -c common.c

filequeue.o: filequeue.c fakek.h
 gcc $(CFLAGS) -c filequeue.c

process.o: process.c fakek.h
 gcc $(CFLAGS) -c process.c

scheduler.o: scheduler.c fakek.h
 gcc $(CFLAGS) -c scheduler.c

clean:
 rm -vf common.o fakek filequeue.o process.o scheduler.o 
thats it

stack implementation - Hello World

This is not the right way to do the things..
But.. it works.. doesn't?

first a header/source file

/* 
 * file: table.h
 */
#ifndef TABLE_H
#define TABLE_H

#ifdef DATATYPE
#ifdef BTMAXSIZE

#include <stdlib.h>
#include <err.h>

struct book_strc {
  DATATYPE data;
  struct book_strc * prev;
} book_stack;


/* Book table */
static struct book_strc * book_table[BTMAXSIZE];
/* Number of stacks in table */
static unsigned int tablen = 0;


void *
xmalloc (size_t siz)
{
  register void * pool = malloc (siz);
  if (!pool)
 err (1, "xmalloc");
  return pool;
}


void
bspush (unsigned int tentry, DATATYPE val)
{
  struct book_strc * new = (struct book_strc *) xmalloc (sizeof (struct book_strc));
  new->data = val;
  new->prev = book_table[tentry];  
  tablen++;
  book_table[tentry] = new;
}

void
bspop (unsigned int tentry, DATATYPE * val)
{
  * val = book_table[tentry]->data;
  struct book_strc * tmp = book_table[tentry];
  book_table[tentry] = book_table[tentry]->prev;
  free (tmp);
  tablen--;
}

#endif
#endif
#endif

and a main program using it ..
#include <stdio.h>
#include <stdlib.h>

#define BTMAXSIZE 100
#define DATATYPE char*
#include "table.h"

int
main (void)
{
  char str1[] = "Hello";
  char str2[] = "World";
  char * str3, * str4;

  bspush (0, str1); 
  bspush (1, str2);
  bspop (1, &str4);
  bspop (0, &str3);
  printf ("%s %s\n", str3, str4);
  return 0;
}
output:
Hello World

Usage:
You declare 2 macros
BTMAXSIZE -> this is the max size of the array of stacks
DATATYPE -> this is the data type of stack objects
then you include the file table.h
this file implement a array of stacks that hold objects of same data type
The design idea is a book table where the stacks are
you can put a book at top of stack by passing the stack number and the object like
bspush (0, 100);
and then retrieve the same item by calling bspop with the number of same stack
and a address of same type object to put the result.. like:
bspop (0, &i);

New purchase - The Minix Book vol 3


good book