Raw File
tasks.c
// This module keeps track of ML tasks.
// It also displays info about DryOS tasks, and requests ML tasks to return at shutdown.
//
// Credits:
// * Indy for task information: http://groups.google.com/group/ml-devel/browse_thread/thread/26cb46acd262b953
// * AJ for the idea of shutting down ML tasks manually, rather than letting DryOS do this job

#define _TASKS_C
#include "dryos.h"
#include "property.h"
#include "bmp.h"

struct task_attr_str {
  unsigned int entry;
  unsigned int args;
  unsigned int stack;
  unsigned int size;
  unsigned int used; // 0x10
  void* name;
  unsigned int off_18;
  unsigned int flags;
  unsigned char wait_id;
  unsigned char pri;
  unsigned char state;
  unsigned char fpu;
  unsigned int id;
}; // size = 0x28


extern int is_taskid_valid(int, int, void*);
extern int get_obj_attr(void*, unsigned char*, int, int);

char* get_task_name_from_id(int id)
{
#ifdef CONFIG_5DC
return "?";
#endif
    
    char* name = "?";
    int c = id & 0xFF;

    struct task_attr_str task_attr;
    int r = is_taskid_valid(1, c, &task_attr); // ok
    if (r==0) {
      //~ r = get_obj_attr( &(task_attr.args), &(task_attr.fpu), 0, 0); // buggy ?
      if (task_attr.name!=0) name=task_attr.name;
      else name="?";
    }
    return name;
}

int what_tasks_to_show=2;
void tasks_print(void* priv, int x0, int y0, int selected)
{
#ifndef CONFIG_5DC
    if (selected) 
    {
        menu_draw_icon(x0, y0, -1, 0);
        bmp_fill(38, 0, 0, 720, 430);
    }

  int c;
  unsigned int r;
  struct task_attr_str task_attr;
  char *name;
  extern unsigned int task_max;

   // wait_id: 0=sleep, 1=sem, 2=flg/event, 3=sendmq, 4=recvmq, 5=mutex
   // state: 0=ready, 1=wait, 2=susp, other=wait+s

  int x = 5;
  int y = 10;
  
  bmp_printf(FONT_MED, x, y, what_tasks_to_show == 1 ? "Canon tasks" : "ML tasks");
  y += font_med.height;

  //~ int k = 0;

  c = 1;
  bmp_printf(FONT_SMALL, x, y, "task_max=%d", task_max);
  y += font_small.height;
  for (c=1; c<(int)task_max; c++) {
    r = is_taskid_valid(1, c, &task_attr); // ok
    if (r==0) {
      r = get_obj_attr( &(task_attr.args), &(task_attr.fpu), 0, 0); // buggy ?
      if (task_attr.name!=0) name=task_attr.name;
      else name="?";
     
     // Canon tasks are named in uppercase (exception: idle); ML tasks are named in lowercase.
     int is_canon_task = (name[0]  < 'a' || name[0] > 'z' || streq(name, "idle") ||  streq(name, "systemtask"));
     if (what_tasks_to_show==1 && !is_canon_task) continue;
     if (what_tasks_to_show!=1 && is_canon_task) continue;
     
     char short_name[] = "                    ";
     my_memcpy(short_name, name, MIN(sizeof(short_name)-1, strlen(name)));
     
     int mem_percent = task_attr.used * 100 / task_attr.size;
     
     bmp_printf(SHADOW_FONT(FONT(FONT_SMALL, mem_percent < 50 ? COLOR_WHITE : mem_percent < 90 ? COLOR_YELLOW : COLOR_RED, 38)), x, y, "%02d %s: p=%2x w=%2x m=%2d%% %d\n", 
        c, short_name, task_attr.pri, task_attr.wait_id, mem_percent, 0, task_attr.state);
      #if defined(CONFIG_5D3) || defined(CONFIG_60D)
      y += font_small.height - (what_tasks_to_show==1 ? 2 : 0); // too many tasks - they don't fit on the screen :)
      #else
      y += font_small.height;
      #endif
      if (y > 410)
      {
          x += 360;
          y = 10;
      }
    }
  }
#endif
}

void ml_shutdown()
{
    ml_shutdown_requested = 1;
    
    info_led_on();
    _card_led_on();
    config_save_at_shutdown();
    info_led_on();
    _card_led_on();
}

PROP_HANDLER(PROP_TERMINATE_SHUT_REQ)
{
    //bmp_printf(FONT_MED, 0, 0, "SHUT REQ %d ", buf[0]);
    if (buf[0] == 0)  ml_shutdown();
}

PROP_HANDLER(PROP_CARD_COVER)
{
    if (buf[0] == 1) ml_shutdown();
}

static int task_holding_bmp_lock = 0;
static int line_holding_bmp_lock = 0;
static char func_holding_bmp_lock[50] = "";

int CheckBmpAcquireRecursiveLock(void* lock, int line, const char* func)
{
    char* task_name = get_task_name_from_id((int)get_current_task());
    
    // just a warning, sometimes we can't get without it (e.g. at redraw), but it's best to avoid
    /*
    if (streq(task_name, "GuiMainTask"))
    {
        int x = 100;
        bmp_puts(FONT_MED, &x, &x, "BMP_LOCK GMT");
    }*/
    
    // this is really bad - don't ever try to block property handling task!
    if (streq(task_name, "PropMgr"))
    {
        extern int current_prop_handler;
        char msg[50];
        snprintf(msg, sizeof(msg), "BMP_LOCK PROP %x!!!", current_prop_handler);
        int x = 100;
        bmp_puts(FONT_MED, (unsigned int *)&x, (unsigned int *)&x, msg);
        beep();
        info_led_blink(20,50,50);
        ASSERT(0);
    }

    int wait = 2000;
    int r;
    while ((r = (int)AcquireRecursiveLock(lock, wait)))
    {
        char msg[100];
        snprintf(msg, sizeof(msg), "%s:%s:%d:\nRLock held by %s:%s:%d  ", get_task_name_from_id((int)get_current_task()), func, line, get_task_name_from_id(task_holding_bmp_lock), func_holding_bmp_lock, line_holding_bmp_lock);//, get_task_name_from_id(task_holding_bmp_lock));
        int x = 100;
        bmp_puts(FONT_MED, (unsigned int *)&x, (unsigned int *)&x, msg);
        ml_assert_handler(msg, __FILE__, __LINE__, __func__);
        wait = 0;
    }
    task_holding_bmp_lock = ((int)get_current_task()) & 0xFF;
    line_holding_bmp_lock = line;
    snprintf(func_holding_bmp_lock, sizeof(func_holding_bmp_lock), func);
    return r;
}

int CheckBmpReleaseRecursiveLock(void* lock)
{
    int r = (int)ReleaseRecursiveLock(lock);
    //~ task_holding_bmp_lock = -1;
    //~ char msg[50] = "                  ";
    //~ int x = 100;
    //~ bmp_puts(FONT_LARGE, &x, &x, msg);
    return r;
}
back to top