aboutsummaryrefslogtreecommitdiffstats
path: root/os/kernel/include/chregistry.h
blob: f9185acb7e856e9b6ffdc1ef704507ce283e493b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
/*
    ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010 Giovanni Di Sirio.

    This file is part of ChibiOS/RT.

    ChibiOS/RT 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 3 of the License, or
    (at your option) any later version.

    ChibiOS/RT 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, see <http://www.gnu.org/licenses/>.
*/

/**
 * @file    chregistry.h
 * @brief   Threads registry macros and structures.
 *
 * @addtogroup registry
 * @{
 */

#ifndef _CHREGISTRY_H_
#define _CHREGISTRY_H_

#if CH_USE_REGISTRY || defined(__DOXYGEN__)

/**
 * @brief   Removes a thread from the registry list.
 * @note    This macro is not meant for use in application code.
 *
 * @param[in] tp        thread to remove from the registry
 */
#define REG_REMOVE(tp) {                                                    \
  (tp)->p_older->p_newer = (tp)->p_newer;                                   \
  (tp)->p_newer->p_older = (tp)->p_older;                                   \
}

/**
 * @brief   Adds a thread to the registry list.
 * @note    This macro is not meant for use in application code.
 *
 * @param[in] tp        thread to add to the registry
 */
#define REG_INSERT(tp) {                                                    \
  (tp)->p_newer = (Thread *)&rlist;                                         \
  (tp)->p_older = rlist.r_older;                                            \
  (tp)->p_older->p_newer = rlist.r_older = (tp);                            \
}

#ifdef __cplusplus
extern "C" {
#endif
  Thread *chRegFirstThread(void);
  Thread *chRegNextThread(Thread *tp);
#ifdef __cplusplus
}
#endif

#endif /* CH_USE_REGISTRY */

#endif /* _CHREGISTRY_H_ */

/** @} */
66; font-weight: bold } /* Name.Exception */ .highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */ .highlight .nl { color: #336699; font-style: italic } /* Name.Label */ .highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */ .highlight .py { color: #336699; font-weight: bold } /* Name.Property */ .highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */ .highlight .nv { color: #336699 } /* Name.Variable */ .highlight .ow { color: #008800 } /* Operator.Word */ .highlight .w { color: #bbbbbb } /* Text.Whitespace */ .highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */ .highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */ .highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */ .highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */ .highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */ .highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */ .highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */ .highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */ .highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */ .highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */ .highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */ .highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */ .highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */ .highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */ .highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */ .highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */ .highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */ .highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */ .highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */ .highlight .vc { color: #336699 } /* Name.Variable.Class */ .highlight .vg { color: #dd7700 } /* Name.Variable.Global */ .highlight .vi { color: #3333bb } /* Name.Variable.Instance */ .highlight .vm { color: #336699 } /* Name.Variable.Magic */ .highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
/*
    ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.

    This file is part of ChibiOS/RT.

    ChibiOS/RT 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 3 of the License, or
    (at your option) any later version.

    ChibiOS/RT 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, see <http://www.gnu.org/licenses/>.
*/

/**
 * @file chheap.c
 * @brief Heap code.
 * @addtogroup heap
 * @{
 */

#include <ch.h>

#if CH_USE_HEAP

#if !CH_USE_MALLOC_HEAP

#define MAGIC 0xF5A0
#define ALIGN_TYPE      void *
#define ALIGN_MASK      (sizeof(ALIGN_TYPE) - 1)
#define ALIGN_SIZE(p)   (((size_t)(p) + ALIGN_MASK) & ~ALIGN_MASK)

struct header {
  union {
    struct header       *h_next;
    size_t              h_magic;
  };
  size_t                h_size;
};

static struct {
  struct header         free;   /* Guaranteed to be not adjacent to the heap */
#if CH_USE_MUTEXES
#define H_LOCK()        chMtxLock(&heap.hmtx)
#define H_UNLOCK()      chMtxUnlock()
  Mutex                 hmtx;
#elif CH_USE_SEMAPHORES
#define H_LOCK()        chSemWait(&heap.hsem)
#define H_UNLOCK()      chSemSignal(&heap.hsem)
  Semaphore             hsem;
#else
#error "The heap allocator requires mutexes or semaphores to be enabled"
#endif
#if CH_HEAP_SIZE > 0
  union {
    ALIGN_TYPE          alignment;
    char                buffer[ALIGN_SIZE(CH_HEAP_SIZE)];
  };
#endif
} heap;

/**
 * @brief Initializes the allocator subsystem.
 *
 * @note Internal use only.
 */
void heap_init(void) {
  struct header *hp;

#if CH_HEAP_SIZE == 0
  extern char __heap_base__;
  extern char __heap_end__;

  hp = (void *)&__heap_base__;
  hp->h_size = &__heap_end__ - &__heap_base__ - sizeof(struct header);
#else
  hp = (void *)&heap.buffer[0];
  hp->h_size = (&heap.buffer[ALIGN_SIZE(CH_HEAP_SIZE)] - &heap.buffer[0]) -
               sizeof(struct header);
#endif
  hp->h_next = NULL;
  heap.free.h_next = hp;
  heap.free.h_size = 0;
#if CH_USE_MUTEXES
  chMtxInit(&heap.hmtx);
#else
  chSemInit(&heap.hsem, 1);
#endif
}

/**
 * @brief Allocates a block of memory from the heap by using the first-fit
 *        algorithm.
 * @details The allocated block is guaranteed to be properly aligned for a
 *          pointer data type.
 *
 * @param[in] size the size of the block to be allocated. Note that the
 *                 allocated block may be a bit bigger than the requested
 *                 size for alignment and fragmentation reasons.
 * @return A pointer to the allocated block.
 * @retval NULL if the block cannot be allocated.
 */
void *chHeapAlloc(size_t size) {
  struct header *qp, *hp, *fp;

  size = ALIGN_SIZE(size);
  qp = &heap.free;
  H_LOCK();

  while (qp->h_next != NULL) {
    hp = qp->h_next;
    if (hp->h_size >= size) {
      if (hp->h_size < size + sizeof(struct header)) {
        /* Gets the whole block even if it is slightly bigger than the
           requested size because the fragment would be too small to be
           useful */
        qp->h_next = hp->h_next;
      }
      else {
        /* Block bigger enough, must split it */
        fp = (void *)((char *)(hp) + sizeof(struct header) + size);
        fp->h_next = hp->h_next;
        fp->h_size = hp->h_size - sizeof(struct header) - size;
        qp->h_next = fp;
        hp->h_size = size;
      }
      hp->h_magic = MAGIC;

      H_UNLOCK();
      return (void *)(hp + 1);
    }
    qp = hp;
  }

  H_UNLOCK();
  return NULL;
}

#define LIMIT(p) (struct header *)((char *)(p) + \
                                   sizeof(struct header) + \
                                   (p)->h_size)

