summaryrefslogtreecommitdiffstats
path: root/pk/kernel/pk_thread_init.c
blob: 686f35121e9c9d5a9f691236a705907399a5869e (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
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
//-----------------------------------------------------------------------------
// *! (C) Copyright International Business Machines Corp. 2014
// *! All Rights Reserved -- Property of IBM
// *! *** IBM Confidential ***
//-----------------------------------------------------------------------------

/// \file pk_thread_init.c
/// \brief PK thread API initialization routines
///
/// The entry points in this file are routines that are typically used during
/// initialization, and their code space could be deallocated and recovered if
/// no longer needed by the application after initialization.

#include "pk.h"

/// Create (initialize) a thread
///
/// \param thread A pointer to an PkThread structure to initialize
///
/// \param thread_routine The subroutine that implements the thread
///
/// \param arg Private data to be passed as the argument to the thread
/// routine when it begins execution
///
/// \param stack The stack space of the thread
///
/// \param stack_size The size of the stack in bytes
///
/// \param priority The initial priority of the thread
///
/// The \a thread argument must be a pointer to an uninitialized or completed
/// or deleted thread.  This \c PkThread structure \em is the thread, so this
/// memory area must not be modified by the application until the thread
/// completes or is deleted.  PK can not tell if an PkThread structure is
/// currently in use as a thread control block.pk_thread_create() will
/// silently overwrite an PkThread structure that is currently in use.
///
/// The stack area must be large enough to hold the dynamic stack requirements
/// of the entry point routine, and all subroutines and functions that might
/// be invoked on any path from the entry point.  The stack must also always
/// be able to hold the thread context in the event the thread is preempted,
/// plus other critical context.  PK aligns stack areas in machine-specific
/// ways, so that the actual stack area may reduced in size slightly if it is
/// not already aligned.
///
/// Threads are created runnable but unmapped.  A newly created thread will
/// not be eligible to run until a call of pk_thread_resume() targets the
/// thread.
///
/// Return values other than PK_OK (0) are errors; see \ref pk_errors
///
/// \retval 0 Successful completion
///
/// \retval -PK_INVALID_THREAD_AT_CREATE The \a thread is a null (0) pointer.
/// 
/// \retval -PK_ILLEGAL_CONTEXT The API was called from a critical interrupt
/// context. 
///
/// \retval -PK_INVALID_ARGUMENT_THREAD1 the \a thread_routine is null (0)
///
/// \retval -PK_INVALID_ARGUMENT_THREAD2 the \a priority is invalid, 
///
/// \retval -PK_INVALID_ARGUMENT_THREAD3 the stack area wraps around 
/// the end of memory.
///
/// \retval -PK_STACK_OVERFLOW The stack area at thread creation is smaller
/// than the minimum safe size.

int
pk_thread_create(PkThread         *thread,
                  PkThreadRoutine  thread_routine,
                  void              *arg,
                  PkAddress        stack,
                  size_t            stack_size,
                  PkThreadPriority priority)
{
    int rc;

    if (PK_ERROR_CHECK_API) {
        PK_ERROR_IF(thread == 0, PK_INVALID_THREAD_AT_CREATE);
        PK_ERROR_IF((thread_routine == 0) ||
                     (priority >= PK_THREADS),
                     PK_INVALID_ARGUMENT_THREAD1);
    }

    rc = __pk_stack_init(&stack, &stack_size);
    if (rc) {
        return rc;
    }

    thread->saved_stack_pointer = stack;
    thread->stack_base = stack;

    if (PK_STACK_DIRECTION < 0) {

        thread->stack_limit = stack - stack_size;
        if (PK_ERROR_CHECK_API) {
            PK_ERROR_IF(thread->stack_limit > thread->stack_base,
                         PK_INVALID_ARGUMENT_THREAD2);
        }

    } else {

        thread->stack_limit = stack + stack_size;
        if (PK_ERROR_CHECK_API) {
            PK_ERROR_IF(thread->stack_limit < thread->stack_base,
                         PK_INVALID_ARGUMENT_THREAD3);
        }
    }

    thread->semaphore = 0;
    thread->priority = priority;
    thread->state = PK_THREAD_STATE_SUSPENDED_RUNNABLE;
    thread->flags = 0;

    pk_timer_create_nonpreemptible(&(thread->timer), 
                                    __pk_thread_timeout, 
                                    (void *)thread);

    __pk_thread_context_initialize(thread, thread_routine, arg);

    return rc;
}
    

    

    

    

        

    
        


OpenPOWER on IntegriCloud