Blame view

RIOT/cpu/x86/include/ucontext.h 5.21 KB
a752c7ab   elopes   add first test an...
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
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
  /*
   * Copyright (C) 2014  René Kijewski  <rene.kijewski@fu-berlin.de>
   *
   * This library is free software; you can redistribute it and/or
   * modify it under the terms of the GNU Lesser General Public
   * License as published by the Free Software Foundation; either
   * version 2.1 of the License, or (at your option) any later version.
   *
   * This library 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
   * Lesser General Public License for more details.
   *
   * You should have received a copy of the GNU Lesser General Public
   * License along with this library; if not, write to the Free Software
   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
   */
  
  /**
   * Coroutine helper functions. The base of the multi-threading system.
   *
   * @ingroup x86-multithreading
   * @{
   * @file
   * @author  René Kijewski <rene.kijewski@fu-berlin.de>
   */
  
  #ifndef UCONTEXT_H
  #define UCONTEXT_H
  
  #include <stdlib.h>
  #include <unistd.h>
  
  #ifdef __cplusplus
  extern "C" {
  #endif
  
  /**
   * @brief   Common stacksize for a signal handler.
   *
   * Do not use this variable.
   * The standard wants us to define this variable, but you are better off the the RIOT specific macros.
   */
  #define SIGSTKSZ (2048)
  
  /**
   * @brief   General purpose registers of an x86 CPU.
   *
   * Used by ucontext_t.
   * Application developers should not use this type directly.
   */
  struct x86_pushad {
      unsigned long ax, cx, dx, bx; /* field in ucontext_t: 3*4 -> 6*4 */
      unsigned long sp, bp, si, di; /* field in ucontext_t: 7*4 -> 10*4 */
  } __attribute__((packed));
  
  /**
   * @brief   Opaque memory needed to store the x87 FPU state.
   *
   * Used by x86_threading.c.
   * Application developers should not use this type directly.
   * There is only enough room for the basic x87 state, not the multimedia extensions.
   */
  struct x86_fxsave {
      char opaque[512];
  } __attribute__((packed, aligned(0x10)));
  
  /**
   * @brief   Machine specific part of the corouting state.
   *
   * Used by ucontext_t.
   * Application developers should not use this type directly.
   */
  typedef struct mcontext {
      unsigned long flags;         /* field in ucontext_t: 2*4 */
      struct x86_pushad registers; /* field in ucontext_t: 3*4 -> 10*4 */
      void *ip;                    /* field in ucontext_t: 11*4 */
  } __attribute__((packed)) mcontext_t;
  
  /**
   * @brief   Stack assigned to a coroutine.
   *
   * Used by ucontext_t.
   * Application developers need to set this values to make coroutines working.
   */
  typedef struct stack {
      void *ss_sp; /* field in ucontext_t: 0*4 */
      //int ss_flags;
      size_t ss_size; /* field in ucontext_t: 1*4 */
  } __attribute__((packed)) stack_info_t;
  
  /**
   * @brief   Extra data to perform an `iret`.
   *
   * Used by x86_interrupts.c to continue a thread
   * if sched_context_switch_request was set set by an ISR.
   * Application developers should not use this type directly.
   */
  struct x86_interrupted_interrupt {
      unsigned long ip;
      unsigned long flags;
  } __attribute__((packed));
  
  /**
   * @brief   Datatype to enable coroutines in userspace.
   *
   * This datatype stores the machine state of a suspended coroutine.
   */
  typedef struct ucontext {
      stack_info_t uc_stack;    /* field in ucontext_t: 0*4 - 1*4 */
      mcontext_t uc_context;    /* field in ucontext_t: 2*4 -> 11*4 */
      struct ucontext *uc_link; /* field in ucontext_t: 12*4 */
      //sigset_t uc_sigmask;
      struct x86_interrupted_interrupt __intr;
      struct x86_fxsave __fxsave;
  } __attribute__((packed)) ucontext_t;
  
  /**
   * @brief   Store current coroutine state.
   *
   * With setcontext() you can jump to this point of execution again.
   * Take care about your stack, though.
   * After your thread of execution left the function calling getcontext() there be dragons.
   *
   * The FPU registers are not stored!
   */
  int getcontext(ucontext_t *ucp);
  
  /**
   * @brief   Restore a coroutine state.
   *
   * The state must be set up by calling getcontext() or makecontext() previously.
   * The FPU registers won't be restored.
   */
  int setcontext(const ucontext_t *ucp) __attribute__((noreturn));
  
  #pragma GCC diagnostic push
  #pragma GCC diagnostic ignored "-Wstrict-prototypes"
  typedef void (*makecontext_fun_t)();
  #pragma GCC diagnostic pop
  
  /**
   * @brief   Create a coroutine / trampoline.
   * @param[in]   func   Function to call.
   * @param[in]   argc   Number of arguments for func. Must not exceed 5.
   *
   * The function arguments shall be passed after argc.
   * The arguments have to be type punnable as an int,
   * this includes integral types up to 4 bytes,
   * but excludes int64_t, float and so on.
   *
   * Different from what the POSIX standard states,
   * you do not have to getcontext() on ucp before calling makecontext().
   * This function creates a whole new coroutine state / trampoline.
   */
  void makecontext(ucontext_t *ucp, makecontext_fun_t func, int argc, ...);
  
  /**
   * @brief   Swap coroutine.
   * @param[out]   oucp   Memory to preserve current coroutine state in.
   * @param[in]    ucp    Coroutine to execute next.
   *
   * This function is an atomic variant of getcontext() and setcontext().
   * Same restrictions apply.
   */
  int swapcontext(ucontext_t *oucp, const ucontext_t *ucp);
  
  #ifdef __cplusplus
  }
  #endif
  
  #endif /* UCONTEXT_H */
  
  /** @} */