aboutsummaryrefslogtreecommitdiffstats
path: root/pathod/libpathod/language/__init__.py
Commit message (Expand)AuthorAgeFilesLines
* add pathodMaximilian Hils2016-02-151-0/+113
n22'>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 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293
/* 
 * lwip-arch.c
 *
 * Arch-specific semaphores and mailboxes for lwIP running on mini-os 
 *
 * Tim Deegan <Tim.Deegan@eu.citrix.net>, July 2007
 */

#include <os.h>
#include <time.h>
#include <console.h>
#include <xmalloc.h>
#include <lwip/sys.h>
#include <stdarg.h>

/* Is called to initialize the sys_arch layer */
void sys_init(void)
{
}

/* Creates and returns a new semaphore. The "count" argument specifies
 * the initial state of the semaphore. */
sys_sem_t sys_sem_new(uint8_t count)
{
    struct semaphore *sem = xmalloc(struct semaphore);
    sem->count = count;
    init_waitqueue_head(&sem->wait);
    return sem;
}

/* Deallocates a semaphore. */
void sys_sem_free(sys_sem_t sem)
{
    xfree(sem);
}

/* Signals a semaphore. */
void sys_sem_signal(sys_sem_t sem)
{
    up(sem);
}

/* Blocks the thread while waiting for the semaphore to be
 * signaled. If the "timeout" argument is non-zero, the thread should
 * only be blocked for the specified time (measured in
 * milliseconds).
 * 
 * If the timeout argument is non-zero, the return value is the number of
 * milliseconds spent waiting for the semaphore to be signaled. If the
 * semaphore wasn't signaled within the specified time, the return value is
 * SYS_ARCH_TIMEOUT. If the thread didn't have to wait for the semaphore
 * (i.e., it was already signaled), the function may return zero. */
uint32_t sys_arch_sem_wait(sys_sem_t sem, uint32_t timeout)
{
    /* Slightly more complicated than the normal minios semaphore:
     * need to wake on timeout *or* signal */
    sys_prot_t prot;
    int64_t then = NOW();
    int64_t deadline;

    if (timeout == 0)
	deadline = 0;
    else
	deadline = then + MILLISECS(timeout);

    while(1) {
        wait_event_deadline(sem->wait, (sem->count > 0), deadline);

        prot = sys_arch_protect();
	/* Atomically check that we can proceed */
	if (sem->count > 0 || (deadline && NOW() >= deadline))
	    break;
        sys_arch_unprotect(prot);
    }

    if (sem->count > 0) {
        sem->count--;
        sys_arch_unprotect(prot);
        return NSEC_TO_MSEC(NOW() - then); 
    }
    
    sys_arch_unprotect(prot);
    return SYS_ARCH_TIMEOUT;
}

/* Creates an empty mailbox. */
sys_mbox_t sys_mbox_new(int size)
{
    struct mbox *mbox = xmalloc(struct mbox);
    if (!size)
        size = 32;
    else if (size == 1)
        size = 2;
    mbox->count = size;
    mbox->messages = xmalloc_array(void*, size);
    init_SEMAPHORE(&mbox->read_sem, 0);
    mbox->reader = 0;
    init_SEMAPHORE(&mbox->write_sem, size);
    mbox->writer = 0;
    return mbox;
}

/* Deallocates a mailbox. If there are messages still present in the
 * mailbox when the mailbox is deallocated, it is an indication of a
 * programming error in lwIP and the developer should be notified. */
void sys_mbox_free(sys_mbox_t mbox)
{
    ASSERT(mbox->reader == mbox->writer);
    xfree(mbox->messages);
    xfree(mbox);
}

/* Posts the "msg" to the mailbox, internal version that actually does the
 * post. */
static void do_mbox_post(sys_mbox_t mbox, void *msg)
{
    /* The caller got a semaphore token, so we are now allowed to increment
     * writer, but we still need to prevent concurrency between writers
     * (interrupt handler vs main) */
    sys_prot_t prot = sys_arch_protect();
    mbox->messages[mbox->writer] = msg;
    mbox->writer = (mbox->writer + 1) % mbox->count;
    ASSERT(mbox->reader != mbox->writer);
    sys_arch_unprotect(prot);
    up(&mbox->read_sem);
}

/* Posts the "msg" to the mailbox. */
void sys_mbox_post(sys_mbox_t mbox, void *msg)
{
    if (mbox == SYS_MBOX_NULL)
        return;
    down(&mbox->write_sem);
    do_mbox_post(mbox, msg);
}

/* Try to post the "msg" to the mailbox. */
err_t sys_mbox_trypost(sys_mbox_t mbox, void *msg)
{
    if (mbox == SYS_MBOX_NULL)
        return ERR_BUF;
    if (!trydown(&mbox->write_sem))
        return ERR_MEM;
    do_mbox_post(mbox, msg);
    return ERR_OK;
}

/*
 * Fetch a message from a mailbox. Internal version that actually does the
 * fetch.
 */
