arch/all-unix: Use default KrnGetCPUCount() implementation
[aros:aros.git] / AROS / arch / all-unix / kernel / smp.c
1 /*
2  * Copyright (C) 2013, The AROS Development Team
3  * All right reserved.
4  * Author: Jason S. McMullan <jason.mcmullan@gmail.com>
5  *
6  * Licensed under the AROS PUBLIC LICENSE (APL) Version 1.1
7  * 
8  * $Id$
9  */
10 #include <aros/debug.h>
11 #include <aros/kernel.h>
12 #include <exec/execbase.h>
13
14 #include "kernel_base.h"
15 #include "kernel_intern.h"
16 #include "kernel_globals.h"
17 #include "kernel_unix.h"
18
19 static void *smp_entry(void *threadp)
20 {
21     struct KernelBase *KernelBase = getKernelBase();
22     struct PlatformData *pd = KernelBase->kb_PlatformData;
23     struct KrnUnixThread *thread = threadp;
24     unsigned int cpu;
25     IPTR res;
26     sigset_t newset;
27
28     /* Determine our CPU
29      */
30     cpu = thread - &pd->thread[0];
31     bug("CPU%d: Kernel IPI\n", cpu);
32     pd->iface->pthread_setspecific(pd->key_cpu, &cpu);
33
34     /* SIGSYS and SIGURG for threads */
35     SIGFILLSET(&newset);
36     SIGDELSET(&newset, SIGSYS);     /* SysCall-stype */
37     SIGDELSET(&newset, SIGURG);     /* IRQ-style */
38     SIGDELSET(&newset, SIGTSTP);    /* Disable() */
39     SIGDELSET(&newset, SIGCONT);    /* Enable() */
40     pd->iface->sigprocmask(SIG_SETMASK, &newset, NULL);
41
42     do {
43         /* Acknowledge that we are ready to go */
44         pd->iface->pthread_mutex_lock(&pd->forbid_mutex);
45         thread->state = STATE_IDLE;
46         pd->iface->pthread_cond_broadcast(&thread->state_cond);
47         pd->iface->pthread_mutex_unlock(&pd->forbid_mutex);
48
49         bug("CPU%d: Idle\n", cpu);
50         while (thread->hook == NULL);
51
52         /* Notify that we are running */
53         pd->iface->pthread_mutex_lock(&pd->forbid_mutex);
54         thread->state = STATE_RUNNING;
55         pd->iface->pthread_cond_broadcast(&thread->state_cond);
56         pd->iface->pthread_mutex_unlock(&pd->forbid_mutex);
57
58         bug("CPU%d: Running hook %p\n", cpu, thread->hook);
59         res = CALLHOOKPKT(thread->hook, &cpu, thread->message);
60
61         thread->hook = NULL;
62     } while (res == 0);
63
64     return (void *)res;
65 }
66
67 int smp_Start(void)
68 {
69     struct KernelBase *KernelBase = getKernelBase();
70     struct PlatformData *pd = KernelBase->kb_PlatformData;
71     struct KernelInterface *iface = pd->iface;
72     sigset_t oldset, newset;
73     ULONG cpu;
74     
75     /* Initialize the boot CPU's per-thread data */
76     pd->threads = KrnGetCPUCount();
77     pd->thread = AllocMem(sizeof(struct KrnUnixThread)*pd->threads, MEMF_ANY | MEMF_CLEAR);
78
79     /* Block all signals..
80      * NOTE: For SMP, sigprocmask is actually pointing to pthread_sigmask,
81      *       as required for pthread support
82      */
83     iface->sigprocmask(0, NULL, &oldset);
84
85     SIGFILLSET(&newset);
86
87     iface->sigprocmask(SIG_SETMASK, &newset, NULL);
88
89     pd->forbid_cpu = -1;
90     pd->forbid_depth = -1;
91     pd->iface->pthread_mutex_init(&pd->forbid_mutex, NULL);
92
93     pd->iface->pthread_key_create(&pd->key_cpu, NULL);
94     pd->iface->pthread_key_create(&pd->key_storage, NULL);
95
96     SIGEMPTYSET(&newset);
97     SIGADDSET(&newset, SIGCONT);
98
99     /* Start all new threads - they will wait for their KrnUnixTLS->CPUId to
100      * be non-zero
101      */
102     pd->thread[0].tid = iface->pthread_self();
103     for (cpu = 1; cpu < pd->threads; cpu++) {
104         int err;
105         struct KrnUnixThread *thread = &pd->thread[cpu];
106 #ifdef HOST_OS_linux
107 #define O_NONBLOCK 04000
108 #endif
109         thread->state = STATE_STOPPED;
110         pd->iface->pthread_cond_init(&thread->state_cond, NULL);
111         pd->iface->pipe2(thread->signal, O_NONBLOCK );
112         err = iface->pthread_create(&thread->tid, NULL, smp_entry, &pd->thread[cpu]);
113         if (err) {
114             D(bug("CPU%d: Could not start\n", cpu));
115         }
116         /* Wait for startup acknowlege */
117         pd->iface->pthread_mutex_lock(&pd->forbid_mutex);
118         while (thread->state != STATE_IDLE) {
119             pd->iface->pthread_cond_wait(&thread->state_cond, &pd->forbid_mutex);
120         }
121         pd->iface->pthread_mutex_unlock(&pd->forbid_mutex);
122     }
123     
124     /* Restore the signal set for the boot thread */
125     iface->sigprocmask(SIG_SETMASK, &oldset, NULL);
126     return 0;
127 }
128
129