/**
 * @brief Frees a previously allocated memory block.
 *
 * @param[in] p the memory block pointer
 */
void chHeapFree(void *p) {
  struct header *qp, *hp;

  chDbgCheck(p != NULL, "chHeapFree");

  hp = (struct header *)p - 1;
  chDbgAssert(hp->h_magic == MAGIC,
              "chHeapFree(), #1",
              "it is not magic");
  qp = &heap.free;
  H_LOCK();

  while (TRUE) {

    chDbgAssert((hp < qp) || (hp >= LIMIT(qp)),
                "chHeapFree(), #2",
                "within free block");

    if (((qp == &heap.free) || (hp > qp)) &&
        ((qp->h_next == NULL) || (hp < qp->h_next))) {
      /* Insertion after qp */
      hp->h_next = qp->h_next;
      qp->h_next = hp;
      /* Verifies if the newly inserted block should be merged */
      if (LIMIT(hp) == hp->h_next) {
        /* Merge with the next block */
        hp->h_size += hp->h_next->h_size + sizeof(struct header);
        hp->h_next = hp->h_next->h_next;
      }
      if ((LIMIT(qp) == hp)) {  /* Cannot happen when qp == &heap.free */
        /* Merge with the previous block */
        qp->h_size += hp->h_size + sizeof(struct header);
        qp->h_next = hp->h_next;
      }

      H_UNLOCK();
      return;
    }
    qp = qp->h_next;
  }
}

/**
 * @brief Reports the heap status.
 *
 * @param[in] sizep pointer to a variable that will receive the total
 *                  fragmented free space
 * @return The number of fragments in the heap.
 * @note This function is meant to be used in the test suite, it should not be
 *       really useful for the application code.
 * @note This function is not implemented when the @p CH_USE_MALLOC_HEAP
 *       configuration option is used (it always returns zero).
 */
size_t chHeapStatus(size_t *sizep) {
  struct header *qp;
  size_t n, sz;

  H_LOCK();

  sz = 0;
  for (n = 0, qp = &heap.free; qp->h_next; n++, qp = qp->h_next)
    sz += qp->h_next->h_size;
  if (sizep)
    *sizep = sz;

  H_UNLOCK();
  return n;
}

#else /* CH_USE_MALLOC_HEAP */

#include <stdlib.h>

#if CH_USE_MUTEXES
#define H_LOCK()        chMtxLock(&hmtx)
#define H_UNLOCK()      chMtxLock(&hmtx)
static Mutex            hmtx;
#elif CH_USE_SEMAPHORES
#define H_LOCK()        chSemWait(&hsem)
#define H_UNLOCK()      chSemSignal(&hsem)
static Semaphore        hsem;
#else
#error "The heap allocator requires mutexes or semaphores to be enabled"
#endif

void heap_init(void) {

#if CH_USE_MUTEXES
  chMtxInit(&hmtx);
#else
  chSemInit(&hsem, 1);
#endif
}

void *chHeapAlloc(size_t size) {
  void *p;

  H_LOCK();
  p = malloc(size);
  H_UNLOCK();
  return p;
}

void chHeapFree(void *p) {

  chDbgCheck(p != NULL, "chHeapFree");

  H_LOCK();
  free(p);
  H_UNLOCK();
}

size_t chHeapStatus(size_t *sizep) {

  if (sizep)
    *sizep = 0;
  return 0;
}

#endif /* CH_USE_MALLOC_HEAP */

#endif /* CH_USE_HEAP */

/** @} */