static void do_mbox_fetch(sys_mbox_t mbox, void **msg)
{
    sys_prot_t prot;
    /* The caller got a semaphore token, so we are now allowed to increment
     * reader, but we may still need to prevent concurrency between readers.
     * FIXME: can there be concurrent readers? */
    prot = sys_arch_protect();
    ASSERT(mbox->reader != mbox->writer);
    if (msg != NULL)
        *msg = mbox->messages[mbox->reader];
    mbox->reader = (mbox->reader + 1) % mbox->count;
    sys_arch_unprotect(prot);
    up(&mbox->write_sem);
}

/* Blocks the thread until a message arrives in the mailbox, but does
 * not block the thread longer than "timeout" milliseconds (similar to
 * the sys_arch_sem_wait() function). The "msg" argument is a result
 * parameter that is set by the function (i.e., by doing "*msg =
 * ptr"). The "msg" parameter maybe NULL to indicate that the message
 * should be dropped.
 *
 * The return values are the same as for the sys_arch_sem_wait() function:
 * Number of milliseconds spent waiting or SYS_ARCH_TIMEOUT if there was a
 * timeout. */
uint32_t sys_arch_mbox_fetch(sys_mbox_t mbox, void **msg, uint32_t timeout)
{
    uint32_t rv;
    if (mbox == SYS_MBOX_NULL)
        return SYS_ARCH_TIMEOUT;

    rv = sys_arch_sem_wait(&mbox->read_sem, timeout);
    if ( rv == SYS_ARCH_TIMEOUT )
        return rv;

    do_mbox_fetch(mbox, msg);
    return 0;
}

/* This is similar to sys_arch_mbox_fetch, however if a message is not
 * present in the mailbox, it immediately returns with the code
 * SYS_MBOX_EMPTY. On success 0 is returned.
 *
 * To allow for efficient implementations, this can be defined as a
 * function-like macro in sys_arch.h instead of a normal function. For
 * example, a naive implementation could be:
 *   #define sys_arch_mbox_tryfetch(mbox,msg) \
 *     sys_arch_mbox_fetch(mbox,msg,1)
 * although this would introduce unnecessary delays. */

uint32_t sys_arch_mbox_tryfetch(sys_mbox_t mbox, void **msg) {
    if (mbox == SYS_MBOX_NULL)
        return SYS_ARCH_TIMEOUT;

    if (!trydown(&mbox->read_sem))
	return SYS_MBOX_EMPTY;

    do_mbox_fetch(mbox, msg);
    return 0;
}


/* Returns a pointer to the per-thread sys_timeouts structure. In lwIP,
 * each thread has a list of timeouts which is repressented as a linked
 * list of sys_timeout structures. The sys_timeouts structure holds a
 * pointer to a linked list of timeouts. This function is called by
 * the lwIP timeout scheduler and must not return a NULL value. 
 *
 * In a single threadd sys_arch implementation, this function will
 * simply return a pointer to a global sys_timeouts variable stored in
 * the sys_arch module. */
struct sys_timeouts *sys_arch_timeouts(void) 
{
    static struct sys_timeouts timeout;
    return &timeout;
}


/* Starts a new thread with priority "prio" that will begin its execution in the
 * function "thread()". The "arg" argument will be passed as an argument to the
 * thread() function. The id of the new thread is returned. Both the id and
 * the priority are system dependent. */
static struct thread *lwip_thread;
sys_thread_t sys_thread_new(char *name, void (* thread)(void *arg), void *arg, int stacksize, int prio)
{
    struct thread *t;
    if (stacksize > STACK_SIZE) {
	printk("Can't start lwIP thread: stack size %d is too large for our %d\n", stacksize, STACK_SIZE);
	do_exit();
    }
    lwip_thread = t = create_thread(name, thread, arg);
    return t;
}

/* This optional function does a "fast" critical region protection and returns
 * the previous protection level. This function is only called during very short
 * critical regions. An embedded system which supports ISR-based drivers might
 * want to implement this function by disabling interrupts. Task-based systems
 * might want to implement this by using a mutex or disabling tasking. This
 * function should support recursive calls from the same task or interrupt. In
 * other words, sys_arch_protect() could be called while already protected. In
 * that case the return value indicates that it is already protected.
 *
 * sys_arch_protect() is only required if your port is supporting an operating
 * system. */
sys_prot_t sys_arch_protect(void)
{
    unsigned long flags;
    local_irq_save(flags);
    return flags;
}

/* This optional function does a "fast" set of critical region protection to the
 * value specified by pval. See the documentation for sys_arch_protect() for
 * more information. This function is only required if your port is supporting
 * an operating system. */
void sys_arch_unprotect(sys_prot_t pval)
{
    local_irq_restore(pval);
}

/* non-fatal, print a message. */
void lwip_printk(char *fmt, ...)
{
    va_list args;
    va_start(args, fmt);
    printk("lwIP: ");
    print(0, fmt, args);
    va_end(args);
}

/* fatal, print message and abandon execution. */
void lwip_die(char *fmt, ...)
{
    va_list args;
    va_start(args, fmt);
    printk("lwIP assertion failed: ");
    print(0, fmt, args);
    va_end(args);
    printk("\n");
    BUG();
}