summaryrefslogtreecommitdiff
path: root/sysdeps/mach/pt-start.c
blob: 5e8cd5aaac2bb29ee974b818d92758cd6999336e (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
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
/* Start thread.  Mach version.
   Copyright (C) 2000,02 Free Software Foundation, Inc.
   This file is part of the GNU C Library.

   The GNU C Library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public License as
   published by the Free Software Foundation; either version 2 of the
   License, or (at your option) any later version.

   The GNU C 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
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public
   License along with the GNU C Library; see the file COPYING.LIB.  If not,
   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
   Boston, MA 02111-1307, USA.  */

#include <assert.h>
#include <errno.h>
#include <string.h>

#include <mach.h>

#include <pt-internal.h>

/* Prepare a wakeup message.  */
static error_t
create_wakeupmsg (struct __pthread *thread)
{
  kern_return_t err;

  /* Build wakeup message.  */
  thread->wakeupmsg.msgh_bits = MACH_MSGH_BITS (MACH_MSG_TYPE_COPY_SEND, 0);
  thread->wakeupmsg.msgh_size = 0;

  err = __mach_port_allocate (__mach_task_self (), MACH_PORT_RIGHT_RECEIVE,
			      &thread->wakeupmsg.msgh_remote_port);
  if (err)
    return EAGAIN;

  thread->wakeupmsg.msgh_local_port = MACH_PORT_NULL;
  thread->wakeupmsg.msgh_seqno = 0;
  thread->wakeupmsg.msgh_id = 0;

  err = __mach_port_insert_right (__mach_task_self (),
				  thread->wakeupmsg.msgh_remote_port,
				  thread->wakeupmsg.msgh_remote_port,
				  MACH_MSG_TYPE_MAKE_SEND);
  if (err)
    {
      __mach_port_deallocate (__mach_task_self (),
			      thread->wakeupmsg.msgh_remote_port);
      return EAGAIN;
    }

  return 0;
}

/* Start THREAD.  We allocate all system-specific resources, including
   a kernel thread, set it up, and get it running.  */
int
__pthread_start (struct __pthread *thread)
{
  error_t err;

  err = create_wakeupmsg (thread);
  if (err)
    return err;

  /* If there are no pthreads in the system then the pthread library
     is bootstrapping and the main thread must create initialize
     itself.  The thread itself is already running, it just has no
     pthread context.  We want to reuse what it already has (including
     the kernel thread), however, we must determine which thread is
     the main thread.

     We cannot test if __pthread_total is one as we later decrement it
     before creating the signal thread.  Currently, we check if
     __pthread_num_threads--the number of allocated thread
     structures--is one.  __pthread_alloc has already been called in
     __pthread_create_internal for us.  This predicate could be
     improved, however, it is sufficient for now.  */
  if (__pthread_num_threads == 1)
    {
      assert (__pthread_total == 1);
      thread->kernel_thread = __mach_thread_self ();
    }
  else
    {
      err = __thread_create (__mach_task_self (), &thread->kernel_thread);
      if (err)
	return EAGAIN;

      err = __thread_set_pcsp (thread->kernel_thread,
			       1, thread->mcontext.pc,
			       1, thread->mcontext.sp);
      assert_perror (err);

      err = __thread_resume (thread->kernel_thread);
      assert_perror (err);
    }

  return 0;
}