home *** CD-ROM | disk | FTP | other *** search
/ hobbes.nmsu.edu 2008 / 2008-06-02_hobbes.nmsu.edu.zip / new / scummc-0.2.0-os2.zip / ScummC / src / scvm_thread.c < prev    next >
Encoding:
C/C++ Source or Header  |  2007-12-17  |  7.9 KB  |  282 lines

  1. /* ScummC
  2.  * Copyright (C) 2006  Alban Bedel
  3.  *
  4.  * This program is free software; you can redistribute it and/or
  5.  * modify it under the terms of the GNU General Public License
  6.  * as published by the Free Software Foundation; either version 2
  7.  * of the License, or (at your option) any later version.
  8.  
  9.  * This program is distributed in the hope that it will be useful,
  10.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.  * GNU General Public License for more details.
  13.  
  14.  * You should have received a copy of the GNU General Public License
  15.  * along with this program; if not, write to the Free Software
  16.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  17.  *
  18.  */
  19.  
  20. /**
  21.  * @file scvm_thread.c
  22.  * @ingroup scvm
  23.  * @brief SCVM thread implementation
  24.  */
  25.  
  26. #include "config.h"
  27.  
  28. #include <stdlib.h>
  29. #include <stdio.h>
  30. #include <string.h>
  31. #include <inttypes.h>
  32. #include <errno.h>
  33. #include <sys/types.h>
  34. #include <sys/stat.h>
  35. #include <fcntl.h>
  36.  
  37. #include "scc_fd.h"
  38. #include "scc_util.h"
  39. #include "scc_cost.h"
  40. #include "scc_box.h"
  41. #include "scvm_res.h"
  42. #include "scvm_thread.h"
  43. #include "scvm.h"
  44.  
  45. char* scvm_thread_state_name(unsigned state) {
  46.   static char* names[] = {
  47.     "stopped", "running", "pended", "delayed", "frozen"
  48.   };
  49.   if(state >= sizeof(names)/sizeof(char*))
  50.     return NULL;
  51.   return names[state];
  52. }
  53.  
  54. void scvm_thread_flags_name(unsigned flags, char* out, int size) {
  55.   char* names[sizeof(unsigned)*8] = {};
  56.   int b,n = 0, len = 0;
  57.   if(size < 1)
  58.     return;
  59.   names[0] = "NO_FREEZE";
  60.   names[1] = "RECURSIVE";
  61.   names[16] = "DELAY";
  62.   names[17] = "AT_BREAKPOINT";
  63.   for(b = 0 ; size > 1 && b < sizeof(unsigned)*8 ; b++) {
  64.     if(!(flags & (1<<b)))
  65.       continue;
  66.     if(names[b])
  67.       len = snprintf(out,size-1,"%s%s",n > 0 ? " " : "", names[b]);
  68.     else
  69.       len = snprintf(out,size-1,"%sFLAG_%X",n > 0 ? " " : "", b);
  70.     out += len;
  71.     size -= len;
  72.     n++;
  73.   }
  74.   out[size-1] = 0;
  75. }
  76.  
  77.  
  78. int scvm_thread_r8(scvm_thread_t* thread, uint8_t* ret) {
  79.   if(thread->code_ptr + 1 > thread->script->size) return SCVM_ERR_SCRIPT_BOUND;
  80.   *ret = thread->script->code[thread->code_ptr];
  81.   thread->code_ptr++;
  82.   return 0;
  83. }
  84.  
  85. int scvm_thread_r16(scvm_thread_t* thread, uint16_t *ret) {
  86.   if(thread->code_ptr + 2 > thread->script->size) return SCVM_ERR_SCRIPT_BOUND;
  87.   *ret = thread->script->code[thread->code_ptr];
  88.   *ret |= (thread->script->code[thread->code_ptr+1]) << 8;
  89.   thread->code_ptr += 2;
  90.   return 0;
  91. }
  92.  
  93. int scvm_thread_r32(scvm_thread_t* thread, uint32_t *ret) {
  94.   if(thread->code_ptr + 4 > thread->script->size) return SCVM_ERR_SCRIPT_BOUND;
  95.   *ret = thread->script->code[thread->code_ptr];
  96.   *ret |= (thread->script->code[thread->code_ptr+1]) << 8;
  97.   *ret |= (thread->script->code[thread->code_ptr+2]) << 16;
  98.   *ret |= (thread->script->code[thread->code_ptr+3]) << 24;
  99.   thread->code_ptr += 4;
  100.   return 0;
  101. }
  102.  
  103. int scvm_thread_strlen(scvm_thread_t* thread,unsigned *ret) {
  104.   unsigned len = 0;
  105.  
  106.   while(thread->script->size > thread->code_ptr+len) {
  107.     if(!thread->script->code[thread->code_ptr+len]) break;
  108.     if(thread->script->code[thread->code_ptr+len] == 0xFF) {
  109.       int type = thread->script->code[thread->code_ptr+len+1];
  110.       len += 2;
  111.       if((type < 1 || type > 3) && type != 8)
  112.         len += 2;
  113.     } else
  114.       len++;
  115.   }
  116.   *ret = len;
  117.   if(len >= thread->script->size-thread->code_ptr)
  118.     return SCVM_ERR_STRING_BOUND;
  119.   return 0;
  120. }
  121.  
  122. int scvm_thread_begin_override(scvm_t* vm, scvm_thread_t* thread) {
  123.   if(thread->override_ptr >= SCVM_MAX_OVERRIDE)
  124.     return SCVM_ERR_OVERRIDE_OVERFLOW;
  125.   thread->override[thread->override_ptr] = thread->code_ptr;
  126.   thread->override_ptr++;
  127.   vm->var->override = 0;
  128.   return 0;
  129. }
  130.  
  131. int scvm_thread_end_override(scvm_t* vm, scvm_thread_t* thread) {
  132.   if(thread->override_ptr < 1)
  133.     return SCVM_ERR_OVERRIDE_UNDERFLOW;
  134.   thread->override_ptr--;
  135.   vm->var->override = 0;
  136.   return 0;
  137. }
  138.  
  139. int scvm_stop_thread(scvm_t* vm, scvm_thread_t* thread) {
  140.   thread->state = SCVM_THREAD_STOPPED;
  141.   return 0;
  142. }
  143.  
  144. int scvm_is_script_running(scvm_t* vm, unsigned id) {
  145.   int i;
  146.   for(i = 0 ; i < vm->num_thread ; i++) {
  147.     if(vm->thread[i].state == SCVM_THREAD_STOPPED ||
  148.        !vm->thread[i].script ||
  149.        vm->thread[i].script->id != id)
  150.       continue;
  151.     return 1;
  152.   }
  153.   return 0;
  154. }
  155.  
  156. int scvm_stop_script(scvm_t* vm, unsigned id) {
  157.   int i,n=0;
  158.   for(i = 0 ; i < vm->num_thread ; i++) {
  159.     if(vm->thread[i].state == SCVM_THREAD_STOPPED ||
  160.        !vm->thread[i].script ||
  161.        vm->thread[i].script->id != id)
  162.       continue;
  163.     scvm_stop_thread(vm,&vm->thread[i]);
  164.     n++;
  165.   }
  166.   return n;
  167. }
  168.  
  169. int scvm_start_thread(scvm_t* vm, scvm_script_t* scr, unsigned code_ptr,
  170.                       unsigned flags, unsigned* args) {
  171.   int i;
  172.   scvm_thread_t* thread;
  173.   
  174.   // find a free thread
  175.   for(i = 0 ; i < vm->num_thread ; i++)
  176.     if(vm->thread[i].state == SCVM_THREAD_STOPPED) break;
  177.   if(i >= vm->num_thread) {
  178.     scc_log(LOG_ERR,"No threads left to start script %d\n",scr->id);
  179.     return -1; // fixme
  180.   }
  181.   thread = &vm->thread[i];
  182.   
  183.   thread->state = SCVM_THREAD_RUNNING;
  184.   thread->flags = flags;
  185.   thread->script = scr;
  186.   thread->code_ptr = code_ptr;
  187.   thread->cycle = vm->cycle;
  188.   thread->parent = NULL;
  189.   if(!thread->var) {
  190.     thread->num_var = 16;
  191.     thread->var = calloc(sizeof(int),vm->thread[i].num_var);
  192.   } else
  193.     memset(thread->var,0,sizeof(int)*vm->thread[i].num_var);
  194.   if(args) {
  195.     int j;
  196.     for(j = 0 ; j < args[0] && j < 16 ; j++)
  197.       thread->var[j] = args[j+1];
  198.   }
  199.   return thread->id;
  200. }
  201.  
  202. int scvm_start_script(scvm_t* vm, unsigned flags, unsigned num, unsigned* args) {
  203.   scvm_script_t* scr;
  204.   
  205.   // get the script
  206.   // local scripts, this 200 shouldn't be hardcoded
  207.   // but where do we get it from?
  208.   if(num >= 200) {
  209.     if(!vm->room || num-200 >= vm->room->num_script ||
  210.        !(scr = vm->room->script[num-200]))
  211.       return SCVM_ERR_BAD_ADDR;
  212.   } else if(!(scr = scvm_load_res(vm,SCVM_RES_SCRIPT,num)))
  213.       return SCVM_ERR_BAD_RESOURCE;
  214.   
  215.   // if it's not recursive kill the script if it run
  216.   if(!(flags & SCVM_THREAD_RECURSIVE))
  217.     scvm_stop_script(vm,num);
  218.  
  219.   return scvm_start_thread(vm,scr,0,flags,args);
  220. }
  221.  
  222. int scvm_thread_do_op(scvm_t* vm, scvm_thread_t* thread, scvm_op_t* optable) {
  223.   int r;
  224.   uint8_t op;
  225.   
  226.   if((r=scvm_thread_r8(thread,&op))) return r;
  227.   
  228.   scc_log(LOG_MSG,"Do op %s (0x%x)\n",optable[op].name,op);
  229.  
  230.   if(!optable[op].op) {
  231.     scc_log(LOG_WARN,"Op %s (0x%x) is missing\n",optable[op].name,op);
  232.     return SCVM_ERR_NO_OP; // not implemented/existing
  233.   }
  234.   return optable[op].op(vm,thread);
  235. }
  236.  
  237.  
  238. int scvm_thread_run(scvm_t* vm, scvm_thread_t* thread) {
  239.   int i,r=0;
  240.   while(thread->state == SCVM_THREAD_RUNNING &&
  241.         thread->cycle <= vm->cycle) {
  242.     thread->op_start = thread->code_ptr;
  243.     // Check if the debugger want to break
  244.     if(vm->dbg && vm->dbg->check_interrupt && vm->dbg->check_interrupt(vm))
  245.       return SCVM_ERR_INTERRUPTED;
  246.     // We check the interupts only every 64 ops
  247.     for(i = 0 ; thread->state == SCVM_THREAD_RUNNING &&
  248.           thread->cycle <= vm->cycle && i < 64 ; i++) {
  249.       thread->op_start = thread->code_ptr;
  250.       // Check for breakpoints
  251.       if(vm->dbg) {
  252.         scvm_breakpoint_t* bp = vm->dbg->breakpoint;
  253.         while(bp - vm->dbg->breakpoint < vm->dbg->num_breakpoint) {
  254.           if((!bp->room_id || (vm->room && bp->room_id == vm->room->id)) &&
  255.              bp->script_id == thread->script->id &&
  256.              bp->pos == thread->code_ptr) {
  257.             if(thread->flags & SCVM_THREAD_AT_BREAKPOINT) {
  258.               thread->flags &= ~SCVM_THREAD_AT_BREAKPOINT;
  259.               break;
  260.             } else {
  261.               thread->flags |= SCVM_THREAD_AT_BREAKPOINT;
  262.               return SCVM_ERR_BREAKPOINT;
  263.             }
  264.           }
  265.           bp++;
  266.         }
  267.       }
  268.       if((r = scvm_thread_do_op(vm,thread,vm->optable)))
  269.         return r;
  270.     }
  271.   }
  272.   return r;
  273. }
  274.  
  275. // Debug helper
  276. int scvm_find_op(scvm_op_t* optable,char* name) {
  277.   int i;
  278.   for(i = 0 ; i < 0x100 ; i++)
  279.     if(!strcmp(optable[i].name,name)) return i;
  280.   return -1;
  281. }
  282.