nckernel  0.1
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
thread.c
Go to the documentation of this file.
1 #include <stddef.h>
2 #include <stdint.h>
3 #include <sys/types.h>
4 #include <stdio.h>
5 #include <fcntl.h>
6 #include <unistd.h>
7 #include <pthread.h>
8 #include <stdlib.h>
9 #include <errno.h>
10 #include <string.h>
11 #include <stdarg.h>
12 #include <assert.h>
13 
14 #include <object.h>
15 #include <list.h>
16 #include <thread.h>
17 #include <vfs.h>
18 
19 #include <debug.h>
20 #include <common.h>
21 #include <interrupt.h>
22 
23 #define THREAD_LIST_LINK(tcb) \
24 do { \
25  unsigned long flag; \
26  struct thread *first_child; \
27  \
28  irq_local_save(&flag); \
29  INIT_LIST_HEAD(&(tcb)->child); \
30  INIT_LIST_HEAD(&(tcb)->sibling); \
31  \
32  first_child = list_entry(tcb->parent->child.next, struct thread, child); \
33  if (first_child) { \
34  list_add_tail(&tcb->sibling, &first_child->sibling); \
35  } else { \
36  list_add_tail(&tcb->child, &tcb->parent->child); \
37  } \
38  \
39  list_add_tail(&(tcb)->link, &(tcb)->root->link); \
40  irq_local_restore(flag); \
41 } while (0)
42 
43 #define THREAD_IS_ROOT(tcb) ((tcb)->parent == NULL && (tcb)->root == (tcb))
44 
45 #define THREAD_LIST_INIT(tcb) \
46 do { \
47  INIT_LIST_HEAD(&(tcb)->sibling); \
48  INIT_LIST_HEAD(&(tcb)->child); \
49  INIT_LIST_HEAD(&(tcb)->link); \
50 } while (0)
51 
53 {
54  struct thread *thread;
55 
56  thread = pthread_self();
57  if (!thread) {
58  return NULL;
59  }
60 
61  if (!thread->file_ctx) {
62  return NULL;
63  }
64 
65  return thread->file_ctx->table + STDIN_FILENO;
66 }
67 
69 {
70  struct thread *thread;
71 
72  thread = pthread_self();
73  if (!thread) {
74  return NULL;
75  }
76 
77  if (!thread->file_ctx) {
78  return NULL;
79  }
80 
81  return thread->file_ctx->table + STDERR_FILENO;
82 }
83 
85 {
86  struct thread *thread;
87 
88  thread = pthread_self();
89  if (!thread) {
90  return NULL;
91  }
92 
93  if (!thread->file_ctx) {
94  return NULL;
95  }
96 
97  return thread->file_ctx->table + STDOUT_FILENO;
98 }
99 
100 static int file_entry_create(struct object *object, void *data)
101 {
102  struct entry *ctx;
103  int ret = 0;
104  struct ninfo *ninfo;
105  struct file_object_info *info;
106 
107  info = data;
108  ninfo = vfs_get_ninfo(NULL, NULL, info->path);
109  if (!ninfo) {
110  dbg_printf("Failed to find ninfo for %s\n", info->path);
111  return -ENOENT;
112  }
113 
114  ctx = object_get(object, struct entry, object);
115 
116  ctx->ninfo = ninfo;
117  ctx->mode = info->mode;
118 
119  if (ninfo->nops.open) {
120  ret = ninfo->nops.open(ninfo, &ctx->nctx);
121  if (ret < 0) {
122  dbg_printf("Failed to do DEVICE open (%s)\n", info->path);
123  }
124  }
125 
126  return ret;
127 }
128 
129 static int file_entry_destroy(struct object *object)
130 {
131  struct ninfo *ninfo;
132  struct entry *ctx;
133  int ret;
134 
135  ctx = object_get(object, struct entry, object);
136 
137  ninfo = ctx->ninfo;
138  if (ninfo && ninfo->nops.close) {
139  ret = ninfo->nops.close(ninfo, &ctx->nctx);
140  } else {
141  ret = 0;
142  }
143 
144  return ret;
145 }
146 
147 static int file_entry_copy(struct object *_dest, struct object *_src)
148 {
149  struct entry *dest;
150  struct entry *src;
151 
152  src = object_get(_src, struct entry, object);
153  dest = object_get(_dest, struct entry, object);
154 
155  dest->mode = src->mode;
156  dest->ninfo = src->ninfo;
157 
165  memcpy(&dest->nctx, &src->nctx, sizeof(src->nctx));
166 
167  return 0;
168 }
169 
170 static int file_object_create(struct object *object, void *data)
171 {
172  struct file *file;
173  struct file_object_info *info = data;
174  struct object_ops entry_ops = {
175  .create = file_entry_create,
176  .destroy = file_entry_destroy,
177  .link = NULL,
178  .copy = file_entry_copy,
179  };
180  int ret;
181 
182  file = object_get(object, struct file, object);
183 
184  file->size = info->size;
185  file->offset = 0;
186  if (file->size) {
187  file->buffer = malloc(file->size);
188  if (!file->buffer) {
189  return -ENOMEM;
190  }
191  } else {
192  file->buffer = NULL;
193  }
194 
195  file->ctx = malloc(sizeof(*file->ctx));
196  if (!file->ctx) {
197  if (file->buffer) {
198  free(file->buffer);
199  }
200  return -ENOMEM;
201  }
202 
203  ret = object_init(&file->ctx->object, &entry_ops);
204  if (ret < 0) {
205  dbg_printf("Failed to initialize entry object\n");
206  if (file->buffer) {
207  free(file->buffer);
208  }
209  free(file->ctx);
210  return ret;
211  }
212 
213  ret = object_create(&file->ctx->object, info);
214  if (ret < 0) {
215  dbg_printf("Failed to create entry context (%s)\n", info->path);
216  if (file->buffer) {
217  free(file->buffer);
218  }
219  free(file->ctx);
220  return ret;
221  }
222 
223  return 0;
224 }
225 
226 static int file_object_destroy(struct object *object)
227 {
228  struct file *file;
229  int ret;
230 
231  file = object_get(object, struct file, object);
232 
233  if (file->ctx) {
234  ret = object_destroy(&file->ctx->object);
235  if (ret < 0) {
236  return ret;
237  }
238 
239  free(file->ctx);
240  file->ctx = NULL;
241  }
242 
243  if (file->buffer) {
244  free(file->buffer);
245  }
246 
247  file->buffer = NULL;
248  file->size = 0;
249  file->offset = 0;
250 
251  return 0;
252 }
253 
254 static int file_object_copy(struct object *dest, struct object *src)
255 {
256  struct file *dest_file;
257  struct file *src_file;
258 
259  dest_file = object_get(dest, struct file, object);
260  src_file = object_get(src, struct file, object);
261 
262  dest_file->size = src_file->size;
263  if (src_file->size) {
264  dest_file->buffer = malloc(src_file->size);
265  if (!dest_file->buffer) {
266  return -ENOMEM;
267  }
268 
269  memcpy(dest_file->buffer, src_file->buffer, src_file->size);
270  }
271  dest_file->offset = src_file->offset;
272 
273  if (src_file->ctx) {
274  int ret;
275  dest_file->ctx = malloc(sizeof(*dest_file->ctx));
276  if (!dest_file->ctx) {
277  free(dest_file->buffer);
278  return -ENOMEM;
279  }
280 
281  ret = object_copy(&dest_file->ctx->object,
282  &src_file->ctx->object);
283  if (ret < 0) {
284  free(dest_file->ctx);
285  free(dest_file->buffer);
286  return ret;
287  }
288  } else {
289  dest_file->ctx = NULL;
290  }
291 
292  return 0;
293 }
294 
295 static int file_ctx_create(struct object *object, void *data)
296 {
297  struct thread_file_ctx *ctx;
298  register int fd;
299  struct object_ops ops = {
300  .create = file_object_create,
301  .destroy = file_object_destroy,
302  .copy = file_object_copy,
303  .link = NULL,
304  };
305 
306  ctx = object_get(object, struct thread_file_ctx, object);
307 
308  for (fd = 0; fd < MAX_ENTRY; fd++) {
309  object_init(&ctx->table[fd].object, &ops);
310  }
311 
312  return 0;
313 }
314 
315 static inline int thread_fini_file_table(struct thread *tcb)
316 {
317  struct thread_file_ctx *fctx;
318  register int i;
319 
320  fctx = tcb->file_ctx;
321  if (!fctx) {
322  return -EINVAL;
323  }
324 
325  for (i = 0; i < MAX_ENTRY; i++) {
326  (void)object_destroy(&fctx->table[i].object);
327  }
328 
329  object_destroy(&fctx->object);
330  free(fctx);
331  tcb->file_ctx = NULL;
332  return 0;
333 }
334 
335 static int file_ctx_destroy(struct object *object)
336 {
337  struct thread_file_ctx *ctx;
338  register int fd;
339 
340  ctx = object_get(object, struct thread_file_ctx, object);
341  for (fd = 0; fd < MAX_ENTRY; fd++) {
342  (void)object_destroy(&ctx->table[fd].object);
343  }
344 
345  return 0;
346 }
347 
348 static int file_ctx_copy(struct object *_dest, struct object *_src)
349 {
350  struct thread_file_ctx *src;
351  struct thread_file_ctx *dest;
352  register int fd;
353  int ret;
354 
355  src = object_get(_src, struct thread_file_ctx, object);
356  dest = object_get(_dest, struct thread_file_ctx, object);
357 
358  for (fd = 0; fd < MAX_ENTRY; fd++) {
359  ret = object_copy(&dest->table[fd].object,
360  &src->table[fd].object);
361  if (ret < 0) {
362  goto errout;
363  }
364  }
365 
366  return 0;
367 
368 errout:
369  while (--fd >= 0) {
370  object_destroy(&dest->table[fd].object);
371  }
372 
373  return ret;
374 }
375 
376 static inline int thread_init_file_table(struct thread *tcb)
377 {
378  const char *dev_node;
379  int ret;
380  struct thread_file_ctx *fctx;
381  struct file_object_info info;
382  struct object_ops ops = {
383  .create = file_ctx_create,
384  .destroy = file_ctx_destroy,
385  .copy = file_ctx_copy,
386  .link = NULL,
387  };
388 
389  tcb->file_ctx = malloc(sizeof(*tcb->file_ctx));
390  if (!tcb->file_ctx) {
391  return -ENOMEM;
392  }
393 
394  ret = object_init(&tcb->file_ctx->object, &ops);
395  if (ret < 0) {
396  free(tcb->file_ctx);
397  tcb->file_ctx = NULL;
398  return ret;
399  }
400 
401  ret = object_create(&tcb->file_ctx->object, NULL);
402  if (ret < 0) {
403  dbg_printf("Failed to create a file context\n");
404  free(tcb->file_ctx);
405  tcb->file_ctx = NULL;
406  return ret;
407  }
408 
409  fctx = tcb->file_ctx;
410 
411  dev_node = getenv("stdin");
412  if (dev_node) {
413  info.size = BUFSIZ;
414  info.path = dev_node;
415  info.mode = O_RDONLY;
416 
417  ret = object_create(&fctx->table[STDIN_FILENO].object, &info);
418  if (ret < 0) {
419  dbg_printf("Failed to initiate the STDIN\n");
420  }
421  }
422 
423  dev_node = getenv("stdout");
424  if (dev_node) {
425  info.size = BUFSIZ;
426  info.path = dev_node;
427  info.mode = O_WRONLY;
428 
429  ret = object_create(&fctx->table[STDOUT_FILENO].object, &info);
430  if (ret < 0) {
431  dbg_printf("Failed to initiate the STDOUT\n");
432  }
433  }
434 
435  dev_node = getenv("stderr");
436  if (dev_node) {
437  info.size = 0;
438  info.path = dev_node;
439  info.mode = O_WRONLY;
440 
441  ret = object_create(&fctx->table[STDERR_FILENO].object, &info);
442  if (ret < 0) {
443  dbg_printf("Failed to initiate the STDERR\n");
444  }
445  }
446 
447  return 0;
448 }
449 
450 static inline int destroy_stack(struct thread *tcb)
451 {
452  if (tcb->attr.stack.is_allocated) {
453  free(tcb->attr.stack.addr);
454  }
455 
456  tcb->attr.stack.addr = NULL;
457  tcb->attr.stack.size = 0;
458  return 0;
459 }
460 
461 static inline int allocate_stack(struct thread *tcb)
462 {
463  int ret;
464  char *tmp;
465 
466  ret = posix_memalign((void **)&tmp,
468  if (ret < 0) {
469  return ret;
470  }
471 
472  tcb->attr.stack.addr = tmp;
473  tcb->attr.stack.is_allocated = 1;
474  return 0;
475 }
476 
477 static inline int create_stack(struct thread *tcb, struct thread_attr *attr)
478 {
479  unsigned int tcb_sz;
480  struct local_tcb *local_tcb;
481  char *tmp;
482 
483  tcb_sz = common_get_tcb_sz();
484  if (!tcb_sz) {
485  return -EFAULT;
486  }
487 
488  if (attr) {
489  memcpy(&tcb->attr, attr, sizeof(*attr));
490  } else {
491  tcb->attr.stack.size = PTHREAD_STACK_MIN + tcb_sz;
492  tcb->attr.stack.addr = NULL;
493  }
494 
495  if (!tcb->attr.stack.addr) {
496  int ret;
497  ret = allocate_stack(tcb);
498  if (ret < 0) {
499  dbg_printf("Heap is not allocated: %d\n", ret);
500  }
501  }
502 
503  tmp = (char *)tcb->attr.stack.addr;
504  tmp += (tcb->attr.stack.size - tcb_sz);
505  local_tcb = (struct local_tcb *)tmp;
506  tcb->esp = (uint32_t *)tmp;
507 
512  local_tcb->tcb_ptr = tcb;
513 
518  strncpy(local_tcb->tag, THREAD_TAG, sizeof(local_tcb->tag));
519  return 0;
520 }
521 
522 static int thread_object_create(struct object *object, void *_attr)
523 {
524  struct thread *tcb;
525  struct thread_attr *attr;
526  int ret;
527 
528  attr = _attr;
529  tcb = object_get(object, struct thread, object);
530 
532  ret = create_stack(tcb, attr);
533  if (ret < 0) {
534  return ret;
535  }
536 
538  ret = thread_init_file_table(tcb);
539  if (ret < 0) {
540  goto error_out;
541  }
542 
543  tcb->sem = NULL;
544 
545  if (!attr || !attr->is_first) {
546  tcb->parent = pthread_self();
547  if (!tcb->parent) {
548  ret = -EFAULT;
549  thread_fini_file_table(tcb);
550  goto error_out;
551  }
552 
553  tcb->root = tcb->parent->root;
554 
555  thread_set_status(tcb, CREATED);
556  THREAD_LIST_LINK(tcb);
557  return 0;
558  }
559 
560  tcb->parent = NULL;
561  tcb->root = tcb;
562 
563  thread_set_status(tcb, RUNNING);
564  THREAD_LIST_INIT(tcb);
565  return 0;
566 
567 error_out:
568  destroy_stack(tcb);
569  return ret;
570 }
571 
572 static int thread_object_destroy(struct object *object)
573 {
574  struct thread *tcb;
575  struct list_head *end_of_sibling;
576  struct thread *tmp;
577  unsigned long flag;
578 
579  tcb = object_get(object, struct thread, object);
580 
581  irq_local_save(&flag);
582  list_del(&tcb->link);
583 
587  tmp = list_entry(tcb->child.next, struct thread, child);
588  if (tmp) {
589  struct list_head *pos;
590  struct thread *i;
591 
592  tmp->parent = tcb->parent;
593  list_for_each(pos, &tmp->sibling) {
594  i = list_entry(pos, struct thread, sibling);
595  i->parent = tcb->parent;
596  }
597  }
598 
599  tmp = list_entry(tcb->parent->child.next, struct thread, child);
600  if (tmp == tcb) {
601  struct thread *i;
605  tmp = list_entry(tcb->child.next, struct thread, child);
606  end_of_sibling = tcb->sibling.prev;
607  list_link(&tmp->sibling, end_of_sibling);
608 
609  tmp = tcb->root;
613  i = list_entry(tcb->sibling.next, struct thread, sibling);
614  tmp->child.prev = &i->child;
615  i->child.next = &tmp->child;
616 
617  tcb->parent->child.next = &i->child;
618  i->child.prev = &tcb->parent->child;
619  } else {
620  end_of_sibling = tmp->sibling.prev;
621  tmp = list_entry(tcb->child.next, struct thread, child);
622  list_link(&tmp->sibling, end_of_sibling);
623 
624  list_del(&tcb->sibling);
625  }
626 
627  thread_fini_file_table(tcb);
628  destroy_stack(tcb);
629  irq_local_restore(flag);
630 
631  return 0;
632 }
633 
634 static int thread_object_copy(struct object *_dest, struct object *_src)
635 {
636  struct thread *src;
637 
638  src = object_get(_src, struct thread, object);
639  if (!src->user_data) {
640  return -EINVAL;
641  }
642 
655  return -ENOSYS;
656 }
657 
658 static struct object *thread_object_link(struct object *object)
659 {
660  struct thread *tcb;
661 
662  tcb = object_get(object, struct thread, object);
663  if (!tcb->user_data) {
664  return NULL;
665  }
666 
667  return object;
668 }
669 
670 int thread_create(struct thread *tcb, struct thread_attr *attr)
671 {
672  int ret;
673  struct object_ops ops = {
674  .create = thread_object_create,
675  .destroy = thread_object_destroy,
676  .copy = thread_object_copy,
677  .link = thread_object_link,
678  };
679 
680  ret = object_init(&tcb->object, &ops);
681  if (ret < 0) {
682  return ret;
683  }
684 
685  ret = object_create(&tcb->object, attr);
686  if (ret < 0) {
687  return ret;
688  }
689 
690  return 0;
691 }
692 
693 void thread_set_status(struct thread *tcb, int status)
694 {
695  assert(tcb && "Invalid argument");
696  tcb->status = status;
697 }
698 
699 int thread_get_status(struct thread *tcb)
700 {
701  assert(tcb && "Invalid argument");
702  return tcb->status;
703 }
704 
705 unsigned long thread_get_stack_pointer(struct thread *tcb)
706 {
707  unsigned long stack_pointer;
708 
709  assert(tcb && "Invalid argument");
710 
711  stack_pointer = (unsigned long)tcb->attr.stack.addr;
712  stack_pointer += tcb->attr.stack.size;
713 
714  return stack_pointer;
715 }
716 
717 void *thread_get_arch_data(struct thread *tcb)
718 {
719  assert(tcb && "Invalid argument");
720  return tcb->arch_data;
721 }
722 
723 void *thread_get_user_data(struct thread *tcb)
724 {
725  assert(tcb && "Invalid argument");
726  return tcb->user_data;
727 }
728 
729 /* End of a file */