Compare commits
No commits in common. "1c7aa6edda81e2a2138a69f2b7880a2c83b5a14a" and "a5e4d1920066b074918662d75f2455e33051c215" have entirely different histories.
1c7aa6edda
...
a5e4d19200
13
.gitignore
vendored
13
.gitignore
vendored
@ -1,3 +1,14 @@
|
|||||||
kern/compile/
|
/.depend
|
||||||
|
/.settings
|
||||||
|
/.project
|
||||||
|
/.cproject
|
||||||
|
/.root
|
||||||
|
/kern/compile/
|
||||||
|
/defs.mk
|
||||||
|
build
|
||||||
|
/userland/testbin/randcall/calls.c
|
||||||
|
/root/
|
||||||
|
*.swo
|
||||||
|
*.swp
|
||||||
build/*
|
build/*
|
||||||
**/build
|
**/build
|
||||||
|
1
Makefile
1
Makefile
@ -46,7 +46,6 @@ tools:
|
|||||||
build:
|
build:
|
||||||
(cd userland && $(MAKE) build)
|
(cd userland && $(MAKE) build)
|
||||||
(cd man && $(MAKE) install-staging)
|
(cd man && $(MAKE) install-staging)
|
||||||
(cd testscripts && $(MAKE) build)
|
|
||||||
|
|
||||||
includes tags depend:
|
includes tags depend:
|
||||||
(cd kern && $(MAKE) $@)
|
(cd kern && $(MAKE) $@)
|
||||||
|
@ -128,3 +128,4 @@ I would put the machine dependent stuffs in `kern/arch` and everything else outs
|
|||||||
The function `splx()` and `splhigh()` is used to enable and restore interrupts
|
The function `splx()` and `splhigh()` is used to enable and restore interrupts
|
||||||
|
|
||||||
This would not be sufficient to ensure mutual exclusion as we still need spinlocks.
|
This would not be sufficient to ensure mutual exclusion as we still need spinlocks.
|
||||||
|
|
||||||
|
46
common/libc/printf/tprintf.c
Normal file
46
common/libc/printf/tprintf.c
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <kern/secret.h>
|
||||||
|
|
||||||
|
#ifdef HOST
|
||||||
|
#include "hostcompat.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* printf variant that is quiet during automated testing */
|
||||||
|
int
|
||||||
|
tprintf(const char *fmt, ...)
|
||||||
|
{
|
||||||
|
int chars;
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
#ifdef SECRET_TESTING
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
va_start(ap, fmt);
|
||||||
|
chars = vprintf(fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
return chars;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* printf variant that is loud during automated testing */
|
||||||
|
int
|
||||||
|
nprintf(const char *fmt, ...)
|
||||||
|
{
|
||||||
|
int chars;
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
#ifndef SECRET_TESTING
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
va_start(ap, fmt);
|
||||||
|
chars = vprintf(fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
return chars;
|
||||||
|
}
|
2511
common/libtest161/config.h
Normal file
2511
common/libtest161/config.h
Normal file
File diff suppressed because it is too large
Load Diff
206
common/libtest161/secure.c
Normal file
206
common/libtest161/secure.c
Normal file
@ -0,0 +1,206 @@
|
|||||||
|
|
||||||
|
// Beware, this code is shared between the kernel and userspace.
|
||||||
|
|
||||||
|
#ifdef _KERNEL
|
||||||
|
#include <types.h>
|
||||||
|
#include <lib.h>
|
||||||
|
#include <kern/errno.h>
|
||||||
|
#else
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <kern/secure.h>
|
||||||
|
#include "sha256.h"
|
||||||
|
|
||||||
|
// The full length (with null) of the hex string of a byte array
|
||||||
|
#define HEXLEN(a) 2*a+1
|
||||||
|
|
||||||
|
#define SHA256_BLOCK_SIZE 64
|
||||||
|
#define SHA256_OUTPUT_SIZE 32
|
||||||
|
|
||||||
|
// Keep this divisible by 4, or else change make_salt()
|
||||||
|
#define SALT_BYTES 8
|
||||||
|
|
||||||
|
// inner and outer padding for HMAC.
|
||||||
|
static const unsigned char ipad[SHA256_BLOCK_SIZE] = { [0 ... SHA256_BLOCK_SIZE-1] = 0x36 };
|
||||||
|
static const unsigned char opad[SHA256_BLOCK_SIZE] = { [0 ... SHA256_BLOCK_SIZE-1] = 0x5c };
|
||||||
|
|
||||||
|
// Hack for not having a userspace malloc until ASST3. We 'allocate' these statuc buffers.
|
||||||
|
// This works because the process single-threaded.
|
||||||
|
#define NUM_BUFFERS 4
|
||||||
|
#define BUFFER_LEN 1024
|
||||||
|
|
||||||
|
static char temp_buffers[NUM_BUFFERS][BUFFER_LEN];
|
||||||
|
static int buf_num = 0;
|
||||||
|
|
||||||
|
#ifndef _KERNEL
|
||||||
|
static int did_random = 0;
|
||||||
|
#define NSEC_PER_MSEC 1000000ULL
|
||||||
|
#define MSEC_PER_SEC 1000ULL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Both userspace and the kernel are using the temp buffers now.
|
||||||
|
static void * _alloc(size_t size)
|
||||||
|
{
|
||||||
|
(void)size;
|
||||||
|
void *ptr = temp_buffers[buf_num];
|
||||||
|
buf_num++;
|
||||||
|
buf_num = buf_num % NUM_BUFFERS;
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _free(void *ptr)
|
||||||
|
{
|
||||||
|
(void)ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* hamc_sha256 follows FIPS 198-1 HMAC using sha256.
|
||||||
|
* See http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf for details.
|
||||||
|
* NOTE: This is only thread-safe if called from within secprintf()!!!
|
||||||
|
*/
|
||||||
|
static int hmac_sha256(const char *msg, size_t msg_len, const char *key, size_t key_len,
|
||||||
|
unsigned char output[SHA256_OUTPUT_SIZE])
|
||||||
|
{
|
||||||
|
// We use a total of 320 bytes of array data on the stack
|
||||||
|
unsigned char k0[SHA256_BLOCK_SIZE];
|
||||||
|
|
||||||
|
// Steps 1-3. Anything less than 64 bytes gets 0s appended.
|
||||||
|
memset(k0, 0, SHA256_BLOCK_SIZE);
|
||||||
|
|
||||||
|
if (key_len <= SHA256_BLOCK_SIZE) {
|
||||||
|
memcpy(k0, key, key_len);
|
||||||
|
} else {
|
||||||
|
mbedtls_sha256((unsigned char *)key, key_len, k0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Steps 4 and 7.
|
||||||
|
unsigned char k_ipad[SHA256_BLOCK_SIZE];
|
||||||
|
unsigned char k_opad[SHA256_BLOCK_SIZE];
|
||||||
|
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < SHA256_BLOCK_SIZE; i++) {
|
||||||
|
k_ipad[i] = k0[i] ^ ipad[i];
|
||||||
|
k_opad[i] = k0[i] ^ opad[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 5 (K0 xor ipad) || msg
|
||||||
|
// We have no idea how big the message is so we allocate this on the heap.
|
||||||
|
unsigned char *data = (unsigned char *)_alloc(msg_len + SHA256_BLOCK_SIZE);
|
||||||
|
if (!data)
|
||||||
|
return ENOMEM;
|
||||||
|
|
||||||
|
memcpy(data, k_ipad, SHA256_BLOCK_SIZE);
|
||||||
|
memcpy(data+SHA256_BLOCK_SIZE, msg, msg_len);
|
||||||
|
|
||||||
|
// Step6: H((k0 xor ipad) || msg)
|
||||||
|
unsigned char h1[SHA256_OUTPUT_SIZE];
|
||||||
|
mbedtls_sha256(data, msg_len + SHA256_BLOCK_SIZE, h1, 0);
|
||||||
|
_free(data);
|
||||||
|
|
||||||
|
// Step 8: (k0 xor opad) || H((k0 xor ipad) || msg)
|
||||||
|
unsigned char inner[SHA256_OUTPUT_SIZE + SHA256_BLOCK_SIZE];
|
||||||
|
memcpy(inner, k_opad, SHA256_BLOCK_SIZE);
|
||||||
|
memcpy(inner + SHA256_BLOCK_SIZE, h1, SHA256_OUTPUT_SIZE);
|
||||||
|
|
||||||
|
// Step 9: Finally, H((k0 xor opad) || H((k0 xor ipad) || msg))
|
||||||
|
mbedtls_sha256(inner, SHA256_OUTPUT_SIZE + SHA256_BLOCK_SIZE, output, 0);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline char to_hex(int n)
|
||||||
|
{
|
||||||
|
return n < 10 ? '0'+n : 'a' + (n-10);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void array_to_hex(unsigned char *a, size_t len, char *res)
|
||||||
|
{
|
||||||
|
size_t i, j;
|
||||||
|
j = 0;
|
||||||
|
for (i = 0; i < len; i++) {
|
||||||
|
res[j++] = to_hex(a[i] >> 4);
|
||||||
|
res[j++] = to_hex(a[i] & 0xF);
|
||||||
|
}
|
||||||
|
res[j] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
static void make_salt(char *salt_str)
|
||||||
|
{
|
||||||
|
#ifndef _KERNEL
|
||||||
|
if (!did_random) {
|
||||||
|
did_random = 1;
|
||||||
|
time_t sec;
|
||||||
|
unsigned long ns;
|
||||||
|
unsigned long long ms;
|
||||||
|
|
||||||
|
__time(&sec, &ns);
|
||||||
|
ms = (unsigned long long)sec * MSEC_PER_SEC;
|
||||||
|
ms += (ns / NSEC_PER_MSEC);
|
||||||
|
srandom((unsigned long)ms);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Compute salt value
|
||||||
|
uint32_t salt[SALT_BYTES/sizeof(uint32_t)];
|
||||||
|
|
||||||
|
size_t i;
|
||||||
|
for (i = 0; i < SALT_BYTES/sizeof(uint32_t); i++)
|
||||||
|
{
|
||||||
|
salt[i] = random();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert to hex string
|
||||||
|
array_to_hex((unsigned char *)salt, SALT_BYTES, salt_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
int hmac(const char *msg, size_t msg_len, const char *key, size_t key_len,
|
||||||
|
char **hash_str)
|
||||||
|
{
|
||||||
|
*hash_str = _alloc(HEXLEN(SHA256_OUTPUT_SIZE));
|
||||||
|
|
||||||
|
if (!(*hash_str))
|
||||||
|
return ENOMEM;
|
||||||
|
|
||||||
|
// Hash it
|
||||||
|
unsigned char hash[SHA256_OUTPUT_SIZE];
|
||||||
|
int res = hmac_sha256(msg, msg_len, key, key_len, hash);
|
||||||
|
if (res)
|
||||||
|
return res;
|
||||||
|
|
||||||
|
// Convert to hex string
|
||||||
|
array_to_hex(hash, SHA256_OUTPUT_SIZE, *hash_str);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: This is only thread-safe if called from within secprintf()!!!
|
||||||
|
int hmac_salted(const char *msg, size_t msg_len, const char *key, size_t key_len,
|
||||||
|
char **hash_str, char **salt_str)
|
||||||
|
{
|
||||||
|
*salt_str = _alloc(HEXLEN(SALT_BYTES));
|
||||||
|
|
||||||
|
if (!(*salt_str))
|
||||||
|
return ENOMEM;
|
||||||
|
|
||||||
|
// Create the salt value
|
||||||
|
make_salt(*salt_str);
|
||||||
|
|
||||||
|
// Concatenate the key and salt, with the resulting string being null-terminated
|
||||||
|
size_t key2_len = key_len + HEXLEN(SALT_BYTES)-1;
|
||||||
|
char *key2 = (char *)_alloc(key2_len+1);
|
||||||
|
if (!key2)
|
||||||
|
return ENOMEM;
|
||||||
|
|
||||||
|
strcpy(key2, key);
|
||||||
|
strcpy(key2+key_len, *salt_str);
|
||||||
|
key2[key2_len] = '\0';
|
||||||
|
|
||||||
|
// Hash it
|
||||||
|
return hmac(msg, msg_len, key2, key2_len, hash_str);
|
||||||
|
}
|
451
common/libtest161/sha256.c
Normal file
451
common/libtest161/sha256.c
Normal file
@ -0,0 +1,451 @@
|
|||||||
|
/*
|
||||||
|
* FIPS-180-2 compliant SHA-256 implementation
|
||||||
|
*
|
||||||
|
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
* not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
* This file is part of mbed TLS (https://tls.mbed.org)
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* The SHA-256 Secure Hash Standard was published by NIST in 2002.
|
||||||
|
*
|
||||||
|
* http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if !defined(MBEDTLS_CONFIG_FILE)
|
||||||
|
#include "config.h"
|
||||||
|
#else
|
||||||
|
#include MBEDTLS_CONFIG_FILE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MBEDTLS_SHA256_C)
|
||||||
|
|
||||||
|
#include "sha256.h"
|
||||||
|
|
||||||
|
#ifdef _KERNEL
|
||||||
|
#include <types.h>
|
||||||
|
#include <lib.h>
|
||||||
|
#else
|
||||||
|
#include <types/size_t.h>
|
||||||
|
#include <string.h>
|
||||||
|
#endif // _KERNEL
|
||||||
|
|
||||||
|
#if defined(MBEDTLS_SELF_TEST)
|
||||||
|
#if defined(MBEDTLS_PLATFORM_C)
|
||||||
|
#include "platform.h"
|
||||||
|
#else
|
||||||
|
#include <stdio.h>
|
||||||
|
#define mbedtls_printf printf
|
||||||
|
#endif /* MBEDTLS_PLATFORM_C */
|
||||||
|
#endif /* MBEDTLS_SELF_TEST */
|
||||||
|
|
||||||
|
#if !defined(MBEDTLS_SHA256_ALT)
|
||||||
|
|
||||||
|
/* Implementation that should never be optimized out by the compiler */
|
||||||
|
static void mbedtls_zeroize( void *v, size_t n ) {
|
||||||
|
volatile unsigned char *p = v; while( n-- ) *p++ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 32-bit integer manipulation macros (big endian)
|
||||||
|
*/
|
||||||
|
#ifndef GET_UINT32_BE
|
||||||
|
#define GET_UINT32_BE(n,b,i) \
|
||||||
|
do { \
|
||||||
|
(n) = ( (uint32_t) (b)[(i) ] << 24 ) \
|
||||||
|
| ( (uint32_t) (b)[(i) + 1] << 16 ) \
|
||||||
|
| ( (uint32_t) (b)[(i) + 2] << 8 ) \
|
||||||
|
| ( (uint32_t) (b)[(i) + 3] ); \
|
||||||
|
} while( 0 )
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef PUT_UINT32_BE
|
||||||
|
#define PUT_UINT32_BE(n,b,i) \
|
||||||
|
do { \
|
||||||
|
(b)[(i) ] = (unsigned char) ( (n) >> 24 ); \
|
||||||
|
(b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \
|
||||||
|
(b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \
|
||||||
|
(b)[(i) + 3] = (unsigned char) ( (n) ); \
|
||||||
|
} while( 0 )
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void mbedtls_sha256_init( mbedtls_sha256_context *ctx )
|
||||||
|
{
|
||||||
|
memset( ctx, 0, sizeof( mbedtls_sha256_context ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
void mbedtls_sha256_free( mbedtls_sha256_context *ctx )
|
||||||
|
{
|
||||||
|
if( ctx == NULL )
|
||||||
|
return;
|
||||||
|
|
||||||
|
mbedtls_zeroize( ctx, sizeof( mbedtls_sha256_context ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
void mbedtls_sha256_clone( mbedtls_sha256_context *dst,
|
||||||
|
const mbedtls_sha256_context *src )
|
||||||
|
{
|
||||||
|
*dst = *src;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SHA-256 context setup
|
||||||
|
*/
|
||||||
|
void mbedtls_sha256_starts( mbedtls_sha256_context *ctx, int is224 )
|
||||||
|
{
|
||||||
|
ctx->total[0] = 0;
|
||||||
|
ctx->total[1] = 0;
|
||||||
|
|
||||||
|
if( is224 == 0 )
|
||||||
|
{
|
||||||
|
/* SHA-256 */
|
||||||
|
ctx->state[0] = 0x6A09E667;
|
||||||
|
ctx->state[1] = 0xBB67AE85;
|
||||||
|
ctx->state[2] = 0x3C6EF372;
|
||||||
|
ctx->state[3] = 0xA54FF53A;
|
||||||
|
ctx->state[4] = 0x510E527F;
|
||||||
|
ctx->state[5] = 0x9B05688C;
|
||||||
|
ctx->state[6] = 0x1F83D9AB;
|
||||||
|
ctx->state[7] = 0x5BE0CD19;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* SHA-224 */
|
||||||
|
ctx->state[0] = 0xC1059ED8;
|
||||||
|
ctx->state[1] = 0x367CD507;
|
||||||
|
ctx->state[2] = 0x3070DD17;
|
||||||
|
ctx->state[3] = 0xF70E5939;
|
||||||
|
ctx->state[4] = 0xFFC00B31;
|
||||||
|
ctx->state[5] = 0x68581511;
|
||||||
|
ctx->state[6] = 0x64F98FA7;
|
||||||
|
ctx->state[7] = 0xBEFA4FA4;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->is224 = is224;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !defined(MBEDTLS_SHA256_PROCESS_ALT)
|
||||||
|
static const uint32_t K[] =
|
||||||
|
{
|
||||||
|
0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5,
|
||||||
|
0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5,
|
||||||
|
0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3,
|
||||||
|
0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174,
|
||||||
|
0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC,
|
||||||
|
0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA,
|
||||||
|
0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7,
|
||||||
|
0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967,
|
||||||
|
0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13,
|
||||||
|
0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85,
|
||||||
|
0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3,
|
||||||
|
0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070,
|
||||||
|
0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5,
|
||||||
|
0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3,
|
||||||
|
0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208,
|
||||||
|
0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define SHR(x,n) ((x & 0xFFFFFFFF) >> n)
|
||||||
|
#define ROTR(x,n) (SHR(x,n) | (x << (32 - n)))
|
||||||
|
|
||||||
|
#define S0(x) (ROTR(x, 7) ^ ROTR(x,18) ^ SHR(x, 3))
|
||||||
|
#define S1(x) (ROTR(x,17) ^ ROTR(x,19) ^ SHR(x,10))
|
||||||
|
|
||||||
|
#define S2(x) (ROTR(x, 2) ^ ROTR(x,13) ^ ROTR(x,22))
|
||||||
|
#define S3(x) (ROTR(x, 6) ^ ROTR(x,11) ^ ROTR(x,25))
|
||||||
|
|
||||||
|
#define F0(x,y,z) ((x & y) | (z & (x | y)))
|
||||||
|
#define F1(x,y,z) (z ^ (x & (y ^ z)))
|
||||||
|
|
||||||
|
#define R(t) \
|
||||||
|
( \
|
||||||
|
W[t] = S1(W[t - 2]) + W[t - 7] + \
|
||||||
|
S0(W[t - 15]) + W[t - 16] \
|
||||||
|
)
|
||||||
|
|
||||||
|
#define P(a,b,c,d,e,f,g,h,x,K) \
|
||||||
|
{ \
|
||||||
|
temp1 = h + S3(e) + F1(e,f,g) + K + x; \
|
||||||
|
temp2 = S2(a) + F0(a,b,c); \
|
||||||
|
d += temp1; h = temp1 + temp2; \
|
||||||
|
}
|
||||||
|
|
||||||
|
void mbedtls_sha256_process( mbedtls_sha256_context *ctx, const unsigned char data[64] )
|
||||||
|
{
|
||||||
|
uint32_t temp1, temp2, W[64];
|
||||||
|
uint32_t A[8];
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
for( i = 0; i < 8; i++ )
|
||||||
|
A[i] = ctx->state[i];
|
||||||
|
|
||||||
|
#if defined(MBEDTLS_SHA256_SMALLER)
|
||||||
|
for( i = 0; i < 64; i++ )
|
||||||
|
{
|
||||||
|
if( i < 16 )
|
||||||
|
GET_UINT32_BE( W[i], data, 4 * i );
|
||||||
|
else
|
||||||
|
R( i );
|
||||||
|
|
||||||
|
P( A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], W[i], K[i] );
|
||||||
|
|
||||||
|
temp1 = A[7]; A[7] = A[6]; A[6] = A[5]; A[5] = A[4]; A[4] = A[3];
|
||||||
|
A[3] = A[2]; A[2] = A[1]; A[1] = A[0]; A[0] = temp1;
|
||||||
|
}
|
||||||
|
#else /* MBEDTLS_SHA256_SMALLER */
|
||||||
|
for( i = 0; i < 16; i++ )
|
||||||
|
GET_UINT32_BE( W[i], data, 4 * i );
|
||||||
|
|
||||||
|
for( i = 0; i < 16; i += 8 )
|
||||||
|
{
|
||||||
|
P( A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], W[i+0], K[i+0] );
|
||||||
|
P( A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], W[i+1], K[i+1] );
|
||||||
|
P( A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], W[i+2], K[i+2] );
|
||||||
|
P( A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], W[i+3], K[i+3] );
|
||||||
|
P( A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], W[i+4], K[i+4] );
|
||||||
|
P( A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], W[i+5], K[i+5] );
|
||||||
|
P( A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], W[i+6], K[i+6] );
|
||||||
|
P( A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], W[i+7], K[i+7] );
|
||||||
|
}
|
||||||
|
|
||||||
|
for( i = 16; i < 64; i += 8 )
|
||||||
|
{
|
||||||
|
P( A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], R(i+0), K[i+0] );
|
||||||
|
P( A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], R(i+1), K[i+1] );
|
||||||
|
P( A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], R(i+2), K[i+2] );
|
||||||
|
P( A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], R(i+3), K[i+3] );
|
||||||
|
P( A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], R(i+4), K[i+4] );
|
||||||
|
P( A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], R(i+5), K[i+5] );
|
||||||
|
P( A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], R(i+6), K[i+6] );
|
||||||
|
P( A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], R(i+7), K[i+7] );
|
||||||
|
}
|
||||||
|
#endif /* MBEDTLS_SHA256_SMALLER */
|
||||||
|
|
||||||
|
for( i = 0; i < 8; i++ )
|
||||||
|
ctx->state[i] += A[i];
|
||||||
|
}
|
||||||
|
#endif /* !MBEDTLS_SHA256_PROCESS_ALT */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SHA-256 process buffer
|
||||||
|
*/
|
||||||
|
void mbedtls_sha256_update( mbedtls_sha256_context *ctx, const unsigned char *input,
|
||||||
|
size_t ilen )
|
||||||
|
{
|
||||||
|
size_t fill;
|
||||||
|
uint32_t left;
|
||||||
|
|
||||||
|
if( ilen == 0 )
|
||||||
|
return;
|
||||||
|
|
||||||
|
left = ctx->total[0] & 0x3F;
|
||||||
|
fill = 64 - left;
|
||||||
|
|
||||||
|
ctx->total[0] += (uint32_t) ilen;
|
||||||
|
ctx->total[0] &= 0xFFFFFFFF;
|
||||||
|
|
||||||
|
if( ctx->total[0] < (uint32_t) ilen )
|
||||||
|
ctx->total[1]++;
|
||||||
|
|
||||||
|
if( left && ilen >= fill )
|
||||||
|
{
|
||||||
|
memcpy( (void *) (ctx->buffer + left), input, fill );
|
||||||
|
mbedtls_sha256_process( ctx, ctx->buffer );
|
||||||
|
input += fill;
|
||||||
|
ilen -= fill;
|
||||||
|
left = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
while( ilen >= 64 )
|
||||||
|
{
|
||||||
|
mbedtls_sha256_process( ctx, input );
|
||||||
|
input += 64;
|
||||||
|
ilen -= 64;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( ilen > 0 )
|
||||||
|
memcpy( (void *) (ctx->buffer + left), input, ilen );
|
||||||
|
}
|
||||||
|
|
||||||
|
static const unsigned char sha256_padding[64] =
|
||||||
|
{
|
||||||
|
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SHA-256 final digest
|
||||||
|
*/
|
||||||
|
void mbedtls_sha256_finish( mbedtls_sha256_context *ctx, unsigned char output[32] )
|
||||||
|
{
|
||||||
|
uint32_t last, padn;
|
||||||
|
uint32_t high, low;
|
||||||
|
unsigned char msglen[8];
|
||||||
|
|
||||||
|
high = ( ctx->total[0] >> 29 )
|
||||||
|
| ( ctx->total[1] << 3 );
|
||||||
|
low = ( ctx->total[0] << 3 );
|
||||||
|
|
||||||
|
PUT_UINT32_BE( high, msglen, 0 );
|
||||||
|
PUT_UINT32_BE( low, msglen, 4 );
|
||||||
|
|
||||||
|
last = ctx->total[0] & 0x3F;
|
||||||
|
padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last );
|
||||||
|
|
||||||
|
mbedtls_sha256_update( ctx, sha256_padding, padn );
|
||||||
|
mbedtls_sha256_update( ctx, msglen, 8 );
|
||||||
|
|
||||||
|
PUT_UINT32_BE( ctx->state[0], output, 0 );
|
||||||
|
PUT_UINT32_BE( ctx->state[1], output, 4 );
|
||||||
|
PUT_UINT32_BE( ctx->state[2], output, 8 );
|
||||||
|
PUT_UINT32_BE( ctx->state[3], output, 12 );
|
||||||
|
PUT_UINT32_BE( ctx->state[4], output, 16 );
|
||||||
|
PUT_UINT32_BE( ctx->state[5], output, 20 );
|
||||||
|
PUT_UINT32_BE( ctx->state[6], output, 24 );
|
||||||
|
|
||||||
|
if( ctx->is224 == 0 )
|
||||||
|
PUT_UINT32_BE( ctx->state[7], output, 28 );
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* !MBEDTLS_SHA256_ALT */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* output = SHA-256( input buffer )
|
||||||
|
*/
|
||||||
|
void mbedtls_sha256( const unsigned char *input, size_t ilen,
|
||||||
|
unsigned char output[32], int is224 )
|
||||||
|
{
|
||||||
|
mbedtls_sha256_context ctx;
|
||||||
|
|
||||||
|
mbedtls_sha256_init( &ctx );
|
||||||
|
mbedtls_sha256_starts( &ctx, is224 );
|
||||||
|
mbedtls_sha256_update( &ctx, input, ilen );
|
||||||
|
mbedtls_sha256_finish( &ctx, output );
|
||||||
|
mbedtls_sha256_free( &ctx );
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(MBEDTLS_SELF_TEST)
|
||||||
|
/*
|
||||||
|
* FIPS-180-2 test vectors
|
||||||
|
*/
|
||||||
|
static const unsigned char sha256_test_buf[3][57] =
|
||||||
|
{
|
||||||
|
{ "abc" },
|
||||||
|
{ "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" },
|
||||||
|
{ "" }
|
||||||
|
};
|
||||||
|
|
||||||
|
static const int sha256_test_buflen[3] =
|
||||||
|
{
|
||||||
|
3, 56, 1000
|
||||||
|
};
|
||||||
|
|
||||||
|
static const unsigned char sha256_test_sum[6][32] =
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* SHA-224 test vectors
|
||||||
|
*/
|
||||||
|
{ 0x23, 0x09, 0x7D, 0x22, 0x34, 0x05, 0xD8, 0x22,
|
||||||
|
0x86, 0x42, 0xA4, 0x77, 0xBD, 0xA2, 0x55, 0xB3,
|
||||||
|
0x2A, 0xAD, 0xBC, 0xE4, 0xBD, 0xA0, 0xB3, 0xF7,
|
||||||
|
0xE3, 0x6C, 0x9D, 0xA7 },
|
||||||
|
{ 0x75, 0x38, 0x8B, 0x16, 0x51, 0x27, 0x76, 0xCC,
|
||||||
|
0x5D, 0xBA, 0x5D, 0xA1, 0xFD, 0x89, 0x01, 0x50,
|
||||||
|
0xB0, 0xC6, 0x45, 0x5C, 0xB4, 0xF5, 0x8B, 0x19,
|
||||||
|
0x52, 0x52, 0x25, 0x25 },
|
||||||
|
{ 0x20, 0x79, 0x46, 0x55, 0x98, 0x0C, 0x91, 0xD8,
|
||||||
|
0xBB, 0xB4, 0xC1, 0xEA, 0x97, 0x61, 0x8A, 0x4B,
|
||||||
|
0xF0, 0x3F, 0x42, 0x58, 0x19, 0x48, 0xB2, 0xEE,
|
||||||
|
0x4E, 0xE7, 0xAD, 0x67 },
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SHA-256 test vectors
|
||||||
|
*/
|
||||||
|
{ 0xBA, 0x78, 0x16, 0xBF, 0x8F, 0x01, 0xCF, 0xEA,
|
||||||
|
0x41, 0x41, 0x40, 0xDE, 0x5D, 0xAE, 0x22, 0x23,
|
||||||
|
0xB0, 0x03, 0x61, 0xA3, 0x96, 0x17, 0x7A, 0x9C,
|
||||||
|
0xB4, 0x10, 0xFF, 0x61, 0xF2, 0x00, 0x15, 0xAD },
|
||||||
|
{ 0x24, 0x8D, 0x6A, 0x61, 0xD2, 0x06, 0x38, 0xB8,
|
||||||
|
0xE5, 0xC0, 0x26, 0x93, 0x0C, 0x3E, 0x60, 0x39,
|
||||||
|
0xA3, 0x3C, 0xE4, 0x59, 0x64, 0xFF, 0x21, 0x67,
|
||||||
|
0xF6, 0xEC, 0xED, 0xD4, 0x19, 0xDB, 0x06, 0xC1 },
|
||||||
|
{ 0xCD, 0xC7, 0x6E, 0x5C, 0x99, 0x14, 0xFB, 0x92,
|
||||||
|
0x81, 0xA1, 0xC7, 0xE2, 0x84, 0xD7, 0x3E, 0x67,
|
||||||
|
0xF1, 0x80, 0x9A, 0x48, 0xA4, 0x97, 0x20, 0x0E,
|
||||||
|
0x04, 0x6D, 0x39, 0xCC, 0xC7, 0x11, 0x2C, 0xD0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Checkup routine
|
||||||
|
*/
|
||||||
|
int mbedtls_sha256_self_test( int verbose )
|
||||||
|
{
|
||||||
|
int i, j, k, buflen, ret = 0;
|
||||||
|
unsigned char buf[1024];
|
||||||
|
unsigned char sha256sum[32];
|
||||||
|
mbedtls_sha256_context ctx;
|
||||||
|
|
||||||
|
mbedtls_sha256_init( &ctx );
|
||||||
|
|
||||||
|
for( i = 0; i < 6; i++ )
|
||||||
|
{
|
||||||
|
j = i % 3;
|
||||||
|
k = i < 3;
|
||||||
|
|
||||||
|
if( verbose != 0 )
|
||||||
|
mbedtls_printf( " SHA-%d test #%d: ", 256 - k * 32, j + 1 );
|
||||||
|
|
||||||
|
mbedtls_sha256_starts( &ctx, k );
|
||||||
|
|
||||||
|
if( j == 2 )
|
||||||
|
{
|
||||||
|
memset( buf, 'a', buflen = 1000 );
|
||||||
|
|
||||||
|
for( j = 0; j < 1000; j++ )
|
||||||
|
mbedtls_sha256_update( &ctx, buf, buflen );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
mbedtls_sha256_update( &ctx, sha256_test_buf[j],
|
||||||
|
sha256_test_buflen[j] );
|
||||||
|
|
||||||
|
mbedtls_sha256_finish( &ctx, sha256sum );
|
||||||
|
|
||||||
|
if( memcmp( sha256sum, sha256_test_sum[i], 32 - k * 4 ) != 0 )
|
||||||
|
{
|
||||||
|
if( verbose != 0 )
|
||||||
|
mbedtls_printf( "failed\n" );
|
||||||
|
|
||||||
|
ret = 1;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( verbose != 0 )
|
||||||
|
mbedtls_printf( "passed\n" );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( verbose != 0 )
|
||||||
|
mbedtls_printf( "\n" );
|
||||||
|
|
||||||
|
exit:
|
||||||
|
mbedtls_sha256_free( &ctx );
|
||||||
|
|
||||||
|
return( ret );
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* MBEDTLS_SELF_TEST */
|
||||||
|
|
||||||
|
#endif /* MBEDTLS_SHA256_C */
|
146
common/libtest161/sha256.h
Normal file
146
common/libtest161/sha256.h
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
/**
|
||||||
|
* \file sha256.h
|
||||||
|
*
|
||||||
|
* \brief SHA-224 and SHA-256 cryptographic hash function
|
||||||
|
*
|
||||||
|
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
* not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
* This file is part of mbed TLS (https://tls.mbed.org)
|
||||||
|
*/
|
||||||
|
#ifndef MBEDTLS_SHA256_H
|
||||||
|
#define MBEDTLS_SHA256_H
|
||||||
|
|
||||||
|
#if !defined(MBEDTLS_CONFIG_FILE)
|
||||||
|
#include "config.h"
|
||||||
|
#else
|
||||||
|
#include MBEDTLS_CONFIG_FILE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _KERNEL
|
||||||
|
#include <types.h>
|
||||||
|
#include <lib.h>
|
||||||
|
#else
|
||||||
|
#include <types/size_t.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#endif //_KERNEL
|
||||||
|
|
||||||
|
#if !defined(MBEDTLS_SHA256_ALT)
|
||||||
|
// Regular implementation
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief SHA-256 context structure
|
||||||
|
*/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint32_t total[2]; /*!< number of bytes processed */
|
||||||
|
uint32_t state[8]; /*!< intermediate digest state */
|
||||||
|
unsigned char buffer[64]; /*!< data block being processed */
|
||||||
|
int is224; /*!< 0 => SHA-256, else SHA-224 */
|
||||||
|
}
|
||||||
|
mbedtls_sha256_context;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Initialize SHA-256 context
|
||||||
|
*
|
||||||
|
* \param ctx SHA-256 context to be initialized
|
||||||
|
*/
|
||||||
|
void mbedtls_sha256_init( mbedtls_sha256_context *ctx );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Clear SHA-256 context
|
||||||
|
*
|
||||||
|
* \param ctx SHA-256 context to be cleared
|
||||||
|
*/
|
||||||
|
void mbedtls_sha256_free( mbedtls_sha256_context *ctx );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Clone (the state of) a SHA-256 context
|
||||||
|
*
|
||||||
|
* \param dst The destination context
|
||||||
|
* \param src The context to be cloned
|
||||||
|
*/
|
||||||
|
void mbedtls_sha256_clone( mbedtls_sha256_context *dst,
|
||||||
|
const mbedtls_sha256_context *src );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief SHA-256 context setup
|
||||||
|
*
|
||||||
|
* \param ctx context to be initialized
|
||||||
|
* \param is224 0 = use SHA256, 1 = use SHA224
|
||||||
|
*/
|
||||||
|
void mbedtls_sha256_starts( mbedtls_sha256_context *ctx, int is224 );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief SHA-256 process buffer
|
||||||
|
*
|
||||||
|
* \param ctx SHA-256 context
|
||||||
|
* \param input buffer holding the data
|
||||||
|
* \param ilen length of the input data
|
||||||
|
*/
|
||||||
|
void mbedtls_sha256_update( mbedtls_sha256_context *ctx, const unsigned char *input,
|
||||||
|
size_t ilen );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief SHA-256 final digest
|
||||||
|
*
|
||||||
|
* \param ctx SHA-256 context
|
||||||
|
* \param output SHA-224/256 checksum result
|
||||||
|
*/
|
||||||
|
void mbedtls_sha256_finish( mbedtls_sha256_context *ctx, unsigned char output[32] );
|
||||||
|
|
||||||
|
/* Internal use */
|
||||||
|
void mbedtls_sha256_process( mbedtls_sha256_context *ctx, const unsigned char data[64] );
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#else /* MBEDTLS_SHA256_ALT */
|
||||||
|
#include "sha256_alt.h"
|
||||||
|
#endif /* MBEDTLS_SHA256_ALT */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Output = SHA-256( input buffer )
|
||||||
|
*
|
||||||
|
* \param input buffer holding the data
|
||||||
|
* \param ilen length of the input data
|
||||||
|
* \param output SHA-224/256 checksum result
|
||||||
|
* \param is224 0 = use SHA256, 1 = use SHA224
|
||||||
|
*/
|
||||||
|
void mbedtls_sha256( const unsigned char *input, size_t ilen,
|
||||||
|
unsigned char output[32], int is224 );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Checkup routine
|
||||||
|
*
|
||||||
|
* \return 0 if successful, or 1 if the test failed
|
||||||
|
*/
|
||||||
|
int mbedtls_sha256_self_test( int verbose );
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* mbedtls_sha256.h */
|
188
common/libtest161/test161.c
Normal file
188
common/libtest161/test161.c
Normal file
@ -0,0 +1,188 @@
|
|||||||
|
// Beware, this code is shared between the kernel and userspace.
|
||||||
|
|
||||||
|
#ifdef _KERNEL
|
||||||
|
#include <types.h>
|
||||||
|
#include <lib.h>
|
||||||
|
#include <synch.h>
|
||||||
|
#include <kern/errno.h>
|
||||||
|
#include <kern/secure.h>
|
||||||
|
#include <kern/test161.h>
|
||||||
|
#else
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <test161/test161.h>
|
||||||
|
#include <test161/secure.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Hack for allocating userspace memory without malloc, and for
|
||||||
|
// allowing secprintf in kmalloc when we're out of memory.
|
||||||
|
#define BUFFER_SIZE 1024
|
||||||
|
|
||||||
|
static char temp_buffer[BUFFER_SIZE];
|
||||||
|
|
||||||
|
#ifndef _KERNEL
|
||||||
|
static char write_buffer[BUFFER_SIZE];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _KERNEL
|
||||||
|
// secprintf needs to be synchronized in the kernel because multiple threads
|
||||||
|
// may be trying to secprintf at the same time.
|
||||||
|
static struct semaphore *test161_sem;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// For now, allocating just passes a reference to our static temp buffer, and
|
||||||
|
// free does nothing.
|
||||||
|
static inline void * _alloc()
|
||||||
|
{
|
||||||
|
return temp_buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void _free(void *ptr)
|
||||||
|
{
|
||||||
|
(void)ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Common success function for kernel tests. If SECRET_TESTING is defined,
|
||||||
|
* ksecprintf will compute the hmac/sha256 hash of any message using the
|
||||||
|
* shared secret and a random salt value. The (secure) server also knows
|
||||||
|
* the secret and can verify the message was generated by a trusted source.
|
||||||
|
* The salt value prevents against replay attacks.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
success(int status, const char * secret, const char * name) {
|
||||||
|
if (status == TEST161_SUCCESS) {
|
||||||
|
return secprintf(secret, "SUCCESS", name);
|
||||||
|
} else {
|
||||||
|
return secprintf(secret, "FAIL", name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
partial_credit(const char *secret, const char *name, int scored, int total)
|
||||||
|
{
|
||||||
|
char buffer[128];
|
||||||
|
snprintf(buffer, 128, "PARTIAL CREDIT %d OF %d", scored, total);
|
||||||
|
return secprintf(secret, buffer, name);
|
||||||
|
}
|
||||||
|
#ifndef _KERNEL
|
||||||
|
|
||||||
|
// Borrowed from parallelvm. We need atomic console writes so our
|
||||||
|
// output doesn't get intermingled since test161 works with lines.
|
||||||
|
static
|
||||||
|
int
|
||||||
|
say(const char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, fmt);
|
||||||
|
vsnprintf(write_buffer, BUFFER_SIZE, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
return write(STDOUT_FILENO, write_buffer, strlen(write_buffer));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef SECRET_TESTING
|
||||||
|
|
||||||
|
int
|
||||||
|
snsecprintf(size_t len, char *buffer, const char *secret, const char *msg, const char *name)
|
||||||
|
{
|
||||||
|
(void)secret;
|
||||||
|
return snprintf(buffer, len, "%s: %s", name, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
secprintf(const char * secret, const char * msg, const char * name)
|
||||||
|
{
|
||||||
|
(void)secret;
|
||||||
|
|
||||||
|
#ifdef _KERNEL
|
||||||
|
return kprintf("\n%s: %s\n", name, msg);
|
||||||
|
#else
|
||||||
|
return say("\n%s: %s\n", name, msg);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
static int
|
||||||
|
secprintf_common(int use_buf, size_t b_len, char *buffer,
|
||||||
|
const char *secret, const char *msg, const char *name)
|
||||||
|
{
|
||||||
|
char *hash, *salt, *fullmsg;
|
||||||
|
int res;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
#ifdef _KERNEL
|
||||||
|
if (test161_sem == NULL) {
|
||||||
|
panic("test161_sem is NULL. Your kernel is missing test161_bootstrap.");
|
||||||
|
}
|
||||||
|
P(test161_sem);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
hash = salt = fullmsg = NULL;
|
||||||
|
|
||||||
|
// test161 expects "name: msg"
|
||||||
|
len = strlen(name) + strlen(msg) + 3; // +3 for " :" and null terminator
|
||||||
|
fullmsg = (char *)_alloc(len);
|
||||||
|
if (fullmsg == NULL) {
|
||||||
|
res = -ENOMEM;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
snprintf(fullmsg, len, "%s: %s", name, msg);
|
||||||
|
|
||||||
|
res = hmac_salted(fullmsg, len-1, secret, strlen(secret), &hash, &salt);
|
||||||
|
if (res) {
|
||||||
|
res = -res;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!use_buf) {
|
||||||
|
#ifdef _KERNEL
|
||||||
|
res = kprintf("\n(%s, %s, %s, %s: %s)\n", name, hash, salt, name, msg);
|
||||||
|
#else
|
||||||
|
res = say("\n(%s, %s, %s, %s: %s)\n", name, hash, salt, name, msg);
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
res = snprintf(buffer, b_len, "\n(%s, %s, %s, %s: %s)\n", name, hash, salt, name, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
// These may be NULL, but that's OK
|
||||||
|
_free(hash);
|
||||||
|
_free(salt);
|
||||||
|
_free(fullmsg);
|
||||||
|
|
||||||
|
#ifdef _KERNEL
|
||||||
|
V(test161_sem);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
snsecprintf(size_t b_len, char *buffer, const char *secret, const char *msg, const char *name)
|
||||||
|
{
|
||||||
|
return secprintf_common(1, b_len, buffer, secret, msg, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
secprintf(const char * secret, const char * msg, const char * name)
|
||||||
|
{
|
||||||
|
return secprintf_common(0, 0, NULL, secret, msg, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _KERNEL
|
||||||
|
void test161_bootstrap()
|
||||||
|
{
|
||||||
|
test161_sem = sem_create("test161", 1);
|
||||||
|
if (test161_sem == NULL) {
|
||||||
|
panic("Failed to create test161 secprintf semaphore");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
28
configure
vendored
28
configure
vendored
@ -29,9 +29,6 @@ DEBUG='-O2'
|
|||||||
# when make runs rather than when this script runs.
|
# when make runs rather than when this script runs.
|
||||||
OSTREE='$(HOME)/os161/root'
|
OSTREE='$(HOME)/os161/root'
|
||||||
|
|
||||||
# By default don't explicitly configure a Python interpreter.
|
|
||||||
PYTHON_INTERPRETER=
|
|
||||||
|
|
||||||
# Assume this
|
# Assume this
|
||||||
HOST_CC=gcc
|
HOST_CC=gcc
|
||||||
|
|
||||||
@ -137,28 +134,6 @@ else
|
|||||||
HOST_CFLAGS="${HOST_CFLAGS} -DDECLARE_NTOHLL"
|
HOST_CFLAGS="${HOST_CFLAGS} -DDECLARE_NTOHLL"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
# Look for a Python interpreter.
|
|
||||||
PYTHON=
|
|
||||||
for PYNAME in \
|
|
||||||
python python2.7 \
|
|
||||||
/usr/local/bin/python /usr/local/bin/python2.7 \
|
|
||||||
/usr/pkg/bin/python /usr/pkg/bin/python2.7 \
|
|
||||||
/opt/bin/python /opt/bin/python2.7 \
|
|
||||||
; do
|
|
||||||
PYVERSION=`($PYNAME -V) 2>&1 || echo none`
|
|
||||||
case "$PYVERSION" in
|
|
||||||
Python\ 2.*|Python\ 3.*) PYTHON=$PYNAME;;
|
|
||||||
none) ;;
|
|
||||||
*) ;; # ?
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
case "$PYTHON" in
|
|
||||||
python) ;;
|
|
||||||
/*) PYTHON_INTERPRETER="$PYTHON";;
|
|
||||||
*) PYTHON_INTERPRETER="/usr/bin/env $PYTHON";;
|
|
||||||
esac
|
|
||||||
|
|
||||||
####################
|
####################
|
||||||
|
|
||||||
# Now generate defs.mk.
|
# Now generate defs.mk.
|
||||||
@ -192,8 +167,5 @@ EOF
|
|||||||
if [ "x$HOST_CFLAGS" != x ]; then
|
if [ "x$HOST_CFLAGS" != x ]; then
|
||||||
echo "HOST_CFLAGS+=$HOST_CFLAGS"
|
echo "HOST_CFLAGS+=$HOST_CFLAGS"
|
||||||
fi
|
fi
|
||||||
if [ "x$PYTHON_INTERPRETER" != x ]; then
|
|
||||||
echo "PYTHON_INTERPRETER=$PYTHON_INTERPRETER"
|
|
||||||
fi
|
|
||||||
|
|
||||||
) > defs.mk
|
) > defs.mk
|
||||||
|
22
defs.mk
22
defs.mk
@ -1,22 +0,0 @@
|
|||||||
# This file was generated by configure. Edits will disappear if you rerun
|
|
||||||
# configure. If you find that you need to edit this file to make things
|
|
||||||
# work, let the course staff know and we'll try to fix the configure script.
|
|
||||||
#
|
|
||||||
# The purpose of this file is to hold all the makefile definitions
|
|
||||||
# needed to adjust the OS/161 build process to any particular
|
|
||||||
# environment. If I've done it right, all you need to do is rerun the
|
|
||||||
# configure script and make clean if you start working on a different
|
|
||||||
# host OS. If I've done it mostly right, you may need to edit this
|
|
||||||
# file but you still hopefully won't need to edit any of the
|
|
||||||
# makefiles.
|
|
||||||
#
|
|
||||||
# The things that can be set here are documented in mk/os161.config.mk.
|
|
||||||
#
|
|
||||||
|
|
||||||
OSTREE=/root/os161/root
|
|
||||||
PLATFORM=sys161
|
|
||||||
MACHINE=mips
|
|
||||||
COMPAT_CFLAGS= -DNEED_NTOHLL
|
|
||||||
COMPAT_TARGETS=
|
|
||||||
HOST_CFLAGS+= -DDECLARE_NTOHLL
|
|
||||||
PYTHON_INTERPRETER=/usr/bin/env
|
|
@ -126,6 +126,15 @@ free_kpages(vaddr_t addr)
|
|||||||
(void)addr;
|
(void)addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned
|
||||||
|
int
|
||||||
|
coremap_used_bytes() {
|
||||||
|
|
||||||
|
/* dumbvm doesn't track page allocations. Return 0 so that khu works. */
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
vm_tlbshootdown(const struct tlbshootdown *ts)
|
vm_tlbshootdown(const struct tlbshootdown *ts)
|
||||||
{
|
{
|
||||||
|
33
kern/conf/ASST1
Normal file
33
kern/conf/ASST1
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
# Kernel config file using dumbvm.
|
||||||
|
# This should be used until you have your own VM system.
|
||||||
|
|
||||||
|
include conf/conf.kern # get definitions of available options
|
||||||
|
|
||||||
|
debug # Compile with debug info.
|
||||||
|
|
||||||
|
#
|
||||||
|
# Device drivers for hardware.
|
||||||
|
#
|
||||||
|
device lamebus0 # System/161 main bus
|
||||||
|
device emu* at lamebus* # Emulator passthrough filesystem
|
||||||
|
device ltrace* at lamebus* # trace161 trace control device
|
||||||
|
device ltimer* at lamebus* # Timer device
|
||||||
|
device lrandom* at lamebus* # Random device
|
||||||
|
device lhd* at lamebus* # Disk device
|
||||||
|
device lser* at lamebus* # Serial port
|
||||||
|
#device lscreen* at lamebus* # Text screen (not supported yet)
|
||||||
|
#device lnet* at lamebus* # Network interface (not supported yet)
|
||||||
|
device beep0 at ltimer* # Abstract beep handler device
|
||||||
|
device con0 at lser* # Abstract console on serial port
|
||||||
|
#device con0 at lscreen* # Abstract console on screen (not supported)
|
||||||
|
device rtclock0 at ltimer* # Abstract realtime clock
|
||||||
|
device random0 at lrandom* # Abstract randomness device
|
||||||
|
|
||||||
|
#options net # Network stack (not supported)
|
||||||
|
options semfs # Semaphores for userland
|
||||||
|
|
||||||
|
options sfs # Always use the file system
|
||||||
|
#options netfs # You might write this as a project.
|
||||||
|
|
||||||
|
options dumbvm # Chewing gum and baling wire.
|
||||||
|
options synchprobs # Uncomment to enable ASST1 synchronization problems
|
33
kern/conf/ASST2
Normal file
33
kern/conf/ASST2
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
# Kernel config file using dumbvm.
|
||||||
|
# This should be used until you have your own VM system.
|
||||||
|
|
||||||
|
include conf/conf.kern # get definitions of available options
|
||||||
|
|
||||||
|
debug # Compile with debug info.
|
||||||
|
|
||||||
|
#
|
||||||
|
# Device drivers for hardware.
|
||||||
|
#
|
||||||
|
device lamebus0 # System/161 main bus
|
||||||
|
device emu* at lamebus* # Emulator passthrough filesystem
|
||||||
|
device ltrace* at lamebus* # trace161 trace control device
|
||||||
|
device ltimer* at lamebus* # Timer device
|
||||||
|
device lrandom* at lamebus* # Random device
|
||||||
|
device lhd* at lamebus* # Disk device
|
||||||
|
device lser* at lamebus* # Serial port
|
||||||
|
#device lscreen* at lamebus* # Text screen (not supported yet)
|
||||||
|
#device lnet* at lamebus* # Network interface (not supported yet)
|
||||||
|
device beep0 at ltimer* # Abstract beep handler device
|
||||||
|
device con0 at lser* # Abstract console on serial port
|
||||||
|
#device con0 at lscreen* # Abstract console on screen (not supported)
|
||||||
|
device rtclock0 at ltimer* # Abstract realtime clock
|
||||||
|
device random0 at lrandom* # Abstract randomness device
|
||||||
|
|
||||||
|
#options net # Network stack (not supported)
|
||||||
|
options semfs # Semaphores for userland
|
||||||
|
|
||||||
|
options sfs # Always use the file system
|
||||||
|
#options netfs # You might write this as a project.
|
||||||
|
|
||||||
|
options dumbvm # Chewing gum and baling wire.
|
||||||
|
#options synchprobs # Uncomment to enable ASST1 synchronization problems
|
33
kern/conf/ASST3
Normal file
33
kern/conf/ASST3
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
# Kernel config file for an ordinary, generic kernel.
|
||||||
|
# This config file should be used once you start working on
|
||||||
|
# your own VM system.
|
||||||
|
|
||||||
|
include conf/conf.kern # get definitions of available options
|
||||||
|
|
||||||
|
debug # Compile with debug info.
|
||||||
|
|
||||||
|
#
|
||||||
|
# Device drivers for hardware.
|
||||||
|
#
|
||||||
|
device lamebus0 # System/161 main bus
|
||||||
|
device emu* at lamebus* # Emulator passthrough filesystem
|
||||||
|
device ltrace* at lamebus* # trace161 trace control device
|
||||||
|
device ltimer* at lamebus* # Timer device
|
||||||
|
device lrandom* at lamebus* # Random device
|
||||||
|
device lhd* at lamebus* # Disk device
|
||||||
|
device lser* at lamebus* # Serial port
|
||||||
|
#device lscreen* at lamebus* # Text screen (not supported yet)
|
||||||
|
#device lnet* at lamebus* # Network interface (not supported yet)
|
||||||
|
device beep0 at ltimer* # Abstract beep handler device
|
||||||
|
device con0 at lser* # Abstract console on serial port
|
||||||
|
#device con0 at lscreen* # Abstract console on screen (not supported)
|
||||||
|
device rtclock0 at ltimer* # Abstract realtime clock
|
||||||
|
device random0 at lrandom* # Abstract randomness device
|
||||||
|
|
||||||
|
#options net # Network stack (not supported)
|
||||||
|
options semfs # Semaphores for userland
|
||||||
|
|
||||||
|
options sfs # Always use the file system
|
||||||
|
#options netfs # You might write this as a project.
|
||||||
|
|
||||||
|
#options dumbvm # Use your own VM system now.
|
@ -32,4 +32,4 @@ options sfs # Always use the file system
|
|||||||
#options netfs # You might write this as a project.
|
#options netfs # You might write this as a project.
|
||||||
|
|
||||||
options dumbvm # Chewing gum and baling wire.
|
options dumbvm # Chewing gum and baling wire.
|
||||||
options synchprobs
|
options synchprobs # Uncomment to enable ASST1 synchronization problems
|
||||||
|
@ -309,6 +309,14 @@ file ../common/libc/string/strlen.c
|
|||||||
file ../common/libc/string/strrchr.c
|
file ../common/libc/string/strrchr.c
|
||||||
file ../common/libc/string/strtok_r.c
|
file ../common/libc/string/strtok_r.c
|
||||||
|
|
||||||
|
#
|
||||||
|
# libtest161 shared code and security functions
|
||||||
|
#
|
||||||
|
|
||||||
|
file ../common/libtest161/test161.c
|
||||||
|
file ../common/libtest161/secure.c
|
||||||
|
file ../common/libtest161/sha256.c
|
||||||
|
|
||||||
########################################
|
########################################
|
||||||
# #
|
# #
|
||||||
# Core kernel source files #
|
# Core kernel source files #
|
||||||
@ -437,12 +445,19 @@ file test/threadlisttest.c
|
|||||||
file test/threadtest.c
|
file test/threadtest.c
|
||||||
file test/tt3.c
|
file test/tt3.c
|
||||||
file test/synchtest.c
|
file test/synchtest.c
|
||||||
|
file test/rwtest.c
|
||||||
file test/semunit.c
|
file test/semunit.c
|
||||||
|
file test/hmacunit.c
|
||||||
file test/kmalloctest.c
|
file test/kmalloctest.c
|
||||||
file test/fstest.c
|
file test/fstest.c
|
||||||
|
file test/lib.c
|
||||||
|
|
||||||
optfile net test/nettest.c
|
optfile net test/nettest.c
|
||||||
|
|
||||||
defoption synchprobs
|
defoption synchprobs
|
||||||
optfile synchprobs synchprobs/whalemating.c
|
optfile synchprobs synchprobs/whalemating.c
|
||||||
optfile synchprobs synchprobs/stoplight.c
|
optfile synchprobs synchprobs/stoplight.c
|
||||||
optfile synchprobs test/synchprobs.c
|
optfile synchprobs test/synchprobs.c
|
||||||
|
|
||||||
|
defoption automationtest
|
||||||
|
optfile automationtest test/automationtest.c
|
||||||
|
@ -208,7 +208,7 @@ echo "$CONFNAME" $CONFTMP | awk '
|
|||||||
#
|
#
|
||||||
|
|
||||||
if [ ! -d "$COMPILEDIR" ]; then
|
if [ ! -d "$COMPILEDIR" ]; then
|
||||||
mkdir $COMPILEDIR
|
mkdir -p $COMPILEDIR
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo -n 'Generating files...'
|
echo -n 'Generating files...'
|
||||||
|
@ -35,6 +35,7 @@
|
|||||||
#include <threadlist.h>
|
#include <threadlist.h>
|
||||||
#include <machine/vm.h> /* for TLBSHOOTDOWN_MAX */
|
#include <machine/vm.h> /* for TLBSHOOTDOWN_MAX */
|
||||||
|
|
||||||
|
extern unsigned num_cpus;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Per-cpu structure
|
* Per-cpu structure
|
||||||
|
50
kern/include/kern/secret.h
Normal file
50
kern/include/kern/secret.h
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* NO NOT MODIFY THIS FILE
|
||||||
|
*
|
||||||
|
* All the contents of this file are overwritten during automated
|
||||||
|
* testing. Please consider this before changing anything in this file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
|
||||||
|
* The President and Fellows of Harvard College.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. Neither the name of the University nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _SECRET_H_
|
||||||
|
#define _SECRET_H_
|
||||||
|
|
||||||
|
/*
|
||||||
|
* During automated testing all instances of KERNEL_SECRET in trusted tests
|
||||||
|
* are rewritten to a random value to ensure that the kernel is actually
|
||||||
|
* running the appropriate tests. So this value is never actually used, but
|
||||||
|
* allows normally compilation and operation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#undef SECRET_TESTING
|
||||||
|
#define SECRET "SECRET"
|
||||||
|
|
||||||
|
#endif /* _SECRET_H_ */
|
18
kern/include/kern/secure.h
Normal file
18
kern/include/kern/secure.h
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#ifndef _KERN_SECURE_H_
|
||||||
|
#define _KERN_SECURE_H_
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Compute the FIPS 198-1 complient HMAC of msg using SHA256.
|
||||||
|
*
|
||||||
|
* hmac_with_salt uses a salted key and sets salt_str to this value (in hex).
|
||||||
|
* Both functions below create hash_str with the hex readable version of the hash.
|
||||||
|
*
|
||||||
|
* Callers need to free hash_str (and salt_str) when done.
|
||||||
|
*/
|
||||||
|
int hmac(const char *msg, size_t msg_len, const char *key, size_t key_len,
|
||||||
|
char **hash_str);
|
||||||
|
|
||||||
|
int hmac_salted(const char *msg, size_t msg_len, const char *key, size_t key_len,
|
||||||
|
char **hash_str, char **salt_str);
|
||||||
|
|
||||||
|
#endif //_KERN_SECURE_H_
|
76
kern/include/kern/test161.h
Normal file
76
kern/include/kern/test161.h
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
|
||||||
|
* The President and Fellows of Harvard College.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. Neither the name of the University nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _KERN_TEST161_H_
|
||||||
|
#define _KERN_TEST161_H_
|
||||||
|
|
||||||
|
#define TEST161_SUCCESS 0
|
||||||
|
#define TEST161_FAIL 1
|
||||||
|
|
||||||
|
#include <kern/secret.h>
|
||||||
|
|
||||||
|
#ifdef _KERNEL
|
||||||
|
#define __TEST161_PROGRESS_N(iter, mod) do { \
|
||||||
|
if (((iter) % mod) == 0) { \
|
||||||
|
kprintf("."); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
#else
|
||||||
|
#include <stdio.h>
|
||||||
|
#define __TEST161_PROGRESS_N(iter, mod) do { \
|
||||||
|
if (((iter) % mod) == 0) { \
|
||||||
|
printf("."); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Always loud
|
||||||
|
#define TEST161_LPROGRESS_N(iter, mod) __TEST161_PROGRESS_N(iter, mod)
|
||||||
|
#define TEST161_LPROGRESS(iter) __TEST161_PROGRESS_N(iter, 100)
|
||||||
|
|
||||||
|
// Depends on whether or not it's automated testing. Some tests are
|
||||||
|
// quite verbose with useful information so these should just stay quiet.
|
||||||
|
#ifdef SECRET_TESTING
|
||||||
|
#define TEST161_TPROGRESS_N(iter, mod) __TEST161_PROGRESS_N(iter, mod)
|
||||||
|
#define TEST161_TPROGRESS(iter) __TEST161_PROGRESS_N(iter, 100)
|
||||||
|
#else
|
||||||
|
#define TEST161_TPROGRESS_N(iter, mod)
|
||||||
|
#define TEST161_TPROGRESS(iter)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int success(int, const char *, const char *);
|
||||||
|
int secprintf(const char *secret, const char *msg, const char *name);
|
||||||
|
int snsecprintf(size_t len, char *buffer, const char *secret, const char *msg, const char *name);
|
||||||
|
int partial_credit(const char *secret, const char *name, int scored, int total);
|
||||||
|
|
||||||
|
#ifdef _KERNEL
|
||||||
|
void test161_bootstrap(void);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _KERN_TEST161_H_ */
|
@ -129,6 +129,8 @@ uint32_t random(void);
|
|||||||
void *kmalloc(size_t size);
|
void *kmalloc(size_t size);
|
||||||
void kfree(void *ptr);
|
void kfree(void *ptr);
|
||||||
void kheap_printstats(void);
|
void kheap_printstats(void);
|
||||||
|
void kheap_printused(void);
|
||||||
|
unsigned long kheap_getused(void);
|
||||||
void kheap_nextgeneration(void);
|
void kheap_nextgeneration(void);
|
||||||
void kheap_dump(void);
|
void kheap_dump(void);
|
||||||
void kheap_dumpall(void);
|
void kheap_dumpall(void);
|
||||||
|
47
kern/include/prompt.h
Normal file
47
kern/include/prompt.h
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* NO NOT MODIFY THIS FILE
|
||||||
|
*
|
||||||
|
* All the contents of this file are overwritten during automated
|
||||||
|
* testing. Please consider this before changing anything in this file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
|
||||||
|
* The President and Fellows of Harvard College.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. Neither the name of the University nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _PROMPT_H_
|
||||||
|
#define _PROMPT_H_
|
||||||
|
|
||||||
|
/*
|
||||||
|
* You can set a custom prompt here, but the default will be used during
|
||||||
|
* testing.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define KERNEL_PROMPT "OS/161 kernel [? for menu]: "
|
||||||
|
|
||||||
|
#endif /* _PROMPT_H_ */
|
@ -92,9 +92,18 @@ void spllower(int oldipl, int newipl);
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
SPL_INLINE
|
SPL_INLINE
|
||||||
int spl0(void) { return splx(IPL_NONE); }
|
int
|
||||||
|
spl0(void)
|
||||||
|
{
|
||||||
|
return splx(IPL_NONE);
|
||||||
|
}
|
||||||
|
|
||||||
SPL_INLINE
|
SPL_INLINE
|
||||||
int splhigh(void) { return splx(IPL_HIGH); }
|
int
|
||||||
|
splhigh(void)
|
||||||
|
{
|
||||||
|
return splx(IPL_HIGH);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif /* _SPL_H_ */
|
#endif /* _SPL_H_ */
|
||||||
|
@ -34,6 +34,7 @@
|
|||||||
* Header file for synchronization primitives.
|
* Header file for synchronization primitives.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include <spinlock.h>
|
#include <spinlock.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -61,6 +62,7 @@ void sem_destroy(struct semaphore *);
|
|||||||
void P(struct semaphore *);
|
void P(struct semaphore *);
|
||||||
void V(struct semaphore *);
|
void V(struct semaphore *);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Simple lock for mutual exclusion.
|
* Simple lock for mutual exclusion.
|
||||||
*
|
*
|
||||||
@ -95,6 +97,7 @@ void lock_acquire(struct lock *);
|
|||||||
void lock_release(struct lock *);
|
void lock_release(struct lock *);
|
||||||
bool lock_do_i_hold(struct lock *);
|
bool lock_do_i_hold(struct lock *);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Condition variable.
|
* Condition variable.
|
||||||
*
|
*
|
||||||
@ -135,4 +138,40 @@ void cv_wait(struct cv *cv, struct lock *lock);
|
|||||||
void cv_signal(struct cv *cv, struct lock *lock);
|
void cv_signal(struct cv *cv, struct lock *lock);
|
||||||
void cv_broadcast(struct cv *cv, struct lock *lock);
|
void cv_broadcast(struct cv *cv, struct lock *lock);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Reader-writer locks.
|
||||||
|
*
|
||||||
|
* When the lock is created, no thread should be holding it. Likewise,
|
||||||
|
* when the lock is destroyed, no thread should be holding it.
|
||||||
|
*
|
||||||
|
* The name field is for easier debugging. A copy of the name is
|
||||||
|
* (should be) made internally.
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct rwlock {
|
||||||
|
char *rwlock_name;
|
||||||
|
// add what you need here
|
||||||
|
// (don't forget to mark things volatile as needed)
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rwlock * rwlock_create(const char *);
|
||||||
|
void rwlock_destroy(struct rwlock *);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Operations:
|
||||||
|
* rwlock_acquire_read - Get the lock for reading. Multiple threads can
|
||||||
|
* hold the lock for reading at the same time.
|
||||||
|
* rwlock_release_read - Free the lock.
|
||||||
|
* rwlock_acquire_write - Get the lock for writing. Only one thread can
|
||||||
|
* hold the write lock at one time.
|
||||||
|
* rwlock_release_write - Free the write lock.
|
||||||
|
*
|
||||||
|
* These operations must be atomic. You get to write them.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void rwlock_acquire_read(struct rwlock *);
|
||||||
|
void rwlock_release_read(struct rwlock *);
|
||||||
|
void rwlock_acquire_write(struct rwlock *);
|
||||||
|
void rwlock_release_write(struct rwlock *);
|
||||||
|
|
||||||
#endif /* _SYNCH_H_ */
|
#endif /* _SYNCH_H_ */
|
||||||
|
@ -30,6 +30,13 @@
|
|||||||
#ifndef _TEST_H_
|
#ifndef _TEST_H_
|
||||||
#define _TEST_H_
|
#define _TEST_H_
|
||||||
|
|
||||||
|
/* Get __PF() for declaring printf-like functions. */
|
||||||
|
#include <cdefs.h>
|
||||||
|
#include <kern/secret.h>
|
||||||
|
|
||||||
|
#include "opt-synchprobs.h"
|
||||||
|
#include "opt-automationtest.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Declarations for test code and other miscellaneous high-level
|
* Declarations for test code and other miscellaneous high-level
|
||||||
* functions.
|
* functions.
|
||||||
@ -52,8 +59,20 @@ int threadtest2(int, char **);
|
|||||||
int threadtest3(int, char **);
|
int threadtest3(int, char **);
|
||||||
int semtest(int, char **);
|
int semtest(int, char **);
|
||||||
int locktest(int, char **);
|
int locktest(int, char **);
|
||||||
|
int locktest2(int, char **);
|
||||||
|
int locktest3(int, char **);
|
||||||
|
int locktest4(int, char **);
|
||||||
|
int locktest5(int, char **);
|
||||||
int cvtest(int, char **);
|
int cvtest(int, char **);
|
||||||
int cvtest2(int, char **);
|
int cvtest2(int, char **);
|
||||||
|
int cvtest3(int, char **);
|
||||||
|
int cvtest4(int, char **);
|
||||||
|
int cvtest5(int, char **);
|
||||||
|
int rwtest(int, char **);
|
||||||
|
int rwtest2(int, char **);
|
||||||
|
int rwtest3(int, char **);
|
||||||
|
int rwtest4(int, char **);
|
||||||
|
int rwtest5(int, char **);
|
||||||
|
|
||||||
/* semaphore unit tests */
|
/* semaphore unit tests */
|
||||||
int semu1(int, char **);
|
int semu1(int, char **);
|
||||||
@ -88,11 +107,15 @@ int longstress(int, char **);
|
|||||||
int createstress(int, char **);
|
int createstress(int, char **);
|
||||||
int printfile(int, char **);
|
int printfile(int, char **);
|
||||||
|
|
||||||
|
/* HMAC/hash tests */
|
||||||
|
int hmacu1(int, char**);
|
||||||
|
|
||||||
/* other tests */
|
/* other tests */
|
||||||
int kmalloctest(int, char **);
|
int kmalloctest(int, char **);
|
||||||
int kmallocstress(int, char **);
|
int kmallocstress(int, char **);
|
||||||
int kmalloctest3(int, char **);
|
int kmalloctest3(int, char **);
|
||||||
int kmalloctest4(int, char **);
|
int kmalloctest4(int, char **);
|
||||||
|
int kmalloctest5(int, char **);
|
||||||
int nettest(int, char **);
|
int nettest(int, char **);
|
||||||
|
|
||||||
/* Routine for running a user-level program. */
|
/* Routine for running a user-level program. */
|
||||||
@ -104,5 +127,75 @@ void menu(char *argstr);
|
|||||||
/* The main function, called from start.S. */
|
/* The main function, called from start.S. */
|
||||||
void kmain(char *bootstring);
|
void kmain(char *bootstring);
|
||||||
|
|
||||||
|
#if OPT_SYNCHPROBS
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Synchronization driver primitives.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void male_start(uint32_t);
|
||||||
|
void male_end(uint32_t);
|
||||||
|
void female_start(uint32_t);
|
||||||
|
void female_end(uint32_t);
|
||||||
|
void matchmaker_start(uint32_t);
|
||||||
|
void matchmaker_end(uint32_t);
|
||||||
|
int whalemating(int, char **);
|
||||||
|
|
||||||
|
void inQuadrant(int, uint32_t);
|
||||||
|
void leaveIntersection(uint32_t);
|
||||||
|
int stoplight(int, char **);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Synchronization problem primitives.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* whalemating.c.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void whalemating_init(void);
|
||||||
|
void whalemating_cleanup(void);
|
||||||
|
void male(uint32_t);
|
||||||
|
void female(uint32_t);
|
||||||
|
void matchmaker(uint32_t);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* stoplight.c.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void gostraight(uint32_t, uint32_t);
|
||||||
|
void turnleft(uint32_t, uint32_t);
|
||||||
|
void turnright(uint32_t, uint32_t);
|
||||||
|
void stoplight_init(void);
|
||||||
|
void stoplight_cleanup(void);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Automation tests for detecting kernel deadlocks and livelocks.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if OPT_AUTOMATIONTEST
|
||||||
|
int dltest(int, char **);
|
||||||
|
int ll1test(int, char **);
|
||||||
|
int ll16test(int, char **);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void random_yielder(uint32_t);
|
||||||
|
void random_spinner(uint32_t);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* kprintf variants that do not (or only) print during automated testing.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef SECRET_TESTING
|
||||||
|
#define kprintf_t(...) kprintf(__VA_ARGS__)
|
||||||
|
#define kprintf_n(...) silent(__VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define kprintf_t(...) silent(__VA_ARGS__)
|
||||||
|
#define kprintf_n(...) kprintf(__VA_ARGS__)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static inline void silent(const char * fmt, ...) { (void)fmt; };
|
||||||
|
|
||||||
#endif /* _TEST_H_ */
|
#endif /* _TEST_H_ */
|
||||||
|
@ -48,6 +48,7 @@ struct cpu;
|
|||||||
|
|
||||||
/* Size of kernel stacks; must be power of 2 */
|
/* Size of kernel stacks; must be power of 2 */
|
||||||
#define STACK_SIZE 4096
|
#define STACK_SIZE 4096
|
||||||
|
#define MAX_NAME_LENGTH 64
|
||||||
|
|
||||||
/* Mask for extracting the stack base address of a kernel stack pointer */
|
/* Mask for extracting the stack base address of a kernel stack pointer */
|
||||||
#define STACK_MASK (~(vaddr_t)(STACK_SIZE-1))
|
#define STACK_MASK (~(vaddr_t)(STACK_SIZE-1))
|
||||||
@ -70,7 +71,16 @@ struct thread {
|
|||||||
* These go up front so they're easy to get to even if the
|
* These go up front so they're easy to get to even if the
|
||||||
* debugger is messed up.
|
* debugger is messed up.
|
||||||
*/
|
*/
|
||||||
char *t_name; /* Name of this thread */
|
|
||||||
|
/*
|
||||||
|
* Name of this thread. Used to be dynamically allocated using kmalloc, but
|
||||||
|
* this can cause small changes in the amount of available memory due to the
|
||||||
|
* fact that it was cleaned up in exorcise. This produces more predictable
|
||||||
|
* behavior at the cost of a small amount of memory overhead and the
|
||||||
|
* inability to give threads huge names.
|
||||||
|
*/
|
||||||
|
|
||||||
|
char t_name[MAX_NAME_LENGTH];
|
||||||
const char *t_wchan_name; /* Name of wait channel, if sleeping */
|
const char *t_wchan_name; /* Name of wait channel, if sleeping */
|
||||||
threadstate_t t_state; /* State this thread is in */
|
threadstate_t t_state; /* State this thread is in */
|
||||||
|
|
||||||
@ -169,5 +179,7 @@ void schedule(void);
|
|||||||
*/
|
*/
|
||||||
void thread_consider_migration(void);
|
void thread_consider_migration(void);
|
||||||
|
|
||||||
|
extern unsigned thread_count;
|
||||||
|
void thread_wait_for_count(unsigned);
|
||||||
|
|
||||||
#endif /* _THREAD_H_ */
|
#endif /* _THREAD_H_ */
|
||||||
|
@ -55,6 +55,13 @@ int vm_fault(int faulttype, vaddr_t faultaddress);
|
|||||||
vaddr_t alloc_kpages(unsigned npages);
|
vaddr_t alloc_kpages(unsigned npages);
|
||||||
void free_kpages(vaddr_t addr);
|
void free_kpages(vaddr_t addr);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return amount of memory (in bytes) used by allocated coremap pages. If
|
||||||
|
* there are ongoing allocations, this value could change after it is returned
|
||||||
|
* to the caller. But it should have been correct at some point in time.
|
||||||
|
*/
|
||||||
|
unsigned int coremap_used_bytes(void);
|
||||||
|
|
||||||
/* TLB shootdown handling called from interprocessor_interrupt */
|
/* TLB shootdown handling called from interprocessor_interrupt */
|
||||||
void vm_tlbshootdown(const struct tlbshootdown *);
|
void vm_tlbshootdown(const struct tlbshootdown *);
|
||||||
|
|
||||||
|
@ -39,6 +39,9 @@
|
|||||||
#include <mainbus.h>
|
#include <mainbus.h>
|
||||||
#include <vfs.h> // for vfs_sync()
|
#include <vfs.h> // for vfs_sync()
|
||||||
#include <lamebus/ltrace.h> // for ltrace_stop()
|
#include <lamebus/ltrace.h> // for ltrace_stop()
|
||||||
|
#include <kern/secret.h>
|
||||||
|
#include <test.h>
|
||||||
|
|
||||||
|
|
||||||
/* Flags word for DEBUG() macro. */
|
/* Flags word for DEBUG() macro. */
|
||||||
uint32_t dbflags = 0;
|
uint32_t dbflags = 0;
|
||||||
@ -49,16 +52,20 @@ static struct lock *kprintf_lock;
|
|||||||
/* Lock for polled kprintfs */
|
/* Lock for polled kprintfs */
|
||||||
static struct spinlock kprintf_spinlock;
|
static struct spinlock kprintf_spinlock;
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Warning: all this has to work from interrupt handlers and when
|
* Warning: all this has to work from interrupt handlers and when
|
||||||
* interrupts are disabled.
|
* interrupts are disabled.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create the kprintf lock. Must be called before creating a second
|
* Create the kprintf lock. Must be called before creating a second
|
||||||
* thread or enabling a second CPU.
|
* thread or enabling a second CPU.
|
||||||
*/
|
*/
|
||||||
void kprintf_bootstrap(void) {
|
void
|
||||||
|
kprintf_bootstrap(void)
|
||||||
|
{
|
||||||
KASSERT(kprintf_lock == NULL);
|
KASSERT(kprintf_lock == NULL);
|
||||||
|
|
||||||
kprintf_lock = lock_create("kprintf_lock");
|
kprintf_lock = lock_create("kprintf_lock");
|
||||||
@ -71,52 +78,78 @@ void kprintf_bootstrap(void) {
|
|||||||
/*
|
/*
|
||||||
* Send characters to the console. Backend for __printf.
|
* Send characters to the console. Backend for __printf.
|
||||||
*/
|
*/
|
||||||
static void console_send(void *junk, const char *data, size_t len) {
|
static
|
||||||
|
void
|
||||||
|
console_send(void *junk, const char *data, size_t len)
|
||||||
|
{
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
(void)junk;
|
(void)junk;
|
||||||
|
|
||||||
for (i = 0; i < len; i++) {
|
for (i=0; i<len; i++) {
|
||||||
putch(data[i]);
|
putch(data[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Printf to the console.
|
* kprintf and tprintf helper function.
|
||||||
*/
|
*/
|
||||||
int kprintf(const char *fmt, ...) {
|
static
|
||||||
|
inline
|
||||||
|
int
|
||||||
|
__kprintf(const char *fmt, va_list ap)
|
||||||
|
{
|
||||||
int chars;
|
int chars;
|
||||||
va_list ap;
|
|
||||||
bool dolock;
|
bool dolock;
|
||||||
|
|
||||||
dolock = kprintf_lock != NULL && curthread->t_in_interrupt == false &&
|
dolock = kprintf_lock != NULL
|
||||||
curthread->t_curspl == 0 && curcpu->c_spinlocks == 0;
|
&& curthread->t_in_interrupt == false
|
||||||
|
&& curthread->t_curspl == 0
|
||||||
|
&& curcpu->c_spinlocks == 0;
|
||||||
|
|
||||||
if (dolock) {
|
if (dolock) {
|
||||||
lock_acquire(kprintf_lock);
|
lock_acquire(kprintf_lock);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
spinlock_acquire(&kprintf_spinlock);
|
spinlock_acquire(&kprintf_spinlock);
|
||||||
}
|
}
|
||||||
|
|
||||||
va_start(ap, fmt);
|
|
||||||
chars = __vprintf(console_send, NULL, fmt, ap);
|
chars = __vprintf(console_send, NULL, fmt, ap);
|
||||||
va_end(ap);
|
|
||||||
|
|
||||||
if (dolock) {
|
if (dolock) {
|
||||||
lock_release(kprintf_lock);
|
lock_release(kprintf_lock);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
spinlock_release(&kprintf_spinlock);
|
spinlock_release(&kprintf_spinlock);
|
||||||
}
|
}
|
||||||
|
|
||||||
return chars;
|
return chars;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Printf to the console.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
kprintf(const char *fmt, ...)
|
||||||
|
{
|
||||||
|
int chars;
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
va_start(ap, fmt);
|
||||||
|
chars = __kprintf(fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
return chars;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* panic() is for fatal errors. It prints the printf arguments it's
|
* panic() is for fatal errors. It prints the printf arguments it's
|
||||||
* passed and then halts the system.
|
* passed and then halts the system.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void panic(const char *fmt, ...) {
|
void
|
||||||
|
panic(const char *fmt, ...)
|
||||||
|
{
|
||||||
va_list ap;
|
va_list ap;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -186,13 +219,15 @@ void panic(const char *fmt, ...) {
|
|||||||
* Last resort, just in case.
|
* Last resort, just in case.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
for (;;)
|
for (;;);
|
||||||
;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Assertion failures go through this.
|
* Assertion failures go through this.
|
||||||
*/
|
*/
|
||||||
void badassert(const char *expr, const char *file, int line, const char *func) {
|
void
|
||||||
panic("Assertion failed: %s, at %s:%d (%s)\n", expr, file, line, func);
|
badassert(const char *expr, const char *file, int line, const char *func)
|
||||||
|
{
|
||||||
|
panic("Assertion failed: %s, at %s:%d (%s)\n",
|
||||||
|
expr, file, line, func);
|
||||||
}
|
}
|
||||||
|
@ -48,9 +48,11 @@
|
|||||||
#include <device.h>
|
#include <device.h>
|
||||||
#include <syscall.h>
|
#include <syscall.h>
|
||||||
#include <test.h>
|
#include <test.h>
|
||||||
|
#include <kern/test161.h>
|
||||||
#include <version.h>
|
#include <version.h>
|
||||||
#include "autoconf.h" // for pseudoconfig
|
#include "autoconf.h" // for pseudoconfig
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* These two pieces of data are maintained by the makefiles and build system.
|
* These two pieces of data are maintained by the makefiles and build system.
|
||||||
* buildconfig is the name of the config file the kernel was configured with.
|
* buildconfig is the name of the config file the kernel was configured with.
|
||||||
@ -70,10 +72,14 @@ static const char harvard_copyright[] =
|
|||||||
"Copyright (c) 2000, 2001-2005, 2008-2011, 2013, 2014\n"
|
"Copyright (c) 2000, 2001-2005, 2008-2011, 2013, 2014\n"
|
||||||
" President and Fellows of Harvard College. All rights reserved.\n";
|
" President and Fellows of Harvard College. All rights reserved.\n";
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initial boot sequence.
|
* Initial boot sequence.
|
||||||
*/
|
*/
|
||||||
static void boot(void) {
|
static
|
||||||
|
void
|
||||||
|
boot(void)
|
||||||
|
{
|
||||||
/*
|
/*
|
||||||
* The order of these is important!
|
* The order of these is important!
|
||||||
* Don't go changing it without thinking about the consequences.
|
* Don't go changing it without thinking about the consequences.
|
||||||
@ -96,8 +102,8 @@ static void boot(void) {
|
|||||||
kprintf("%s", harvard_copyright);
|
kprintf("%s", harvard_copyright);
|
||||||
kprintf("\n");
|
kprintf("\n");
|
||||||
|
|
||||||
kprintf("Minh Tran's system version %s (%s #%d)\n", GROUP_VERSION,
|
kprintf("Put-your-group-name-here's system version %s (%s #%d)\n",
|
||||||
buildconfig, buildversion);
|
GROUP_VERSION, buildconfig, buildversion);
|
||||||
kprintf("\n");
|
kprintf("\n");
|
||||||
|
|
||||||
/* Early initialization. */
|
/* Early initialization. */
|
||||||
@ -122,6 +128,7 @@ static void boot(void) {
|
|||||||
vm_bootstrap();
|
vm_bootstrap();
|
||||||
kprintf_bootstrap();
|
kprintf_bootstrap();
|
||||||
thread_start_cpus();
|
thread_start_cpus();
|
||||||
|
test161_bootstrap();
|
||||||
|
|
||||||
/* Default bootfs - but ignore failure, in case emu0 doesn't exist */
|
/* Default bootfs - but ignore failure, in case emu0 doesn't exist */
|
||||||
vfs_setbootfs("emu0");
|
vfs_setbootfs("emu0");
|
||||||
@ -138,7 +145,10 @@ static void boot(void) {
|
|||||||
/*
|
/*
|
||||||
* Shutdown sequence. Opposite to boot().
|
* Shutdown sequence. Opposite to boot().
|
||||||
*/
|
*/
|
||||||
static void shutdown(void) {
|
static
|
||||||
|
void
|
||||||
|
shutdown(void)
|
||||||
|
{
|
||||||
|
|
||||||
kprintf("Shutting down.\n");
|
kprintf("Shutting down.\n");
|
||||||
|
|
||||||
@ -160,7 +170,9 @@ static void shutdown(void) {
|
|||||||
* not because this is where system call code should go. Other syscall
|
* not because this is where system call code should go. Other syscall
|
||||||
* code should probably live in the "syscall" directory.
|
* code should probably live in the "syscall" directory.
|
||||||
*/
|
*/
|
||||||
int sys_reboot(int code) {
|
int
|
||||||
|
sys_reboot(int code)
|
||||||
|
{
|
||||||
switch (code) {
|
switch (code) {
|
||||||
case RB_REBOOT:
|
case RB_REBOOT:
|
||||||
case RB_HALT:
|
case RB_HALT:
|
||||||
@ -195,7 +207,9 @@ int sys_reboot(int code) {
|
|||||||
* Kernel main. Boot up, then fork the menu thread; wait for a reboot
|
* Kernel main. Boot up, then fork the menu thread; wait for a reboot
|
||||||
* request, and then shut down.
|
* request, and then shut down.
|
||||||
*/
|
*/
|
||||||
void kmain(char *arguments) {
|
void
|
||||||
|
kmain(char *arguments)
|
||||||
|
{
|
||||||
boot();
|
boot();
|
||||||
|
|
||||||
menu(arguments);
|
menu(arguments);
|
||||||
|
119
kern/main/menu.c
119
kern/main/menu.c
@ -43,8 +43,11 @@
|
|||||||
#include <sfs.h>
|
#include <sfs.h>
|
||||||
#include <syscall.h>
|
#include <syscall.h>
|
||||||
#include <test.h>
|
#include <test.h>
|
||||||
|
#include <prompt.h>
|
||||||
#include "opt-sfs.h"
|
#include "opt-sfs.h"
|
||||||
#include "opt-net.h"
|
#include "opt-net.h"
|
||||||
|
#include "opt-synchprobs.h"
|
||||||
|
#include "opt-automationtest.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* In-kernel menu and command dispatcher.
|
* In-kernel menu and command dispatcher.
|
||||||
@ -116,6 +119,7 @@ common_prog(int nargs, char **args)
|
|||||||
{
|
{
|
||||||
struct proc *proc;
|
struct proc *proc;
|
||||||
int result;
|
int result;
|
||||||
|
unsigned tc;
|
||||||
|
|
||||||
/* Create a process for the new program to run in. */
|
/* Create a process for the new program to run in. */
|
||||||
proc = proc_create_runprogram(args[0] /* name */);
|
proc = proc_create_runprogram(args[0] /* name */);
|
||||||
@ -123,6 +127,8 @@ common_prog(int nargs, char **args)
|
|||||||
return ENOMEM;
|
return ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tc = thread_count;
|
||||||
|
|
||||||
result = thread_fork(args[0] /* thread name */,
|
result = thread_fork(args[0] /* thread name */,
|
||||||
proc /* new process */,
|
proc /* new process */,
|
||||||
cmd_progthread /* thread function */,
|
cmd_progthread /* thread function */,
|
||||||
@ -138,6 +144,10 @@ common_prog(int nargs, char **args)
|
|||||||
* once you write the code for handling that.
|
* once you write the code for handling that.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// Wait for all threads to finish cleanup, otherwise khu be a bit behind,
|
||||||
|
// especially once swapping is enabled.
|
||||||
|
thread_wait_for_count(tc);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -465,6 +475,18 @@ cmd_kheapstats(int nargs, char **args)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int
|
||||||
|
cmd_kheapused(int nargs, char **args)
|
||||||
|
{
|
||||||
|
(void)nargs;
|
||||||
|
(void)args;
|
||||||
|
|
||||||
|
kheap_printused();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
int
|
int
|
||||||
cmd_kheapgeneration(int nargs, char **args)
|
cmd_kheapgeneration(int nargs, char **args)
|
||||||
@ -560,16 +582,33 @@ static const char *testmenu[] = {
|
|||||||
"[km2] kmalloc stress test ",
|
"[km2] kmalloc stress test ",
|
||||||
"[km3] Large kmalloc test ",
|
"[km3] Large kmalloc test ",
|
||||||
"[km4] Multipage kmalloc test ",
|
"[km4] Multipage kmalloc test ",
|
||||||
|
"[km5] kmalloc coremap alloc test ",
|
||||||
"[tt1] Thread test 1 ",
|
"[tt1] Thread test 1 ",
|
||||||
"[tt2] Thread test 2 ",
|
"[tt2] Thread test 2 ",
|
||||||
"[tt3] Thread test 3 ",
|
"[tt3] Thread test 3 ",
|
||||||
#if OPT_NET
|
#if OPT_NET
|
||||||
"[net] Network test ",
|
"[net] Network test ",
|
||||||
#endif
|
#endif
|
||||||
"[sy1] Semaphore test ",
|
"[sem1] Semaphore test ",
|
||||||
"[sy2] Lock test (1) ",
|
"[lt1] Lock test 1 (1) ",
|
||||||
"[sy3] CV test (1) ",
|
"[lt2] Lock test 2 (1*) ",
|
||||||
"[sy4] CV test #2 (1) ",
|
"[lt3] Lock test 3 (1*) ",
|
||||||
|
"[lt4] Lock test 4 (1*) ",
|
||||||
|
"[lt5] Lock test 5 (1*) ",
|
||||||
|
"[cvt1] CV test 1 (1) ",
|
||||||
|
"[cvt2] CV test 2 (1) ",
|
||||||
|
"[cvt3] CV test 3 (1*) ",
|
||||||
|
"[cvt4] CV test 4 (1*) ",
|
||||||
|
"[cvt5] CV test 5 (1) ",
|
||||||
|
"[rwt1] RW lock test (1?) ",
|
||||||
|
"[rwt2] RW lock test 2 (1?) ",
|
||||||
|
"[rwt3] RW lock test 3 (1?) ",
|
||||||
|
"[rwt4] RW lock test 4 (1?) ",
|
||||||
|
"[rwt5] RW lock test 5 (1?) ",
|
||||||
|
#if OPT_SYNCHPROBS
|
||||||
|
"[sp1] Whalemating test (1) ",
|
||||||
|
"[sp2] Stoplight test (1) ",
|
||||||
|
#endif
|
||||||
"[semu1-22] Semaphore unit tests ",
|
"[semu1-22] Semaphore unit tests ",
|
||||||
"[fs1] Filesystem test ",
|
"[fs1] Filesystem test ",
|
||||||
"[fs2] FS read stress ",
|
"[fs2] FS read stress ",
|
||||||
@ -577,6 +616,7 @@ static const char *testmenu[] = {
|
|||||||
"[fs4] FS write stress 2 ",
|
"[fs4] FS write stress 2 ",
|
||||||
"[fs5] FS long stress ",
|
"[fs5] FS long stress ",
|
||||||
"[fs6] FS create stress ",
|
"[fs6] FS create stress ",
|
||||||
|
"[hm1] HMAC unit test ",
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -590,15 +630,41 @@ cmd_testmenu(int n, char **a)
|
|||||||
showmenu("OS/161 tests menu", testmenu);
|
showmenu("OS/161 tests menu", testmenu);
|
||||||
kprintf(" (1) These tests will fail until you finish the "
|
kprintf(" (1) These tests will fail until you finish the "
|
||||||
"synch assignment.\n");
|
"synch assignment.\n");
|
||||||
|
kprintf(" (*) These tests will panic on success.\n");
|
||||||
|
kprintf(" (?) These tests are left to you to implement.\n");
|
||||||
kprintf("\n");
|
kprintf("\n");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if OPT_AUTOMATIONTEST
|
||||||
|
static const char *automationmenu[] = {
|
||||||
|
"[dl] Deadlock test (*) ",
|
||||||
|
"[ll1] Livelock test (1 thread) ",
|
||||||
|
"[ll16] Livelock test (16 threads) ",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
static
|
||||||
|
int
|
||||||
|
cmd_automationmenu(int n, char **a)
|
||||||
|
{
|
||||||
|
(void)n;
|
||||||
|
(void)a;
|
||||||
|
|
||||||
|
showmenu("OS/161 automation tests menu", automationmenu);
|
||||||
|
kprintf(" (*) These tests require locks.\n");
|
||||||
|
kprintf("\n");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static const char *mainmenu[] = {
|
static const char *mainmenu[] = {
|
||||||
"[?o] Operations menu ",
|
"[?o] Operations menu ",
|
||||||
"[?t] Tests menu ",
|
"[?t] Tests menu ",
|
||||||
"[kh] Kernel heap stats ",
|
"[kh] Kernel heap stats ",
|
||||||
|
"[khu] Kernel heap usage ",
|
||||||
"[khgen] Next kernel heap generation ",
|
"[khgen] Next kernel heap generation ",
|
||||||
"[khdump] Dump kernel heap ",
|
"[khdump] Dump kernel heap ",
|
||||||
"[q] Quit and shut down ",
|
"[q] Quit and shut down ",
|
||||||
@ -630,6 +696,9 @@ static struct {
|
|||||||
{ "help", cmd_mainmenu },
|
{ "help", cmd_mainmenu },
|
||||||
{ "?o", cmd_opsmenu },
|
{ "?o", cmd_opsmenu },
|
||||||
{ "?t", cmd_testmenu },
|
{ "?t", cmd_testmenu },
|
||||||
|
#if OPT_AUTOMATIONTEST
|
||||||
|
{ "?a", cmd_automationmenu },
|
||||||
|
#endif
|
||||||
|
|
||||||
/* operations */
|
/* operations */
|
||||||
{ "s", cmd_shell },
|
{ "s", cmd_shell },
|
||||||
@ -650,6 +719,7 @@ static struct {
|
|||||||
|
|
||||||
/* stats */
|
/* stats */
|
||||||
{ "kh", cmd_kheapstats },
|
{ "kh", cmd_kheapstats },
|
||||||
|
{ "khu", cmd_kheapused },
|
||||||
{ "khgen", cmd_kheapgeneration },
|
{ "khgen", cmd_kheapgeneration },
|
||||||
{ "khdump", cmd_kheapdump },
|
{ "khdump", cmd_kheapdump },
|
||||||
|
|
||||||
@ -662,18 +732,35 @@ static struct {
|
|||||||
{ "km2", kmallocstress },
|
{ "km2", kmallocstress },
|
||||||
{ "km3", kmalloctest3 },
|
{ "km3", kmalloctest3 },
|
||||||
{ "km4", kmalloctest4 },
|
{ "km4", kmalloctest4 },
|
||||||
|
{ "km5", kmalloctest5 },
|
||||||
#if OPT_NET
|
#if OPT_NET
|
||||||
{ "net", nettest },
|
{ "net", nettest },
|
||||||
#endif
|
#endif
|
||||||
{ "tt1", threadtest },
|
{ "tt1", threadtest },
|
||||||
{ "tt2", threadtest2 },
|
{ "tt2", threadtest2 },
|
||||||
{ "tt3", threadtest3 },
|
{ "tt3", threadtest3 },
|
||||||
{ "sy1", semtest },
|
|
||||||
|
|
||||||
/* synchronization assignment tests */
|
/* synchronization assignment tests */
|
||||||
{ "sy2", locktest },
|
{ "sem1", semtest },
|
||||||
{ "sy3", cvtest },
|
{ "lt1", locktest },
|
||||||
{ "sy4", cvtest2 },
|
{ "lt2", locktest2 },
|
||||||
|
{ "lt3", locktest3 },
|
||||||
|
{ "lt4", locktest4 },
|
||||||
|
{ "lt5", locktest5 },
|
||||||
|
{ "cvt1", cvtest },
|
||||||
|
{ "cvt2", cvtest2 },
|
||||||
|
{ "cvt3", cvtest3 },
|
||||||
|
{ "cvt4", cvtest4 },
|
||||||
|
{ "cvt5", cvtest5 },
|
||||||
|
{ "rwt1", rwtest },
|
||||||
|
{ "rwt2", rwtest2 },
|
||||||
|
{ "rwt3", rwtest3 },
|
||||||
|
{ "rwt4", rwtest4 },
|
||||||
|
{ "rwt5", rwtest5 },
|
||||||
|
#if OPT_SYNCHPROBS
|
||||||
|
{ "sp1", whalemating },
|
||||||
|
{ "sp2", stoplight },
|
||||||
|
#endif
|
||||||
|
|
||||||
/* semaphore unit tests */
|
/* semaphore unit tests */
|
||||||
{ "semu1", semu1 },
|
{ "semu1", semu1 },
|
||||||
@ -707,6 +794,16 @@ static struct {
|
|||||||
{ "fs5", longstress },
|
{ "fs5", longstress },
|
||||||
{ "fs6", createstress },
|
{ "fs6", createstress },
|
||||||
|
|
||||||
|
/* HMAC unit tests */
|
||||||
|
{ "hm1", hmacu1 },
|
||||||
|
|
||||||
|
#if OPT_AUTOMATIONTEST
|
||||||
|
/* automation tests */
|
||||||
|
{ "dl", dltest },
|
||||||
|
{ "ll1", ll1test },
|
||||||
|
{ "ll16", ll16test },
|
||||||
|
#endif
|
||||||
|
|
||||||
{ NULL, NULL }
|
{ NULL, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -820,7 +917,11 @@ menu(char *args)
|
|||||||
menu_execute(args, 1);
|
menu_execute(args, 1);
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
kprintf("OS/161 kernel [? for menu]: ");
|
/*
|
||||||
|
* Defined in overwrite.h. If you want to change the kernel prompt, please
|
||||||
|
* do it in that file. Otherwise automated test testing will break.
|
||||||
|
*/
|
||||||
|
kprintf(KERNEL_PROMPT);
|
||||||
kgets(buf, sizeof(buf));
|
kgets(buf, sizeof(buf));
|
||||||
menu_execute(buf, 0);
|
menu_execute(buf, 0);
|
||||||
}
|
}
|
||||||
|
118
kern/synchprobs/stoplight.c
Normal file
118
kern/synchprobs/stoplight.c
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2001, 2002, 2009
|
||||||
|
* The President and Fellows of Harvard College.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. Neither the name of the University nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Driver code is in kern/tests/synchprobs.c We will replace that file. This
|
||||||
|
* file is yours to modify as you see fit.
|
||||||
|
*
|
||||||
|
* You should implement your solution to the stoplight problem below. The
|
||||||
|
* quadrant and direction mappings for reference: (although the problem is, of
|
||||||
|
* course, stable under rotation)
|
||||||
|
*
|
||||||
|
* |0 |
|
||||||
|
* - --
|
||||||
|
* 01 1
|
||||||
|
* 3 32
|
||||||
|
* -- --
|
||||||
|
* | 2|
|
||||||
|
*
|
||||||
|
* As way to think about it, assuming cars drive on the right: a car entering
|
||||||
|
* the intersection from direction X will enter intersection quadrant X first.
|
||||||
|
* The semantics of the problem are that once a car enters any quadrant it has
|
||||||
|
* to be somewhere in the intersection until it call leaveIntersection(),
|
||||||
|
* which it should call while in the final quadrant.
|
||||||
|
*
|
||||||
|
* As an example, let's say a car approaches the intersection and needs to
|
||||||
|
* pass through quadrants 0, 3 and 2. Once you call inQuadrant(0), the car is
|
||||||
|
* considered in quadrant 0 until you call inQuadrant(3). After you call
|
||||||
|
* inQuadrant(2), the car is considered in quadrant 2 until you call
|
||||||
|
* leaveIntersection().
|
||||||
|
*
|
||||||
|
* You will probably want to write some helper functions to assist with the
|
||||||
|
* mappings. Modular arithmetic can help, e.g. a car passing straight through
|
||||||
|
* the intersection entering from direction X will leave to direction (X + 2)
|
||||||
|
* % 4 and pass through quadrants X and (X + 3) % 4. Boo-yah.
|
||||||
|
*
|
||||||
|
* Your solutions below should call the inQuadrant() and leaveIntersection()
|
||||||
|
* functions in synchprobs.c to record their progress.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <types.h>
|
||||||
|
#include <lib.h>
|
||||||
|
#include <thread.h>
|
||||||
|
#include <test.h>
|
||||||
|
#include <synch.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Called by the driver during initialization.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void
|
||||||
|
stoplight_init() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Called by the driver during teardown.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void stoplight_cleanup() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
turnright(uint32_t direction, uint32_t index)
|
||||||
|
{
|
||||||
|
(void)direction;
|
||||||
|
(void)index;
|
||||||
|
/*
|
||||||
|
* Implement this function.
|
||||||
|
*/
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
void
|
||||||
|
gostraight(uint32_t direction, uint32_t index)
|
||||||
|
{
|
||||||
|
(void)direction;
|
||||||
|
(void)index;
|
||||||
|
/*
|
||||||
|
* Implement this function.
|
||||||
|
*/
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
void
|
||||||
|
turnleft(uint32_t direction, uint32_t index)
|
||||||
|
{
|
||||||
|
(void)direction;
|
||||||
|
(void)index;
|
||||||
|
/*
|
||||||
|
* Implement this function.
|
||||||
|
*/
|
||||||
|
return;
|
||||||
|
}
|
91
kern/synchprobs/whalemating.c
Normal file
91
kern/synchprobs/whalemating.c
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2001, 2002, 2009
|
||||||
|
* The President and Fellows of Harvard College.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. Neither the name of the University nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Driver code is in kern/tests/synchprobs.c We will
|
||||||
|
* replace that file. This file is yours to modify as you see fit.
|
||||||
|
*
|
||||||
|
* You should implement your solution to the whalemating problem below.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <types.h>
|
||||||
|
#include <lib.h>
|
||||||
|
#include <thread.h>
|
||||||
|
#include <test.h>
|
||||||
|
#include <synch.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Called by the driver during initialization.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void whalemating_init() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Called by the driver during teardown.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void
|
||||||
|
whalemating_cleanup() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
male(uint32_t index)
|
||||||
|
{
|
||||||
|
(void)index;
|
||||||
|
/*
|
||||||
|
* Implement this function by calling male_start and male_end when
|
||||||
|
* appropriate.
|
||||||
|
*/
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
female(uint32_t index)
|
||||||
|
{
|
||||||
|
(void)index;
|
||||||
|
/*
|
||||||
|
* Implement this function by calling female_start and female_end when
|
||||||
|
* appropriate.
|
||||||
|
*/
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
matchmaker(uint32_t index)
|
||||||
|
{
|
||||||
|
(void)index;
|
||||||
|
/*
|
||||||
|
* Implement this function by calling matchmaker_start and matchmaker_end
|
||||||
|
* when appropriate.
|
||||||
|
*/
|
||||||
|
return;
|
||||||
|
}
|
175
kern/test/automationtest.c
Normal file
175
kern/test/automationtest.c
Normal file
@ -0,0 +1,175 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
|
||||||
|
* The President and Fellows of Harvard College.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. Neither the name of the University nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Automation test code for creating (and detecting) kernel dead and livelocks.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <types.h>
|
||||||
|
#include <kern/wait.h>
|
||||||
|
#include <lib.h>
|
||||||
|
#include <clock.h>
|
||||||
|
#include <thread.h>
|
||||||
|
#include <synch.h>
|
||||||
|
#include <test.h>
|
||||||
|
#include <kern/secret.h>
|
||||||
|
#include <spinlock.h>
|
||||||
|
|
||||||
|
#define MAX_SPINNERS 16
|
||||||
|
|
||||||
|
static struct lock *deadlock_locks[2];
|
||||||
|
static struct semaphore *deadlock_sem;
|
||||||
|
|
||||||
|
struct spinlock spinners_lock[MAX_SPINNERS];
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
inititems(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < 2; i++) {
|
||||||
|
deadlock_locks[i] = lock_create("deadlock lock");
|
||||||
|
if (deadlock_locks[i] == NULL) {
|
||||||
|
panic("automationtest: lock_create failed\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
deadlock_sem = sem_create("deadlock sem", 0);
|
||||||
|
if (deadlock_sem == NULL) {
|
||||||
|
panic("automationtest: sem_create failed\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < MAX_SPINNERS; i++) {
|
||||||
|
spinlock_init(&(spinners_lock[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
dltestthread(void *junk1, unsigned long junk2)
|
||||||
|
{
|
||||||
|
(void)junk1;
|
||||||
|
(void)junk2;
|
||||||
|
|
||||||
|
lock_acquire(deadlock_locks[1]);
|
||||||
|
V(deadlock_sem);
|
||||||
|
lock_acquire(deadlock_locks[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
dltest(int nargs, char **args)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
|
||||||
|
(void)nargs;
|
||||||
|
(void)args;
|
||||||
|
|
||||||
|
inititems();
|
||||||
|
|
||||||
|
lock_acquire(deadlock_locks[0]);
|
||||||
|
|
||||||
|
result = thread_fork("dltest", NULL, dltestthread, NULL, (unsigned long)0);
|
||||||
|
if (result) {
|
||||||
|
panic("dltest: thread_fork failed: %s\n", strerror(result));
|
||||||
|
}
|
||||||
|
|
||||||
|
P(deadlock_sem);
|
||||||
|
lock_acquire(deadlock_locks[1]);
|
||||||
|
|
||||||
|
panic("dltest: didn't create deadlock (locks probably don't work)\n");
|
||||||
|
|
||||||
|
// 09 Jan 2015 : GWA : Shouldn't return.
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
static
|
||||||
|
void
|
||||||
|
infinite_spinner(unsigned long i)
|
||||||
|
{
|
||||||
|
(void)i;
|
||||||
|
volatile int j;
|
||||||
|
|
||||||
|
for (j=0; j<10000000; j++);
|
||||||
|
|
||||||
|
spinlock_acquire(&(spinners_lock[i]));
|
||||||
|
|
||||||
|
for (j=0; j<=1000; j++) {
|
||||||
|
if (j == 1000) {
|
||||||
|
j = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
panic("ll1test: infinite spin loop completed\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
ll1test(int nargs, char **args)
|
||||||
|
{
|
||||||
|
(void)nargs;
|
||||||
|
(void)args;
|
||||||
|
|
||||||
|
inititems();
|
||||||
|
|
||||||
|
infinite_spinner((unsigned long) 0);
|
||||||
|
|
||||||
|
// 09 Jan 2015 : GWA : Shouldn't return.
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
ll16testthread(void *junk1, unsigned long i)
|
||||||
|
{
|
||||||
|
(void)junk1;
|
||||||
|
|
||||||
|
infinite_spinner(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
ll16test(int nargs, char **args)
|
||||||
|
{
|
||||||
|
int i, result;
|
||||||
|
|
||||||
|
inititems();
|
||||||
|
|
||||||
|
(void)nargs;
|
||||||
|
(void)args;
|
||||||
|
|
||||||
|
for (i=1; i<16; i++) {
|
||||||
|
result = thread_fork("ll16testthread", NULL, ll16testthread, NULL, (unsigned long)i);
|
||||||
|
if (result) {
|
||||||
|
panic("ll16test: thread_fork failed: %s\n", strerror(result));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
infinite_spinner(0);
|
||||||
|
|
||||||
|
// 09 Jan 2015 : GWA : Shouldn't return.
|
||||||
|
return 0;
|
||||||
|
}
|
99
kern/test/hmacunit.c
Normal file
99
kern/test/hmacunit.c
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2015
|
||||||
|
* The President and Fellows of Harvard College.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. Neither the name of the University nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <types.h>
|
||||||
|
#include <lib.h>
|
||||||
|
#include <spinlock.h>
|
||||||
|
#include <synch.h>
|
||||||
|
#include <thread.h>
|
||||||
|
#include <current.h>
|
||||||
|
#include <clock.h>
|
||||||
|
#include <test.h>
|
||||||
|
#include <kern/secure.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Unit tests for hmac/sha256 hashing.
|
||||||
|
*/
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// support code
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
ok(void)
|
||||||
|
{
|
||||||
|
kprintf("Test passed.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Unit test 1
|
||||||
|
*
|
||||||
|
* Test some known msg/key/hashes to make sure we produce the
|
||||||
|
* right results.
|
||||||
|
*/
|
||||||
|
static const char *plaintext1[] = {
|
||||||
|
"The quick brown fox jumps over the lazy dog",
|
||||||
|
"The only people for me are the mad ones",
|
||||||
|
"I don't exactly know what I mean by that, but I mean it.",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *keys1[] = {
|
||||||
|
"xqWmgzbvGuLIeeKOrwMA",
|
||||||
|
"ZxuvolLXL7C68pDjsclX",
|
||||||
|
"PYeuVzKuB03awYDgJotS",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *hashes1[] = {
|
||||||
|
"251ab1da03c94435daf44898fcd11606669e222270e4ac90d04a18a9df8fdfd6",
|
||||||
|
"75bbf48c53ccba08c244447ef7eff2e0a02f23acfdac6502282ec431823fb393",
|
||||||
|
"6d7d2b5eabcda504f26de7547185483b19f9953a6eaeec6c364bb45e20b28598",
|
||||||
|
};
|
||||||
|
|
||||||
|
#define N_TESTS_1 3
|
||||||
|
|
||||||
|
int
|
||||||
|
hmacu1(int nargs, char **args)
|
||||||
|
{
|
||||||
|
char *hash;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
(void)nargs; (void)args;
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < N_TESTS_1; i++)
|
||||||
|
{
|
||||||
|
res = hmac(plaintext1[i], strlen(plaintext1[i]), keys1[i], strlen(keys1[i]), &hash);
|
||||||
|
KASSERT(!res);
|
||||||
|
KASSERT(strcmp(hash, hashes1[i]) == 0);
|
||||||
|
kfree(hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
ok();
|
||||||
|
/* clean up */
|
||||||
|
return 0;
|
||||||
|
}
|
@ -33,13 +33,19 @@
|
|||||||
#include <types.h>
|
#include <types.h>
|
||||||
#include <kern/errno.h>
|
#include <kern/errno.h>
|
||||||
#include <lib.h>
|
#include <lib.h>
|
||||||
|
#include <cpu.h>
|
||||||
#include <thread.h>
|
#include <thread.h>
|
||||||
#include <synch.h>
|
#include <synch.h>
|
||||||
#include <vm.h> /* for PAGE_SIZE */
|
#include <vm.h> /* for PAGE_SIZE */
|
||||||
#include <test.h>
|
#include <test.h>
|
||||||
|
#include <kern/test161.h>
|
||||||
|
#include <mainbus.h>
|
||||||
|
|
||||||
#include "opt-dumbvm.h"
|
#include "opt-dumbvm.h"
|
||||||
|
|
||||||
|
// from arch/mips/vm/ram.c
|
||||||
|
extern vaddr_t firstfree;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
// km1/km2
|
// km1/km2
|
||||||
|
|
||||||
@ -58,6 +64,12 @@
|
|||||||
#define ITEMSIZE 997
|
#define ITEMSIZE 997
|
||||||
#define NTHREADS 8
|
#define NTHREADS 8
|
||||||
|
|
||||||
|
#define PROGRESS(iter) do { \
|
||||||
|
if ((iter % 100) == 0) { \
|
||||||
|
kprintf("."); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
static
|
static
|
||||||
void
|
void
|
||||||
kmallocthread(void *sm, unsigned long num)
|
kmallocthread(void *sm, unsigned long num)
|
||||||
@ -69,15 +81,16 @@ kmallocthread(void *sm, unsigned long num)
|
|||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i=0; i<NTRIES; i++) {
|
for (i=0; i<NTRIES; i++) {
|
||||||
|
PROGRESS(i);
|
||||||
ptr = kmalloc(ITEMSIZE);
|
ptr = kmalloc(ITEMSIZE);
|
||||||
if (ptr==NULL) {
|
if (ptr==NULL) {
|
||||||
if (sem) {
|
if (sem) {
|
||||||
kprintf("thread %lu: kmalloc returned NULL\n",
|
kprintf("thread %lu: kmalloc returned NULL\n",
|
||||||
num);
|
num);
|
||||||
goto done;
|
panic("kmalloc test failed");
|
||||||
}
|
}
|
||||||
kprintf("kmalloc returned null; test failed.\n");
|
kprintf("kmalloc returned null; test failed.\n");
|
||||||
goto done;
|
panic("kmalloc test failed");
|
||||||
}
|
}
|
||||||
if (oldptr2) {
|
if (oldptr2) {
|
||||||
kfree(oldptr2);
|
kfree(oldptr2);
|
||||||
@ -85,7 +98,7 @@ kmallocthread(void *sm, unsigned long num)
|
|||||||
oldptr2 = oldptr;
|
oldptr2 = oldptr;
|
||||||
oldptr = ptr;
|
oldptr = ptr;
|
||||||
}
|
}
|
||||||
done:
|
|
||||||
if (oldptr2) {
|
if (oldptr2) {
|
||||||
kfree(oldptr2);
|
kfree(oldptr2);
|
||||||
}
|
}
|
||||||
@ -105,7 +118,8 @@ kmalloctest(int nargs, char **args)
|
|||||||
|
|
||||||
kprintf("Starting kmalloc test...\n");
|
kprintf("Starting kmalloc test...\n");
|
||||||
kmallocthread(NULL, 0);
|
kmallocthread(NULL, 0);
|
||||||
kprintf("kmalloc test done\n");
|
kprintf("\n");
|
||||||
|
success(TEST161_SUCCESS, SECRET, "km1");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -140,7 +154,8 @@ kmallocstress(int nargs, char **args)
|
|||||||
}
|
}
|
||||||
|
|
||||||
sem_destroy(sem);
|
sem_destroy(sem);
|
||||||
kprintf("kmalloc stress test done\n");
|
kprintf("\n");
|
||||||
|
success(TEST161_SUCCESS, SECRET, "km2");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -252,6 +267,7 @@ kmalloctest3(int nargs, char **args)
|
|||||||
curpos = 0;
|
curpos = 0;
|
||||||
cursizeindex = 0;
|
cursizeindex = 0;
|
||||||
for (i=0; i<numptrs; i++) {
|
for (i=0; i<numptrs; i++) {
|
||||||
|
PROGRESS(i);
|
||||||
cursize = sizes[cursizeindex];
|
cursize = sizes[cursizeindex];
|
||||||
ptr = ptrblocks[curblock][curpos];
|
ptr = ptrblocks[curblock][curpos];
|
||||||
KASSERT(ptr != NULL);
|
KASSERT(ptr != NULL);
|
||||||
@ -282,13 +298,15 @@ kmalloctest3(int nargs, char **args)
|
|||||||
|
|
||||||
/* Free the lower tier. */
|
/* Free the lower tier. */
|
||||||
for (i=0; i<numptrblocks; i++) {
|
for (i=0; i<numptrblocks; i++) {
|
||||||
|
PROGRESS(i);
|
||||||
KASSERT(ptrblocks[i] != NULL);
|
KASSERT(ptrblocks[i] != NULL);
|
||||||
kfree(ptrblocks[i]);
|
kfree(ptrblocks[i]);
|
||||||
}
|
}
|
||||||
/* Free the upper tier. */
|
/* Free the upper tier. */
|
||||||
kfree(ptrblocks);
|
kfree(ptrblocks);
|
||||||
|
|
||||||
kprintf("kmalloctest3: passed\n");
|
kprintf("\n");
|
||||||
|
success(TEST161_SUCCESS, SECRET, "km3");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -300,20 +318,24 @@ void
|
|||||||
kmalloctest4thread(void *sm, unsigned long num)
|
kmalloctest4thread(void *sm, unsigned long num)
|
||||||
{
|
{
|
||||||
#define NUM_KM4_SIZES 5
|
#define NUM_KM4_SIZES 5
|
||||||
|
#define ITERATIONS 50
|
||||||
static const unsigned sizes[NUM_KM4_SIZES] = { 1, 3, 5, 2, 4 };
|
static const unsigned sizes[NUM_KM4_SIZES] = { 1, 3, 5, 2, 4 };
|
||||||
|
|
||||||
struct semaphore *sem = sm;
|
struct semaphore *sem = sm;
|
||||||
void *ptrs[NUM_KM4_SIZES];
|
void *ptrs[NUM_KM4_SIZES];
|
||||||
unsigned p, q;
|
unsigned p, q;
|
||||||
unsigned i;
|
unsigned i, j, k;
|
||||||
|
uint32_t magic;
|
||||||
|
|
||||||
for (i=0; i<NUM_KM4_SIZES; i++) {
|
for (i=0; i<NUM_KM4_SIZES; i++) {
|
||||||
ptrs[i] = NULL;
|
ptrs[i] = NULL;
|
||||||
}
|
}
|
||||||
p = 0;
|
p = 0;
|
||||||
q = NUM_KM4_SIZES / 2;
|
q = NUM_KM4_SIZES / 2;
|
||||||
|
magic = random();
|
||||||
|
|
||||||
for (i=0; i<NTRIES; i++) {
|
for (i=0; i<NTRIES; i++) {
|
||||||
|
PROGRESS(i);
|
||||||
if (ptrs[q] != NULL) {
|
if (ptrs[q] != NULL) {
|
||||||
kfree(ptrs[q]);
|
kfree(ptrs[q]);
|
||||||
ptrs[q] = NULL;
|
ptrs[q] = NULL;
|
||||||
@ -324,6 +346,24 @@ kmalloctest4thread(void *sm, unsigned long num)
|
|||||||
"allocating %u pages failed\n",
|
"allocating %u pages failed\n",
|
||||||
num, sizes[p]);
|
num, sizes[p]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Write to each page of the allocated memory and make sure nothing
|
||||||
|
// overwrites it.
|
||||||
|
for (k = 0; k < sizes[p]; k++) {
|
||||||
|
*((uint32_t *)ptrs[p] + k*PAGE_SIZE/sizeof(uint32_t)) = magic;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (j = 0; j < ITERATIONS; j++) {
|
||||||
|
random_yielder(4);
|
||||||
|
for (k = 0; k < sizes[p]; k++) {
|
||||||
|
uint32_t actual = *((uint32_t *)ptrs[p] + k*PAGE_SIZE/sizeof(uint32_t));
|
||||||
|
if (actual != magic) {
|
||||||
|
panic("km4: expected %u got %u. Your VM is broken!",
|
||||||
|
magic, actual);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
magic++;
|
||||||
p = (p + 1) % NUM_KM4_SIZES;
|
p = (p + 1) % NUM_KM4_SIZES;
|
||||||
q = (q + 1) % NUM_KM4_SIZES;
|
q = (q + 1) % NUM_KM4_SIZES;
|
||||||
}
|
}
|
||||||
@ -375,6 +415,193 @@ kmalloctest4(int nargs, char **args)
|
|||||||
}
|
}
|
||||||
|
|
||||||
sem_destroy(sem);
|
sem_destroy(sem);
|
||||||
kprintf("Multipage kmalloc test done\n");
|
|
||||||
|
kprintf("\n");
|
||||||
|
success(TEST161_SUCCESS, SECRET, "km4");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline
|
||||||
|
void
|
||||||
|
km5_usage()
|
||||||
|
{
|
||||||
|
kprintf("usage: km5 [--avail <num_pages>] [--kernel <num_pages>]\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Allocate and free all physical memory a number of times. Along the we, we
|
||||||
|
* check coremap_used_bytes to make sure it's reporting the number we're
|
||||||
|
* expecting.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
kmalloctest5(int nargs, char **args)
|
||||||
|
{
|
||||||
|
#define KM5_ITERATIONS 5
|
||||||
|
|
||||||
|
// We're expecting an even number of arguments, less arg[0].
|
||||||
|
if (nargs > 5 || (nargs % 2) == 0) {
|
||||||
|
km5_usage();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned avail_page_slack = 0, kernel_page_limit = 0;
|
||||||
|
int arg = 1;
|
||||||
|
|
||||||
|
while (arg < nargs) {
|
||||||
|
if (strcmp(args[arg], "--avail") == 0) {
|
||||||
|
arg++;
|
||||||
|
avail_page_slack = atoi(args[arg++]);
|
||||||
|
} else if (strcmp(args[arg], "--kernel") == 0) {
|
||||||
|
arg++;
|
||||||
|
kernel_page_limit = atoi(args[arg++]);
|
||||||
|
} else {
|
||||||
|
km5_usage();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if OPT_DUMBVM
|
||||||
|
kprintf("(This test will not work with dumbvm)\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// First, we need to figure out how much memory we're running with and how
|
||||||
|
// much space it will take up if we maintain a pointer to each allocated
|
||||||
|
// page. We do something similar to km3 - for 32 bit systems with
|
||||||
|
// PAGE_SIZE == 4096, we can store 1024 pointers on a page. We keep an array
|
||||||
|
// of page size blocks of pointers which in total can hold enough pointers
|
||||||
|
// for each page of available physical memory.
|
||||||
|
unsigned orig_used, ptrs_per_page, num_ptr_blocks, max_pages;
|
||||||
|
unsigned total_ram, avail_ram, magic, orig_magic, known_pages;
|
||||||
|
|
||||||
|
ptrs_per_page = PAGE_SIZE / sizeof(void *);
|
||||||
|
total_ram = mainbus_ramsize();
|
||||||
|
avail_ram = total_ram - (uint32_t)(firstfree - MIPS_KSEG0);
|
||||||
|
max_pages = (avail_ram + PAGE_SIZE-1) / PAGE_SIZE;
|
||||||
|
num_ptr_blocks = (max_pages + ptrs_per_page-1) / ptrs_per_page;
|
||||||
|
|
||||||
|
// The array can go on the stack, we won't have that many
|
||||||
|
// (sys161 16M max => 4 blocks)
|
||||||
|
void **ptrs[num_ptr_blocks];
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < num_ptr_blocks; i++) {
|
||||||
|
ptrs[i] = kmalloc(PAGE_SIZE);
|
||||||
|
if (ptrs[i] == NULL) {
|
||||||
|
panic("Can't allocate ptr page!");
|
||||||
|
}
|
||||||
|
bzero(ptrs[i], PAGE_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
kprintf("km5 --> phys ram: %uk avail ram: %uk (%u pages) ptr blocks: %u\n", total_ram/1024,
|
||||||
|
avail_ram/1024, max_pages, num_ptr_blocks);
|
||||||
|
|
||||||
|
// Initially, there must be at least 1 page allocated for each thread stack,
|
||||||
|
// one page for kmalloc for this thread struct, plus what we just allocated).
|
||||||
|
// This probably isn't the GLB, but its a decent lower bound.
|
||||||
|
orig_used = coremap_used_bytes();
|
||||||
|
known_pages = num_cpus + num_ptr_blocks + 1;
|
||||||
|
if (orig_used < known_pages * PAGE_SIZE) {
|
||||||
|
panic ("Not enough pages initially allocated");
|
||||||
|
}
|
||||||
|
if ((orig_used % PAGE_SIZE) != 0) {
|
||||||
|
panic("Coremap used bytes should be a multiple of PAGE_SIZE");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test for kernel bloat.
|
||||||
|
if (kernel_page_limit > 0) {
|
||||||
|
uint32_t kpages = (total_ram - avail_ram + PAGE_SIZE) / PAGE_SIZE;
|
||||||
|
if (kpages > kernel_page_limit) {
|
||||||
|
panic("You're kernel is bloated! Max allowed pages: %d, used pages: %d",
|
||||||
|
kernel_page_limit, kpages);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
orig_magic = magic = random();
|
||||||
|
|
||||||
|
for (int i = 0; i < KM5_ITERATIONS; i++) {
|
||||||
|
// Step 1: allocate all physical memory, with checks along the way
|
||||||
|
unsigned int block, pos, oom, pages, used, prev;
|
||||||
|
void *page;
|
||||||
|
|
||||||
|
block = pos = oom = pages = used = 0;
|
||||||
|
prev = orig_used;
|
||||||
|
|
||||||
|
while (pages < max_pages+1) {
|
||||||
|
PROGRESS(pages);
|
||||||
|
page = kmalloc(PAGE_SIZE);
|
||||||
|
if (page == NULL) {
|
||||||
|
oom = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure we can write to the page
|
||||||
|
*(uint32_t *)page = magic++;
|
||||||
|
|
||||||
|
// Make sure the number of used bytes is going up, and by increments of PAGE_SIZE
|
||||||
|
used = coremap_used_bytes();
|
||||||
|
if (used != prev + PAGE_SIZE) {
|
||||||
|
panic("Allocation not equal to PAGE_SIZE. prev: %u used: %u", prev, used);
|
||||||
|
}
|
||||||
|
prev = used;
|
||||||
|
|
||||||
|
ptrs[block][pos] = page;
|
||||||
|
pos++;
|
||||||
|
if (pos >= ptrs_per_page) {
|
||||||
|
pos = 0;
|
||||||
|
block++;
|
||||||
|
}
|
||||||
|
pages++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 2: Check that we were able to allocate a reasonable number of pages
|
||||||
|
unsigned expected;
|
||||||
|
if (avail_page_slack > 0 ) {
|
||||||
|
// max avail pages + what we can prove we allocated + some slack
|
||||||
|
expected = max_pages - (known_pages + avail_page_slack);
|
||||||
|
} else {
|
||||||
|
// At the very least, just so we know things are working.
|
||||||
|
expected = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pages < expected) {
|
||||||
|
panic("Expected to allocate at least %d pages, only allocated %d",
|
||||||
|
expected, pages);
|
||||||
|
}
|
||||||
|
|
||||||
|
// We tried to allocate 1 more page than is available in physical memory. That
|
||||||
|
// should fail unless you're swapping out kernel pages, which you should
|
||||||
|
// probably not be doing.
|
||||||
|
if (!oom) {
|
||||||
|
panic("Allocated more pages than physical memory. Are you swapping kernel pages?");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 3: free everything and check that we're back to where we started
|
||||||
|
for (block = 0; block < num_ptr_blocks; block++) {
|
||||||
|
for (pos = 0; pos < ptrs_per_page; pos++) {
|
||||||
|
if (ptrs[block][pos] != NULL) {
|
||||||
|
// Make sure we got unique addresses
|
||||||
|
if ((*(uint32_t *)ptrs[block][pos]) != orig_magic++) {
|
||||||
|
panic("km5: expected %u got %u - your VM is broken!",
|
||||||
|
orig_magic-1, (*(uint32_t *)ptrs[block][pos]));
|
||||||
|
}
|
||||||
|
kfree(ptrs[block][pos]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that we're back to where we started
|
||||||
|
used = coremap_used_bytes();
|
||||||
|
if (used != orig_used) {
|
||||||
|
panic("orig (%u) != used (%u)", orig_used, used);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Clean up the pointer blocks
|
||||||
|
for (unsigned i = 0; i < num_ptr_blocks; i++) {
|
||||||
|
kfree(ptrs[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
kprintf("\n");
|
||||||
|
success(TEST161_SUCCESS, SECRET, "km5");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
28
kern/test/lib.c
Normal file
28
kern/test/lib.c
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
#include <types.h>
|
||||||
|
#include <thread.h>
|
||||||
|
#include <test.h>
|
||||||
|
#include <lib.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Helper functions used by testing and problem driver code
|
||||||
|
* to establish better mixtures of threads.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void
|
||||||
|
random_yielder(uint32_t max_yield_count)
|
||||||
|
{
|
||||||
|
uint32_t i;
|
||||||
|
for (i = 0; i < random() % max_yield_count; i++) {
|
||||||
|
thread_yield();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
random_spinner(uint32_t max_spin_count)
|
||||||
|
{
|
||||||
|
uint32_t i;
|
||||||
|
volatile int spin;
|
||||||
|
for (i = 0; i < random() % max_spin_count; i++) {
|
||||||
|
spin += i;
|
||||||
|
}
|
||||||
|
}
|
67
kern/test/rwtest.c
Normal file
67
kern/test/rwtest.c
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
/*
|
||||||
|
* All the contents of this file are overwritten during automated
|
||||||
|
* testing. Please consider this before changing anything in this file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <types.h>
|
||||||
|
#include <lib.h>
|
||||||
|
#include <clock.h>
|
||||||
|
#include <thread.h>
|
||||||
|
#include <synch.h>
|
||||||
|
#include <test.h>
|
||||||
|
#include <kern/test161.h>
|
||||||
|
#include <spinlock.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Use these stubs to test your reader-writer locks.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int rwtest(int nargs, char **args) {
|
||||||
|
(void)nargs;
|
||||||
|
(void)args;
|
||||||
|
|
||||||
|
kprintf_n("rwt1 unimplemented\n");
|
||||||
|
success(TEST161_FAIL, SECRET, "rwt1");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rwtest2(int nargs, char **args) {
|
||||||
|
(void)nargs;
|
||||||
|
(void)args;
|
||||||
|
|
||||||
|
kprintf_n("rwt2 unimplemented\n");
|
||||||
|
success(TEST161_FAIL, SECRET, "rwt2");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rwtest3(int nargs, char **args) {
|
||||||
|
(void)nargs;
|
||||||
|
(void)args;
|
||||||
|
|
||||||
|
kprintf_n("rwt3 unimplemented\n");
|
||||||
|
success(TEST161_FAIL, SECRET, "rwt3");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rwtest4(int nargs, char **args) {
|
||||||
|
(void)nargs;
|
||||||
|
(void)args;
|
||||||
|
|
||||||
|
kprintf_n("rwt4 unimplemented\n");
|
||||||
|
success(TEST161_FAIL, SECRET, "rwt4");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rwtest5(int nargs, char **args) {
|
||||||
|
(void)nargs;
|
||||||
|
(void)args;
|
||||||
|
|
||||||
|
kprintf_n("rwt5 unimplemented\n");
|
||||||
|
success(TEST161_FAIL, SECRET, "rwt5");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
688
kern/test/synchprobs.c
Normal file
688
kern/test/synchprobs.c
Normal file
@ -0,0 +1,688 @@
|
|||||||
|
/*
|
||||||
|
* All the contents of this file are overwritten during automated
|
||||||
|
* testing. Please consider this before changing anything in this file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <types.h>
|
||||||
|
#include <lib.h>
|
||||||
|
#include <thread.h>
|
||||||
|
#include <test.h>
|
||||||
|
#include <current.h>
|
||||||
|
#include <synch.h>
|
||||||
|
#include <kern/test161.h>
|
||||||
|
#include <spinlock.h>
|
||||||
|
|
||||||
|
#define PROBLEMS_MAX_YIELDER 16
|
||||||
|
#define PROBLEMS_MAX_SPINNER 8192
|
||||||
|
|
||||||
|
#define TEST161_SUCCESS 0
|
||||||
|
#define TEST161_FAIL 1
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Shared initialization routines
|
||||||
|
*/
|
||||||
|
|
||||||
|
static uint32_t startcount;
|
||||||
|
static struct lock *testlock;
|
||||||
|
static struct cv *startcv;
|
||||||
|
static struct semaphore *startsem;
|
||||||
|
static struct semaphore *endsem;
|
||||||
|
|
||||||
|
struct spinlock status_lock;
|
||||||
|
static bool test_status = TEST161_FAIL;
|
||||||
|
const char *test_message;
|
||||||
|
|
||||||
|
static
|
||||||
|
bool
|
||||||
|
failif(bool condition, const char *message) {
|
||||||
|
if (condition) {
|
||||||
|
spinlock_acquire(&status_lock);
|
||||||
|
test_status = TEST161_FAIL;
|
||||||
|
test_message = message;
|
||||||
|
spinlock_release(&status_lock);
|
||||||
|
}
|
||||||
|
return condition;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Helper function to initialize the thread pool.
|
||||||
|
*/
|
||||||
|
static
|
||||||
|
void
|
||||||
|
initialize_thread(volatile void* threads[], uint32_t index) {
|
||||||
|
failif((threads[index] != NULL), "failed: incorrect thread type");
|
||||||
|
threads[index] = curthread->t_stack;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Helper function to check whether current thread is valid.
|
||||||
|
*/
|
||||||
|
static
|
||||||
|
void
|
||||||
|
check_thread(volatile void* threads[], uint32_t index) {
|
||||||
|
failif((threads[index] != curthread->t_stack), "failed: incorrect thread type");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Driver code for the whalemating problem.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define NMATING 10
|
||||||
|
#define MALE 0
|
||||||
|
#define FEMALE 1
|
||||||
|
#define MATCHMAKER 2
|
||||||
|
#define CHECK_TIMES 32
|
||||||
|
|
||||||
|
static volatile int male_start_count;
|
||||||
|
static volatile int male_end_count;
|
||||||
|
static volatile int female_start_count;
|
||||||
|
static volatile int female_end_count;
|
||||||
|
static volatile int matchmaker_start_count;
|
||||||
|
static volatile int matchmaker_end_count;
|
||||||
|
static volatile int match_count;
|
||||||
|
static volatile int concurrent_matchmakers;
|
||||||
|
static volatile int max_concurrent_matchmakers;
|
||||||
|
|
||||||
|
static volatile void* whale_threads[3 * NMATING];
|
||||||
|
static volatile int whale_roles[3 * NMATING];
|
||||||
|
static struct semaphore *matcher_sem;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Enforce male_start() and male_end() called from male thread.
|
||||||
|
* Similar for female and matchmaker threads
|
||||||
|
*/
|
||||||
|
static
|
||||||
|
void
|
||||||
|
check_role(uint32_t index, int role) {
|
||||||
|
failif((whale_roles[index] != role), "failed: incorrect role");
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
male_wrapper(void * unused1, unsigned long index) {
|
||||||
|
(void)unused1;
|
||||||
|
|
||||||
|
random_yielder(4);
|
||||||
|
lock_acquire(testlock);
|
||||||
|
initialize_thread(whale_threads, (uint32_t)index);
|
||||||
|
whale_roles[index] = MALE;
|
||||||
|
lock_release(testlock);
|
||||||
|
male((uint32_t)index);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
void
|
||||||
|
male_start(uint32_t index) {
|
||||||
|
(void)index;
|
||||||
|
lock_acquire(testlock);
|
||||||
|
check_thread(whale_threads, index);
|
||||||
|
check_role(index, MALE);
|
||||||
|
male_start_count++;
|
||||||
|
kprintf_n("%s starting\n", curthread->t_name);
|
||||||
|
kprintf_t(".");
|
||||||
|
lock_release(testlock);
|
||||||
|
random_yielder(PROBLEMS_MAX_YIELDER);
|
||||||
|
random_spinner(PROBLEMS_MAX_SPINNER);
|
||||||
|
V(startsem);
|
||||||
|
}
|
||||||
|
void
|
||||||
|
male_end(uint32_t index) {
|
||||||
|
(void)index;
|
||||||
|
lock_acquire(testlock);
|
||||||
|
check_thread(whale_threads, index);
|
||||||
|
check_role(index, MALE);
|
||||||
|
male_end_count++;
|
||||||
|
kprintf_n("%s ending\n", curthread->t_name);
|
||||||
|
kprintf_t(".");
|
||||||
|
lock_release(testlock);
|
||||||
|
random_yielder(PROBLEMS_MAX_YIELDER);
|
||||||
|
random_spinner(PROBLEMS_MAX_SPINNER);
|
||||||
|
V(endsem);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
female_wrapper(void * unused1, unsigned long index) {
|
||||||
|
(void)unused1;
|
||||||
|
|
||||||
|
random_yielder(4);
|
||||||
|
lock_acquire(testlock);
|
||||||
|
initialize_thread(whale_threads, (uint32_t)index);
|
||||||
|
whale_roles[index] = FEMALE;
|
||||||
|
lock_release(testlock);
|
||||||
|
female((uint32_t)index);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
void
|
||||||
|
female_start(uint32_t index) {
|
||||||
|
(void) index;
|
||||||
|
lock_acquire(testlock);
|
||||||
|
check_thread(whale_threads, index);
|
||||||
|
check_role(index, FEMALE);
|
||||||
|
female_start_count++;
|
||||||
|
kprintf_n("%s starting\n", curthread->t_name);
|
||||||
|
kprintf_t(".");
|
||||||
|
lock_release(testlock);
|
||||||
|
random_yielder(PROBLEMS_MAX_YIELDER);
|
||||||
|
random_spinner(PROBLEMS_MAX_SPINNER);
|
||||||
|
V(startsem);
|
||||||
|
}
|
||||||
|
void
|
||||||
|
female_end(uint32_t index) {
|
||||||
|
(void) index;
|
||||||
|
lock_acquire(testlock);
|
||||||
|
check_thread(whale_threads, index);
|
||||||
|
check_role(index, FEMALE);
|
||||||
|
female_end_count++;
|
||||||
|
kprintf_n("%s ending\n", curthread->t_name);
|
||||||
|
kprintf_t(".");
|
||||||
|
lock_release(testlock);
|
||||||
|
random_yielder(PROBLEMS_MAX_YIELDER);
|
||||||
|
random_spinner(PROBLEMS_MAX_SPINNER);
|
||||||
|
V(endsem);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
matchmaker_wrapper(void * unused1, unsigned long index) {
|
||||||
|
(void)unused1;
|
||||||
|
|
||||||
|
random_yielder(4);
|
||||||
|
lock_acquire(testlock);
|
||||||
|
initialize_thread(whale_threads, (uint32_t)index);
|
||||||
|
whale_roles[index] = MATCHMAKER;
|
||||||
|
lock_release(testlock);
|
||||||
|
matchmaker((uint32_t)index);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
void
|
||||||
|
matchmaker_start(uint32_t index) {
|
||||||
|
(void)index;
|
||||||
|
P(matcher_sem);
|
||||||
|
lock_acquire(testlock);
|
||||||
|
check_thread(whale_threads, index);
|
||||||
|
check_role(index, MATCHMAKER);
|
||||||
|
matchmaker_start_count++;
|
||||||
|
concurrent_matchmakers++;
|
||||||
|
if (concurrent_matchmakers > max_concurrent_matchmakers) {
|
||||||
|
max_concurrent_matchmakers = concurrent_matchmakers;
|
||||||
|
}
|
||||||
|
kprintf_n("%s starting\n", curthread->t_name);
|
||||||
|
kprintf_t(".");
|
||||||
|
lock_release(testlock);
|
||||||
|
random_yielder(PROBLEMS_MAX_YIELDER);
|
||||||
|
random_spinner(PROBLEMS_MAX_SPINNER);
|
||||||
|
V(startsem);
|
||||||
|
}
|
||||||
|
void
|
||||||
|
matchmaker_end(uint32_t index) {
|
||||||
|
(void)index;
|
||||||
|
lock_acquire(testlock);
|
||||||
|
check_thread(whale_threads, index);
|
||||||
|
check_role(index, MATCHMAKER);
|
||||||
|
match_count++;
|
||||||
|
matchmaker_end_count++;
|
||||||
|
concurrent_matchmakers--;
|
||||||
|
kprintf_n("%s ending\n", curthread->t_name);
|
||||||
|
kprintf_t(".");
|
||||||
|
lock_release(testlock);
|
||||||
|
random_yielder(PROBLEMS_MAX_YIELDER);
|
||||||
|
random_spinner(PROBLEMS_MAX_SPINNER);
|
||||||
|
V(endsem);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
whalemating(int nargs, char **args) {
|
||||||
|
(void) nargs;
|
||||||
|
(void) args;
|
||||||
|
|
||||||
|
int i, j, err = 0;
|
||||||
|
char name[32];
|
||||||
|
bool loop_status;
|
||||||
|
int total_count = 0;
|
||||||
|
|
||||||
|
male_start_count = 0 ;
|
||||||
|
male_end_count = 0 ;
|
||||||
|
female_start_count = 0 ;
|
||||||
|
female_end_count = 0 ;
|
||||||
|
matchmaker_start_count = 0;
|
||||||
|
matchmaker_end_count = 0;
|
||||||
|
match_count = 0;
|
||||||
|
concurrent_matchmakers = 0;
|
||||||
|
max_concurrent_matchmakers = 0;
|
||||||
|
|
||||||
|
kprintf_n("Starting sp1...\n");
|
||||||
|
kprintf_n("If this tests hangs, your solution is incorrect.\n");
|
||||||
|
|
||||||
|
testlock = lock_create("testlock");
|
||||||
|
if (testlock == NULL) {
|
||||||
|
panic("sp1: lock_create failed\n");
|
||||||
|
}
|
||||||
|
startsem = sem_create("startsem", 0);
|
||||||
|
if (startsem == NULL) {
|
||||||
|
panic("sp1: sem_create failed\n");
|
||||||
|
}
|
||||||
|
endsem = sem_create("endsem", 0);
|
||||||
|
if (endsem == NULL) {
|
||||||
|
panic("sp1: sem_create failed\n");
|
||||||
|
}
|
||||||
|
matcher_sem = sem_create("matcher_sem", 0);
|
||||||
|
if (matcher_sem == NULL) {
|
||||||
|
panic("sp1: sem_create failed\n");
|
||||||
|
}
|
||||||
|
spinlock_init(&status_lock);
|
||||||
|
test_status = TEST161_SUCCESS;
|
||||||
|
test_message = "";
|
||||||
|
|
||||||
|
whalemating_init();
|
||||||
|
|
||||||
|
/* Start males and females only. */
|
||||||
|
for (i = 0; i < 2; i++) {
|
||||||
|
for (j = 0; j < NMATING; j++) {
|
||||||
|
kprintf_t(".");
|
||||||
|
int index = (i * NMATING) + j;
|
||||||
|
whale_threads[index] = NULL;
|
||||||
|
switch (i) {
|
||||||
|
case 0:
|
||||||
|
snprintf(name, sizeof(name), "Male Whale Thread %d", index);
|
||||||
|
err = thread_fork(name, NULL, male_wrapper, NULL, index);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
snprintf(name, sizeof(name), "Female Whale Thread %d", index);
|
||||||
|
err = thread_fork(name, NULL, female_wrapper, NULL, index);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
total_count += 1;
|
||||||
|
if (err) {
|
||||||
|
panic("sp1: thread_fork failed: (%s)\n", strerror(err));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Wait for males and females to start. */
|
||||||
|
for (i = 0; i < NMATING * 2; i++) {
|
||||||
|
kprintf_t(".");
|
||||||
|
P(startsem);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make sure nothing is happening... */
|
||||||
|
loop_status = TEST161_SUCCESS;
|
||||||
|
for (i = 0; i < CHECK_TIMES && loop_status == TEST161_SUCCESS; i++) {
|
||||||
|
kprintf_t(".");
|
||||||
|
random_spinner(PROBLEMS_MAX_SPINNER);
|
||||||
|
lock_acquire(testlock);
|
||||||
|
if ((male_start_count != NMATING) || (female_start_count != NMATING) ||
|
||||||
|
(matchmaker_start_count + male_end_count + female_end_count + matchmaker_end_count != 0)) {
|
||||||
|
loop_status = TEST161_FAIL;
|
||||||
|
}
|
||||||
|
lock_release(testlock);
|
||||||
|
}
|
||||||
|
if (failif((loop_status == TEST161_FAIL), "failed: uncoordinated matchmaking is occurring")) {
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create the matchmakers */
|
||||||
|
for (j = 0; j < NMATING; j++) {
|
||||||
|
kprintf_t(".");
|
||||||
|
int index = (2 * NMATING) + j;
|
||||||
|
whale_threads[index] = NULL;
|
||||||
|
snprintf(name, sizeof(name), "Matchmaker Whale Thread %d", index);
|
||||||
|
err = thread_fork(name, NULL, matchmaker_wrapper, NULL, index);
|
||||||
|
if (err) {
|
||||||
|
panic("sp1: thread_fork failed: (%s)\n", strerror(err));
|
||||||
|
}
|
||||||
|
total_count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Release a random number of matchmakers and wait for them and their
|
||||||
|
* matches to finish.
|
||||||
|
*/
|
||||||
|
int pivot = (random() % (NMATING - 2)) + 1;
|
||||||
|
for (i = 0; i < pivot; i++) {
|
||||||
|
kprintf_t(".");
|
||||||
|
V(matcher_sem);
|
||||||
|
}
|
||||||
|
for (i = 0; i < 3 * pivot; i++) {
|
||||||
|
kprintf_t(".");
|
||||||
|
P(endsem);
|
||||||
|
total_count--;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make sure nothing else is happening... */
|
||||||
|
loop_status = TEST161_SUCCESS;
|
||||||
|
for (i = 0; i < CHECK_TIMES && loop_status == TEST161_SUCCESS; i++) {
|
||||||
|
kprintf_t(".");
|
||||||
|
random_spinner(PROBLEMS_MAX_SPINNER);
|
||||||
|
lock_acquire(testlock);
|
||||||
|
if ((male_start_count != NMATING) || (female_start_count != NMATING) ||
|
||||||
|
(matchmaker_start_count != pivot) || (male_end_count != pivot) ||
|
||||||
|
(female_end_count != pivot) || (matchmaker_end_count != pivot)) {
|
||||||
|
loop_status = TEST161_FAIL;
|
||||||
|
}
|
||||||
|
lock_release(testlock);
|
||||||
|
}
|
||||||
|
if (failif((loop_status == TEST161_FAIL), "failed: uncoordinated matchmaking is occurring")) {
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Release the rest of the matchmakers and wait for everyone to finish.
|
||||||
|
*/
|
||||||
|
|
||||||
|
for (i = pivot; i < NMATING; i++) {
|
||||||
|
kprintf_t(".");
|
||||||
|
V(matcher_sem);
|
||||||
|
}
|
||||||
|
for (i = 0; i < 3; i++) {
|
||||||
|
for (j = pivot; j < NMATING; j++) {
|
||||||
|
kprintf_t(".");
|
||||||
|
P(endsem);
|
||||||
|
total_count--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
failif((max_concurrent_matchmakers == 1), "failed: no matchmaker concurrency");
|
||||||
|
|
||||||
|
whalemating_cleanup();
|
||||||
|
|
||||||
|
done:
|
||||||
|
for (i = 0; i < total_count; i++) {
|
||||||
|
P(endsem);
|
||||||
|
}
|
||||||
|
|
||||||
|
lock_destroy(testlock);
|
||||||
|
sem_destroy(startsem);
|
||||||
|
sem_destroy(endsem);
|
||||||
|
sem_destroy(matcher_sem);
|
||||||
|
|
||||||
|
kprintf_t("\n");
|
||||||
|
if (test_status != TEST161_SUCCESS) {
|
||||||
|
secprintf(SECRET, test_message, "sp1");
|
||||||
|
}
|
||||||
|
success(test_status, SECRET, "sp1");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Driver code for the stoplight problem.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define NCARS 64
|
||||||
|
#define NUM_QUADRANTS 4
|
||||||
|
#define UNKNOWN_CAR -1
|
||||||
|
#define PASSED_CAR -2
|
||||||
|
|
||||||
|
#define GO_STRAIGHT 0
|
||||||
|
#define TURN_LEFT 1
|
||||||
|
#define TURN_RIGHT 2
|
||||||
|
|
||||||
|
static volatile int quadrant_array[NUM_QUADRANTS];
|
||||||
|
static volatile int max_car_count;
|
||||||
|
static volatile int all_quadrant;
|
||||||
|
static volatile int car_locations[NCARS];
|
||||||
|
static volatile int car_directions[NCARS];
|
||||||
|
static volatile int car_turns[NCARS];
|
||||||
|
static volatile int car_turn_times[NCARS];
|
||||||
|
static volatile void* car_threads[NCARS];
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
initialize_car_thread(uint32_t index, uint32_t direction, uint32_t turn) {
|
||||||
|
initialize_thread(car_threads, index);
|
||||||
|
car_directions[index] = direction;
|
||||||
|
car_turns[index] = turn;
|
||||||
|
car_turn_times[index] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
check_intersection() {
|
||||||
|
int n = 0;
|
||||||
|
for (int i = 0; i < NUM_QUADRANTS; i++) {
|
||||||
|
failif((quadrant_array[i] > 1), "failed: collision");
|
||||||
|
n += quadrant_array[i];
|
||||||
|
}
|
||||||
|
max_car_count = n > max_car_count ? n : max_car_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When car move, must call this function and hold a lock.
|
||||||
|
* It first checks current intersection status make sure no more than one car in one quadrant.
|
||||||
|
* Then it removes current car from previous location.
|
||||||
|
* In the end, it returns current car's index for inQuadrant, to let inQuadrant update car_locations array.
|
||||||
|
*/
|
||||||
|
static
|
||||||
|
int
|
||||||
|
move(uint32_t index) {
|
||||||
|
check_thread(car_threads, index);
|
||||||
|
check_intersection();
|
||||||
|
int pre_location = car_locations[index];
|
||||||
|
if (pre_location != UNKNOWN_CAR && pre_location != PASSED_CAR) {
|
||||||
|
quadrant_array[pre_location]--;
|
||||||
|
}
|
||||||
|
return pre_location;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
turnright_wrapper(void *index, unsigned long direction)
|
||||||
|
{
|
||||||
|
random_yielder(4);
|
||||||
|
lock_acquire(testlock);
|
||||||
|
initialize_car_thread((uint32_t)index, (uint32_t)direction, TURN_RIGHT);
|
||||||
|
startcount--;
|
||||||
|
if (startcount == 0) {
|
||||||
|
cv_broadcast(startcv, testlock);
|
||||||
|
} else {
|
||||||
|
cv_wait(startcv, testlock);
|
||||||
|
}
|
||||||
|
lock_release(testlock);
|
||||||
|
turnright((uint32_t)direction, (uint32_t)index);
|
||||||
|
V(endsem);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
static
|
||||||
|
void
|
||||||
|
gostraight_wrapper(void *index, unsigned long direction)
|
||||||
|
{
|
||||||
|
random_yielder(4);
|
||||||
|
lock_acquire(testlock);
|
||||||
|
initialize_car_thread((uint32_t)index, (uint32_t)direction, GO_STRAIGHT);
|
||||||
|
startcount--;
|
||||||
|
if (startcount == 0) {
|
||||||
|
cv_broadcast(startcv, testlock);
|
||||||
|
} else {
|
||||||
|
cv_wait(startcv, testlock);
|
||||||
|
}
|
||||||
|
lock_release(testlock);
|
||||||
|
gostraight((uint32_t)direction, (uint32_t)index);
|
||||||
|
V(endsem);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
static
|
||||||
|
void
|
||||||
|
turnleft_wrapper(void *index, unsigned long direction)
|
||||||
|
{
|
||||||
|
random_yielder(4);
|
||||||
|
lock_acquire(testlock);
|
||||||
|
initialize_car_thread((uint32_t)index, (uint32_t)direction, TURN_LEFT);
|
||||||
|
startcount--;
|
||||||
|
if (startcount == 0) {
|
||||||
|
cv_broadcast(startcv, testlock);
|
||||||
|
} else {
|
||||||
|
cv_wait(startcv, testlock);
|
||||||
|
}
|
||||||
|
lock_release(testlock);
|
||||||
|
turnleft((uint32_t)direction, (uint32_t)index);
|
||||||
|
V(endsem);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
inQuadrant(int quadrant, uint32_t index) {
|
||||||
|
random_yielder(PROBLEMS_MAX_YIELDER);
|
||||||
|
random_spinner(PROBLEMS_MAX_SPINNER);
|
||||||
|
lock_acquire(testlock);
|
||||||
|
int pre_quadrant = move(index);
|
||||||
|
|
||||||
|
int target_quadrant = car_directions[index];
|
||||||
|
switch (car_turn_times[index]) {
|
||||||
|
case 0:
|
||||||
|
failif((pre_quadrant != UNKNOWN_CAR), "failed: invalid turn");
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
failif((pre_quadrant != target_quadrant), "failed: invalid turn");
|
||||||
|
target_quadrant = (target_quadrant + NUM_QUADRANTS - 1) % NUM_QUADRANTS;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
target_quadrant = (target_quadrant + NUM_QUADRANTS - 1) % NUM_QUADRANTS;
|
||||||
|
failif((pre_quadrant != target_quadrant), "failed: invalid turn");
|
||||||
|
target_quadrant = (target_quadrant + NUM_QUADRANTS - 1) % NUM_QUADRANTS;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
failif(true, "failed: invalid turn");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
failif((quadrant != target_quadrant), "failed: invalid turn");
|
||||||
|
car_turn_times[index]++;
|
||||||
|
|
||||||
|
failif((quadrant_array[quadrant] > 0), "failed: collision");
|
||||||
|
|
||||||
|
quadrant_array[quadrant]++;
|
||||||
|
car_locations[index] = quadrant;
|
||||||
|
all_quadrant++;
|
||||||
|
|
||||||
|
lock_release(testlock);
|
||||||
|
kprintf_n("%s in quadrant %d\n", curthread->t_name, quadrant);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
leaveIntersection(uint32_t index) {
|
||||||
|
random_yielder(PROBLEMS_MAX_YIELDER);
|
||||||
|
random_spinner(PROBLEMS_MAX_SPINNER);
|
||||||
|
lock_acquire(testlock);
|
||||||
|
move(index);
|
||||||
|
|
||||||
|
switch (car_turns[index]) {
|
||||||
|
case GO_STRAIGHT:
|
||||||
|
failif((car_turn_times[index] != 2), "failed: incorrect turn");
|
||||||
|
break;
|
||||||
|
case TURN_LEFT:
|
||||||
|
failif((car_turn_times[index] != 3), "failed: incorrect turn");
|
||||||
|
break;
|
||||||
|
case TURN_RIGHT:
|
||||||
|
failif((car_turn_times[index] != 1), "failed: incorrect turn");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
failif(true, "failed: incorrect turn");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
car_locations[index] = PASSED_CAR;
|
||||||
|
lock_release(testlock);
|
||||||
|
kprintf_n("%s left the intersection\n", curthread->t_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
int stoplight(int nargs, char **args) {
|
||||||
|
(void) nargs;
|
||||||
|
(void) args;
|
||||||
|
int i, direction, turn, err = 0;
|
||||||
|
char name[32];
|
||||||
|
int required_quadrant = 0;
|
||||||
|
int passed = 0;
|
||||||
|
|
||||||
|
max_car_count = 0;
|
||||||
|
all_quadrant = 0;
|
||||||
|
|
||||||
|
kprintf_n("Starting sp2...\n");
|
||||||
|
kprintf_n("If this tests hangs, your solution is incorrect.\n");
|
||||||
|
|
||||||
|
for (i = 0; i < NUM_QUADRANTS; i++) {
|
||||||
|
quadrant_array[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < NCARS; i++) {
|
||||||
|
car_locations[i] = UNKNOWN_CAR;
|
||||||
|
car_threads[i] = NULL;
|
||||||
|
car_directions[i] = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
startcount = NCARS;
|
||||||
|
testlock = lock_create("testlock");
|
||||||
|
if (testlock == NULL) {
|
||||||
|
panic("sp2: lock_create failed\n");
|
||||||
|
}
|
||||||
|
startcv = cv_create("startcv");
|
||||||
|
if (startcv == NULL) {
|
||||||
|
panic("sp2: cv_create failed\n");
|
||||||
|
}
|
||||||
|
endsem = sem_create("endsem", 0);
|
||||||
|
if (endsem == NULL) {
|
||||||
|
panic("sp2: sem_create failed\n");
|
||||||
|
}
|
||||||
|
spinlock_init(&status_lock);
|
||||||
|
test_status = TEST161_SUCCESS;
|
||||||
|
|
||||||
|
stoplight_init();
|
||||||
|
|
||||||
|
for (i = 0; i < NCARS; i++) {
|
||||||
|
kprintf_t(".");
|
||||||
|
|
||||||
|
direction = random() % 4;
|
||||||
|
turn = random() % 3;
|
||||||
|
|
||||||
|
snprintf(name, sizeof(name), "Car Thread %d", i);
|
||||||
|
|
||||||
|
switch (turn) {
|
||||||
|
case GO_STRAIGHT:
|
||||||
|
err = thread_fork(name, NULL, gostraight_wrapper, (void *)i, direction);
|
||||||
|
required_quadrant += 2;
|
||||||
|
break;
|
||||||
|
case TURN_LEFT:
|
||||||
|
err = thread_fork(name, NULL, turnleft_wrapper, (void *)i, direction);
|
||||||
|
required_quadrant += 3;
|
||||||
|
break;
|
||||||
|
case TURN_RIGHT:
|
||||||
|
err = thread_fork(name, NULL, turnright_wrapper, (void *)i, direction);
|
||||||
|
required_quadrant += 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (err) {
|
||||||
|
panic("sp2: thread_fork failed: (%s)\n", strerror(err));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < NCARS; i++) {
|
||||||
|
kprintf_t(".");
|
||||||
|
P(endsem);
|
||||||
|
}
|
||||||
|
|
||||||
|
stoplight_cleanup();
|
||||||
|
|
||||||
|
for (i = 0; i < NCARS; i++) {
|
||||||
|
passed += car_locations[i] == PASSED_CAR ? 1 : 0;
|
||||||
|
}
|
||||||
|
if ((test_status == TEST161_SUCCESS) &&
|
||||||
|
(!(failif((passed != NCARS), "failed: not enough cars"))) &&
|
||||||
|
(!(failif((all_quadrant != required_quadrant), "failed: didn't do the right turns"))) &&
|
||||||
|
(!(failif((max_car_count <= 1), "failed: no concurrency achieved")))) {};
|
||||||
|
|
||||||
|
lock_destroy(testlock);
|
||||||
|
cv_destroy(startcv);
|
||||||
|
sem_destroy(endsem);
|
||||||
|
|
||||||
|
kprintf_t("\n");
|
||||||
|
if (test_status != TEST161_SUCCESS) {
|
||||||
|
secprintf(SECRET, test_message, "sp2");
|
||||||
|
}
|
||||||
|
success(test_status, SECRET, "sp2");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
@ -29,6 +29,9 @@
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Synchronization test code.
|
* Synchronization test code.
|
||||||
|
*
|
||||||
|
* All the contents of this file are overwritten during automated
|
||||||
|
* testing. Please consider this before changing anything in this file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <types.h>
|
#include <types.h>
|
||||||
@ -37,186 +40,423 @@
|
|||||||
#include <thread.h>
|
#include <thread.h>
|
||||||
#include <synch.h>
|
#include <synch.h>
|
||||||
#include <test.h>
|
#include <test.h>
|
||||||
|
#include <kern/test161.h>
|
||||||
|
#include <spinlock.h>
|
||||||
|
|
||||||
|
#define CREATELOOPS 8
|
||||||
#define NSEMLOOPS 63
|
#define NSEMLOOPS 63
|
||||||
#define NLOCKLOOPS 120
|
#define NLOCKLOOPS 120
|
||||||
#define NCVLOOPS 5
|
#define NCVLOOPS 5
|
||||||
#define NTHREADS 32
|
#define NTHREADS 32
|
||||||
|
#define SYNCHTEST_YIELDER_MAX 16
|
||||||
|
|
||||||
static volatile unsigned long testval1;
|
static volatile unsigned long testval1;
|
||||||
static volatile unsigned long testval2;
|
static volatile unsigned long testval2;
|
||||||
static volatile unsigned long testval3;
|
static volatile unsigned long testval3;
|
||||||
static struct semaphore *testsem;
|
static volatile int32_t testval4;
|
||||||
static struct lock *testlock;
|
|
||||||
static struct cv *testcv;
|
static struct semaphore *testsem = NULL;
|
||||||
static struct semaphore *donesem;
|
static struct semaphore *testsem2 = NULL;
|
||||||
|
static struct lock *testlock = NULL;
|
||||||
|
static struct lock *testlock2 = NULL;
|
||||||
|
static struct cv *testcv = NULL;
|
||||||
|
static struct semaphore *donesem = NULL;
|
||||||
|
|
||||||
|
struct spinlock status_lock;
|
||||||
|
static bool test_status = TEST161_FAIL;
|
||||||
|
|
||||||
|
static unsigned long semtest_current;
|
||||||
|
|
||||||
static
|
static
|
||||||
void
|
bool
|
||||||
inititems(void)
|
failif(bool condition) {
|
||||||
{
|
if (condition) {
|
||||||
if (testsem==NULL) {
|
spinlock_acquire(&status_lock);
|
||||||
testsem = sem_create("testsem", 2);
|
test_status = TEST161_FAIL;
|
||||||
if (testsem == NULL) {
|
spinlock_release(&status_lock);
|
||||||
panic("synchtest: sem_create failed\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (testlock==NULL) {
|
|
||||||
testlock = lock_create("testlock");
|
|
||||||
if (testlock == NULL) {
|
|
||||||
panic("synchtest: lock_create failed\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (testcv==NULL) {
|
|
||||||
testcv = cv_create("testlock");
|
|
||||||
if (testcv == NULL) {
|
|
||||||
panic("synchtest: cv_create failed\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (donesem==NULL) {
|
|
||||||
donesem = sem_create("donesem", 0);
|
|
||||||
if (donesem == NULL) {
|
|
||||||
panic("synchtest: sem_create failed\n");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
return condition;
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
void
|
void
|
||||||
semtestthread(void *junk, unsigned long num)
|
semtestthread(void *junk, unsigned long num)
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
(void)junk;
|
(void)junk;
|
||||||
|
|
||||||
|
int i;
|
||||||
|
|
||||||
|
random_yielder(4);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Only one of these should print at a time.
|
* Only one of these should print at a time.
|
||||||
*/
|
*/
|
||||||
P(testsem);
|
P(testsem);
|
||||||
kprintf("Thread %2lu: ", num);
|
semtest_current = num;
|
||||||
|
|
||||||
|
kprintf_n("Thread %2lu: ", num);
|
||||||
for (i=0; i<NSEMLOOPS; i++) {
|
for (i=0; i<NSEMLOOPS; i++) {
|
||||||
kprintf("%c", (int)num+64);
|
kprintf_t(".");
|
||||||
|
kprintf_n("%2lu", num);
|
||||||
|
random_yielder(4);
|
||||||
|
failif((semtest_current != num));
|
||||||
}
|
}
|
||||||
kprintf("\n");
|
kprintf_n("\n");
|
||||||
|
|
||||||
V(donesem);
|
V(donesem);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
semtest(int nargs, char **args)
|
semtest(int nargs, char **args)
|
||||||
{
|
{
|
||||||
int i, result;
|
|
||||||
|
|
||||||
(void)nargs;
|
(void)nargs;
|
||||||
(void)args;
|
(void)args;
|
||||||
|
|
||||||
inititems();
|
int i, result;
|
||||||
kprintf("Starting semaphore test...\n");
|
|
||||||
kprintf("If this hangs, it's broken: ");
|
kprintf_n("Starting sem1...\n");
|
||||||
|
for (i=0; i<CREATELOOPS; i++) {
|
||||||
|
kprintf_t(".");
|
||||||
|
testsem = sem_create("testsem", 2);
|
||||||
|
if (testsem == NULL) {
|
||||||
|
panic("sem1: sem_create failed\n");
|
||||||
|
}
|
||||||
|
donesem = sem_create("donesem", 0);
|
||||||
|
if (donesem == NULL) {
|
||||||
|
panic("sem1: sem_create failed\n");
|
||||||
|
}
|
||||||
|
if (i != CREATELOOPS - 1) {
|
||||||
|
sem_destroy(testsem);
|
||||||
|
sem_destroy(donesem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
spinlock_init(&status_lock);
|
||||||
|
test_status = TEST161_SUCCESS;
|
||||||
|
|
||||||
|
kprintf_n("If this hangs, it's broken: ");
|
||||||
P(testsem);
|
P(testsem);
|
||||||
P(testsem);
|
P(testsem);
|
||||||
kprintf("ok\n");
|
kprintf_n("OK\n");
|
||||||
|
kprintf_t(".");
|
||||||
|
|
||||||
for (i=0; i<NTHREADS; i++) {
|
for (i=0; i<NTHREADS; i++) {
|
||||||
|
kprintf_t(".");
|
||||||
result = thread_fork("semtest", NULL, semtestthread, NULL, i);
|
result = thread_fork("semtest", NULL, semtestthread, NULL, i);
|
||||||
if (result) {
|
if (result) {
|
||||||
panic("semtest: thread_fork failed: %s\n",
|
panic("sem1: thread_fork failed: %s\n",
|
||||||
strerror(result));
|
strerror(result));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i=0; i<NTHREADS; i++) {
|
for (i=0; i<NTHREADS; i++) {
|
||||||
|
kprintf_t(".");
|
||||||
V(testsem);
|
V(testsem);
|
||||||
P(donesem);
|
P(donesem);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* so we can run it again */
|
sem_destroy(testsem);
|
||||||
V(testsem);
|
sem_destroy(donesem);
|
||||||
V(testsem);
|
testsem = donesem = NULL;
|
||||||
|
|
||||||
|
kprintf_t("\n");
|
||||||
|
success(test_status, SECRET, "sem1");
|
||||||
|
|
||||||
kprintf("Semaphore test done.\n");
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
|
||||||
void
|
|
||||||
fail(unsigned long num, const char *msg)
|
|
||||||
{
|
|
||||||
kprintf("thread %lu: Mismatch on %s\n", num, msg);
|
|
||||||
kprintf("Test failed\n");
|
|
||||||
|
|
||||||
lock_release(testlock);
|
|
||||||
|
|
||||||
V(donesem);
|
|
||||||
thread_exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
static
|
static
|
||||||
void
|
void
|
||||||
locktestthread(void *junk, unsigned long num)
|
locktestthread(void *junk, unsigned long num)
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
(void)junk;
|
(void)junk;
|
||||||
|
|
||||||
|
int i;
|
||||||
|
|
||||||
for (i=0; i<NLOCKLOOPS; i++) {
|
for (i=0; i<NLOCKLOOPS; i++) {
|
||||||
|
kprintf_t(".");
|
||||||
|
KASSERT(!(lock_do_i_hold(testlock)));
|
||||||
lock_acquire(testlock);
|
lock_acquire(testlock);
|
||||||
|
KASSERT(lock_do_i_hold(testlock));
|
||||||
|
random_yielder(4);
|
||||||
|
|
||||||
testval1 = num;
|
testval1 = num;
|
||||||
testval2 = num*num;
|
testval2 = num*num;
|
||||||
testval3 = num%3;
|
testval3 = num%3;
|
||||||
|
|
||||||
if (testval2 != testval1*testval1) {
|
if (testval2 != testval1*testval1) {
|
||||||
fail(num, "testval2/testval1");
|
goto fail;
|
||||||
}
|
}
|
||||||
|
random_yielder(4);
|
||||||
|
KASSERT(lock_do_i_hold(testlock));
|
||||||
|
|
||||||
if (testval2%3 != (testval3*testval3)%3) {
|
if (testval2%3 != (testval3*testval3)%3) {
|
||||||
fail(num, "testval2/testval3");
|
goto fail;
|
||||||
}
|
}
|
||||||
|
random_yielder(4);
|
||||||
|
KASSERT(lock_do_i_hold(testlock));
|
||||||
|
|
||||||
if (testval3 != testval1%3) {
|
if (testval3 != testval1%3) {
|
||||||
fail(num, "testval3/testval1");
|
goto fail;
|
||||||
}
|
}
|
||||||
|
random_yielder(4);
|
||||||
|
KASSERT(lock_do_i_hold(testlock));
|
||||||
|
|
||||||
if (testval1 != num) {
|
if (testval1 != num) {
|
||||||
fail(num, "testval1/num");
|
goto fail;
|
||||||
}
|
}
|
||||||
|
random_yielder(4);
|
||||||
|
KASSERT(lock_do_i_hold(testlock));
|
||||||
|
|
||||||
if (testval2 != num*num) {
|
if (testval2 != num*num) {
|
||||||
fail(num, "testval2/num");
|
goto fail;
|
||||||
}
|
}
|
||||||
|
random_yielder(4);
|
||||||
|
KASSERT(lock_do_i_hold(testlock));
|
||||||
|
|
||||||
if (testval3 != num%3) {
|
if (testval3 != num%3) {
|
||||||
fail(num, "testval3/num");
|
goto fail;
|
||||||
}
|
}
|
||||||
|
random_yielder(4);
|
||||||
|
KASSERT(lock_do_i_hold(testlock));
|
||||||
|
|
||||||
|
if (!(lock_do_i_hold(testlock))) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
random_yielder(4);
|
||||||
|
KASSERT(lock_do_i_hold(testlock));
|
||||||
|
|
||||||
lock_release(testlock);
|
lock_release(testlock);
|
||||||
|
KASSERT(!(lock_do_i_hold(testlock)));
|
||||||
}
|
}
|
||||||
V(donesem);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/* Check for solutions that don't track ownership properly */
|
||||||
|
|
||||||
|
for (i=0; i<NLOCKLOOPS; i++) {
|
||||||
|
kprintf_t(".");
|
||||||
|
if (lock_do_i_hold(testlock)) {
|
||||||
|
goto fail2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
V(donesem);
|
||||||
|
return;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
lock_release(testlock);
|
||||||
|
fail2:
|
||||||
|
failif(true);
|
||||||
|
V(donesem);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
locktest(int nargs, char **args)
|
locktest(int nargs, char **args)
|
||||||
{
|
{
|
||||||
int i, result;
|
|
||||||
|
|
||||||
(void)nargs;
|
(void)nargs;
|
||||||
(void)args;
|
(void)args;
|
||||||
|
|
||||||
inititems();
|
int i, result;
|
||||||
kprintf("Starting lock test...\n");
|
|
||||||
|
kprintf_n("Starting lt1...\n");
|
||||||
|
for (i=0; i<CREATELOOPS; i++) {
|
||||||
|
kprintf_t(".");
|
||||||
|
testlock = lock_create("testlock");
|
||||||
|
if (testlock == NULL) {
|
||||||
|
panic("lt1: lock_create failed\n");
|
||||||
|
}
|
||||||
|
donesem = sem_create("donesem", 0);
|
||||||
|
if (donesem == NULL) {
|
||||||
|
panic("lt1: sem_create failed\n");
|
||||||
|
}
|
||||||
|
if (i != CREATELOOPS - 1) {
|
||||||
|
lock_destroy(testlock);
|
||||||
|
sem_destroy(donesem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
spinlock_init(&status_lock);
|
||||||
|
test_status = TEST161_SUCCESS;
|
||||||
|
|
||||||
for (i=0; i<NTHREADS; i++) {
|
for (i=0; i<NTHREADS; i++) {
|
||||||
result = thread_fork("synchtest", NULL, locktestthread,
|
kprintf_t(".");
|
||||||
NULL, i);
|
result = thread_fork("synchtest", NULL, locktestthread, NULL, i);
|
||||||
if (result) {
|
if (result) {
|
||||||
panic("locktest: thread_fork failed: %s\n",
|
panic("lt1: thread_fork failed: %s\n", strerror(result));
|
||||||
strerror(result));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (i=0; i<NTHREADS; i++) {
|
for (i=0; i<NTHREADS; i++) {
|
||||||
|
kprintf_t(".");
|
||||||
P(donesem);
|
P(donesem);
|
||||||
}
|
}
|
||||||
|
|
||||||
kprintf("Lock test done.\n");
|
lock_destroy(testlock);
|
||||||
|
sem_destroy(donesem);
|
||||||
|
testlock = NULL;
|
||||||
|
donesem = NULL;
|
||||||
|
|
||||||
|
kprintf_t("\n");
|
||||||
|
success(test_status, SECRET, "lt1");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Note that the following tests that panic on success do minimal cleanup
|
||||||
|
* afterward. This is to avoid causing a panic that could be unintentiontally
|
||||||
|
* considered a success signal by test161. As a result, they leak memory,
|
||||||
|
* don't destroy synchronization primitives, etc.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
locktest2(int nargs, char **args) {
|
||||||
|
(void)nargs;
|
||||||
|
(void)args;
|
||||||
|
|
||||||
|
kprintf_n("Starting lt2...\n");
|
||||||
|
kprintf_n("(This test panics on success!)\n");
|
||||||
|
|
||||||
|
testlock = lock_create("testlock");
|
||||||
|
if (testlock == NULL) {
|
||||||
|
panic("lt2: lock_create failed\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
secprintf(SECRET, "Should panic...", "lt2");
|
||||||
|
lock_release(testlock);
|
||||||
|
|
||||||
|
/* Should not get here on success. */
|
||||||
|
|
||||||
|
success(TEST161_FAIL, SECRET, "lt2");
|
||||||
|
|
||||||
|
/* Don't do anything that could panic. */
|
||||||
|
|
||||||
|
testlock = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
locktest3(int nargs, char **args) {
|
||||||
|
(void)nargs;
|
||||||
|
(void)args;
|
||||||
|
|
||||||
|
kprintf_n("Starting lt3...\n");
|
||||||
|
kprintf_n("(This test panics on success!)\n");
|
||||||
|
|
||||||
|
testlock = lock_create("testlock");
|
||||||
|
if (testlock == NULL) {
|
||||||
|
panic("lt3: lock_create failed\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
secprintf(SECRET, "Should panic...", "lt3");
|
||||||
|
lock_acquire(testlock);
|
||||||
|
lock_destroy(testlock);
|
||||||
|
|
||||||
|
/* Should not get here on success. */
|
||||||
|
|
||||||
|
success(TEST161_FAIL, SECRET, "lt3");
|
||||||
|
|
||||||
|
/* Don't do anything that could panic. */
|
||||||
|
|
||||||
|
testlock = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Used by both lt4 and lt5 below. Simply acquires a lock in a separate
|
||||||
|
* thread. Uses a semaphore as a barrier to make sure it gets the lock before
|
||||||
|
* the driver completes.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
locktestacquirer(void * junk, unsigned long num)
|
||||||
|
{
|
||||||
|
(void)junk;
|
||||||
|
(void)num;
|
||||||
|
|
||||||
|
lock_acquire(testlock);
|
||||||
|
V(donesem);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
locktest4(int nargs, char **args) {
|
||||||
|
(void) nargs;
|
||||||
|
(void) args;
|
||||||
|
|
||||||
|
int result;
|
||||||
|
|
||||||
|
kprintf_n("Starting lt4...\n");
|
||||||
|
kprintf_n("(This test panics on success!)\n");
|
||||||
|
|
||||||
|
testlock = lock_create("testlock");
|
||||||
|
if (testlock == NULL) {
|
||||||
|
panic("lt4: lock_create failed\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
donesem = sem_create("donesem", 0);
|
||||||
|
if (donesem == NULL) {
|
||||||
|
lock_destroy(testlock);
|
||||||
|
panic("lt4: sem_create failed\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
result = thread_fork("lt4", NULL, locktestacquirer, NULL, 0);
|
||||||
|
if (result) {
|
||||||
|
panic("lt4: thread_fork failed: %s\n", strerror(result));
|
||||||
|
}
|
||||||
|
|
||||||
|
P(donesem);
|
||||||
|
secprintf(SECRET, "Should panic...", "lt4");
|
||||||
|
lock_release(testlock);
|
||||||
|
|
||||||
|
/* Should not get here on success. */
|
||||||
|
|
||||||
|
success(TEST161_FAIL, SECRET, "lt4");
|
||||||
|
|
||||||
|
/* Don't do anything that could panic. */
|
||||||
|
|
||||||
|
testlock = NULL;
|
||||||
|
donesem = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
locktest5(int nargs, char **args) {
|
||||||
|
(void) nargs;
|
||||||
|
(void) args;
|
||||||
|
|
||||||
|
int result;
|
||||||
|
|
||||||
|
kprintf_n("Starting lt5...\n");
|
||||||
|
kprintf_n("(This test panics on success!)\n");
|
||||||
|
|
||||||
|
testlock = lock_create("testlock");
|
||||||
|
if (testlock == NULL) {
|
||||||
|
panic("lt5: lock_create failed\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
donesem = sem_create("donesem", 0);
|
||||||
|
if (donesem == NULL) {
|
||||||
|
lock_destroy(testlock);
|
||||||
|
panic("lt5: sem_create failed\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
result = thread_fork("lt5", NULL, locktestacquirer, NULL, 0);
|
||||||
|
if (result) {
|
||||||
|
panic("lt5: thread_fork failed: %s\n", strerror(result));
|
||||||
|
}
|
||||||
|
|
||||||
|
P(donesem);
|
||||||
|
secprintf(SECRET, "Should panic...", "lt5");
|
||||||
|
KASSERT(lock_do_i_hold(testlock));
|
||||||
|
|
||||||
|
/* Should not get here on success. */
|
||||||
|
|
||||||
|
success(TEST161_FAIL, SECRET, "lt5");
|
||||||
|
|
||||||
|
/* Don't do anything that could panic. */
|
||||||
|
|
||||||
|
testlock = NULL;
|
||||||
|
donesem = NULL;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -224,35 +464,38 @@ static
|
|||||||
void
|
void
|
||||||
cvtestthread(void *junk, unsigned long num)
|
cvtestthread(void *junk, unsigned long num)
|
||||||
{
|
{
|
||||||
|
(void)junk;
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
volatile int j;
|
volatile int j;
|
||||||
struct timespec ts1, ts2;
|
struct timespec ts1, ts2;
|
||||||
|
|
||||||
(void)junk;
|
|
||||||
|
|
||||||
for (i=0; i<NCVLOOPS; i++) {
|
for (i=0; i<NCVLOOPS; i++) {
|
||||||
|
kprintf_t(".");
|
||||||
lock_acquire(testlock);
|
lock_acquire(testlock);
|
||||||
while (testval1 != num) {
|
while (testval1 != num) {
|
||||||
|
testval2 = 0;
|
||||||
|
random_yielder(4);
|
||||||
gettime(&ts1);
|
gettime(&ts1);
|
||||||
cv_wait(testcv, testlock);
|
cv_wait(testcv, testlock);
|
||||||
gettime(&ts2);
|
gettime(&ts2);
|
||||||
|
random_yielder(4);
|
||||||
|
|
||||||
/* ts2 -= ts1 */
|
/* ts2 -= ts1 */
|
||||||
timespec_sub(&ts2, &ts1, &ts2);
|
timespec_sub(&ts2, &ts1, &ts2);
|
||||||
|
|
||||||
/* Require at least 2000 cpu cycles (we're 25mhz) */
|
/* Require at least 2000 cpu cycles (we're 25mhz) */
|
||||||
if (ts2.tv_sec == 0 && ts2.tv_nsec < 40*2000) {
|
if (ts2.tv_sec == 0 && ts2.tv_nsec < 40*2000) {
|
||||||
kprintf("cv_wait took only %u ns\n",
|
kprintf_n("cv_wait took only %u ns\n", ts2.tv_nsec);
|
||||||
ts2.tv_nsec);
|
kprintf_n("That's too fast... you must be busy-looping\n");
|
||||||
kprintf("That's too fast... you must be "
|
failif(true);
|
||||||
"busy-looping\n");
|
|
||||||
V(donesem);
|
V(donesem);
|
||||||
thread_exit();
|
thread_exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
testval2 = 0xFFFFFFFF;
|
||||||
}
|
}
|
||||||
kprintf("Thread %lu\n", num);
|
testval2 = num;
|
||||||
testval1 = (testval1 + NTHREADS - 1)%NTHREADS;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* loop a little while to make sure we can measure the
|
* loop a little while to make sure we can measure the
|
||||||
@ -260,7 +503,13 @@ cvtestthread(void *junk, unsigned long num)
|
|||||||
*/
|
*/
|
||||||
for (j=0; j<3000; j++);
|
for (j=0; j<3000; j++);
|
||||||
|
|
||||||
|
random_yielder(4);
|
||||||
cv_broadcast(testcv, testlock);
|
cv_broadcast(testcv, testlock);
|
||||||
|
random_yielder(4);
|
||||||
|
failif((testval1 != testval2));
|
||||||
|
|
||||||
|
kprintf_n("Thread %lu\n", testval2);
|
||||||
|
testval1 = (testval1 + NTHREADS - 1) % NTHREADS;
|
||||||
lock_release(testlock);
|
lock_release(testlock);
|
||||||
}
|
}
|
||||||
V(donesem);
|
V(donesem);
|
||||||
@ -269,30 +518,57 @@ cvtestthread(void *junk, unsigned long num)
|
|||||||
int
|
int
|
||||||
cvtest(int nargs, char **args)
|
cvtest(int nargs, char **args)
|
||||||
{
|
{
|
||||||
|
|
||||||
int i, result;
|
|
||||||
|
|
||||||
(void)nargs;
|
(void)nargs;
|
||||||
(void)args;
|
(void)args;
|
||||||
|
|
||||||
inititems();
|
int i, result;
|
||||||
kprintf("Starting CV test...\n");
|
|
||||||
kprintf("Threads should print out in reverse order.\n");
|
kprintf_n("Starting cvt1...\n");
|
||||||
|
for (i=0; i<CREATELOOPS; i++) {
|
||||||
|
kprintf_t(".");
|
||||||
|
testlock = lock_create("testlock");
|
||||||
|
if (testlock == NULL) {
|
||||||
|
panic("cvt1: lock_create failed\n");
|
||||||
|
}
|
||||||
|
testcv = cv_create("testcv");
|
||||||
|
if (testcv == NULL) {
|
||||||
|
panic("cvt1: cv_create failed\n");
|
||||||
|
}
|
||||||
|
donesem = sem_create("donesem", 0);
|
||||||
|
if (donesem == NULL) {
|
||||||
|
panic("cvt1: sem_create failed\n");
|
||||||
|
}
|
||||||
|
if (i != CREATELOOPS - 1) {
|
||||||
|
lock_destroy(testlock);
|
||||||
|
cv_destroy(testcv);
|
||||||
|
sem_destroy(donesem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
spinlock_init(&status_lock);
|
||||||
|
test_status = TEST161_SUCCESS;
|
||||||
|
|
||||||
testval1 = NTHREADS-1;
|
testval1 = NTHREADS-1;
|
||||||
|
|
||||||
for (i=0; i<NTHREADS; i++) {
|
for (i=0; i<NTHREADS; i++) {
|
||||||
result = thread_fork("synchtest", NULL, cvtestthread, NULL, i);
|
kprintf_t(".");
|
||||||
|
result = thread_fork("cvt1", NULL, cvtestthread, NULL, (long unsigned) i);
|
||||||
if (result) {
|
if (result) {
|
||||||
panic("cvtest: thread_fork failed: %s\n",
|
panic("cvt1: thread_fork failed: %s\n", strerror(result));
|
||||||
strerror(result));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (i=0; i<NTHREADS; i++) {
|
for (i=0; i<NTHREADS; i++) {
|
||||||
|
kprintf_t(".");
|
||||||
P(donesem);
|
P(donesem);
|
||||||
}
|
}
|
||||||
|
|
||||||
kprintf("CV test done\n");
|
lock_destroy(testlock);
|
||||||
|
cv_destroy(testcv);
|
||||||
|
sem_destroy(donesem);
|
||||||
|
testlock = NULL;
|
||||||
|
testcv = NULL;
|
||||||
|
donesem = NULL;
|
||||||
|
|
||||||
|
kprintf_t("\n");
|
||||||
|
success(test_status, SECRET, "cvt1");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -318,19 +594,28 @@ static
|
|||||||
void
|
void
|
||||||
sleepthread(void *junk1, unsigned long junk2)
|
sleepthread(void *junk1, unsigned long junk2)
|
||||||
{
|
{
|
||||||
unsigned i, j;
|
|
||||||
|
|
||||||
(void)junk1;
|
(void)junk1;
|
||||||
(void)junk2;
|
(void)junk2;
|
||||||
|
|
||||||
|
unsigned i, j;
|
||||||
|
|
||||||
|
random_yielder(4);
|
||||||
|
|
||||||
for (j=0; j<NLOOPS; j++) {
|
for (j=0; j<NLOOPS; j++) {
|
||||||
|
kprintf_t(".");
|
||||||
for (i=0; i<NCVS; i++) {
|
for (i=0; i<NCVS; i++) {
|
||||||
lock_acquire(testlocks[i]);
|
lock_acquire(testlocks[i]);
|
||||||
|
random_yielder(4);
|
||||||
V(gatesem);
|
V(gatesem);
|
||||||
|
random_yielder(4);
|
||||||
|
spinlock_acquire(&status_lock);
|
||||||
|
testval4++;
|
||||||
|
spinlock_release(&status_lock);
|
||||||
cv_wait(testcvs[i], testlocks[i]);
|
cv_wait(testcvs[i], testlocks[i]);
|
||||||
|
random_yielder(4);
|
||||||
lock_release(testlocks[i]);
|
lock_release(testlocks[i]);
|
||||||
}
|
}
|
||||||
kprintf("sleepthread: %u\n", j);
|
kprintf_n("sleepthread: %u\n", j);
|
||||||
}
|
}
|
||||||
V(exitsem);
|
V(exitsem);
|
||||||
}
|
}
|
||||||
@ -339,19 +624,28 @@ static
|
|||||||
void
|
void
|
||||||
wakethread(void *junk1, unsigned long junk2)
|
wakethread(void *junk1, unsigned long junk2)
|
||||||
{
|
{
|
||||||
unsigned i, j;
|
|
||||||
|
|
||||||
(void)junk1;
|
(void)junk1;
|
||||||
(void)junk2;
|
(void)junk2;
|
||||||
|
|
||||||
|
unsigned i, j;
|
||||||
|
|
||||||
|
random_yielder(4);
|
||||||
|
|
||||||
for (j=0; j<NLOOPS; j++) {
|
for (j=0; j<NLOOPS; j++) {
|
||||||
|
kprintf_t(".");
|
||||||
for (i=0; i<NCVS; i++) {
|
for (i=0; i<NCVS; i++) {
|
||||||
|
random_yielder(4);
|
||||||
P(gatesem);
|
P(gatesem);
|
||||||
|
random_yielder(4);
|
||||||
lock_acquire(testlocks[i]);
|
lock_acquire(testlocks[i]);
|
||||||
|
random_yielder(4);
|
||||||
|
testval4--;
|
||||||
|
failif((testval4 != 0));
|
||||||
cv_signal(testcvs[i], testlocks[i]);
|
cv_signal(testcvs[i], testlocks[i]);
|
||||||
|
random_yielder(4);
|
||||||
lock_release(testlocks[i]);
|
lock_release(testlocks[i]);
|
||||||
}
|
}
|
||||||
kprintf("wakethread: %u\n", j);
|
kprintf_n("wakethread: %u\n", j);
|
||||||
}
|
}
|
||||||
V(exitsem);
|
V(exitsem);
|
||||||
}
|
}
|
||||||
@ -359,30 +653,44 @@ wakethread(void *junk1, unsigned long junk2)
|
|||||||
int
|
int
|
||||||
cvtest2(int nargs, char **args)
|
cvtest2(int nargs, char **args)
|
||||||
{
|
{
|
||||||
unsigned i;
|
|
||||||
int result;
|
|
||||||
|
|
||||||
(void)nargs;
|
(void)nargs;
|
||||||
(void)args;
|
(void)args;
|
||||||
|
|
||||||
|
unsigned i;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
kprintf_n("Starting cvt2...\n");
|
||||||
|
for (i=0; i<CREATELOOPS; i++) {
|
||||||
|
kprintf_t(".");
|
||||||
|
gatesem = sem_create("gatesem", 0);
|
||||||
|
if (gatesem == NULL) {
|
||||||
|
panic("cvt2: sem_create failed\n");
|
||||||
|
}
|
||||||
|
exitsem = sem_create("exitsem", 0);
|
||||||
|
if (exitsem == NULL) {
|
||||||
|
panic("cvt2: sem_create failed\n");
|
||||||
|
}
|
||||||
|
if (i != CREATELOOPS - 1) {
|
||||||
|
sem_destroy(gatesem);
|
||||||
|
sem_destroy(exitsem);
|
||||||
|
}
|
||||||
|
}
|
||||||
for (i=0; i<NCVS; i++) {
|
for (i=0; i<NCVS; i++) {
|
||||||
|
kprintf_t(".");
|
||||||
testlocks[i] = lock_create("cvtest2 lock");
|
testlocks[i] = lock_create("cvtest2 lock");
|
||||||
testcvs[i] = cv_create("cvtest2 cv");
|
testcvs[i] = cv_create("cvtest2 cv");
|
||||||
}
|
}
|
||||||
gatesem = sem_create("gatesem", 0);
|
spinlock_init(&status_lock);
|
||||||
exitsem = sem_create("exitsem", 0);
|
test_status = TEST161_SUCCESS;
|
||||||
|
|
||||||
kprintf("cvtest2...\n");
|
result = thread_fork("cvt2", NULL, sleepthread, NULL, 0);
|
||||||
|
|
||||||
result = thread_fork("cvtest2", NULL, sleepthread, NULL, 0);
|
|
||||||
if (result) {
|
if (result) {
|
||||||
panic("cvtest2: thread_fork failed\n");
|
panic("cvt2: thread_fork failed\n");
|
||||||
}
|
}
|
||||||
result = thread_fork("cvtest2", NULL, wakethread, NULL, 0);
|
result = thread_fork("cvt2", NULL, wakethread, NULL, 0);
|
||||||
if (result) {
|
if (result) {
|
||||||
panic("cvtest2: thread_fork failed\n");
|
panic("cvt2: thread_fork failed\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
P(exitsem);
|
P(exitsem);
|
||||||
P(exitsem);
|
P(exitsem);
|
||||||
|
|
||||||
@ -390,12 +698,194 @@ cvtest2(int nargs, char **args)
|
|||||||
sem_destroy(gatesem);
|
sem_destroy(gatesem);
|
||||||
exitsem = gatesem = NULL;
|
exitsem = gatesem = NULL;
|
||||||
for (i=0; i<NCVS; i++) {
|
for (i=0; i<NCVS; i++) {
|
||||||
|
kprintf_t(".");
|
||||||
lock_destroy(testlocks[i]);
|
lock_destroy(testlocks[i]);
|
||||||
cv_destroy(testcvs[i]);
|
cv_destroy(testcvs[i]);
|
||||||
testlocks[i] = NULL;
|
testlocks[i] = NULL;
|
||||||
testcvs[i] = NULL;
|
testcvs[i] = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
kprintf("cvtest2 done\n");
|
kprintf_t("\n");
|
||||||
|
success(test_status, SECRET, "cvt2");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
cvtest3(int nargs, char **args) {
|
||||||
|
(void)nargs;
|
||||||
|
(void)args;
|
||||||
|
|
||||||
|
kprintf_n("Starting cvt3...\n");
|
||||||
|
kprintf_n("(This test panics on success!)\n");
|
||||||
|
|
||||||
|
testlock = lock_create("testlock");
|
||||||
|
if (testlock == NULL) {
|
||||||
|
panic("cvt3: lock_create failed\n");
|
||||||
|
}
|
||||||
|
testcv = cv_create("testcv");
|
||||||
|
if (testcv == NULL) {
|
||||||
|
panic("cvt3: cv_create failed\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
secprintf(SECRET, "Should panic...", "cvt3");
|
||||||
|
cv_wait(testcv, testlock);
|
||||||
|
|
||||||
|
/* Should not get here on success. */
|
||||||
|
|
||||||
|
success(TEST161_FAIL, SECRET, "cvt3");
|
||||||
|
|
||||||
|
lock_destroy(testlock);
|
||||||
|
cv_destroy(testcv);
|
||||||
|
testcv = NULL;
|
||||||
|
testlock = NULL;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
cvtest4(int nargs, char **args) {
|
||||||
|
(void)nargs;
|
||||||
|
(void)args;
|
||||||
|
|
||||||
|
kprintf_n("Starting cvt4...\n");
|
||||||
|
kprintf_n("(This test panics on success!)\n");
|
||||||
|
|
||||||
|
testlock = lock_create("testlock");
|
||||||
|
if (testlock == NULL) {
|
||||||
|
panic("cvt4: lock_create failed\n");
|
||||||
|
}
|
||||||
|
testcv = cv_create("testcv");
|
||||||
|
if (testcv == NULL) {
|
||||||
|
panic("cvt4: cv_create failed\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
secprintf(SECRET, "Should panic...", "cvt4");
|
||||||
|
cv_broadcast(testcv, testlock);
|
||||||
|
|
||||||
|
/* Should not get here on success. */
|
||||||
|
|
||||||
|
success(TEST161_FAIL, SECRET, "cvt4");
|
||||||
|
|
||||||
|
lock_destroy(testlock);
|
||||||
|
cv_destroy(testcv);
|
||||||
|
testcv = NULL;
|
||||||
|
testlock = NULL;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
sleeperthread(void *junk1, unsigned long junk2) {
|
||||||
|
(void)junk1;
|
||||||
|
(void)junk2;
|
||||||
|
|
||||||
|
random_yielder(4);
|
||||||
|
lock_acquire(testlock);
|
||||||
|
random_yielder(4);
|
||||||
|
failif((testval1 != 0));
|
||||||
|
testval1 = 1;
|
||||||
|
cv_signal(testcv, testlock);
|
||||||
|
|
||||||
|
random_yielder(4);
|
||||||
|
cv_wait(testcv, testlock);
|
||||||
|
failif((testval1 != 3));
|
||||||
|
testval1 = 4;
|
||||||
|
random_yielder(4);
|
||||||
|
lock_release(testlock);
|
||||||
|
random_yielder(4);
|
||||||
|
|
||||||
|
V(exitsem);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
wakerthread(void *junk1, unsigned long junk2) {
|
||||||
|
(void)junk1;
|
||||||
|
(void)junk2;
|
||||||
|
|
||||||
|
random_yielder(4);
|
||||||
|
lock_acquire(testlock2);
|
||||||
|
failif((testval1 != 2));
|
||||||
|
testval1 = 3;
|
||||||
|
|
||||||
|
random_yielder(4);
|
||||||
|
cv_signal(testcv, testlock2);
|
||||||
|
random_yielder(4);
|
||||||
|
lock_release(testlock2);
|
||||||
|
random_yielder(4);
|
||||||
|
|
||||||
|
V(exitsem);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
cvtest5(int nargs, char **args) {
|
||||||
|
(void)nargs;
|
||||||
|
(void)args;
|
||||||
|
|
||||||
|
int result;
|
||||||
|
|
||||||
|
kprintf_n("Starting cvt5...\n");
|
||||||
|
|
||||||
|
testlock = lock_create("testlock");
|
||||||
|
if (testlock == NULL) {
|
||||||
|
panic("cvt5: lock_create failed\n");
|
||||||
|
}
|
||||||
|
testlock2 = lock_create("testlock2");
|
||||||
|
if (testlock == NULL) {
|
||||||
|
panic("cvt5: lock_create failed\n");
|
||||||
|
}
|
||||||
|
testcv = cv_create("testcv");
|
||||||
|
if (testcv == NULL) {
|
||||||
|
panic("cvt5: cv_create failed\n");
|
||||||
|
}
|
||||||
|
exitsem = sem_create("exitsem", 0);
|
||||||
|
if (exitsem == NULL) {
|
||||||
|
panic("cvt5: sem_create failed\n");
|
||||||
|
}
|
||||||
|
spinlock_init(&status_lock);
|
||||||
|
test_status = TEST161_SUCCESS;
|
||||||
|
testval1 = 0;
|
||||||
|
|
||||||
|
lock_acquire(testlock);
|
||||||
|
lock_acquire(testlock2);
|
||||||
|
|
||||||
|
result = thread_fork("cvt5", NULL, sleeperthread, NULL, 0);
|
||||||
|
if (result) {
|
||||||
|
panic("cvt5: thread_fork failed\n");
|
||||||
|
}
|
||||||
|
result = thread_fork("cvt5", NULL, wakerthread, NULL, 0);
|
||||||
|
if (result) {
|
||||||
|
panic("cvt5: thread_fork failed\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
random_yielder(4);
|
||||||
|
cv_wait(testcv, testlock);
|
||||||
|
failif((testval1 != 1));
|
||||||
|
testval1 = 2;
|
||||||
|
random_yielder(4);
|
||||||
|
lock_release(testlock);
|
||||||
|
random_yielder(4);
|
||||||
|
lock_release(testlock2);
|
||||||
|
|
||||||
|
P(exitsem);
|
||||||
|
P(exitsem);
|
||||||
|
failif((testval1 != 4));
|
||||||
|
|
||||||
|
sem_destroy(exitsem);
|
||||||
|
cv_destroy(testcv);
|
||||||
|
lock_destroy(testlock2);
|
||||||
|
lock_destroy(testlock);
|
||||||
|
|
||||||
|
success(test_status, SECRET, "cvt5");
|
||||||
|
|
||||||
|
exitsem = NULL;
|
||||||
|
testcv = NULL;
|
||||||
|
testlock2 = NULL;
|
||||||
|
testlock = NULL;
|
||||||
|
testsem2 = NULL;
|
||||||
|
testsem = NULL;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -66,10 +66,7 @@ fakethread_create(const char *name)
|
|||||||
}
|
}
|
||||||
/* ignore most of the fields, zero everything for tidiness */
|
/* ignore most of the fields, zero everything for tidiness */
|
||||||
bzero(t, sizeof(*t));
|
bzero(t, sizeof(*t));
|
||||||
t->t_name = kstrdup(name);
|
strcpy(t->t_name, name);
|
||||||
if (t->t_name == NULL) {
|
|
||||||
panic("threadlisttest: Out of memory\n");
|
|
||||||
}
|
|
||||||
t->t_stack = FAKE_MAGIC;
|
t->t_stack = FAKE_MAGIC;
|
||||||
threadlistnode_init(&t->t_listnode, t);
|
threadlistnode_init(&t->t_listnode, t);
|
||||||
return t;
|
return t;
|
||||||
@ -84,7 +81,6 @@ fakethread_destroy(struct thread *t)
|
|||||||
{
|
{
|
||||||
KASSERT(t->t_stack == FAKE_MAGIC);
|
KASSERT(t->t_stack == FAKE_MAGIC);
|
||||||
threadlistnode_cleanup(&t->t_listnode);
|
threadlistnode_cleanup(&t->t_listnode);
|
||||||
kfree(t->t_name);
|
|
||||||
kfree(t);
|
kfree(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,7 +44,9 @@
|
|||||||
//
|
//
|
||||||
// Semaphore.
|
// Semaphore.
|
||||||
|
|
||||||
struct semaphore *sem_create(const char *name, unsigned initial_count) {
|
struct semaphore *
|
||||||
|
sem_create(const char *name, unsigned initial_count)
|
||||||
|
{
|
||||||
struct semaphore *sem;
|
struct semaphore *sem;
|
||||||
|
|
||||||
sem = kmalloc(sizeof(*sem));
|
sem = kmalloc(sizeof(*sem));
|
||||||
@ -71,7 +73,9 @@ struct semaphore *sem_create(const char *name, unsigned initial_count) {
|
|||||||
return sem;
|
return sem;
|
||||||
}
|
}
|
||||||
|
|
||||||
void sem_destroy(struct semaphore *sem) {
|
void
|
||||||
|
sem_destroy(struct semaphore *sem)
|
||||||
|
{
|
||||||
KASSERT(sem != NULL);
|
KASSERT(sem != NULL);
|
||||||
|
|
||||||
/* wchan_cleanup will assert if anyone's waiting on it */
|
/* wchan_cleanup will assert if anyone's waiting on it */
|
||||||
@ -81,7 +85,9 @@ void sem_destroy(struct semaphore *sem) {
|
|||||||
kfree(sem);
|
kfree(sem);
|
||||||
}
|
}
|
||||||
|
|
||||||
void P(struct semaphore *sem) {
|
void
|
||||||
|
P(struct semaphore *sem)
|
||||||
|
{
|
||||||
KASSERT(sem != NULL);
|
KASSERT(sem != NULL);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -114,7 +120,9 @@ void P(struct semaphore *sem) {
|
|||||||
spinlock_release(&sem->sem_lock);
|
spinlock_release(&sem->sem_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
void V(struct semaphore *sem) {
|
void
|
||||||
|
V(struct semaphore *sem)
|
||||||
|
{
|
||||||
KASSERT(sem != NULL);
|
KASSERT(sem != NULL);
|
||||||
|
|
||||||
spinlock_acquire(&sem->sem_lock);
|
spinlock_acquire(&sem->sem_lock);
|
||||||
@ -130,7 +138,9 @@ void V(struct semaphore *sem) {
|
|||||||
//
|
//
|
||||||
// Lock.
|
// Lock.
|
||||||
|
|
||||||
struct lock *lock_create(const char *name) {
|
struct lock *
|
||||||
|
lock_create(const char *name)
|
||||||
|
{
|
||||||
struct lock *lock;
|
struct lock *lock;
|
||||||
|
|
||||||
lock = kmalloc(sizeof(*lock));
|
lock = kmalloc(sizeof(*lock));
|
||||||
@ -151,7 +161,9 @@ struct lock *lock_create(const char *name) {
|
|||||||
return lock;
|
return lock;
|
||||||
}
|
}
|
||||||
|
|
||||||
void lock_destroy(struct lock *lock) {
|
void
|
||||||
|
lock_destroy(struct lock *lock)
|
||||||
|
{
|
||||||
KASSERT(lock != NULL);
|
KASSERT(lock != NULL);
|
||||||
|
|
||||||
// add stuff here as needed
|
// add stuff here as needed
|
||||||
@ -160,28 +172,34 @@ void lock_destroy(struct lock *lock) {
|
|||||||
kfree(lock);
|
kfree(lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
void lock_acquire(struct lock *lock) {
|
void
|
||||||
|
lock_acquire(struct lock *lock)
|
||||||
|
{
|
||||||
/* Call this (atomically) before waiting for a lock */
|
/* Call this (atomically) before waiting for a lock */
|
||||||
// HANGMAN_WAIT(&curthread->t_hangman, &lock->lk_hangman);
|
//HANGMAN_WAIT(&curthread->t_hangman, &lock->lk_hangman);
|
||||||
|
|
||||||
// Write this
|
// Write this
|
||||||
|
|
||||||
(void)lock; // suppress warning until code gets written
|
(void)lock; // suppress warning until code gets written
|
||||||
|
|
||||||
/* Call this (atomically) once the lock is acquired */
|
/* Call this (atomically) once the lock is acquired */
|
||||||
// HANGMAN_ACQUIRE(&curthread->t_hangman, &lock->lk_hangman);
|
//HANGMAN_ACQUIRE(&curthread->t_hangman, &lock->lk_hangman);
|
||||||
}
|
}
|
||||||
|
|
||||||
void lock_release(struct lock *lock) {
|
void
|
||||||
|
lock_release(struct lock *lock)
|
||||||
|
{
|
||||||
/* Call this (atomically) when the lock is released */
|
/* Call this (atomically) when the lock is released */
|
||||||
// HANGMAN_RELEASE(&curthread->t_hangman, &lock->lk_hangman);
|
//HANGMAN_RELEASE(&curthread->t_hangman, &lock->lk_hangman);
|
||||||
|
|
||||||
// Write this
|
// Write this
|
||||||
|
|
||||||
(void)lock; // suppress warning until code gets written
|
(void)lock; // suppress warning until code gets written
|
||||||
}
|
}
|
||||||
|
|
||||||
bool lock_do_i_hold(struct lock *lock) {
|
bool
|
||||||
|
lock_do_i_hold(struct lock *lock)
|
||||||
|
{
|
||||||
// Write this
|
// Write this
|
||||||
|
|
||||||
(void)lock; // suppress warning until code gets written
|
(void)lock; // suppress warning until code gets written
|
||||||
@ -193,7 +211,10 @@ bool lock_do_i_hold(struct lock *lock) {
|
|||||||
//
|
//
|
||||||
// CV
|
// CV
|
||||||
|
|
||||||
struct cv *cv_create(const char *name) {
|
|
||||||
|
struct cv *
|
||||||
|
cv_create(const char *name)
|
||||||
|
{
|
||||||
struct cv *cv;
|
struct cv *cv;
|
||||||
|
|
||||||
cv = kmalloc(sizeof(*cv));
|
cv = kmalloc(sizeof(*cv));
|
||||||
@ -202,7 +223,7 @@ struct cv *cv_create(const char *name) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
cv->cv_name = kstrdup(name);
|
cv->cv_name = kstrdup(name);
|
||||||
if (cv->cv_name == NULL) {
|
if (cv->cv_name==NULL) {
|
||||||
kfree(cv);
|
kfree(cv);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -212,7 +233,9 @@ struct cv *cv_create(const char *name) {
|
|||||||
return cv;
|
return cv;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cv_destroy(struct cv *cv) {
|
void
|
||||||
|
cv_destroy(struct cv *cv)
|
||||||
|
{
|
||||||
KASSERT(cv != NULL);
|
KASSERT(cv != NULL);
|
||||||
|
|
||||||
// add stuff here as needed
|
// add stuff here as needed
|
||||||
@ -221,19 +244,25 @@ void cv_destroy(struct cv *cv) {
|
|||||||
kfree(cv);
|
kfree(cv);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cv_wait(struct cv *cv, struct lock *lock) {
|
void
|
||||||
|
cv_wait(struct cv *cv, struct lock *lock)
|
||||||
|
{
|
||||||
// Write this
|
// Write this
|
||||||
(void)cv; // suppress warning until code gets written
|
(void)cv; // suppress warning until code gets written
|
||||||
(void)lock; // suppress warning until code gets written
|
(void)lock; // suppress warning until code gets written
|
||||||
}
|
}
|
||||||
|
|
||||||
void cv_signal(struct cv *cv, struct lock *lock) {
|
void
|
||||||
|
cv_signal(struct cv *cv, struct lock *lock)
|
||||||
|
{
|
||||||
// Write this
|
// Write this
|
||||||
(void)cv; // suppress warning until code gets written
|
(void)cv; // suppress warning until code gets written
|
||||||
(void)lock; // suppress warning until code gets written
|
(void)lock; // suppress warning until code gets written
|
||||||
}
|
}
|
||||||
|
|
||||||
void cv_broadcast(struct cv *cv, struct lock *lock) {
|
void
|
||||||
|
cv_broadcast(struct cv *cv, struct lock *lock)
|
||||||
|
{
|
||||||
// Write this
|
// Write this
|
||||||
(void)cv; // suppress warning until code gets written
|
(void)cv; // suppress warning until code gets written
|
||||||
(void)lock; // suppress warning until code gets written
|
(void)lock; // suppress warning until code gets written
|
||||||
|
@ -51,6 +51,7 @@
|
|||||||
#include <mainbus.h>
|
#include <mainbus.h>
|
||||||
#include <vnode.h>
|
#include <vnode.h>
|
||||||
|
|
||||||
|
|
||||||
/* Magic number used as a guard value on kernel thread stacks. */
|
/* Magic number used as a guard value on kernel thread stacks. */
|
||||||
#define THREAD_STACK_MAGIC 0xbaadf00d
|
#define THREAD_STACK_MAGIC 0xbaadf00d
|
||||||
|
|
||||||
@ -64,10 +65,16 @@ struct wchan {
|
|||||||
DECLARRAY(cpu, static __UNUSED inline);
|
DECLARRAY(cpu, static __UNUSED inline);
|
||||||
DEFARRAY(cpu, static __UNUSED inline);
|
DEFARRAY(cpu, static __UNUSED inline);
|
||||||
static struct cpuarray allcpus;
|
static struct cpuarray allcpus;
|
||||||
|
unsigned num_cpus;
|
||||||
|
|
||||||
/* Used to wait for secondary CPUs to come online. */
|
/* Used to wait for secondary CPUs to come online. */
|
||||||
static struct semaphore *cpu_startup_sem;
|
static struct semaphore *cpu_startup_sem;
|
||||||
|
|
||||||
|
/* Used to synchronize exit cleanup. */
|
||||||
|
unsigned thread_count = 0;
|
||||||
|
static struct spinlock thread_count_lock = SPINLOCK_INITIALIZER;
|
||||||
|
static struct wchan *thread_count_wchan;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -75,7 +82,10 @@ static struct semaphore *cpu_startup_sem;
|
|||||||
* (sometimes) catch kernel stack overflows. Use thread_checkstack()
|
* (sometimes) catch kernel stack overflows. Use thread_checkstack()
|
||||||
* to test this.
|
* to test this.
|
||||||
*/
|
*/
|
||||||
static void thread_checkstack_init(struct thread *thread) {
|
static
|
||||||
|
void
|
||||||
|
thread_checkstack_init(struct thread *thread)
|
||||||
|
{
|
||||||
((uint32_t *)thread->t_stack)[0] = THREAD_STACK_MAGIC;
|
((uint32_t *)thread->t_stack)[0] = THREAD_STACK_MAGIC;
|
||||||
((uint32_t *)thread->t_stack)[1] = THREAD_STACK_MAGIC;
|
((uint32_t *)thread->t_stack)[1] = THREAD_STACK_MAGIC;
|
||||||
((uint32_t *)thread->t_stack)[2] = THREAD_STACK_MAGIC;
|
((uint32_t *)thread->t_stack)[2] = THREAD_STACK_MAGIC;
|
||||||
@ -92,12 +102,15 @@ static void thread_checkstack_init(struct thread *thread) {
|
|||||||
* cannot be freed (which in turn is the case if the stack is the boot
|
* cannot be freed (which in turn is the case if the stack is the boot
|
||||||
* stack, and the thread is the boot thread) this doesn't do anything.
|
* stack, and the thread is the boot thread) this doesn't do anything.
|
||||||
*/
|
*/
|
||||||
static void thread_checkstack(struct thread *thread) {
|
static
|
||||||
|
void
|
||||||
|
thread_checkstack(struct thread *thread)
|
||||||
|
{
|
||||||
if (thread->t_stack != NULL) {
|
if (thread->t_stack != NULL) {
|
||||||
KASSERT(((uint32_t *)thread->t_stack)[0] == THREAD_STACK_MAGIC);
|
KASSERT(((uint32_t*)thread->t_stack)[0] == THREAD_STACK_MAGIC);
|
||||||
KASSERT(((uint32_t *)thread->t_stack)[1] == THREAD_STACK_MAGIC);
|
KASSERT(((uint32_t*)thread->t_stack)[1] == THREAD_STACK_MAGIC);
|
||||||
KASSERT(((uint32_t *)thread->t_stack)[2] == THREAD_STACK_MAGIC);
|
KASSERT(((uint32_t*)thread->t_stack)[2] == THREAD_STACK_MAGIC);
|
||||||
KASSERT(((uint32_t *)thread->t_stack)[3] == THREAD_STACK_MAGIC);
|
KASSERT(((uint32_t*)thread->t_stack)[3] == THREAD_STACK_MAGIC);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -105,21 +118,23 @@ static void thread_checkstack(struct thread *thread) {
|
|||||||
* Create a thread. This is used both to create a first thread
|
* Create a thread. This is used both to create a first thread
|
||||||
* for each CPU and to create subsequent forked threads.
|
* for each CPU and to create subsequent forked threads.
|
||||||
*/
|
*/
|
||||||
static struct thread *thread_create(const char *name) {
|
static
|
||||||
|
struct thread *
|
||||||
|
thread_create(const char *name)
|
||||||
|
{
|
||||||
struct thread *thread;
|
struct thread *thread;
|
||||||
|
|
||||||
DEBUGASSERT(name != NULL);
|
DEBUGASSERT(name != NULL);
|
||||||
|
if (strlen(name) > MAX_NAME_LENGTH) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
thread = kmalloc(sizeof(*thread));
|
thread = kmalloc(sizeof(*thread));
|
||||||
if (thread == NULL) {
|
if (thread == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
thread->t_name = kstrdup(name);
|
strcpy(thread->t_name, name);
|
||||||
if (thread->t_name == NULL) {
|
|
||||||
kfree(thread);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
thread->t_wchan_name = "NEW";
|
thread->t_wchan_name = "NEW";
|
||||||
thread->t_state = S_READY;
|
thread->t_state = S_READY;
|
||||||
|
|
||||||
@ -150,7 +165,9 @@ static struct thread *thread_create(const char *name) {
|
|||||||
* board config or whatnot) is tracked separately because it is not
|
* board config or whatnot) is tracked separately because it is not
|
||||||
* necessarily anything sane or meaningful.
|
* necessarily anything sane or meaningful.
|
||||||
*/
|
*/
|
||||||
struct cpu *cpu_create(unsigned hardware_number) {
|
struct cpu *
|
||||||
|
cpu_create(unsigned hardware_number)
|
||||||
|
{
|
||||||
struct cpu *c;
|
struct cpu *c;
|
||||||
int result;
|
int result;
|
||||||
char namebuf[16];
|
char namebuf[16];
|
||||||
@ -196,7 +213,8 @@ struct cpu *cpu_create(unsigned hardware_number) {
|
|||||||
* make it possible to free the boot stack?)
|
* make it possible to free the boot stack?)
|
||||||
*/
|
*/
|
||||||
/*c->c_curthread->t_stack = ... */
|
/*c->c_curthread->t_stack = ... */
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
c->c_curthread->t_stack = kmalloc(STACK_SIZE);
|
c->c_curthread->t_stack = kmalloc(STACK_SIZE);
|
||||||
if (c->c_curthread->t_stack == NULL) {
|
if (c->c_curthread->t_stack == NULL) {
|
||||||
panic("cpu_create: couldn't allocate stack");
|
panic("cpu_create: couldn't allocate stack");
|
||||||
@ -246,16 +264,17 @@ struct cpu *cpu_create(unsigned hardware_number) {
|
|||||||
* Nor can it be called on a running thread.
|
* Nor can it be called on a running thread.
|
||||||
*
|
*
|
||||||
* (Freeing the stack you're actually using to run is ... inadvisable.)
|
* (Freeing the stack you're actually using to run is ... inadvisable.)
|
||||||
|
*
|
||||||
|
* Thread destroy should finish the process of cleaning up a thread started by
|
||||||
|
* thread_exit.
|
||||||
*/
|
*/
|
||||||
static void thread_destroy(struct thread *thread) {
|
static
|
||||||
|
void
|
||||||
|
thread_destroy(struct thread *thread)
|
||||||
|
{
|
||||||
KASSERT(thread != curthread);
|
KASSERT(thread != curthread);
|
||||||
KASSERT(thread->t_state != S_RUN);
|
KASSERT(thread->t_state != S_RUN);
|
||||||
|
|
||||||
/*
|
|
||||||
* If you add things to struct thread, be sure to clean them up
|
|
||||||
* either here or in thread_exit(). (And not both...)
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Thread subsystem fields */
|
/* Thread subsystem fields */
|
||||||
KASSERT(thread->t_proc == NULL);
|
KASSERT(thread->t_proc == NULL);
|
||||||
if (thread->t_stack != NULL) {
|
if (thread->t_stack != NULL) {
|
||||||
@ -267,7 +286,6 @@ static void thread_destroy(struct thread *thread) {
|
|||||||
/* sheer paranoia */
|
/* sheer paranoia */
|
||||||
thread->t_wchan_name = "DESTROYED";
|
thread->t_wchan_name = "DESTROYED";
|
||||||
|
|
||||||
kfree(thread->t_name);
|
|
||||||
kfree(thread);
|
kfree(thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -277,7 +295,10 @@ static void thread_destroy(struct thread *thread) {
|
|||||||
*
|
*
|
||||||
* The list of zombies is per-cpu.
|
* The list of zombies is per-cpu.
|
||||||
*/
|
*/
|
||||||
static void exorcise(void) {
|
static
|
||||||
|
void
|
||||||
|
exorcise(void)
|
||||||
|
{
|
||||||
struct thread *z;
|
struct thread *z;
|
||||||
|
|
||||||
while ((z = threadlist_remhead(&curcpu->c_zombies)) != NULL) {
|
while ((z = threadlist_remhead(&curcpu->c_zombies)) != NULL) {
|
||||||
@ -292,7 +313,9 @@ static void exorcise(void) {
|
|||||||
* possible) to make sure we don't end up letting any other threads
|
* possible) to make sure we don't end up letting any other threads
|
||||||
* run.
|
* run.
|
||||||
*/
|
*/
|
||||||
void thread_panic(void) {
|
void
|
||||||
|
thread_panic(void)
|
||||||
|
{
|
||||||
/*
|
/*
|
||||||
* Kill off other CPUs.
|
* Kill off other CPUs.
|
||||||
*
|
*
|
||||||
@ -332,7 +355,9 @@ void thread_panic(void) {
|
|||||||
/*
|
/*
|
||||||
* At system shutdown, ask the other CPUs to switch off.
|
* At system shutdown, ask the other CPUs to switch off.
|
||||||
*/
|
*/
|
||||||
void thread_shutdown(void) {
|
void
|
||||||
|
thread_shutdown(void)
|
||||||
|
{
|
||||||
/*
|
/*
|
||||||
* Stop the other CPUs.
|
* Stop the other CPUs.
|
||||||
*
|
*
|
||||||
@ -345,7 +370,9 @@ void thread_shutdown(void) {
|
|||||||
/*
|
/*
|
||||||
* Thread system initialization.
|
* Thread system initialization.
|
||||||
*/
|
*/
|
||||||
void thread_bootstrap(void) {
|
void
|
||||||
|
thread_bootstrap(void)
|
||||||
|
{
|
||||||
cpuarray_init(&allcpus);
|
cpuarray_init(&allcpus);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -377,7 +404,9 @@ void thread_bootstrap(void) {
|
|||||||
* to do anything. The startup thread can just exit; we only need it
|
* to do anything. The startup thread can just exit; we only need it
|
||||||
* to be able to get into thread_switch() properly.
|
* to be able to get into thread_switch() properly.
|
||||||
*/
|
*/
|
||||||
void cpu_hatch(unsigned software_number) {
|
void
|
||||||
|
cpu_hatch(unsigned software_number)
|
||||||
|
{
|
||||||
char buf[64];
|
char buf[64];
|
||||||
|
|
||||||
KASSERT(curcpu != NULL);
|
KASSERT(curcpu != NULL);
|
||||||
@ -387,8 +416,6 @@ void cpu_hatch(unsigned software_number) {
|
|||||||
spl0();
|
spl0();
|
||||||
cpu_identify(buf, sizeof(buf));
|
cpu_identify(buf, sizeof(buf));
|
||||||
|
|
||||||
kprintf("cpu%u: %s\n", software_number, buf);
|
|
||||||
|
|
||||||
V(cpu_startup_sem);
|
V(cpu_startup_sem);
|
||||||
thread_exit();
|
thread_exit();
|
||||||
}
|
}
|
||||||
@ -396,7 +423,9 @@ void cpu_hatch(unsigned software_number) {
|
|||||||
/*
|
/*
|
||||||
* Start up secondary cpus. Called from boot().
|
* Start up secondary cpus. Called from boot().
|
||||||
*/
|
*/
|
||||||
void thread_start_cpus(void) {
|
void
|
||||||
|
thread_start_cpus(void)
|
||||||
|
{
|
||||||
char buf[64];
|
char buf[64];
|
||||||
unsigned i;
|
unsigned i;
|
||||||
|
|
||||||
@ -404,13 +433,26 @@ void thread_start_cpus(void) {
|
|||||||
kprintf("cpu0: %s\n", buf);
|
kprintf("cpu0: %s\n", buf);
|
||||||
|
|
||||||
cpu_startup_sem = sem_create("cpu_hatch", 0);
|
cpu_startup_sem = sem_create("cpu_hatch", 0);
|
||||||
|
thread_count_wchan = wchan_create("thread_count");
|
||||||
mainbus_start_cpus();
|
mainbus_start_cpus();
|
||||||
|
|
||||||
for (i = 0; i < cpuarray_num(&allcpus) - 1; i++) {
|
num_cpus = cpuarray_num(&allcpus);
|
||||||
|
for (i=0; i<num_cpus - 1; i++) {
|
||||||
P(cpu_startup_sem);
|
P(cpu_startup_sem);
|
||||||
}
|
}
|
||||||
sem_destroy(cpu_startup_sem);
|
sem_destroy(cpu_startup_sem);
|
||||||
|
if (i == 0) {
|
||||||
|
kprintf("1 CPU online\n");
|
||||||
|
} else {
|
||||||
|
kprintf("%d CPUs online\n", i + 1);
|
||||||
|
}
|
||||||
cpu_startup_sem = NULL;
|
cpu_startup_sem = NULL;
|
||||||
|
|
||||||
|
// Gross hack to deal with os/161 "idle" threads. Hardcode the thread count
|
||||||
|
// to 1 so the inc/dec properly works in thread_[fork/exit]. The one thread
|
||||||
|
// is the cpu0 boot thread (menu), which is the only thread that hasn't
|
||||||
|
// exited yet.
|
||||||
|
thread_count = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -418,8 +460,10 @@ void thread_start_cpus(void) {
|
|||||||
*
|
*
|
||||||
* targetcpu might be curcpu; it might not be, too.
|
* targetcpu might be curcpu; it might not be, too.
|
||||||
*/
|
*/
|
||||||
static void thread_make_runnable(struct thread *target,
|
static
|
||||||
bool already_have_lock) {
|
void
|
||||||
|
thread_make_runnable(struct thread *target, bool already_have_lock)
|
||||||
|
{
|
||||||
struct cpu *targetcpu;
|
struct cpu *targetcpu;
|
||||||
|
|
||||||
/* Lock the run queue of the target thread's cpu. */
|
/* Lock the run queue of the target thread's cpu. */
|
||||||
@ -428,7 +472,8 @@ static void thread_make_runnable(struct thread *target,
|
|||||||
if (already_have_lock) {
|
if (already_have_lock) {
|
||||||
/* The target thread's cpu should be already locked. */
|
/* The target thread's cpu should be already locked. */
|
||||||
KASSERT(spinlock_do_i_hold(&targetcpu->c_runqueue_lock));
|
KASSERT(spinlock_do_i_hold(&targetcpu->c_runqueue_lock));
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
spinlock_acquire(&targetcpu->c_runqueue_lock);
|
spinlock_acquire(&targetcpu->c_runqueue_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -459,9 +504,12 @@ static void thread_make_runnable(struct thread *target,
|
|||||||
* process is inherited from the caller. It will start on the same CPU
|
* process is inherited from the caller. It will start on the same CPU
|
||||||
* as the caller, unless the scheduler intervenes first.
|
* as the caller, unless the scheduler intervenes first.
|
||||||
*/
|
*/
|
||||||
int thread_fork(const char *name, struct proc *proc,
|
int
|
||||||
|
thread_fork(const char *name,
|
||||||
|
struct proc *proc,
|
||||||
void (*entrypoint)(void *data1, unsigned long data2),
|
void (*entrypoint)(void *data1, unsigned long data2),
|
||||||
void *data1, unsigned long data2) {
|
void *data1, unsigned long data2)
|
||||||
|
{
|
||||||
struct thread *newthread;
|
struct thread *newthread;
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
@ -503,6 +551,11 @@ int thread_fork(const char *name, struct proc *proc,
|
|||||||
*/
|
*/
|
||||||
newthread->t_iplhigh_count++;
|
newthread->t_iplhigh_count++;
|
||||||
|
|
||||||
|
spinlock_acquire(&thread_count_lock);
|
||||||
|
++thread_count;
|
||||||
|
wchan_wakeall(thread_count_wchan, &thread_count_lock);
|
||||||
|
spinlock_release(&thread_count_lock);
|
||||||
|
|
||||||
/* Set up the switchframe so entrypoint() gets called */
|
/* Set up the switchframe so entrypoint() gets called */
|
||||||
switchframe_init(newthread, entrypoint, data1, data2);
|
switchframe_init(newthread, entrypoint, data1, data2);
|
||||||
|
|
||||||
@ -522,8 +575,10 @@ int thread_fork(const char *name, struct proc *proc,
|
|||||||
* WC, protected by the spinlock LK. Otherwise WC and Lk should be
|
* WC, protected by the spinlock LK. Otherwise WC and Lk should be
|
||||||
* NULL.
|
* NULL.
|
||||||
*/
|
*/
|
||||||
static void thread_switch(threadstate_t newstate, struct wchan *wc,
|
static
|
||||||
struct spinlock *lk) {
|
void
|
||||||
|
thread_switch(threadstate_t newstate, struct wchan *wc, struct spinlock *lk)
|
||||||
|
{
|
||||||
struct thread *cur, *next;
|
struct thread *cur, *next;
|
||||||
int spl;
|
int spl;
|
||||||
|
|
||||||
@ -672,6 +727,7 @@ static void thread_switch(threadstate_t newstate, struct wchan *wc,
|
|||||||
* thread_startup.
|
* thread_startup.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
/* Clear the wait channel and set the thread state. */
|
/* Clear the wait channel and set the thread state. */
|
||||||
cur->t_wchan_name = NULL;
|
cur->t_wchan_name = NULL;
|
||||||
cur->t_state = S_RUN;
|
cur->t_state = S_RUN;
|
||||||
@ -697,8 +753,10 @@ static void thread_switch(threadstate_t newstate, struct wchan *wc,
|
|||||||
* thread_switch, the beginning part of this function must match the
|
* thread_switch, the beginning part of this function must match the
|
||||||
* tail of thread_switch.
|
* tail of thread_switch.
|
||||||
*/
|
*/
|
||||||
void thread_startup(void (*entrypoint)(void *data1, unsigned long data2),
|
void
|
||||||
void *data1, unsigned long data2) {
|
thread_startup(void (*entrypoint)(void *data1, unsigned long data2),
|
||||||
|
void *data1, unsigned long data2)
|
||||||
|
{
|
||||||
struct thread *cur;
|
struct thread *cur;
|
||||||
|
|
||||||
cur = curthread;
|
cur = curthread;
|
||||||
@ -733,9 +791,18 @@ void thread_startup(void (*entrypoint)(void *data1, unsigned long data2),
|
|||||||
* should be cleaned up right away. The rest has to wait until
|
* should be cleaned up right away. The rest has to wait until
|
||||||
* thread_destroy is called from exorcise().
|
* thread_destroy is called from exorcise().
|
||||||
*
|
*
|
||||||
|
* Note that any dynamically-allocated structures that can vary in size from
|
||||||
|
* thread to thread should be cleaned up here, not in thread_destroy. This is
|
||||||
|
* because the last thread left on each core runs the idle loop and does not
|
||||||
|
* get cleaned up until new threads are created. Differences in the amount of
|
||||||
|
* memory used by different threads after thread_exit will make it look like
|
||||||
|
* your kernel in leaking memory and cause some of the test161 checks to fail.
|
||||||
|
*
|
||||||
* Does not return.
|
* Does not return.
|
||||||
*/
|
*/
|
||||||
void thread_exit(void) {
|
void
|
||||||
|
thread_exit(void)
|
||||||
|
{
|
||||||
struct thread *cur;
|
struct thread *cur;
|
||||||
|
|
||||||
cur = curthread;
|
cur = curthread;
|
||||||
@ -752,6 +819,14 @@ void thread_exit(void) {
|
|||||||
/* Check the stack guard band. */
|
/* Check the stack guard band. */
|
||||||
thread_checkstack(cur);
|
thread_checkstack(cur);
|
||||||
|
|
||||||
|
// Decrement the thread count and notify anyone interested.
|
||||||
|
if (thread_count) {
|
||||||
|
spinlock_acquire(&thread_count_lock);
|
||||||
|
--thread_count;
|
||||||
|
wchan_wakeall(thread_count_wchan, &thread_count_lock);
|
||||||
|
spinlock_release(&thread_count_lock);
|
||||||
|
}
|
||||||
|
|
||||||
/* Interrupts off on this processor */
|
/* Interrupts off on this processor */
|
||||||
splhigh();
|
splhigh();
|
||||||
thread_switch(S_ZOMBIE, NULL, NULL);
|
thread_switch(S_ZOMBIE, NULL, NULL);
|
||||||
@ -761,7 +836,11 @@ void thread_exit(void) {
|
|||||||
/*
|
/*
|
||||||
* Yield the cpu to another process, but stay runnable.
|
* Yield the cpu to another process, but stay runnable.
|
||||||
*/
|
*/
|
||||||
void thread_yield(void) { thread_switch(S_READY, NULL, NULL); }
|
void
|
||||||
|
thread_yield(void)
|
||||||
|
{
|
||||||
|
thread_switch(S_READY, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
@ -772,7 +851,9 @@ void thread_yield(void) { thread_switch(S_READY, NULL, NULL); }
|
|||||||
* the current CPU's run queue by job priority.
|
* the current CPU's run queue by job priority.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void schedule(void) {
|
void
|
||||||
|
schedule(void)
|
||||||
|
{
|
||||||
/*
|
/*
|
||||||
* You can write this. If we do nothing, threads will run in
|
* You can write this. If we do nothing, threads will run in
|
||||||
* round-robin fashion.
|
* round-robin fashion.
|
||||||
@ -796,7 +877,9 @@ void schedule(void) {
|
|||||||
* System/161 does not (yet) model such cache effects, we'll be very
|
* System/161 does not (yet) model such cache effects, we'll be very
|
||||||
* aggressive.
|
* aggressive.
|
||||||
*/
|
*/
|
||||||
void thread_consider_migration(void) {
|
void
|
||||||
|
thread_consider_migration(void)
|
||||||
|
{
|
||||||
unsigned my_count, total_count, one_share, to_send;
|
unsigned my_count, total_count, one_share, to_send;
|
||||||
unsigned i, numcpus;
|
unsigned i, numcpus;
|
||||||
struct cpu *c;
|
struct cpu *c;
|
||||||
@ -805,7 +888,7 @@ void thread_consider_migration(void) {
|
|||||||
|
|
||||||
my_count = total_count = 0;
|
my_count = total_count = 0;
|
||||||
numcpus = cpuarray_num(&allcpus);
|
numcpus = cpuarray_num(&allcpus);
|
||||||
for (i = 0; i < numcpus; i++) {
|
for (i=0; i<numcpus; i++) {
|
||||||
c = cpuarray_get(&allcpus, i);
|
c = cpuarray_get(&allcpus, i);
|
||||||
spinlock_acquire(&c->c_runqueue_lock);
|
spinlock_acquire(&c->c_runqueue_lock);
|
||||||
total_count += c->c_runqueue.tl_count;
|
total_count += c->c_runqueue.tl_count;
|
||||||
@ -823,13 +906,13 @@ void thread_consider_migration(void) {
|
|||||||
to_send = my_count - one_share;
|
to_send = my_count - one_share;
|
||||||
threadlist_init(&victims);
|
threadlist_init(&victims);
|
||||||
spinlock_acquire(&curcpu->c_runqueue_lock);
|
spinlock_acquire(&curcpu->c_runqueue_lock);
|
||||||
for (i = 0; i < to_send; i++) {
|
for (i=0; i<to_send; i++) {
|
||||||
t = threadlist_remtail(&curcpu->c_runqueue);
|
t = threadlist_remtail(&curcpu->c_runqueue);
|
||||||
threadlist_addhead(&victims, t);
|
threadlist_addhead(&victims, t);
|
||||||
}
|
}
|
||||||
spinlock_release(&curcpu->c_runqueue_lock);
|
spinlock_release(&curcpu->c_runqueue_lock);
|
||||||
|
|
||||||
for (i = 0; i < numcpus && to_send > 0; i++) {
|
for (i=0; i < numcpus && to_send > 0; i++) {
|
||||||
c = cpuarray_get(&allcpus, i);
|
c = cpuarray_get(&allcpus, i);
|
||||||
if (c == curcpu->c_self) {
|
if (c == curcpu->c_self) {
|
||||||
continue;
|
continue;
|
||||||
@ -867,8 +950,9 @@ void thread_consider_migration(void) {
|
|||||||
|
|
||||||
t->t_cpu = c;
|
t->t_cpu = c;
|
||||||
threadlist_addtail(&c->c_runqueue, t);
|
threadlist_addtail(&c->c_runqueue, t);
|
||||||
DEBUG(DB_THREADS, "Migrated thread %s: cpu %u -> %u", t->t_name,
|
DEBUG(DB_THREADS,
|
||||||
curcpu->c_number, c->c_number);
|
"Migrated thread %s: cpu %u -> %u",
|
||||||
|
t->t_name, curcpu->c_number, c->c_number);
|
||||||
to_send--;
|
to_send--;
|
||||||
if (c->c_isidle) {
|
if (c->c_isidle) {
|
||||||
/*
|
/*
|
||||||
@ -912,7 +996,9 @@ void thread_consider_migration(void) {
|
|||||||
* arrangements should be made to free it after the wait channel is
|
* arrangements should be made to free it after the wait channel is
|
||||||
* destroyed.
|
* destroyed.
|
||||||
*/
|
*/
|
||||||
struct wchan *wchan_create(const char *name) {
|
struct wchan *
|
||||||
|
wchan_create(const char *name)
|
||||||
|
{
|
||||||
struct wchan *wc;
|
struct wchan *wc;
|
||||||
|
|
||||||
wc = kmalloc(sizeof(*wc));
|
wc = kmalloc(sizeof(*wc));
|
||||||
@ -929,7 +1015,9 @@ struct wchan *wchan_create(const char *name) {
|
|||||||
* Destroy a wait channel. Must be empty and unlocked.
|
* Destroy a wait channel. Must be empty and unlocked.
|
||||||
* (The corresponding cleanup functions require this.)
|
* (The corresponding cleanup functions require this.)
|
||||||
*/
|
*/
|
||||||
void wchan_destroy(struct wchan *wc) {
|
void
|
||||||
|
wchan_destroy(struct wchan *wc)
|
||||||
|
{
|
||||||
threadlist_cleanup(&wc->wc_threads);
|
threadlist_cleanup(&wc->wc_threads);
|
||||||
kfree(wc);
|
kfree(wc);
|
||||||
}
|
}
|
||||||
@ -941,7 +1029,9 @@ void wchan_destroy(struct wchan *wc) {
|
|||||||
* be locked. The call to thread_switch unlocks it; we relock it
|
* be locked. The call to thread_switch unlocks it; we relock it
|
||||||
* before returning.
|
* before returning.
|
||||||
*/
|
*/
|
||||||
void wchan_sleep(struct wchan *wc, struct spinlock *lk) {
|
void
|
||||||
|
wchan_sleep(struct wchan *wc, struct spinlock *lk)
|
||||||
|
{
|
||||||
/* may not sleep in an interrupt handler */
|
/* may not sleep in an interrupt handler */
|
||||||
KASSERT(!curthread->t_in_interrupt);
|
KASSERT(!curthread->t_in_interrupt);
|
||||||
|
|
||||||
@ -958,7 +1048,9 @@ void wchan_sleep(struct wchan *wc, struct spinlock *lk) {
|
|||||||
/*
|
/*
|
||||||
* Wake up one thread sleeping on a wait channel.
|
* Wake up one thread sleeping on a wait channel.
|
||||||
*/
|
*/
|
||||||
void wchan_wakeone(struct wchan *wc, struct spinlock *lk) {
|
void
|
||||||
|
wchan_wakeone(struct wchan *wc, struct spinlock *lk)
|
||||||
|
{
|
||||||
struct thread *target;
|
struct thread *target;
|
||||||
|
|
||||||
KASSERT(spinlock_do_i_hold(lk));
|
KASSERT(spinlock_do_i_hold(lk));
|
||||||
@ -985,7 +1077,9 @@ void wchan_wakeone(struct wchan *wc, struct spinlock *lk) {
|
|||||||
/*
|
/*
|
||||||
* Wake up all threads sleeping on a wait channel.
|
* Wake up all threads sleeping on a wait channel.
|
||||||
*/
|
*/
|
||||||
void wchan_wakeall(struct wchan *wc, struct spinlock *lk) {
|
void
|
||||||
|
wchan_wakeall(struct wchan *wc, struct spinlock *lk)
|
||||||
|
{
|
||||||
struct thread *target;
|
struct thread *target;
|
||||||
struct threadlist list;
|
struct threadlist list;
|
||||||
|
|
||||||
@ -1017,7 +1111,9 @@ void wchan_wakeall(struct wchan *wc, struct spinlock *lk) {
|
|||||||
* Return nonzero if there are no threads sleeping on the channel.
|
* Return nonzero if there are no threads sleeping on the channel.
|
||||||
* This is meant to be used only for diagnostic purposes.
|
* This is meant to be used only for diagnostic purposes.
|
||||||
*/
|
*/
|
||||||
bool wchan_isempty(struct wchan *wc, struct spinlock *lk) {
|
bool
|
||||||
|
wchan_isempty(struct wchan *wc, struct spinlock *lk)
|
||||||
|
{
|
||||||
bool ret;
|
bool ret;
|
||||||
|
|
||||||
KASSERT(spinlock_do_i_hold(lk));
|
KASSERT(spinlock_do_i_hold(lk));
|
||||||
@ -1035,7 +1131,9 @@ bool wchan_isempty(struct wchan *wc, struct spinlock *lk) {
|
|||||||
/*
|
/*
|
||||||
* Send an IPI (inter-processor interrupt) to the specified CPU.
|
* Send an IPI (inter-processor interrupt) to the specified CPU.
|
||||||
*/
|
*/
|
||||||
void ipi_send(struct cpu *target, int code) {
|
void
|
||||||
|
ipi_send(struct cpu *target, int code)
|
||||||
|
{
|
||||||
KASSERT(code >= 0 && code < 32);
|
KASSERT(code >= 0 && code < 32);
|
||||||
|
|
||||||
spinlock_acquire(&target->c_ipi_lock);
|
spinlock_acquire(&target->c_ipi_lock);
|
||||||
@ -1047,11 +1145,13 @@ void ipi_send(struct cpu *target, int code) {
|
|||||||
/*
|
/*
|
||||||
* Send an IPI to all CPUs.
|
* Send an IPI to all CPUs.
|
||||||
*/
|
*/
|
||||||
void ipi_broadcast(int code) {
|
void
|
||||||
|
ipi_broadcast(int code)
|
||||||
|
{
|
||||||
unsigned i;
|
unsigned i;
|
||||||
struct cpu *c;
|
struct cpu *c;
|
||||||
|
|
||||||
for (i = 0; i < cpuarray_num(&allcpus); i++) {
|
for (i=0; i < cpuarray_num(&allcpus); i++) {
|
||||||
c = cpuarray_get(&allcpus, i);
|
c = cpuarray_get(&allcpus, i);
|
||||||
if (c != curcpu->c_self) {
|
if (c != curcpu->c_self) {
|
||||||
ipi_send(c, code);
|
ipi_send(c, code);
|
||||||
@ -1062,7 +1162,9 @@ void ipi_broadcast(int code) {
|
|||||||
/*
|
/*
|
||||||
* Send a TLB shootdown IPI to the specified CPU.
|
* Send a TLB shootdown IPI to the specified CPU.
|
||||||
*/
|
*/
|
||||||
void ipi_tlbshootdown(struct cpu *target, const struct tlbshootdown *mapping) {
|
void
|
||||||
|
ipi_tlbshootdown(struct cpu *target, const struct tlbshootdown *mapping)
|
||||||
|
{
|
||||||
unsigned n;
|
unsigned n;
|
||||||
|
|
||||||
spinlock_acquire(&target->c_ipi_lock);
|
spinlock_acquire(&target->c_ipi_lock);
|
||||||
@ -1079,9 +1181,10 @@ void ipi_tlbshootdown(struct cpu *target, const struct tlbshootdown *mapping) {
|
|||||||
* reduce the number of unnecessary shootdowns.
|
* reduce the number of unnecessary shootdowns.
|
||||||
*/
|
*/
|
||||||
panic("ipi_tlbshootdown: Too many shootdowns queued\n");
|
panic("ipi_tlbshootdown: Too many shootdowns queued\n");
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
target->c_shootdown[n] = *mapping;
|
target->c_shootdown[n] = *mapping;
|
||||||
target->c_numshootdown = n + 1;
|
target->c_numshootdown = n+1;
|
||||||
}
|
}
|
||||||
|
|
||||||
target->c_ipi_pending |= (uint32_t)1 << IPI_TLBSHOOTDOWN;
|
target->c_ipi_pending |= (uint32_t)1 << IPI_TLBSHOOTDOWN;
|
||||||
@ -1093,7 +1196,9 @@ void ipi_tlbshootdown(struct cpu *target, const struct tlbshootdown *mapping) {
|
|||||||
/*
|
/*
|
||||||
* Handle an incoming interprocessor interrupt.
|
* Handle an incoming interprocessor interrupt.
|
||||||
*/
|
*/
|
||||||
void interprocessor_interrupt(void) {
|
void
|
||||||
|
interprocessor_interrupt(void)
|
||||||
|
{
|
||||||
uint32_t bits;
|
uint32_t bits;
|
||||||
unsigned i;
|
unsigned i;
|
||||||
|
|
||||||
@ -1110,10 +1215,10 @@ void interprocessor_interrupt(void) {
|
|||||||
spinlock_release(&curcpu->c_ipi_lock);
|
spinlock_release(&curcpu->c_ipi_lock);
|
||||||
spinlock_acquire(&curcpu->c_runqueue_lock);
|
spinlock_acquire(&curcpu->c_runqueue_lock);
|
||||||
if (!curcpu->c_isidle) {
|
if (!curcpu->c_isidle) {
|
||||||
kprintf("cpu%d: offline: warning: not idle\n", curcpu->c_number);
|
kprintf("cpu%d: offline: warning: not idle\n",
|
||||||
|
curcpu->c_number);
|
||||||
}
|
}
|
||||||
spinlock_release(&curcpu->c_runqueue_lock);
|
spinlock_release(&curcpu->c_runqueue_lock);
|
||||||
kprintf("cpu%d: offline.\n", curcpu->c_number);
|
|
||||||
cpu_halt();
|
cpu_halt();
|
||||||
}
|
}
|
||||||
if (bits & (1U << IPI_UNIDLE)) {
|
if (bits & (1U << IPI_UNIDLE)) {
|
||||||
@ -1128,7 +1233,7 @@ void interprocessor_interrupt(void) {
|
|||||||
* need to release the ipi lock while calling
|
* need to release the ipi lock while calling
|
||||||
* vm_tlbshootdown.
|
* vm_tlbshootdown.
|
||||||
*/
|
*/
|
||||||
for (i = 0; i < curcpu->c_numshootdown; i++) {
|
for (i=0; i<curcpu->c_numshootdown; i++) {
|
||||||
vm_tlbshootdown(&curcpu->c_shootdown[i]);
|
vm_tlbshootdown(&curcpu->c_shootdown[i]);
|
||||||
}
|
}
|
||||||
curcpu->c_numshootdown = 0;
|
curcpu->c_numshootdown = 0;
|
||||||
@ -1137,3 +1242,15 @@ void interprocessor_interrupt(void) {
|
|||||||
curcpu->c_ipi_pending = 0;
|
curcpu->c_ipi_pending = 0;
|
||||||
spinlock_release(&curcpu->c_ipi_lock);
|
spinlock_release(&curcpu->c_ipi_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Wait for the thread count to equal tc.
|
||||||
|
*/
|
||||||
|
void thread_wait_for_count(unsigned tc)
|
||||||
|
{
|
||||||
|
spinlock_acquire(&thread_count_lock);
|
||||||
|
while (thread_count != tc) {
|
||||||
|
wchan_sleep(thread_count_wchan, &thread_count_lock);
|
||||||
|
}
|
||||||
|
spinlock_release(&thread_count_lock);
|
||||||
|
}
|
||||||
|
@ -31,19 +31,25 @@
|
|||||||
#include <lib.h>
|
#include <lib.h>
|
||||||
#include <spinlock.h>
|
#include <spinlock.h>
|
||||||
#include <vm.h>
|
#include <vm.h>
|
||||||
|
#include <kern/test161.h>
|
||||||
|
#include <test.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Kernel malloc.
|
* Kernel malloc.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Fill a block with 0xdeadbeef.
|
* Fill a block with 0xdeadbeef.
|
||||||
*/
|
*/
|
||||||
static void fill_deadbeef(void *vptr, size_t len) {
|
static
|
||||||
|
void
|
||||||
|
fill_deadbeef(void *vptr, size_t len)
|
||||||
|
{
|
||||||
uint32_t *ptr = vptr;
|
uint32_t *ptr = vptr;
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
for (i = 0; i < len / sizeof(uint32_t); i++) {
|
for (i=0; i<len/sizeof(uint32_t); i++) {
|
||||||
ptr[i] = 0xdeadbeef;
|
ptr[i] = 0xdeadbeef;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -122,7 +128,7 @@ static void fill_deadbeef(void *vptr, size_t len) {
|
|||||||
#if PAGE_SIZE == 4096
|
#if PAGE_SIZE == 4096
|
||||||
|
|
||||||
#define NSIZES 8
|
#define NSIZES 8
|
||||||
static const size_t sizes[NSIZES] = {16, 32, 64, 128, 256, 512, 1024, 2048};
|
static const size_t sizes[NSIZES] = { 16, 32, 64, 128, 256, 512, 1024, 2048 };
|
||||||
|
|
||||||
#define SMALLEST_SUBPAGE_SIZE 16
|
#define SMALLEST_SUBPAGE_SIZE 16
|
||||||
#define LARGEST_SUBPAGE_SIZE 2048
|
#define LARGEST_SUBPAGE_SIZE 2048
|
||||||
@ -151,7 +157,7 @@ struct pageref {
|
|||||||
|
|
||||||
#define PR_PAGEADDR(pr) ((pr)->pageaddr_and_blocktype & PAGE_FRAME)
|
#define PR_PAGEADDR(pr) ((pr)->pageaddr_and_blocktype & PAGE_FRAME)
|
||||||
#define PR_BLOCKTYPE(pr) ((pr)->pageaddr_and_blocktype & ~PAGE_FRAME)
|
#define PR_BLOCKTYPE(pr) ((pr)->pageaddr_and_blocktype & ~PAGE_FRAME)
|
||||||
#define MKPAB(pa, blk) (((pa) & PAGE_FRAME) | ((blk) & ~PAGE_FRAME))
|
#define MKPAB(pa, blk) (((pa)&PAGE_FRAME) | ((blk) & ~PAGE_FRAME))
|
||||||
|
|
||||||
////////////////////////////////////////
|
////////////////////////////////////////
|
||||||
|
|
||||||
@ -211,7 +217,10 @@ static struct kheap_root kheaproots[NUM_PAGEREFPAGES];
|
|||||||
/*
|
/*
|
||||||
* Allocate a page to hold pagerefs.
|
* Allocate a page to hold pagerefs.
|
||||||
*/
|
*/
|
||||||
static void allocpagerefpage(struct kheap_root *root) {
|
static
|
||||||
|
void
|
||||||
|
allocpagerefpage(struct kheap_root *root)
|
||||||
|
{
|
||||||
vaddr_t va;
|
vaddr_t va;
|
||||||
|
|
||||||
KASSERT(root->page == NULL);
|
KASSERT(root->page == NULL);
|
||||||
@ -246,13 +255,16 @@ static void allocpagerefpage(struct kheap_root *root) {
|
|||||||
/*
|
/*
|
||||||
* Allocate a pageref structure.
|
* Allocate a pageref structure.
|
||||||
*/
|
*/
|
||||||
static struct pageref *allocpageref(void) {
|
static
|
||||||
unsigned i, j;
|
struct pageref *
|
||||||
|
allocpageref(void)
|
||||||
|
{
|
||||||
|
unsigned i,j;
|
||||||
uint32_t k;
|
uint32_t k;
|
||||||
unsigned whichroot;
|
unsigned whichroot;
|
||||||
struct kheap_root *root;
|
struct kheap_root *root;
|
||||||
|
|
||||||
for (whichroot = 0; whichroot < NUM_PAGEREFPAGES; whichroot++) {
|
for (whichroot=0; whichroot < NUM_PAGEREFPAGES; whichroot++) {
|
||||||
root = &kheaproots[whichroot];
|
root = &kheaproots[whichroot];
|
||||||
if (root->numinuse >= NPAGEREFS_PER_PAGE) {
|
if (root->numinuse >= NPAGEREFS_PER_PAGE) {
|
||||||
continue;
|
continue;
|
||||||
@ -261,13 +273,13 @@ static struct pageref *allocpageref(void) {
|
|||||||
/*
|
/*
|
||||||
* This should probably not be a linear search.
|
* This should probably not be a linear search.
|
||||||
*/
|
*/
|
||||||
for (i = 0; i < INUSE_WORDS; i++) {
|
for (i=0; i<INUSE_WORDS; i++) {
|
||||||
if (root->pagerefs_inuse[i] == 0xffffffff) {
|
if (root->pagerefs_inuse[i]==0xffffffff) {
|
||||||
/* full */
|
/* full */
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
for (k = 1, j = 0; k != 0; k <<= 1, j++) {
|
for (k=1,j=0; k!=0; k<<=1,j++) {
|
||||||
if ((root->pagerefs_inuse[i] & k) == 0) {
|
if ((root->pagerefs_inuse[i] & k)==0) {
|
||||||
root->pagerefs_inuse[i] |= k;
|
root->pagerefs_inuse[i] |= k;
|
||||||
root->numinuse++;
|
root->numinuse++;
|
||||||
if (root->page == NULL) {
|
if (root->page == NULL) {
|
||||||
@ -276,7 +288,7 @@ static struct pageref *allocpageref(void) {
|
|||||||
if (root->page == NULL) {
|
if (root->page == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
return &root->page->refs[i * 32 + j];
|
return &root->page->refs[i*32 + j];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
KASSERT(0);
|
KASSERT(0);
|
||||||
@ -290,14 +302,17 @@ static struct pageref *allocpageref(void) {
|
|||||||
/*
|
/*
|
||||||
* Release a pageref structure.
|
* Release a pageref structure.
|
||||||
*/
|
*/
|
||||||
static void freepageref(struct pageref *p) {
|
static
|
||||||
|
void
|
||||||
|
freepageref(struct pageref *p)
|
||||||
|
{
|
||||||
size_t i, j;
|
size_t i, j;
|
||||||
uint32_t k;
|
uint32_t k;
|
||||||
unsigned whichroot;
|
unsigned whichroot;
|
||||||
struct kheap_root *root;
|
struct kheap_root *root;
|
||||||
struct pagerefpage *page;
|
struct pagerefpage *page;
|
||||||
|
|
||||||
for (whichroot = 0; whichroot < NUM_PAGEREFPAGES; whichroot++) {
|
for (whichroot=0; whichroot < NUM_PAGEREFPAGES; whichroot++) {
|
||||||
root = &kheaproots[whichroot];
|
root = &kheaproots[whichroot];
|
||||||
|
|
||||||
page = root->page;
|
page = root->page;
|
||||||
@ -306,12 +321,12 @@ static void freepageref(struct pageref *p) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
j = p - page->refs;
|
j = p-page->refs;
|
||||||
/* note: j is unsigned, don't test < 0 */
|
/* note: j is unsigned, don't test < 0 */
|
||||||
if (j < NPAGEREFS_PER_PAGE) {
|
if (j < NPAGEREFS_PER_PAGE) {
|
||||||
/* on this page */
|
/* on this page */
|
||||||
i = j / 32;
|
i = j/32;
|
||||||
k = ((uint32_t)1) << (j % 32);
|
k = ((uint32_t)1) << (j%32);
|
||||||
KASSERT((root->pagerefs_inuse[i] & k) != 0);
|
KASSERT((root->pagerefs_inuse[i] & k) != 0);
|
||||||
root->pagerefs_inuse[i] &= ~k;
|
root->pagerefs_inuse[i] &= ~k;
|
||||||
KASSERT(root->numinuse > 0);
|
KASSERT(root->numinuse > 0);
|
||||||
@ -352,8 +367,10 @@ static struct pageref *allbase;
|
|||||||
/*
|
/*
|
||||||
* Set up the guard values in a block we're about to return.
|
* Set up the guard values in a block we're about to return.
|
||||||
*/
|
*/
|
||||||
static void *establishguardband(void *block, size_t clientsize,
|
static
|
||||||
size_t blocksize) {
|
void *
|
||||||
|
establishguardband(void *block, size_t clientsize, size_t blocksize)
|
||||||
|
{
|
||||||
vaddr_t lowguard, lowsize, data, enddata, highguard, highsize, i;
|
vaddr_t lowguard, lowsize, data, enddata, highguard, highsize, i;
|
||||||
|
|
||||||
KASSERT(clientsize + GUARD_OVERHEAD <= blocksize);
|
KASSERT(clientsize + GUARD_OVERHEAD <= blocksize);
|
||||||
@ -368,10 +385,10 @@ static void *establishguardband(void *block, size_t clientsize,
|
|||||||
|
|
||||||
*(uint16_t *)lowguard = GUARD_HALFWORD;
|
*(uint16_t *)lowguard = GUARD_HALFWORD;
|
||||||
*(uint16_t *)lowsize = clientsize;
|
*(uint16_t *)lowsize = clientsize;
|
||||||
for (i = data; i < enddata; i++) {
|
for (i=data; i<enddata; i++) {
|
||||||
*(uint8_t *)i = GUARD_RETBYTE;
|
*(uint8_t *)i = GUARD_RETBYTE;
|
||||||
}
|
}
|
||||||
for (i = enddata; i < highguard; i++) {
|
for (i=enddata; i<highguard; i++) {
|
||||||
*(uint8_t *)i = GUARD_FILLBYTE;
|
*(uint8_t *)i = GUARD_FILLBYTE;
|
||||||
}
|
}
|
||||||
*(uint16_t *)highguard = GUARD_HALFWORD;
|
*(uint16_t *)highguard = GUARD_HALFWORD;
|
||||||
@ -383,8 +400,10 @@ static void *establishguardband(void *block, size_t clientsize,
|
|||||||
/*
|
/*
|
||||||
* Validate the guard values in an existing block.
|
* Validate the guard values in an existing block.
|
||||||
*/
|
*/
|
||||||
static void checkguardband(vaddr_t blockaddr, size_t smallerblocksize,
|
static
|
||||||
size_t blocksize) {
|
void
|
||||||
|
checkguardband(vaddr_t blockaddr, size_t smallerblocksize, size_t blocksize)
|
||||||
|
{
|
||||||
/*
|
/*
|
||||||
* The first two bytes of the block are the lower guard band.
|
* The first two bytes of the block are the lower guard band.
|
||||||
* The next two bytes are the real size (the size of the
|
* The next two bytes are the real size (the size of the
|
||||||
@ -413,7 +432,7 @@ static void checkguardband(vaddr_t blockaddr, size_t smallerblocksize,
|
|||||||
KASSERT(clientsize + GUARD_OVERHEAD > smallerblocksize);
|
KASSERT(clientsize + GUARD_OVERHEAD > smallerblocksize);
|
||||||
KASSERT(clientsize + GUARD_OVERHEAD <= blocksize);
|
KASSERT(clientsize + GUARD_OVERHEAD <= blocksize);
|
||||||
enddata = data + clientsize;
|
enddata = data + clientsize;
|
||||||
for (i = enddata; i < highguard; i++) {
|
for (i=enddata; i<highguard; i++) {
|
||||||
KASSERT(*(uint8_t *)i == GUARD_FILLBYTE);
|
KASSERT(*(uint8_t *)i == GUARD_FILLBYTE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -440,11 +459,14 @@ static void checkguardband(vaddr_t blockaddr, size_t smallerblocksize,
|
|||||||
* The first word of the block is a freelist pointer and should not be
|
* The first word of the block is a freelist pointer and should not be
|
||||||
* deadbeef; the rest of the block should be only deadbeef.
|
* deadbeef; the rest of the block should be only deadbeef.
|
||||||
*/
|
*/
|
||||||
static void checkdeadbeef(void *block, size_t blocksize) {
|
static
|
||||||
|
void
|
||||||
|
checkdeadbeef(void *block, size_t blocksize)
|
||||||
|
{
|
||||||
uint32_t *ptr = block;
|
uint32_t *ptr = block;
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
for (i = 1; i < blocksize / sizeof(uint32_t); i++) {
|
for (i=1; i < blocksize/sizeof(uint32_t); i++) {
|
||||||
KASSERT(ptr[i] == 0xdeadbeef);
|
KASSERT(ptr[i] == 0xdeadbeef);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -470,11 +492,14 @@ static void checkdeadbeef(void *block, size_t blocksize) {
|
|||||||
* assertion as a bit in isfree is set twice; if not, a circular
|
* assertion as a bit in isfree is set twice; if not, a circular
|
||||||
* freelist will cause an infinite loop.
|
* freelist will cause an infinite loop.
|
||||||
*/
|
*/
|
||||||
static void checksubpage(struct pageref *pr) {
|
static
|
||||||
|
void
|
||||||
|
checksubpage(struct pageref *pr)
|
||||||
|
{
|
||||||
vaddr_t prpage, fla;
|
vaddr_t prpage, fla;
|
||||||
struct freelist *fl;
|
struct freelist *fl;
|
||||||
int blktype;
|
int blktype;
|
||||||
int nfree = 0;
|
int nfree=0;
|
||||||
size_t blocksize;
|
size_t blocksize;
|
||||||
#ifdef CHECKGUARDS
|
#ifdef CHECKGUARDS
|
||||||
const unsigned maxblocks = PAGE_SIZE / SMALLEST_SUBPAGE_SIZE;
|
const unsigned maxblocks = PAGE_SIZE / SMALLEST_SUBPAGE_SIZE;
|
||||||
@ -487,7 +512,7 @@ static void checksubpage(struct pageref *pr) {
|
|||||||
KASSERT(spinlock_do_i_hold(&kmalloc_spinlock));
|
KASSERT(spinlock_do_i_hold(&kmalloc_spinlock));
|
||||||
|
|
||||||
if (pr->freelist_offset == INVALID_OFFSET) {
|
if (pr->freelist_offset == INVALID_OFFSET) {
|
||||||
KASSERT(pr->nfree == 0);
|
KASSERT(pr->nfree==0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -498,7 +523,7 @@ static void checksubpage(struct pageref *pr) {
|
|||||||
|
|
||||||
#ifdef CHECKGUARDS
|
#ifdef CHECKGUARDS
|
||||||
smallerblocksize = blktype > 0 ? sizes[blktype - 1] : 0;
|
smallerblocksize = blktype > 0 ? sizes[blktype - 1] : 0;
|
||||||
for (i = 0; i < numfreewords; i++) {
|
for (i=0; i<numfreewords; i++) {
|
||||||
isfree[i] = 0;
|
isfree[i] = 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -517,12 +542,12 @@ static void checksubpage(struct pageref *pr) {
|
|||||||
for (; fl != NULL; fl = fl->next) {
|
for (; fl != NULL; fl = fl->next) {
|
||||||
fla = (vaddr_t)fl;
|
fla = (vaddr_t)fl;
|
||||||
KASSERT(fla >= prpage && fla < prpage + PAGE_SIZE);
|
KASSERT(fla >= prpage && fla < prpage + PAGE_SIZE);
|
||||||
KASSERT((fla - prpage) % blocksize == 0);
|
KASSERT((fla-prpage) % blocksize == 0);
|
||||||
#ifdef CHECKBEEF
|
#ifdef CHECKBEEF
|
||||||
checkdeadbeef(fl, blocksize);
|
checkdeadbeef(fl, blocksize);
|
||||||
#endif
|
#endif
|
||||||
#ifdef CHECKGUARDS
|
#ifdef CHECKGUARDS
|
||||||
blocknum = (fla - prpage) / blocksize;
|
blocknum = (fla-prpage) / blocksize;
|
||||||
mask = 1U << (blocknum % 32);
|
mask = 1U << (blocknum % 32);
|
||||||
KASSERT((isfree[blocknum / 32] & mask) == 0);
|
KASSERT((isfree[blocknum / 32] & mask) == 0);
|
||||||
isfree[blocknum / 32] |= mask;
|
isfree[blocknum / 32] |= mask;
|
||||||
@ -530,14 +555,15 @@ static void checksubpage(struct pageref *pr) {
|
|||||||
KASSERT(fl->next != fl);
|
KASSERT(fl->next != fl);
|
||||||
nfree++;
|
nfree++;
|
||||||
}
|
}
|
||||||
KASSERT(nfree == pr->nfree);
|
KASSERT(nfree==pr->nfree);
|
||||||
|
|
||||||
#ifdef CHECKGUARDS
|
#ifdef CHECKGUARDS
|
||||||
numblocks = PAGE_SIZE / blocksize;
|
numblocks = PAGE_SIZE / blocksize;
|
||||||
for (i = 0; i < numblocks; i++) {
|
for (i=0; i<numblocks; i++) {
|
||||||
mask = 1U << (i % 32);
|
mask = 1U << (i % 32);
|
||||||
if ((isfree[i / 32] & mask) == 0) {
|
if ((isfree[i / 32] & mask) == 0) {
|
||||||
checkguardband(prpage + i * blocksize, smallerblocksize, blocksize);
|
checkguardband(prpage + i * blocksize,
|
||||||
|
smallerblocksize, blocksize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -551,14 +577,17 @@ static void checksubpage(struct pageref *pr) {
|
|||||||
* Run checksubpage on all heap pages. This also checks that the
|
* Run checksubpage on all heap pages. This also checks that the
|
||||||
* linked lists of pagerefs are more or less intact.
|
* linked lists of pagerefs are more or less intact.
|
||||||
*/
|
*/
|
||||||
static void checksubpages(void) {
|
static
|
||||||
|
void
|
||||||
|
checksubpages(void)
|
||||||
|
{
|
||||||
struct pageref *pr;
|
struct pageref *pr;
|
||||||
int i;
|
int i;
|
||||||
unsigned sc = 0, ac = 0;
|
unsigned sc=0, ac=0;
|
||||||
|
|
||||||
KASSERT(spinlock_do_i_hold(&kmalloc_spinlock));
|
KASSERT(spinlock_do_i_hold(&kmalloc_spinlock));
|
||||||
|
|
||||||
for (i = 0; i < NSIZES; i++) {
|
for (i=0; i<NSIZES; i++) {
|
||||||
for (pr = sizebases[i]; pr != NULL; pr = pr->next_samesize) {
|
for (pr = sizebases[i]; pr != NULL; pr = pr->next_samesize) {
|
||||||
checksubpage(pr);
|
checksubpage(pr);
|
||||||
KASSERT(sc < TOTAL_PAGEREFS);
|
KASSERT(sc < TOTAL_PAGEREFS);
|
||||||
@ -572,7 +601,7 @@ static void checksubpages(void) {
|
|||||||
ac++;
|
ac++;
|
||||||
}
|
}
|
||||||
|
|
||||||
KASSERT(sc == ac);
|
KASSERT(sc==ac);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
#define checksubpages()
|
#define checksubpages()
|
||||||
@ -595,7 +624,10 @@ static unsigned mallocgeneration;
|
|||||||
/*
|
/*
|
||||||
* Label a block of memory.
|
* Label a block of memory.
|
||||||
*/
|
*/
|
||||||
static void *establishlabel(void *block, vaddr_t label) {
|
static
|
||||||
|
void *
|
||||||
|
establishlabel(void *block, vaddr_t label)
|
||||||
|
{
|
||||||
struct malloclabel *ml;
|
struct malloclabel *ml;
|
||||||
|
|
||||||
ml = block;
|
ml = block;
|
||||||
@ -605,7 +637,10 @@ static void *establishlabel(void *block, vaddr_t label) {
|
|||||||
return ml;
|
return ml;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dump_subpage(struct pageref *pr, unsigned generation) {
|
static
|
||||||
|
void
|
||||||
|
dump_subpage(struct pageref *pr, unsigned generation)
|
||||||
|
{
|
||||||
unsigned blocksize = sizes[PR_BLOCKTYPE(pr)];
|
unsigned blocksize = sizes[PR_BLOCKTYPE(pr)];
|
||||||
unsigned numblocks = PAGE_SIZE / blocksize;
|
unsigned numblocks = PAGE_SIZE / blocksize;
|
||||||
unsigned numfreewords = DIVROUNDUP(numblocks, 32);
|
unsigned numfreewords = DIVROUNDUP(numblocks, 32);
|
||||||
@ -616,7 +651,7 @@ static void dump_subpage(struct pageref *pr, unsigned generation) {
|
|||||||
struct malloclabel *ml;
|
struct malloclabel *ml;
|
||||||
unsigned i;
|
unsigned i;
|
||||||
|
|
||||||
for (i = 0; i < numfreewords; i++) {
|
for (i=0; i<numfreewords; i++) {
|
||||||
isfree[i] = 0;
|
isfree[i] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -628,7 +663,7 @@ static void dump_subpage(struct pageref *pr, unsigned generation) {
|
|||||||
isfree[i / 32] |= mask;
|
isfree[i / 32] |= mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < numblocks; i++) {
|
for (i=0; i<numblocks; i++) {
|
||||||
mask = 1U << (i % 32);
|
mask = 1U << (i % 32);
|
||||||
if (isfree[i / 32] & mask) {
|
if (isfree[i / 32] & mask) {
|
||||||
continue;
|
continue;
|
||||||
@ -638,17 +673,20 @@ static void dump_subpage(struct pageref *pr, unsigned generation) {
|
|||||||
if (ml->generation != generation) {
|
if (ml->generation != generation) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
kprintf("%5zu bytes at %p, allocated at %p\n", blocksize, (void *)blockaddr,
|
kprintf("%5zu bytes at %p, allocated at %p\n",
|
||||||
(void *)ml->label);
|
blocksize, (void *)blockaddr, (void *)ml->label);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dump_subpages(unsigned generation) {
|
static
|
||||||
|
void
|
||||||
|
dump_subpages(unsigned generation)
|
||||||
|
{
|
||||||
struct pageref *pr;
|
struct pageref *pr;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
kprintf("Remaining allocations from generation %u:\n", generation);
|
kprintf("Remaining allocations from generation %u:\n", generation);
|
||||||
for (i = 0; i < NSIZES; i++) {
|
for (i=0; i<NSIZES; i++) {
|
||||||
for (pr = sizebases[i]; pr != NULL; pr = pr->next_samesize) {
|
for (pr = sizebases[i]; pr != NULL; pr = pr->next_samesize) {
|
||||||
dump_subpage(pr, generation);
|
dump_subpage(pr, generation);
|
||||||
}
|
}
|
||||||
@ -661,7 +699,9 @@ static void dump_subpages(unsigned generation) {
|
|||||||
|
|
||||||
#endif /* LABELS */
|
#endif /* LABELS */
|
||||||
|
|
||||||
void kheap_nextgeneration(void) {
|
void
|
||||||
|
kheap_nextgeneration(void)
|
||||||
|
{
|
||||||
#ifdef LABELS
|
#ifdef LABELS
|
||||||
spinlock_acquire(&kmalloc_spinlock);
|
spinlock_acquire(&kmalloc_spinlock);
|
||||||
mallocgeneration++;
|
mallocgeneration++;
|
||||||
@ -669,7 +709,9 @@ void kheap_nextgeneration(void) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void kheap_dump(void) {
|
void
|
||||||
|
kheap_dump(void)
|
||||||
|
{
|
||||||
#ifdef LABELS
|
#ifdef LABELS
|
||||||
/* print the whole thing with interrupts off */
|
/* print the whole thing with interrupts off */
|
||||||
spinlock_acquire(&kmalloc_spinlock);
|
spinlock_acquire(&kmalloc_spinlock);
|
||||||
@ -680,13 +722,15 @@ void kheap_dump(void) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void kheap_dumpall(void) {
|
void
|
||||||
|
kheap_dumpall(void)
|
||||||
|
{
|
||||||
#ifdef LABELS
|
#ifdef LABELS
|
||||||
unsigned i;
|
unsigned i;
|
||||||
|
|
||||||
/* print the whole thing with interrupts off */
|
/* print the whole thing with interrupts off */
|
||||||
spinlock_acquire(&kmalloc_spinlock);
|
spinlock_acquire(&kmalloc_spinlock);
|
||||||
for (i = 0; i <= mallocgeneration; i++) {
|
for (i=0; i<=mallocgeneration; i++) {
|
||||||
dump_subpages(i);
|
dump_subpages(i);
|
||||||
}
|
}
|
||||||
spinlock_release(&kmalloc_spinlock);
|
spinlock_release(&kmalloc_spinlock);
|
||||||
@ -700,18 +744,21 @@ void kheap_dumpall(void) {
|
|||||||
/*
|
/*
|
||||||
* Print the allocated/freed map of a single kernel heap page.
|
* Print the allocated/freed map of a single kernel heap page.
|
||||||
*/
|
*/
|
||||||
static void subpage_stats(struct pageref *pr) {
|
static
|
||||||
|
unsigned long
|
||||||
|
subpage_stats(struct pageref *pr, bool quiet)
|
||||||
|
{
|
||||||
vaddr_t prpage, fla;
|
vaddr_t prpage, fla;
|
||||||
struct freelist *fl;
|
struct freelist *fl;
|
||||||
int blktype;
|
int blktype;
|
||||||
unsigned i, n, index;
|
unsigned i, n, index;
|
||||||
uint32_t freemap[PAGE_SIZE / (SMALLEST_SUBPAGE_SIZE * 32)];
|
uint32_t freemap[PAGE_SIZE / (SMALLEST_SUBPAGE_SIZE*32)];
|
||||||
|
|
||||||
checksubpage(pr);
|
checksubpage(pr);
|
||||||
KASSERT(spinlock_do_i_hold(&kmalloc_spinlock));
|
KASSERT(spinlock_do_i_hold(&kmalloc_spinlock));
|
||||||
|
|
||||||
/* clear freemap[] */
|
/* clear freemap[] */
|
||||||
for (i = 0; i < ARRAYCOUNT(freemap); i++) {
|
for (i=0; i<ARRAYCOUNT(freemap); i++) {
|
||||||
freemap[i] = 0;
|
freemap[i] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -729,29 +776,35 @@ static void subpage_stats(struct pageref *pr) {
|
|||||||
|
|
||||||
for (; fl != NULL; fl = fl->next) {
|
for (; fl != NULL; fl = fl->next) {
|
||||||
fla = (vaddr_t)fl;
|
fla = (vaddr_t)fl;
|
||||||
index = (fla - prpage) / sizes[blktype];
|
index = (fla-prpage) / sizes[blktype];
|
||||||
KASSERT(index < n);
|
KASSERT(index<n);
|
||||||
freemap[index / 32] |= (1 << (index % 32));
|
freemap[index/32] |= (1<<(index%32));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
kprintf("at 0x%08lx: size %-4lu %u/%u free\n", (unsigned long)prpage,
|
if (!quiet) {
|
||||||
(unsigned long)sizes[blktype], (unsigned)pr->nfree, n);
|
kprintf("at 0x%08lx: size %-4lu %u/%u free\n",
|
||||||
|
(unsigned long)prpage, (unsigned long) sizes[blktype],
|
||||||
|
(unsigned) pr->nfree, n);
|
||||||
kprintf(" ");
|
kprintf(" ");
|
||||||
for (i = 0; i < n; i++) {
|
for (i=0; i<n; i++) {
|
||||||
int val = (freemap[i / 32] & (1 << (i % 32))) != 0;
|
int val = (freemap[i/32] & (1<<(i%32)))!=0;
|
||||||
kprintf("%c", val ? '.' : '*');
|
kprintf("%c", val ? '.' : '*');
|
||||||
if (i % 64 == 63 && i < n - 1) {
|
if (i%64==63 && i<n-1) {
|
||||||
kprintf("\n ");
|
kprintf("\n ");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
kprintf("\n");
|
kprintf("\n");
|
||||||
|
}
|
||||||
|
return ((unsigned long)sizes[blktype] * (n - (unsigned) pr->nfree));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Print the whole heap.
|
* Print the whole heap.
|
||||||
*/
|
*/
|
||||||
void kheap_printstats(void) {
|
void
|
||||||
|
kheap_printstats(void)
|
||||||
|
{
|
||||||
struct pageref *pr;
|
struct pageref *pr;
|
||||||
|
|
||||||
/* print the whole thing with interrupts off */
|
/* print the whole thing with interrupts off */
|
||||||
@ -760,21 +813,67 @@ void kheap_printstats(void) {
|
|||||||
kprintf("Subpage allocator status:\n");
|
kprintf("Subpage allocator status:\n");
|
||||||
|
|
||||||
for (pr = allbase; pr != NULL; pr = pr->next_all) {
|
for (pr = allbase; pr != NULL; pr = pr->next_all) {
|
||||||
subpage_stats(pr);
|
subpage_stats(pr, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
spinlock_release(&kmalloc_spinlock);
|
spinlock_release(&kmalloc_spinlock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return the number of used bytes.
|
||||||
|
*/
|
||||||
|
|
||||||
|
unsigned long
|
||||||
|
kheap_getused(void) {
|
||||||
|
struct pageref *pr;
|
||||||
|
unsigned long total = 0;
|
||||||
|
unsigned int num_pages = 0, coremap_bytes = 0;
|
||||||
|
|
||||||
|
/* compute with interrupts off */
|
||||||
|
spinlock_acquire(&kmalloc_spinlock);
|
||||||
|
for (pr = allbase; pr != NULL; pr = pr->next_all) {
|
||||||
|
total += subpage_stats(pr, true);
|
||||||
|
num_pages++;
|
||||||
|
}
|
||||||
|
|
||||||
|
coremap_bytes = coremap_used_bytes();
|
||||||
|
|
||||||
|
// Don't double-count the pages we're using for subpage allocation;
|
||||||
|
// we've already accounted for the used portion.
|
||||||
|
if (coremap_bytes > 0) {
|
||||||
|
total += coremap_bytes - (num_pages * PAGE_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
spinlock_release(&kmalloc_spinlock);
|
||||||
|
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Print number of used bytes.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void
|
||||||
|
kheap_printused(void)
|
||||||
|
{
|
||||||
|
char total_string[32];
|
||||||
|
snprintf(total_string, sizeof(total_string), "%lu", kheap_getused());
|
||||||
|
secprintf(SECRET, total_string, "khu");
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////
|
////////////////////////////////////////
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Remove a pageref from both lists that it's on.
|
* Remove a pageref from both lists that it's on.
|
||||||
*/
|
*/
|
||||||
static void remove_lists(struct pageref *pr, int blktype) {
|
static
|
||||||
|
void
|
||||||
|
remove_lists(struct pageref *pr, int blktype)
|
||||||
|
{
|
||||||
struct pageref **guy;
|
struct pageref **guy;
|
||||||
|
|
||||||
KASSERT(blktype >= 0 && blktype < NSIZES);
|
KASSERT(blktype>=0 && blktype<NSIZES);
|
||||||
|
|
||||||
for (guy = &sizebases[blktype]; *guy; guy = &(*guy)->next_samesize) {
|
for (guy = &sizebases[blktype]; *guy; guy = &(*guy)->next_samesize) {
|
||||||
checksubpage(*guy);
|
checksubpage(*guy);
|
||||||
@ -797,15 +896,19 @@ static void remove_lists(struct pageref *pr, int blktype) {
|
|||||||
* Given a requested client size, return the block type, that is, the
|
* Given a requested client size, return the block type, that is, the
|
||||||
* index into the sizes[] array for the block size to use.
|
* index into the sizes[] array for the block size to use.
|
||||||
*/
|
*/
|
||||||
static inline int blocktype(size_t clientsz) {
|
static
|
||||||
|
inline
|
||||||
|
int blocktype(size_t clientsz)
|
||||||
|
{
|
||||||
unsigned i;
|
unsigned i;
|
||||||
for (i = 0; i < NSIZES; i++) {
|
for (i=0; i<NSIZES; i++) {
|
||||||
if (clientsz <= sizes[i]) {
|
if (clientsz <= sizes[i]) {
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
panic("Subpage allocator cannot handle allocation of size %zu\n", clientsz);
|
panic("Subpage allocator cannot handle allocation of size %zu\n",
|
||||||
|
clientsz);
|
||||||
|
|
||||||
// keep compiler happy
|
// keep compiler happy
|
||||||
return 0;
|
return 0;
|
||||||
@ -815,12 +918,14 @@ static inline int blocktype(size_t clientsz) {
|
|||||||
* Allocate a block of size SZ, where SZ is not large enough to
|
* Allocate a block of size SZ, where SZ is not large enough to
|
||||||
* warrant a whole-page allocation.
|
* warrant a whole-page allocation.
|
||||||
*/
|
*/
|
||||||
static void *subpage_kmalloc(size_t sz
|
static
|
||||||
|
void *
|
||||||
|
subpage_kmalloc(size_t sz
|
||||||
#ifdef LABELS
|
#ifdef LABELS
|
||||||
,
|
, vaddr_t label
|
||||||
vaddr_t label
|
|
||||||
#endif
|
#endif
|
||||||
) {
|
)
|
||||||
|
{
|
||||||
unsigned blktype; // index into sizes[] that we're using
|
unsigned blktype; // index into sizes[] that we're using
|
||||||
struct pageref *pr; // pageref for page we're allocating from
|
struct pageref *pr; // pageref for page we're allocating from
|
||||||
vaddr_t prpage; // PR_PAGEADDR(pr)
|
vaddr_t prpage; // PR_PAGEADDR(pr)
|
||||||
@ -878,7 +983,8 @@ static void *subpage_kmalloc(size_t sz
|
|||||||
fla = (vaddr_t)fl;
|
fla = (vaddr_t)fl;
|
||||||
KASSERT(fla - prpage < PAGE_SIZE);
|
KASSERT(fla - prpage < PAGE_SIZE);
|
||||||
pr->freelist_offset = fla - prpage;
|
pr->freelist_offset = fla - prpage;
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
KASSERT(pr->nfree == 0);
|
KASSERT(pr->nfree == 0);
|
||||||
pr->freelist_offset = INVALID_OFFSET;
|
pr->freelist_offset = INVALID_OFFSET;
|
||||||
}
|
}
|
||||||
@ -907,9 +1013,9 @@ static void *subpage_kmalloc(size_t sz
|
|||||||
|
|
||||||
spinlock_release(&kmalloc_spinlock);
|
spinlock_release(&kmalloc_spinlock);
|
||||||
prpage = alloc_kpages(1);
|
prpage = alloc_kpages(1);
|
||||||
if (prpage == 0) {
|
if (prpage==0) {
|
||||||
/* Out of memory. */
|
/* Out of memory. */
|
||||||
kprintf("kmalloc: Subpage allocator couldn't get a page\n");
|
silent("kmalloc: Subpage allocator couldn't get a page\n");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
KASSERT(prpage % PAGE_SIZE == 0);
|
KASSERT(prpage % PAGE_SIZE == 0);
|
||||||
@ -920,7 +1026,7 @@ static void *subpage_kmalloc(size_t sz
|
|||||||
spinlock_acquire(&kmalloc_spinlock);
|
spinlock_acquire(&kmalloc_spinlock);
|
||||||
|
|
||||||
pr = allocpageref();
|
pr = allocpageref();
|
||||||
if (pr == NULL) {
|
if (pr==NULL) {
|
||||||
/* Couldn't allocate accounting space for the new page. */
|
/* Couldn't allocate accounting space for the new page. */
|
||||||
spinlock_release(&kmalloc_spinlock);
|
spinlock_release(&kmalloc_spinlock);
|
||||||
free_kpages(prpage);
|
free_kpages(prpage);
|
||||||
@ -940,14 +1046,14 @@ static void *subpage_kmalloc(size_t sz
|
|||||||
fla = prpage;
|
fla = prpage;
|
||||||
fl = (struct freelist *)fla;
|
fl = (struct freelist *)fla;
|
||||||
fl->next = NULL;
|
fl->next = NULL;
|
||||||
for (i = 1; i < pr->nfree; i++) {
|
for (i=1; i<pr->nfree; i++) {
|
||||||
fl = (struct freelist *)(fla + i * sizes[blktype]);
|
fl = (struct freelist *)(fla + i*sizes[blktype]);
|
||||||
fl->next = (struct freelist *)(fla + (i - 1) * sizes[blktype]);
|
fl->next = (struct freelist *)(fla + (i-1)*sizes[blktype]);
|
||||||
KASSERT(fl != fl->next);
|
KASSERT(fl != fl->next);
|
||||||
}
|
}
|
||||||
fla = (vaddr_t)fl;
|
fla = (vaddr_t) fl;
|
||||||
pr->freelist_offset = fla - prpage;
|
pr->freelist_offset = fla - prpage;
|
||||||
KASSERT(pr->freelist_offset == (pr->nfree - 1) * sizes[blktype]);
|
KASSERT(pr->freelist_offset == (pr->nfree-1)*sizes[blktype]);
|
||||||
|
|
||||||
pr->next_samesize = sizebases[blktype];
|
pr->next_samesize = sizebases[blktype];
|
||||||
sizebases[blktype] = pr;
|
sizebases[blktype] = pr;
|
||||||
@ -963,7 +1069,10 @@ static void *subpage_kmalloc(size_t sz
|
|||||||
* Free a pointer previously returned from subpage_kmalloc. If the
|
* Free a pointer previously returned from subpage_kmalloc. If the
|
||||||
* pointer is not on any heap page we recognize, return -1.
|
* pointer is not on any heap page we recognize, return -1.
|
||||||
*/
|
*/
|
||||||
static int subpage_kfree(void *ptr) {
|
static
|
||||||
|
int
|
||||||
|
subpage_kfree(void *ptr)
|
||||||
|
{
|
||||||
int blktype; // index into sizes[] that we're using
|
int blktype; // index into sizes[] that we're using
|
||||||
vaddr_t ptraddr; // same as ptr
|
vaddr_t ptraddr; // same as ptr
|
||||||
struct pageref *pr; // pageref for page we're freeing in
|
struct pageref *pr; // pageref for page we're freeing in
|
||||||
@ -1014,7 +1123,7 @@ static int subpage_kfree(void *ptr) {
|
|||||||
KASSERT(blktype >= 0 && blktype < NSIZES);
|
KASSERT(blktype >= 0 && blktype < NSIZES);
|
||||||
|
|
||||||
/* check for corruption */
|
/* check for corruption */
|
||||||
KASSERT(blktype >= 0 && blktype < NSIZES);
|
KASSERT(blktype>=0 && blktype<NSIZES);
|
||||||
checksubpage(pr);
|
checksubpage(pr);
|
||||||
|
|
||||||
if (ptraddr >= prpage && ptraddr < prpage + PAGE_SIZE) {
|
if (ptraddr >= prpage && ptraddr < prpage + PAGE_SIZE) {
|
||||||
@ -1022,7 +1131,7 @@ static int subpage_kfree(void *ptr) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pr == NULL) {
|
if (pr==NULL) {
|
||||||
/* Not on any of our pages - not a subpage allocation */
|
/* Not on any of our pages - not a subpage allocation */
|
||||||
spinlock_release(&kmalloc_spinlock);
|
spinlock_release(&kmalloc_spinlock);
|
||||||
return -1;
|
return -1;
|
||||||
@ -1084,7 +1193,8 @@ static int subpage_kfree(void *ptr) {
|
|||||||
/* Call free_kpages without kmalloc_spinlock. */
|
/* Call free_kpages without kmalloc_spinlock. */
|
||||||
spinlock_release(&kmalloc_spinlock);
|
spinlock_release(&kmalloc_spinlock);
|
||||||
free_kpages(prpage);
|
free_kpages(prpage);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
spinlock_release(&kmalloc_spinlock);
|
spinlock_release(&kmalloc_spinlock);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1104,7 +1214,9 @@ static int subpage_kfree(void *ptr) {
|
|||||||
* Allocate a block of size SZ. Redirect either to subpage_kmalloc or
|
* Allocate a block of size SZ. Redirect either to subpage_kmalloc or
|
||||||
* alloc_kpages depending on how big SZ is.
|
* alloc_kpages depending on how big SZ is.
|
||||||
*/
|
*/
|
||||||
void *kmalloc(size_t sz) {
|
void *
|
||||||
|
kmalloc(size_t sz)
|
||||||
|
{
|
||||||
size_t checksz;
|
size_t checksz;
|
||||||
#ifdef LABELS
|
#ifdef LABELS
|
||||||
vaddr_t label;
|
vaddr_t label;
|
||||||
@ -1124,9 +1236,9 @@ void *kmalloc(size_t sz) {
|
|||||||
vaddr_t address;
|
vaddr_t address;
|
||||||
|
|
||||||
/* Round up to a whole number of pages. */
|
/* Round up to a whole number of pages. */
|
||||||
npages = (sz + PAGE_SIZE - 1) / PAGE_SIZE;
|
npages = (sz + PAGE_SIZE - 1)/PAGE_SIZE;
|
||||||
address = alloc_kpages(npages);
|
address = alloc_kpages(npages);
|
||||||
if (address == 0) {
|
if (address==0) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
KASSERT(address % PAGE_SIZE == 0);
|
KASSERT(address % PAGE_SIZE == 0);
|
||||||
@ -1144,14 +1256,17 @@ void *kmalloc(size_t sz) {
|
|||||||
/*
|
/*
|
||||||
* Free a block previously returned from kmalloc.
|
* Free a block previously returned from kmalloc.
|
||||||
*/
|
*/
|
||||||
void kfree(void *ptr) {
|
void
|
||||||
|
kfree(void *ptr)
|
||||||
|
{
|
||||||
/*
|
/*
|
||||||
* Try subpage first; if that fails, assume it's a big allocation.
|
* Try subpage first; if that fails, assume it's a big allocation.
|
||||||
*/
|
*/
|
||||||
if (ptr == NULL) {
|
if (ptr == NULL) {
|
||||||
return;
|
return;
|
||||||
} else if (subpage_kfree(ptr)) {
|
} else if (subpage_kfree(ptr)) {
|
||||||
KASSERT((vaddr_t)ptr % PAGE_SIZE == 0);
|
KASSERT((vaddr_t)ptr%PAGE_SIZE==0);
|
||||||
free_kpages((vaddr_t)ptr);
|
free_kpages((vaddr_t)ptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@ Standard C Library (libc, -lc)
|
|||||||
<p>
|
<p>
|
||||||
<tt>#include <unistd.h></tt><br>
|
<tt>#include <unistd.h></tt><br>
|
||||||
<br>
|
<br>
|
||||||
<tt>void,</tt><br>
|
<tt>void</tt><br>
|
||||||
<tt>_exit(int </tt><em>exitcode</em><tt>);</tt>
|
<tt>_exit(int </tt><em>exitcode</em><tt>);</tt>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
@ -55,8 +55,8 @@ Standard C Library (libc, -lc)
|
|||||||
|
|
||||||
<h3>Description</h3>
|
<h3>Description</h3>
|
||||||
<p>
|
<p>
|
||||||
The file handle <em>fd</em> is closed. The same file handle may then
|
The file handle identified by file descriptor <em>fd</em> is closed.
|
||||||
be returned again from <A HREF=open.html>open</A>,
|
The same file handle may then be returned again from <A HREF=open.html>open</A>,
|
||||||
<A HREF=dup2.html>dup2</A>, <A HREF=pipe.html>pipe</A>, or similar
|
<A HREF=dup2.html>dup2</A>, <A HREF=pipe.html>pipe</A>, or similar
|
||||||
calls.
|
calls.
|
||||||
</p>
|
</p>
|
||||||
@ -87,7 +87,7 @@ mentioned here.
|
|||||||
<table width=90%>
|
<table width=90%>
|
||||||
<tr><td width=5% rowspan=10> </td>
|
<tr><td width=5% rowspan=10> </td>
|
||||||
<td width=10%>EBADF</td>
|
<td width=10%>EBADF</td>
|
||||||
<td><em>fd</em> is not a valid file handle.</td></tr>
|
<td><em>fd</em> is not a valid file descriptor.</td></tr>
|
||||||
<tr><td>EIO</td> <td>A hard I/O error occurred.</td></tr>
|
<tr><td>EIO</td> <td>A hard I/O error occurred.</td></tr>
|
||||||
</table>
|
</table>
|
||||||
</p>
|
</p>
|
||||||
|
@ -55,9 +55,9 @@ Standard C Library (libc, -lc)
|
|||||||
|
|
||||||
<h3>Description</h3>
|
<h3>Description</h3>
|
||||||
<p>
|
<p>
|
||||||
<tt>dup2</tt> clones the file handle <em>oldfd</em> onto the file
|
<tt>dup2</tt> clones the file handle identifed by file descriptor <em>oldfd</em>
|
||||||
handle <em>newfd</em>. If <em>newfd</em> names an already-open file,
|
onto the file handle identified by <em>newfd</em>. If <em>newfd</em>
|
||||||
that file is closed.
|
names an already-open file, that file is closed.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
@ -74,8 +74,8 @@ dup2 is most commonly used to relocate opened files onto
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Both filehandles must be non-negative, and, if applicable, smaller
|
Both file descriptors must be non-negative, and, if applicable,
|
||||||
than the maximum allowed file handle number.
|
smaller than the maximum allowed file handle number.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
@ -116,9 +116,9 @@ here.
|
|||||||
<tr><td width=5% rowspan=3> </td>
|
<tr><td width=5% rowspan=3> </td>
|
||||||
<td width=10% valign=top>EBADF</td>
|
<td width=10% valign=top>EBADF</td>
|
||||||
<td><em>oldfd</em> is not a valid file
|
<td><em>oldfd</em> is not a valid file
|
||||||
handle, or <em>newfd</em> is a value
|
descriptor, or <em>newfd</em> is a value
|
||||||
that cannot be a valid file
|
that cannot be a valid file
|
||||||
handle.</td></tr>
|
descriptor.</td></tr>
|
||||||
<tr><td valign=top>EMFILE</td> <td>The process's file table was full, or a
|
<tr><td valign=top>EMFILE</td> <td>The process's file table was full, or a
|
||||||
process-specific limit on open files
|
process-specific limit on open files
|
||||||
was reached.</td></tr>
|
was reached.</td></tr>
|
||||||
|
@ -57,7 +57,7 @@ struct stat *</tt><em>statbuf</em><tt>);</tt>
|
|||||||
<h3>Description</h3>
|
<h3>Description</h3>
|
||||||
<p>
|
<p>
|
||||||
<tt>fstat</tt> retrieves status information about the file referred to
|
<tt>fstat</tt> retrieves status information about the file referred to
|
||||||
by the file handle <em>fd</em> and stores it in the stat structure
|
by the file descriptor <em>fd</em> and stores it in the stat structure
|
||||||
pointed to by <em>statbuf</em>.
|
pointed to by <em>statbuf</em>.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
@ -87,8 +87,8 @@ mentioned here.
|
|||||||
<table width=90%>
|
<table width=90%>
|
||||||
<tr><td width=5% rowspan=3> </td>
|
<tr><td width=5% rowspan=3> </td>
|
||||||
<td width=10% valign=top>EBADF</td>
|
<td width=10% valign=top>EBADF</td>
|
||||||
<td><em>fd</em> is not a valid file handle, or
|
<td><em>fd</em> is not a valid file descriptor,
|
||||||
it is not open for writing.</td></tr>
|
or it is not open for writing.</td></tr>
|
||||||
<tr><td valign=top>EIO</td> <td>A hard I/O error occurred.</td></tr>
|
<tr><td valign=top>EIO</td> <td>A hard I/O error occurred.</td></tr>
|
||||||
<tr><td valign=top>EFAULT</td> <td><em>buf</em> points to an invalid
|
<tr><td valign=top>EFAULT</td> <td><em>buf</em> points to an invalid
|
||||||
address.</td></tr>
|
address.</td></tr>
|
||||||
|
@ -57,7 +57,7 @@ size_t </tt><em>buflen</em><tt>);</tt>
|
|||||||
<h3>Description</h3>
|
<h3>Description</h3>
|
||||||
<p>
|
<p>
|
||||||
<tt>getdirentry</tt> retrieves the next filename from a directory
|
<tt>getdirentry</tt> retrieves the next filename from a directory
|
||||||
referred to by the file handle <em>filehandle</em>. The name is stored
|
referred to by the file descriptor <em>fd</em>. The name is stored
|
||||||
in <em>buf</em>, an area of size <em>buflen</em>. The length of of the
|
in <em>buf</em>, an area of size <em>buflen</em>. The length of of the
|
||||||
name actually found is returned.
|
name actually found is returned.
|
||||||
</p>
|
</p>
|
||||||
|
@ -57,7 +57,7 @@ void *</tt><em>data</em><tt>);</tt>
|
|||||||
<h3>Description</h3>
|
<h3>Description</h3>
|
||||||
<p>
|
<p>
|
||||||
<tt>ioctl</tt> performs an object-specific operation <em>code</em> on
|
<tt>ioctl</tt> performs an object-specific operation <em>code</em> on
|
||||||
the object referred to by the file handle <em>fd</em>. The
|
the object referred to by the file descriptor <em>fd</em>. The
|
||||||
<em>data</em> argument may point to supplemental data required or
|
<em>data</em> argument may point to supplemental data required or
|
||||||
returned by the operation. The size of buffer required, if any, and
|
returned by the operation. The size of buffer required, if any, and
|
||||||
other such matters are operation-specific.
|
other such matters are operation-specific.
|
||||||
|
@ -57,8 +57,8 @@ int </tt><em>whence</em><tt>);</tt>
|
|||||||
<h3>Description</h3>
|
<h3>Description</h3>
|
||||||
<p>
|
<p>
|
||||||
<tt>lseek</tt> alters the current seek position of the file handle
|
<tt>lseek</tt> alters the current seek position of the file handle
|
||||||
<em>filehandle</em>, seeking to a new position based on <em>pos</em>
|
identified by file descriptor <em>fd</em>, seeking to a new position
|
||||||
and <em>whence</em>.
|
based on <em>pos</em> and <em>whence</em>.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
@ -122,7 +122,7 @@ mentioned here.
|
|||||||
<tr><td width=5% rowspan=4> </td>
|
<tr><td width=5% rowspan=4> </td>
|
||||||
<td width=10% valign=top>EBADF</td>
|
<td width=10% valign=top>EBADF</td>
|
||||||
<td><em>fd</em> is not a valid file
|
<td><em>fd</em> is not a valid file
|
||||||
handle.</td></tr>
|
descriptor.</td></tr>
|
||||||
<tr><td valign=top>ESPIPE</td> <td><em>fd</em> refers to an object
|
<tr><td valign=top>ESPIPE</td> <td><em>fd</em> refers to an object
|
||||||
which does not support seeking.</td></tr>
|
which does not support seeking.</td></tr>
|
||||||
<tr><td valign=top>EINVAL</td> <td><em>whence</em> is invalid.</td></tr>
|
<tr><td valign=top>EINVAL</td> <td><em>whence</em> is invalid.</td></tr>
|
||||||
|
@ -99,12 +99,12 @@ course's assignments.)
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<tt>open</tt> returns a file handle suitable for passing to
|
<tt>open</tt> returns a file descriptor suitable for passing to
|
||||||
<A HREF=read.html>read</A>,
|
<A HREF=read.html>read</A>,
|
||||||
<A HREF=write.html>write</A>,
|
<A HREF=write.html>write</A>,
|
||||||
<A HREF=close.html>close</A>,
|
<A HREF=close.html>close</A>,
|
||||||
etc. This file handle must be greater than or equal to zero. Note
|
etc. This file descriptor must be greater than or equal to zero. Note
|
||||||
that file handles 0 (STDIN_FILENO), 1 (STDOUT_FILENO), and 2
|
that file descriptors 0 (STDIN_FILENO), 1 (STDOUT_FILENO), and 2
|
||||||
(STDERR_FILENO) are used in special ways and are typically assumed by
|
(STDERR_FILENO) are used in special ways and are typically assumed by
|
||||||
user-level code to always be open.
|
user-level code to always be open.
|
||||||
</p>
|
</p>
|
||||||
@ -128,9 +128,9 @@ contain <tt>..</tt> is usually not quite atomic.
|
|||||||
|
|
||||||
<h3>Return Values</h3>
|
<h3>Return Values</h3>
|
||||||
<p>
|
<p>
|
||||||
On success, <tt>open</tt> returns a nonnegative file handle. On error,
|
On success, <tt>open</tt> returns a nonnegative file descriptor. On
|
||||||
-1 is returned, and <A HREF=errno.html>errno</A> is set according to
|
error, -1 is returned, and <A HREF=errno.html>errno</A> is set
|
||||||
the error encountered.
|
according to the error encountered.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h3>Errors</h3>
|
<h3>Errors</h3>
|
||||||
|
@ -51,7 +51,7 @@ Standard C Library (libc, -lc)
|
|||||||
<br>
|
<br>
|
||||||
<tt>ssize_t</tt><br>
|
<tt>ssize_t</tt><br>
|
||||||
<tt>write(int </tt><em>fd</em><tt>, const void *</tt><em>buf</em><tt>,
|
<tt>write(int </tt><em>fd</em><tt>, const void *</tt><em>buf</em><tt>,
|
||||||
size_t </tt><em>nbytes</em><tt>);</tt>
|
size_t </tt><em>buflen</em><tt>);</tt>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h3>Description</h3>
|
<h3>Description</h3>
|
||||||
|
@ -87,15 +87,6 @@
|
|||||||
# These build variables can be set explicitly for further control if
|
# These build variables can be set explicitly for further control if
|
||||||
# desired, but should in general not need attention.
|
# desired, but should in general not need attention.
|
||||||
#
|
#
|
||||||
# (Tools.)
|
|
||||||
#
|
|
||||||
# PYTHON_INTERPRETER Location of Python interpreter.
|
|
||||||
# Default is "/usr/bin/env python".
|
|
||||||
#
|
|
||||||
# This may need to be changed on some platforms; but the configure
|
|
||||||
# script is supposed to take care of it for you. If that fails, or
|
|
||||||
# picks the wrong thing, please file a bug report.
|
|
||||||
#
|
|
||||||
# (Locations.)
|
# (Locations.)
|
||||||
#
|
#
|
||||||
# BUILDTOP Top of tree where .o files go.
|
# BUILDTOP Top of tree where .o files go.
|
||||||
@ -479,7 +470,7 @@ MORECFLAGS+=-I$(INSTALLTOP)/include
|
|||||||
LDFLAGS+=-nostdlib -L$(INSTALLTOP)/lib $(INSTALLTOP)/lib/crt0.o
|
LDFLAGS+=-nostdlib -L$(INSTALLTOP)/lib $(INSTALLTOP)/lib/crt0.o
|
||||||
MORELIBS+=-lc
|
MORELIBS+=-lc
|
||||||
LIBDEPS+=$(INSTALLTOP)/lib/crt0.o $(INSTALLTOP)/lib/libc.a
|
LIBDEPS+=$(INSTALLTOP)/lib/crt0.o $(INSTALLTOP)/lib/libc.a
|
||||||
|
LIBS+=-ltest161
|
||||||
############################################################
|
############################################################
|
||||||
|
|
||||||
# end.
|
# end.
|
||||||
|
@ -56,7 +56,7 @@ all-local: $(MYBUILDDIR) .WAIT $(MYBUILDDIR)/$(_LIB_)
|
|||||||
install-staging-local: $(TOOLDIR)/hostlib .WAIT $(TOOLDIR)/hostlib/$(_LIB_)
|
install-staging-local: $(TOOLDIR)/hostlib .WAIT $(TOOLDIR)/hostlib/$(_LIB_)
|
||||||
$(TOOLDIR)/hostlib/$(_LIB_): $(MYBUILDDIR)/$(_LIB_)
|
$(TOOLDIR)/hostlib/$(_LIB_): $(MYBUILDDIR)/$(_LIB_)
|
||||||
rm -f $(.TARGET)
|
rm -f $(.TARGET)
|
||||||
ln $(MYBUILDDIR)/$(_LIB_) $(.TARGET) || \
|
ln $(MYBUILDDIR)/$(_LIB_) $(.TARGET) >/dev/null 2>&1 || \
|
||||||
cp $(MYBUILDDIR)/$(_LIB_) $(.TARGET)
|
cp $(MYBUILDDIR)/$(_LIB_) $(.TARGET)
|
||||||
|
|
||||||
install-local:
|
install-local:
|
||||||
|
@ -76,14 +76,14 @@ cleanhostprog:
|
|||||||
install-staging-local: $(_INSTALLDIR_) .WAIT $(_INSTALLDIR_)/$(_PROG_)
|
install-staging-local: $(_INSTALLDIR_) .WAIT $(_INSTALLDIR_)/$(_PROG_)
|
||||||
$(_INSTALLDIR_)/$(_PROG_): $(MYBUILDDIR)/$(_PROG_)
|
$(_INSTALLDIR_)/$(_PROG_): $(MYBUILDDIR)/$(_PROG_)
|
||||||
rm -f $(.TARGET)
|
rm -f $(.TARGET)
|
||||||
ln $(MYBUILDDIR)/$(_PROG_) $(.TARGET) || \
|
ln $(MYBUILDDIR)/$(_PROG_) $(.TARGET) >/dev/null 2>&1 || \
|
||||||
cp $(MYBUILDDIR)/$(_PROG_) $(.TARGET)
|
cp $(MYBUILDDIR)/$(_PROG_) $(.TARGET)
|
||||||
|
|
||||||
.if defined(HOSTBINDIR)
|
.if defined(HOSTBINDIR)
|
||||||
install-local: install-hostprog
|
install-local: install-hostprog
|
||||||
install-hostprog: $(OSTREE)$(HOSTBINDIR) $(MYBUILDDIR)/$(_PROG_)
|
install-hostprog: $(OSTREE)$(HOSTBINDIR) $(MYBUILDDIR)/$(_PROG_)
|
||||||
rm -f $(OSTREE)$(HOSTBINDIR)/$(_PROG_)
|
rm -f $(OSTREE)$(HOSTBINDIR)/$(_PROG_)
|
||||||
ln $(MYBUILDDIR)/$(_PROG_) $(OSTREE)$(HOSTBINDIR)/$(_PROG_) || \
|
ln $(MYBUILDDIR)/$(_PROG_) $(OSTREE)$(HOSTBINDIR)/$(_PROG_) >/dev/null 2>&1 || \
|
||||||
cp $(MYBUILDDIR)/$(_PROG_) $(OSTREE)$(HOSTBINDIR)/$(_PROG_)
|
cp $(MYBUILDDIR)/$(_PROG_) $(OSTREE)$(HOSTBINDIR)/$(_PROG_)
|
||||||
.else
|
.else
|
||||||
install-local:
|
install-local:
|
||||||
|
@ -163,6 +163,9 @@ includelinks:
|
|||||||
clean:
|
clean:
|
||||||
rm -f *.o *.a tags $(KERNEL)
|
rm -f *.o *.a tags $(KERNEL)
|
||||||
rm -rf includelinks
|
rm -rf includelinks
|
||||||
|
@ABSTOP=$$(readlink -f $(TOP))
|
||||||
|
rm -f $(OSTREE)/.src
|
||||||
|
rm -f $(TOP)/.root
|
||||||
|
|
||||||
distclean cleandir: clean
|
distclean cleandir: clean
|
||||||
rm -f .depend
|
rm -f .depend
|
||||||
@ -188,6 +191,9 @@ install:
|
|||||||
cp $(KERNEL) $(OSTREE)/$(KERNEL)-$(CONFNAME)
|
cp $(KERNEL) $(OSTREE)/$(KERNEL)-$(CONFNAME)
|
||||||
-rm -f $(OSTREE)/$(KERNEL)
|
-rm -f $(OSTREE)/$(KERNEL)
|
||||||
ln -s $(KERNEL)-$(CONFNAME) $(OSTREE)/$(KERNEL)
|
ln -s $(KERNEL)-$(CONFNAME) $(OSTREE)/$(KERNEL)
|
||||||
|
@ABSTOP=$$(readlink -f $(TOP))
|
||||||
|
ln -Tsf $(ABSTOP) $(OSTREE)/.src
|
||||||
|
ln -Tsf $(OSTREE) $(ABSTOP)/.root
|
||||||
|
|
||||||
#
|
#
|
||||||
# Run tags on all the sources and header files. This is probably not
|
# Run tags on all the sources and header files. This is probably not
|
||||||
|
@ -59,13 +59,13 @@ all-local: $(MYBUILDDIR) .WAIT $(MYBUILDDIR)/$(_LIB_)
|
|||||||
install-staging-local: $(INSTALLTOP)$(LIBDIR) .WAIT $(INSTALLTOP)$(LIBDIR)/$(_LIB_)
|
install-staging-local: $(INSTALLTOP)$(LIBDIR) .WAIT $(INSTALLTOP)$(LIBDIR)/$(_LIB_)
|
||||||
$(INSTALLTOP)$(LIBDIR)/$(_LIB_): $(MYBUILDDIR)/$(_LIB_)
|
$(INSTALLTOP)$(LIBDIR)/$(_LIB_): $(MYBUILDDIR)/$(_LIB_)
|
||||||
rm -f $(.TARGET)
|
rm -f $(.TARGET)
|
||||||
ln $(MYBUILDDIR)/$(_LIB_) $(.TARGET) || \
|
ln $(MYBUILDDIR)/$(_LIB_) $(.TARGET) >/dev/null 2>&1 || \
|
||||||
cp $(MYBUILDDIR)/$(_LIB_) $(.TARGET)
|
cp $(MYBUILDDIR)/$(_LIB_) $(.TARGET)
|
||||||
|
|
||||||
install-local: $(OSTREE)$(LIBDIR) $(MYBUILDDIR)/$(_LIB_)
|
install-local: $(OSTREE)$(LIBDIR) $(MYBUILDDIR)/$(_LIB_)
|
||||||
@echo "Warning: manually installing library without relinking anything"
|
@echo "Warning: manually installing library without relinking anything"
|
||||||
rm -f $(OSTREE)$(LIBDIR)/$(_LIB_)
|
rm -f $(OSTREE)$(LIBDIR)/$(_LIB_)
|
||||||
ln $(MYBUILDDIR)/$(_LIB_) $(OSTREE)$(LIBDIR)/$(_LIB_) || \
|
ln $(MYBUILDDIR)/$(_LIB_) $(OSTREE)$(LIBDIR)/$(_LIB_) >/dev/null 2>&1 || \
|
||||||
cp $(MYBUILDDIR)/$(_LIB_) $(OSTREE)$(LIBDIR)/$(_LIB_)
|
cp $(MYBUILDDIR)/$(_LIB_) $(OSTREE)$(LIBDIR)/$(_LIB_)
|
||||||
|
|
||||||
# Build the library.
|
# Build the library.
|
||||||
|
@ -44,14 +44,14 @@ install-staging-local: $(INSTALLTOP)$(MANDIR) .WAIT
|
|||||||
install-staging-local: $(INSTALLTOP)$(MANDIR)/$(_F_)
|
install-staging-local: $(INSTALLTOP)$(MANDIR)/$(_F_)
|
||||||
$(INSTALLTOP)$(MANDIR)/$(_F_): $(_F_)
|
$(INSTALLTOP)$(MANDIR)/$(_F_): $(_F_)
|
||||||
rm -f $(.TARGET)
|
rm -f $(.TARGET)
|
||||||
ln $(_F_) $(.TARGET) || cp $(_F_) $(.TARGET)
|
ln $(_F_) $(.TARGET) >/dev/null 2>&1 || cp $(_F_) $(.TARGET)
|
||||||
.endfor
|
.endfor
|
||||||
|
|
||||||
install-local: $(OSTREE)$(MANDIR) .WAIT installmanpages
|
install-local: $(OSTREE)$(MANDIR) .WAIT installmanpages
|
||||||
installmanpages:
|
installmanpages:
|
||||||
.for _F_ in $(MANFILES)
|
.for _F_ in $(MANFILES)
|
||||||
rm -f $(OSTREE)$(MANDIR)/$(_F_)
|
rm -f $(OSTREE)$(MANDIR)/$(_F_)
|
||||||
ln $(_F_) $(OSTREE)$(MANDIR)/$(_F_) || \
|
ln $(_F_) $(OSTREE)$(MANDIR)/$(_F_) >/dev/null 2>&1 || \
|
||||||
cp $(_F_) $(OSTREE)$(MANDIR)/$(_F_)
|
cp $(_F_) $(OSTREE)$(MANDIR)/$(_F_)
|
||||||
.endfor
|
.endfor
|
||||||
|
|
||||||
|
@ -61,13 +61,13 @@ cleanprog:
|
|||||||
install-staging-local: $(INSTALLTOP)$(BINDIR) .WAIT $(INSTALLTOP)$(BINDIR)/$(PROG)
|
install-staging-local: $(INSTALLTOP)$(BINDIR) .WAIT $(INSTALLTOP)$(BINDIR)/$(PROG)
|
||||||
$(INSTALLTOP)$(BINDIR)/$(PROG): $(MYBUILDDIR)/$(PROG)
|
$(INSTALLTOP)$(BINDIR)/$(PROG): $(MYBUILDDIR)/$(PROG)
|
||||||
rm -f $(.TARGET)
|
rm -f $(.TARGET)
|
||||||
ln $(MYBUILDDIR)/$(PROG) $(.TARGET) || \
|
ln $(MYBUILDDIR)/$(PROG) $(.TARGET) >/dev/null 2>&1 || \
|
||||||
cp $(MYBUILDDIR)/$(PROG) $(.TARGET)
|
cp $(MYBUILDDIR)/$(PROG) $(.TARGET)
|
||||||
|
|
||||||
install-local: install-prog
|
install-local: install-prog
|
||||||
install-prog: $(OSTREE)$(BINDIR) $(MYBUILDDIR)/$(PROG)
|
install-prog: $(OSTREE)$(BINDIR) $(MYBUILDDIR)/$(PROG)
|
||||||
rm -f $(OSTREE)$(BINDIR)/$(PROG)
|
rm -f $(OSTREE)$(BINDIR)/$(PROG)
|
||||||
ln $(MYBUILDDIR)/$(PROG) $(OSTREE)$(BINDIR)/$(PROG) || \
|
ln $(MYBUILDDIR)/$(PROG) $(OSTREE)$(BINDIR)/$(PROG) >/dev/null 2>&1 || \
|
||||||
cp $(MYBUILDDIR)/$(PROG) $(OSTREE)$(BINDIR)/$(PROG)
|
cp $(MYBUILDDIR)/$(PROG) $(OSTREE)$(BINDIR)/$(PROG)
|
||||||
|
|
||||||
# Link the program.
|
# Link the program.
|
||||||
|
61
test161/commands/asst2.tc
Normal file
61
test161/commands/asst2.tc
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
templates:
|
||||||
|
- name: /testbin/consoletest
|
||||||
|
panics: maybe
|
||||||
|
output:
|
||||||
|
- text: "/testbin/consoletest: Able was i ere i saw elbA"
|
||||||
|
- name: /testbin/opentest
|
||||||
|
panics: maybe
|
||||||
|
- name: /testbin/readwritetest
|
||||||
|
panics: maybe
|
||||||
|
output:
|
||||||
|
- text: "/testbin/readwritetest: h4xa0rRq0Vgbc96tiYJ^!#nXzZSAKPO"
|
||||||
|
- name: /testbin/closetest
|
||||||
|
panics: maybe
|
||||||
|
- name: /testbin/fileonlytest
|
||||||
|
panics: maybe
|
||||||
|
- name: /testbin/redirect
|
||||||
|
- name: /testbin/sparsefile
|
||||||
|
panics: maybe
|
||||||
|
- name: /testbin/badcall
|
||||||
|
- name: faulter
|
||||||
|
- name: /testbin/forkbomb
|
||||||
|
timesout: yes
|
||||||
|
timeout: 15.0
|
||||||
|
- name: kmalloc
|
||||||
|
output:
|
||||||
|
- text: "kmalloc: out of memory"
|
||||||
|
- name: /testbin/crash
|
||||||
|
- name: /testbin/forktest
|
||||||
|
- name: /testbin/randcall
|
||||||
|
- name: /testbin/shelltest
|
||||||
|
output:
|
||||||
|
- text: "/testbin/shelltest: line-1: Able was i ere i saw elbA"
|
||||||
|
- text: "/testbin/shelltest: line-2: Able was i ere i saw elbA"
|
||||||
|
- text: "/testbin/shelltest: line-3: Able was i ere i saw elbA"
|
||||||
|
- name: /testbin/argtest
|
||||||
|
input:
|
||||||
|
- "{{randString 1 2}}"
|
||||||
|
- "{{randString 4 5}}"
|
||||||
|
- "{{randString 9 10}}"
|
||||||
|
- "{{randString 10 11}}"
|
||||||
|
- "{{randString 11 12}}"
|
||||||
|
- "{{randString 12 13}}"
|
||||||
|
- "{{randString 13 14}}"
|
||||||
|
- "{{randString 200 513}}"
|
||||||
|
output:
|
||||||
|
- text: "/testbin/argtest: argc: {{add 1 .ArgLen}}"
|
||||||
|
- text: "/testbin/argtest: /testbin/argtest"
|
||||||
|
- text: "{{range $index, $element := .Args}}/testbin/argtest: {{$element}}\n{{end}}"
|
||||||
|
- text: "/testbin/argtest: [NULL]"
|
||||||
|
- name: /testbin/bigexec
|
||||||
|
- name: /testbin/factorial
|
||||||
|
input:
|
||||||
|
- "{{randInt 6 10}}"
|
||||||
|
output:
|
||||||
|
- text: "/testbin/factorial: {{$n:= index .Args 0 | atoi}}{{factorial $n}}\n"
|
||||||
|
- name: /testbin/add
|
||||||
|
input:
|
||||||
|
- "{{randInt 2 1000}}"
|
||||||
|
- "{{randInt 2 4000}}"
|
||||||
|
output:
|
||||||
|
- text: "/testbin/add: {{$x:= index .Args 0 | atoi}}{{$y := index .Args 1 | atoi}}{{add $x $y}}"
|
6
test161/commands/coremap.tc
Normal file
6
test161/commands/coremap.tc
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
templates:
|
||||||
|
- name: km1
|
||||||
|
- name: km2
|
||||||
|
- name: km3
|
||||||
|
- name: km4
|
||||||
|
- name: km5
|
34
test161/commands/misc.tc
Normal file
34
test161/commands/misc.tc
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
# These commands expect no output, but must not panic
|
||||||
|
templates:
|
||||||
|
- name: tt1
|
||||||
|
output:
|
||||||
|
- text: ""
|
||||||
|
|
||||||
|
- name: tt2
|
||||||
|
output:
|
||||||
|
- text: ""
|
||||||
|
|
||||||
|
- name: tt3
|
||||||
|
output:
|
||||||
|
- text: ""
|
||||||
|
|
||||||
|
- name: khu
|
||||||
|
output:
|
||||||
|
- text: ""
|
||||||
|
|
||||||
|
- name: q
|
||||||
|
output:
|
||||||
|
- text: ""
|
||||||
|
|
||||||
|
- name: s
|
||||||
|
output:
|
||||||
|
- text: ""
|
||||||
|
|
||||||
|
- name: boot
|
||||||
|
output:
|
||||||
|
- text:
|
||||||
|
|
||||||
|
- name: exit
|
||||||
|
output:
|
||||||
|
- text: ""
|
||||||
|
|
38
test161/commands/sync.tc
Normal file
38
test161/commands/sync.tc
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
templates:
|
||||||
|
- name: sem1
|
||||||
|
- name: lt1
|
||||||
|
- name: lt2
|
||||||
|
panics: yes
|
||||||
|
output:
|
||||||
|
- text: "lt2: Should panic..."
|
||||||
|
- name: lt3
|
||||||
|
panics: yes
|
||||||
|
output:
|
||||||
|
- text: "lt3: Should panic..."
|
||||||
|
- name: cvt1
|
||||||
|
- name: cvt2
|
||||||
|
- name: cvt3
|
||||||
|
panics: yes
|
||||||
|
output:
|
||||||
|
- text: "cvt3: Should panic..."
|
||||||
|
- name: cvt4
|
||||||
|
panics: yes
|
||||||
|
output:
|
||||||
|
- text: "cvt4: Should panic..."
|
||||||
|
- name: cvt5
|
||||||
|
- name: rwt1
|
||||||
|
- name: rwt2
|
||||||
|
- name: rwt3
|
||||||
|
panics: yes
|
||||||
|
output:
|
||||||
|
- text: "rwt3: Should panic..."
|
||||||
|
- name: rwt4
|
||||||
|
panics: yes
|
||||||
|
output:
|
||||||
|
- text: "rwt4: Should panic..."
|
||||||
|
- name: rwt5
|
||||||
|
panics: yes
|
||||||
|
output:
|
||||||
|
- text: "rwt5: Should panic..."
|
||||||
|
- name: sp1
|
||||||
|
- name: sp2
|
52
test161/commands/vm.tc
Normal file
52
test161/commands/vm.tc
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
templates:
|
||||||
|
#Single tests - everything has the default output
|
||||||
|
- name: /testbin/bigfork
|
||||||
|
- name: /testbin/ctest
|
||||||
|
- name: /testbin/huge
|
||||||
|
- name: /testbin/matmult
|
||||||
|
- name: /testbin/palin
|
||||||
|
- name: /testbin/parallelvm
|
||||||
|
- name: /testbin/sbrktest
|
||||||
|
- name: /testbin/sort
|
||||||
|
- name: /testbin/stacktest
|
||||||
|
- name: /testbin/zero
|
||||||
|
|
||||||
|
#Triples
|
||||||
|
- name: /testbin/triplehuge
|
||||||
|
output:
|
||||||
|
- {text: /testbin/huge, external: true, trusted: true}
|
||||||
|
- {text: /testbin/huge, external: true, trusted: true}
|
||||||
|
- {text: /testbin/huge, external: true, trusted: true}
|
||||||
|
- name: /testbin/triplemat
|
||||||
|
output:
|
||||||
|
- {text: /testbin/matmult, external: true, trusted: true}
|
||||||
|
- {text: /testbin/matmult, external: true, trusted: true}
|
||||||
|
- {text: /testbin/matmult, external: true, trusted: true}
|
||||||
|
- name: /testbin/triplesort
|
||||||
|
output:
|
||||||
|
- {text: /testbin/sort, external: true, trusted: true}
|
||||||
|
- {text: /testbin/sort, external: true, trusted: true}
|
||||||
|
- {text: /testbin/sort, external: true, trusted: true}
|
||||||
|
|
||||||
|
#Quints
|
||||||
|
- name: /testbin/quinthuge
|
||||||
|
output:
|
||||||
|
- {text: /testbin/huge, external: true, trusted: true}
|
||||||
|
- {text: /testbin/huge, external: true, trusted: true}
|
||||||
|
- {text: /testbin/huge, external: true, trusted: true}
|
||||||
|
- {text: /testbin/huge, external: true, trusted: true}
|
||||||
|
- {text: /testbin/huge, external: true, trusted: true}
|
||||||
|
- name: /testbin/quintmat
|
||||||
|
output:
|
||||||
|
- {text: /testbin/matmult, external: true, trusted: true}
|
||||||
|
- {text: /testbin/matmult, external: true, trusted: true}
|
||||||
|
- {text: /testbin/matmult, external: true, trusted: true}
|
||||||
|
- {text: /testbin/matmult, external: true, trusted: true}
|
||||||
|
- {text: /testbin/matmult, external: true, trusted: true}
|
||||||
|
- name: /testbin/quintsort
|
||||||
|
output:
|
||||||
|
- {text: /testbin/sort, external: true, trusted: true}
|
||||||
|
- {text: /testbin/sort, external: true, trusted: true}
|
||||||
|
- {text: /testbin/sort, external: true, trusted: true}
|
||||||
|
- {text: /testbin/sort, external: true, trusted: true}
|
||||||
|
- {text: /testbin/sort, external: true, trusted: true}
|
70
test161/tags/all.td
Normal file
70
test161/tags/all.td
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
tags:
|
||||||
|
- name: badcall
|
||||||
|
desc: "All badcall tests for the various system calls"
|
||||||
|
- name: boot
|
||||||
|
desc: "Tests that check if your kernel can boot"
|
||||||
|
- name: console
|
||||||
|
desc: "Tests that check if you have a working userspace console"
|
||||||
|
- name: coremap
|
||||||
|
desc: "All coremap-related tests"
|
||||||
|
- name: crash
|
||||||
|
desc: "Tests that attempt to crash your kernel"
|
||||||
|
- name: cvs
|
||||||
|
desc: "Condition variable tests"
|
||||||
|
- name: filesyscalls
|
||||||
|
desc: "Filesystem syscall tests, e.g. read, write, open, close, etc."
|
||||||
|
- name: kleaks
|
||||||
|
desc: "Synch tests that also check for memory leaks"
|
||||||
|
- name: locks
|
||||||
|
desc: "Kernel lock tests"
|
||||||
|
- name: not-dumbvm
|
||||||
|
desc: "Tests that verify your coremap is not using dumbvm"
|
||||||
|
- name: not-dumbvm-vm
|
||||||
|
desc: "Tests that verify your VM system is not using dumbvm"
|
||||||
|
- name: proc
|
||||||
|
desc: "Misc. process system call tests"
|
||||||
|
- name: procsyscalls
|
||||||
|
desc: "Tests that test process system calls, e.g. fork, exec, waitpid"
|
||||||
|
- name: rwlocks
|
||||||
|
desc: "Reader/writer lock tests"
|
||||||
|
- name: sbrk
|
||||||
|
desc: "sbrk tests"
|
||||||
|
- name: semaphores
|
||||||
|
desc: "Kernel semaphore tests"
|
||||||
|
- name: shell
|
||||||
|
desc: "Tests that check for a working userspace shell"
|
||||||
|
- name: stability
|
||||||
|
desc: "System call stability tests that stress test and check various error conditions"
|
||||||
|
- name: stability-vm
|
||||||
|
desc: "VM stress testing"
|
||||||
|
- name: swap
|
||||||
|
desc: "Tests that stress test your VM swapping implementation"
|
||||||
|
- name: swap-basic
|
||||||
|
desc: "Less stressful swap tests to ensure a swapping implementation"
|
||||||
|
- name: synch
|
||||||
|
desc: "All sychronization primitive tests"
|
||||||
|
- name: synchprobs
|
||||||
|
desc: "Synchronization problems that test your ablility to use synch primitives"
|
||||||
|
- name: sys_close
|
||||||
|
desc: "close() syscall tests"
|
||||||
|
- name: sys_dup2
|
||||||
|
desc: "dup2() syscall tests"
|
||||||
|
- name: sys_exec
|
||||||
|
desc: "exec() syscall tests"
|
||||||
|
- name: sys_fork
|
||||||
|
desc: "fork() syscall tests"
|
||||||
|
- name: sys_lseek
|
||||||
|
desc: "lseek() syscall tests"
|
||||||
|
- name: sys_open
|
||||||
|
desc: "open() syscall tests"
|
||||||
|
- name: sys_read
|
||||||
|
desc: "read() syscall tests"
|
||||||
|
- name: sys_write
|
||||||
|
desc: "write() syscall tests"
|
||||||
|
- name: syscalls
|
||||||
|
desc: "Tests that check the basic functionality of your system call implementations"
|
||||||
|
- name: threads
|
||||||
|
desc: "Kernel thread tests"
|
||||||
|
- name: vm
|
||||||
|
desc: "All non-swapping VM tests"
|
||||||
|
|
40
test161/targets/asst1.tt
Normal file
40
test161/targets/asst1.tt
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
name: asst1
|
||||||
|
print_name: ASST1
|
||||||
|
description: >
|
||||||
|
In this assignment you will implement new synchronization
|
||||||
|
primitives for OS/161 and use them to solve several synchronization problems.
|
||||||
|
version: 1
|
||||||
|
points: 50
|
||||||
|
type: asst
|
||||||
|
kconfig: ASST1
|
||||||
|
tests:
|
||||||
|
- id: synch/lt1.t
|
||||||
|
points: 8
|
||||||
|
- id: synch/lt2.t
|
||||||
|
points: 1
|
||||||
|
- id: synch/lt3.t
|
||||||
|
points: 1
|
||||||
|
- id: synch/cvt1.t
|
||||||
|
points: 4
|
||||||
|
- id: synch/cvt2.t
|
||||||
|
points: 3
|
||||||
|
- id: synch/cvt3.t
|
||||||
|
points: 1
|
||||||
|
- id: synch/cvt4.t
|
||||||
|
points: 1
|
||||||
|
- id: synch/cvt5.t
|
||||||
|
points: 1
|
||||||
|
- id: synch/rwt1.t
|
||||||
|
points: 5
|
||||||
|
- id: synch/rwt2.t
|
||||||
|
points: 2
|
||||||
|
- id: synch/rwt3.t
|
||||||
|
points: 1
|
||||||
|
- id: synch/rwt4.t
|
||||||
|
points: 1
|
||||||
|
- id: synch/rwt5.t
|
||||||
|
points: 1
|
||||||
|
- id: synchprobs/sp1.t
|
||||||
|
points: 10
|
||||||
|
- id: synchprobs/sp2.t
|
||||||
|
points: 10
|
51
test161/targets/asst2-single.tt
Normal file
51
test161/targets/asst2-single.tt
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
name: asst2-single
|
||||||
|
print_name: "ASST2 (Single)"
|
||||||
|
description: >
|
||||||
|
In this assignment you will add process and system call support to your
|
||||||
|
OS/161 kernel. This is the single-submitter version for students that are
|
||||||
|
working alone and were provided the file system system calls.
|
||||||
|
leaderboard: false
|
||||||
|
version: 1
|
||||||
|
points: 80
|
||||||
|
type: asst
|
||||||
|
kconfig: ASST2
|
||||||
|
userland: true
|
||||||
|
tests:
|
||||||
|
# Process system call tests (50 points)
|
||||||
|
- id: syscalls/forktest.t
|
||||||
|
points: 15
|
||||||
|
- id: syscalls/shell.t
|
||||||
|
points: 10
|
||||||
|
- id: syscalls/argtest.t
|
||||||
|
points: 5
|
||||||
|
- id: syscalls/bigexec.t
|
||||||
|
points: 10
|
||||||
|
- id: syscalls/factorial.t
|
||||||
|
points: 5
|
||||||
|
- id: syscalls/add.t
|
||||||
|
points: 5
|
||||||
|
# Stability tests (30 points)
|
||||||
|
# Bad calls (5 points)
|
||||||
|
- id: stability/badcall/badcall-execv.t
|
||||||
|
points: 3
|
||||||
|
- id: stability/badcall/badcall-waitpid.t
|
||||||
|
points: 2
|
||||||
|
# crash
|
||||||
|
- id: stability/crash/crash-allS.t
|
||||||
|
points: 3
|
||||||
|
# randcall
|
||||||
|
- id: stability/randcall.t
|
||||||
|
points: 2
|
||||||
|
commands:
|
||||||
|
- id: /testbin/randcall
|
||||||
|
args:
|
||||||
|
- "-f"
|
||||||
|
- "-c 100"
|
||||||
|
- "-r 421"
|
||||||
|
- "2"
|
||||||
|
# forkbomb
|
||||||
|
- id: stability/forkbomb.t
|
||||||
|
points: 10
|
||||||
|
# forktest
|
||||||
|
- id: stability/forktest-stability.t
|
||||||
|
points: 10
|
15
test161/targets/asst2.1.tt
Normal file
15
test161/targets/asst2.1.tt
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
name: asst2.1
|
||||||
|
print_name: ASST2.1
|
||||||
|
description: >
|
||||||
|
In this part of the assignment, you will add console support.
|
||||||
|
version: 1
|
||||||
|
points: 20
|
||||||
|
type: asst
|
||||||
|
kconfig: ASST2
|
||||||
|
userland: true
|
||||||
|
meta_name: asst2
|
||||||
|
leaderboard: false
|
||||||
|
tests:
|
||||||
|
# Make sure the console works (10 points)
|
||||||
|
- id: syscalls/consoletest.t
|
||||||
|
points: 20
|
76
test161/targets/asst2.2.tt
Normal file
76
test161/targets/asst2.2.tt
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
name: asst2.2
|
||||||
|
print_name: ASST2.1
|
||||||
|
description: >
|
||||||
|
In this assignment you will add process and system call support to your
|
||||||
|
OS/161 kernel.
|
||||||
|
version: 1
|
||||||
|
points: 130
|
||||||
|
type: asst
|
||||||
|
kconfig: ASST2
|
||||||
|
userland: true
|
||||||
|
meta_name: asst2
|
||||||
|
leaderboard: false
|
||||||
|
tests:
|
||||||
|
# File system system calls (47 points)
|
||||||
|
- id: syscalls/opentest.t
|
||||||
|
points: 5
|
||||||
|
- id: syscalls/closetest.t
|
||||||
|
points: 5
|
||||||
|
- id: syscalls/readwritetest.t
|
||||||
|
points: 10
|
||||||
|
- id: syscalls/fileonlytest.t
|
||||||
|
points: 12
|
||||||
|
- id: syscalls/redirect.t
|
||||||
|
points: 10
|
||||||
|
- id: syscalls/sparsefile.t
|
||||||
|
points: 5
|
||||||
|
# Process system call tests (47 points)
|
||||||
|
- id: syscalls/forktest.t
|
||||||
|
points: 15
|
||||||
|
- id: syscalls/shell.t
|
||||||
|
points: 10
|
||||||
|
- id: syscalls/argtest.t
|
||||||
|
points: 5
|
||||||
|
- id: syscalls/bigexec.t
|
||||||
|
points: 8
|
||||||
|
- id: syscalls/factorial.t
|
||||||
|
points: 5
|
||||||
|
- id: syscalls/add.t
|
||||||
|
points: 4
|
||||||
|
# Stability tests (36 points)
|
||||||
|
# Bad calls (8 points)
|
||||||
|
- id: stability/badcall/badcall-open.t
|
||||||
|
points: 1
|
||||||
|
- id: stability/badcall/badcall-close.t
|
||||||
|
points: 1
|
||||||
|
- id: stability/badcall/badcall-read.t
|
||||||
|
points: 1
|
||||||
|
- id: stability/badcall/badcall-write.t
|
||||||
|
points: 1
|
||||||
|
- id: stability/badcall/badcall-lseek.t
|
||||||
|
points: 1
|
||||||
|
- id: stability/badcall/badcall-dup2.t
|
||||||
|
points: 1
|
||||||
|
- id: stability/badcall/badcall-execv.t
|
||||||
|
points: 1
|
||||||
|
- id: stability/badcall/badcall-waitpid.t
|
||||||
|
points: 1
|
||||||
|
# crash
|
||||||
|
- id: stability/crash/crash-allS.t
|
||||||
|
points: 4
|
||||||
|
# randcall
|
||||||
|
- id: stability/randcall.t
|
||||||
|
points: 4
|
||||||
|
commands:
|
||||||
|
- id: /testbin/randcall
|
||||||
|
args:
|
||||||
|
- "-f"
|
||||||
|
- "-c 100"
|
||||||
|
- "-r 421"
|
||||||
|
- "2"
|
||||||
|
# forkbomb
|
||||||
|
- id: stability/forkbomb.t
|
||||||
|
points: 10
|
||||||
|
# forktest
|
||||||
|
- id: stability/forktest-stability.t
|
||||||
|
points: 10
|
12
test161/targets/asst2.tt
Normal file
12
test161/targets/asst2.tt
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
name: asst2
|
||||||
|
print_name: ASST2
|
||||||
|
description: >
|
||||||
|
In this assignment you will add process and system call support to your
|
||||||
|
OS/161 kernel.
|
||||||
|
version: 2
|
||||||
|
points: 150
|
||||||
|
type: asst
|
||||||
|
kconfig: ASST2
|
||||||
|
userland: true
|
||||||
|
is_meta_target: true
|
||||||
|
sub_target_names: ["asst2.1", "asst2.2"]
|
31
test161/targets/asst3.1.tt
Normal file
31
test161/targets/asst3.1.tt
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
name: asst3.1
|
||||||
|
print_name: ASST3.1
|
||||||
|
description: >
|
||||||
|
In this part of ASST3, you will begin writing your own VM by adding your
|
||||||
|
coremap and page allocator.
|
||||||
|
version: 1
|
||||||
|
points: 60
|
||||||
|
type: asst
|
||||||
|
kconfig: ASST3
|
||||||
|
userland: true
|
||||||
|
meta_name: asst3
|
||||||
|
leaderboard: false
|
||||||
|
tests:
|
||||||
|
- id: coremap/not-dumbvm.t
|
||||||
|
points: 15
|
||||||
|
- id: coremap/km1.t
|
||||||
|
points: 5
|
||||||
|
mem_leak_points: 2
|
||||||
|
- id: coremap/km2.t
|
||||||
|
points: 5
|
||||||
|
mem_leak_points: 2
|
||||||
|
- id: coremap/km3.t
|
||||||
|
points: 5
|
||||||
|
mem_leak_points: 2
|
||||||
|
- id: coremap/km4.t
|
||||||
|
points: 15
|
||||||
|
mem_leak_points: 2
|
||||||
|
- id: coremap/coremap-loose.t
|
||||||
|
points: 5
|
||||||
|
- id: coremap/coremap-tight.t
|
||||||
|
points: 10
|
55
test161/targets/asst3.2.tt
Normal file
55
test161/targets/asst3.2.tt
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
name: asst3.2
|
||||||
|
print_name: ASST3.2
|
||||||
|
description: >
|
||||||
|
In this part of ASST3, you will add virtual address spaces to your VM.
|
||||||
|
version: 1
|
||||||
|
points: 120
|
||||||
|
type: asst
|
||||||
|
kconfig: ASST3
|
||||||
|
userland: true
|
||||||
|
meta_name: asst3
|
||||||
|
leaderboard: false
|
||||||
|
tests:
|
||||||
|
# Basic VM (30 points)
|
||||||
|
- id: vm/not-dumbvm-vm.t
|
||||||
|
points: 5
|
||||||
|
- id: vm/sort.t
|
||||||
|
points: 5
|
||||||
|
- id: vm/palin.t
|
||||||
|
points: 5
|
||||||
|
- id: vm/matmult.t
|
||||||
|
mem_leak_points: 2
|
||||||
|
points: 5
|
||||||
|
- id: vm/ctest.t
|
||||||
|
points: 5
|
||||||
|
- id: vm/stacktest.t
|
||||||
|
points: 5
|
||||||
|
|
||||||
|
# Concurrent VM (50 points)
|
||||||
|
- id: vm/bigfork.t
|
||||||
|
points: 10
|
||||||
|
mem_leak_points: 2
|
||||||
|
- id: vm/parallelvm.t
|
||||||
|
points: 10
|
||||||
|
- id: vm/quintsort.t
|
||||||
|
points: 10
|
||||||
|
- id: vm/quintmat.t
|
||||||
|
points: 10
|
||||||
|
- id: vm/quinthuge.t
|
||||||
|
points: 10
|
||||||
|
|
||||||
|
# Heap (10 points)
|
||||||
|
- id: vm/sbrktest.t
|
||||||
|
points: 8
|
||||||
|
mem_leak_points: 2
|
||||||
|
- id: vm/sbrk-badcall.t
|
||||||
|
points: 2
|
||||||
|
|
||||||
|
# Stress tests/misc (30 points)
|
||||||
|
- id: vm/zero.t
|
||||||
|
points: 5
|
||||||
|
- id: vm/stability/vm-stability.t
|
||||||
|
points: 20
|
||||||
|
mem_leak_points: 2
|
||||||
|
- id: vm/stability/forkbomb.t
|
||||||
|
points: 5
|
37
test161/targets/asst3.3.tt
Normal file
37
test161/targets/asst3.3.tt
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
name: asst3.3
|
||||||
|
print_name: ASST3.3
|
||||||
|
description: >
|
||||||
|
In this part of ASST3, you will add swapping to your VM.
|
||||||
|
version: 1
|
||||||
|
points: 120
|
||||||
|
type: asst
|
||||||
|
kconfig: ASST3
|
||||||
|
userland: true
|
||||||
|
meta_name: asst3
|
||||||
|
leaderboard: false
|
||||||
|
tests:
|
||||||
|
# Basic Swapping (40 points)
|
||||||
|
- id: vm/swap/sort.t
|
||||||
|
mem_leak_points: 2
|
||||||
|
points: 20
|
||||||
|
- id: vm/swap/matmult.t
|
||||||
|
mem_leak_points: 2
|
||||||
|
points: 20
|
||||||
|
|
||||||
|
# Concurrent Swapping (80 points)
|
||||||
|
- id: vm/swap/bigfork.t
|
||||||
|
points: 10
|
||||||
|
- id: vm/swap/bigfork-32.t
|
||||||
|
points: 15
|
||||||
|
mem_leak_points: 2
|
||||||
|
- id: vm/swap/parallelvm.t
|
||||||
|
points: 10
|
||||||
|
- id: vm/swap/parallelvm-32.t
|
||||||
|
points: 15
|
||||||
|
- id: vm/swap/quintsort.t
|
||||||
|
points: 10
|
||||||
|
- id: vm/swap/quintmat.t
|
||||||
|
points: 10
|
||||||
|
- id: vm/swap/quinthuge.t
|
||||||
|
points: 10
|
||||||
|
mem_leak_points: 2
|
12
test161/targets/asst3.tt
Normal file
12
test161/targets/asst3.tt
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
name: asst3
|
||||||
|
print_name: ASST3
|
||||||
|
description: >
|
||||||
|
In this assignment you will add support for virtual memory to your OS/161
|
||||||
|
kernel.
|
||||||
|
version: 4
|
||||||
|
points: 300
|
||||||
|
type: asst
|
||||||
|
kconfig: ASST3
|
||||||
|
userland: true
|
||||||
|
is_meta_target: true
|
||||||
|
sub_target_names: ["asst3.1", "asst3.2", "asst3.3"]
|
9
test161/tests/boot.t
Normal file
9
test161/tests/boot.t
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
---
|
||||||
|
name: Kernel Boot
|
||||||
|
description:
|
||||||
|
Tests whether your kernel will boot.
|
||||||
|
tags: [boot]
|
||||||
|
sys161:
|
||||||
|
cpus: 2
|
||||||
|
---
|
||||||
|
q
|
11
test161/tests/coremap/coremap-loose.t
Normal file
11
test161/tests/coremap/coremap-loose.t
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
---
|
||||||
|
name: "Coremap Test (Loose Bounds)"
|
||||||
|
description: >
|
||||||
|
Allocates and frees all physical memory multiple times checking
|
||||||
|
that the amount allocated is within a reasonable bound.
|
||||||
|
tags: [coremap]
|
||||||
|
depends: [not-dumbvm.t]
|
||||||
|
sys161:
|
||||||
|
ram: 4M
|
||||||
|
---
|
||||||
|
| km5 --avail 32 --kernel 125
|
11
test161/tests/coremap/coremap-tight.t
Normal file
11
test161/tests/coremap/coremap-tight.t
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
---
|
||||||
|
name: "Coremap Test (Tight Bounds)"
|
||||||
|
description: >
|
||||||
|
Allocates and frees all physical memory multiple times checking
|
||||||
|
that the amount allocated is within a reasonable bound.
|
||||||
|
tags: [coremap]
|
||||||
|
depends: [not-dumbvm.t]
|
||||||
|
sys161:
|
||||||
|
ram: 4M
|
||||||
|
---
|
||||||
|
| km5 --avail 20 --kernel 105
|
9
test161/tests/coremap/km1.t
Normal file
9
test161/tests/coremap/km1.t
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
---
|
||||||
|
name: "Basic kmalloc Test"
|
||||||
|
description: >
|
||||||
|
Tests the kernel subpage allocator by allocating a large number of objects
|
||||||
|
and freeing them somewhat later.
|
||||||
|
tags: [coremap]
|
||||||
|
depends: [not-dumbvm.t]
|
||||||
|
---
|
||||||
|
| km1
|
8
test161/tests/coremap/km2.t
Normal file
8
test161/tests/coremap/km2.t
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
---
|
||||||
|
name: "kmalloc Stress Test"
|
||||||
|
description: >
|
||||||
|
Similar to km1 but uses multiple concurrent threads.
|
||||||
|
tags: [coremap]
|
||||||
|
depends: [not-dumbvm.t]
|
||||||
|
---
|
||||||
|
| km2
|
9
test161/tests/coremap/km3.t
Normal file
9
test161/tests/coremap/km3.t
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
---
|
||||||
|
name: "Large kmalloc Test"
|
||||||
|
description: >
|
||||||
|
Stresses the subpage allocator by allocating and freeing a large number of
|
||||||
|
objects of various sizes.
|
||||||
|
tags: [coremap]
|
||||||
|
depends: [not-dumbvm.t]
|
||||||
|
---
|
||||||
|
| km3 5000
|
9
test161/tests/coremap/km4.t
Normal file
9
test161/tests/coremap/km4.t
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
---
|
||||||
|
name: "Multipage allococation Test"
|
||||||
|
description: >
|
||||||
|
Allocates and frees between 1 and 5 pages a number of times by a number of
|
||||||
|
concurrent threads.
|
||||||
|
tags: [coremap]
|
||||||
|
depends: [not-dumbvm.t]
|
||||||
|
---
|
||||||
|
| km4
|
9
test161/tests/coremap/not-dumbvm.t
Normal file
9
test161/tests/coremap/not-dumbvm.t
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
---
|
||||||
|
name: "Smarter VM"
|
||||||
|
description:
|
||||||
|
Test whether you are using dumbvm by allocating and freeing all physical
|
||||||
|
memory multiple times.
|
||||||
|
tags: [coremap, not-dumbvm]
|
||||||
|
depends: [boot]
|
||||||
|
---
|
||||||
|
| km5
|
10
test161/tests/stability/badcall/badcall-close.t
Normal file
10
test161/tests/stability/badcall/badcall-close.t
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
---
|
||||||
|
name: "Bad Close"
|
||||||
|
description: >
|
||||||
|
Stability test for sys_close.
|
||||||
|
tags: [badcall,stability]
|
||||||
|
depends: [shell]
|
||||||
|
sys161:
|
||||||
|
ram: 2M
|
||||||
|
---
|
||||||
|
$ /testbin/badcall f
|
10
test161/tests/stability/badcall/badcall-dup2.t
Normal file
10
test161/tests/stability/badcall/badcall-dup2.t
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
---
|
||||||
|
name: "Bad Dup"
|
||||||
|
description:
|
||||||
|
Stability test for sys_dup2.
|
||||||
|
tags: [badcall,stability]
|
||||||
|
depends: [shell]
|
||||||
|
sys161:
|
||||||
|
ram: 2M
|
||||||
|
---
|
||||||
|
$ /testbin/badcall w
|
10
test161/tests/stability/badcall/badcall-execv.t
Normal file
10
test161/tests/stability/badcall/badcall-execv.t
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
---
|
||||||
|
name: "Bad Exec"
|
||||||
|
description:
|
||||||
|
Stability test for sys_exec.
|
||||||
|
tags: [badcall,stability]
|
||||||
|
depends: [shell]
|
||||||
|
sys161:
|
||||||
|
ram: 2M
|
||||||
|
---
|
||||||
|
$ /testbin/badcall a
|
10
test161/tests/stability/badcall/badcall-lseek.t
Normal file
10
test161/tests/stability/badcall/badcall-lseek.t
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
---
|
||||||
|
name: "Bad Seek"
|
||||||
|
description:
|
||||||
|
Stability test for sys_lseek.
|
||||||
|
tags: [badcall,stability]
|
||||||
|
depends: [shell]
|
||||||
|
sys161:
|
||||||
|
ram: 2M
|
||||||
|
---
|
||||||
|
$ /testbin/badcall j
|
10
test161/tests/stability/badcall/badcall-open.t
Normal file
10
test161/tests/stability/badcall/badcall-open.t
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
---
|
||||||
|
name: "Bad Open"
|
||||||
|
description:
|
||||||
|
Stability test for sys_open.
|
||||||
|
tags: [badcall,stability]
|
||||||
|
depends: [shell]
|
||||||
|
sys161:
|
||||||
|
ram: 2M
|
||||||
|
---
|
||||||
|
$ /testbin/badcall c
|
10
test161/tests/stability/badcall/badcall-read.t
Normal file
10
test161/tests/stability/badcall/badcall-read.t
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
---
|
||||||
|
name: "Bad Read"
|
||||||
|
description:
|
||||||
|
Stability test for sys_read.
|
||||||
|
tags: [badcall,stability]
|
||||||
|
depends: [shell]
|
||||||
|
sys161:
|
||||||
|
ram: 2M
|
||||||
|
---
|
||||||
|
$ /testbin/badcall d
|
10
test161/tests/stability/badcall/badcall-waitpid.t
Normal file
10
test161/tests/stability/badcall/badcall-waitpid.t
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
---
|
||||||
|
name: "Bad Wait"
|
||||||
|
description:
|
||||||
|
Stability test for sys_wait.
|
||||||
|
tags: [badcall,stability]
|
||||||
|
depends: [shell]
|
||||||
|
sys161:
|
||||||
|
ram: 2M
|
||||||
|
---
|
||||||
|
$ /testbin/badcall b
|
10
test161/tests/stability/badcall/badcall-write.t
Normal file
10
test161/tests/stability/badcall/badcall-write.t
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
---
|
||||||
|
name: "Bad Write"
|
||||||
|
description:
|
||||||
|
Stability test for sys_write.
|
||||||
|
tags: [badcall,stability]
|
||||||
|
depends: [shell]
|
||||||
|
sys161:
|
||||||
|
ram: 2M
|
||||||
|
---
|
||||||
|
$ /testbin/badcall e
|
11
test161/tests/stability/crash/crash-allS.t
Normal file
11
test161/tests/stability/crash/crash-allS.t
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
---
|
||||||
|
name: "Crash"
|
||||||
|
description: >
|
||||||
|
Tests whether your system correctly handles a variety of bad process
|
||||||
|
behavior.
|
||||||
|
tags: [crash,stability]
|
||||||
|
depends: [shell,sys_fork]
|
||||||
|
sys161:
|
||||||
|
ram: 4M
|
||||||
|
---
|
||||||
|
$ /testbin/crash *
|
10
test161/tests/stability/crash/crash-template
Normal file
10
test161/tests/stability/crash/crash-template
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
---
|
||||||
|
name: "Crash-template Test"
|
||||||
|
description:
|
||||||
|
Tests whether your system correctly handles a variety of
|
||||||
|
illegal attempts from userspace processes to access resources that
|
||||||
|
do not belong to it. Please see userland/testbin/crash for more info.
|
||||||
|
tags: [stability, crash]
|
||||||
|
depends: [console]
|
||||||
|
---
|
||||||
|
p /extratests/crash-template
|
54
test161/tests/stability/crash/script.py
Normal file
54
test161/tests/stability/crash/script.py
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
import os,sys
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
RANGE=[chr(i) for i in range(ord('a'), ord('p'))]
|
||||||
|
|
||||||
|
# First create crash-a/b/c.t files
|
||||||
|
template = open('crash-template').read()
|
||||||
|
|
||||||
|
def add_sys161_opts(content, sys161_opts):
|
||||||
|
content = content.split('\n')
|
||||||
|
idx = content[1:].index('---') + 1
|
||||||
|
content.insert(idx, sys161_opts.strip())
|
||||||
|
content = '\n'.join(content)
|
||||||
|
return content
|
||||||
|
|
||||||
|
def create_crash(char, sys161_opts=None):
|
||||||
|
content = template.replace('-template', '-%s' % char)
|
||||||
|
content = content.replace(', crash]', ', crash-fork]')
|
||||||
|
content = content.replace('[console]', '[console, /asst2/process/forktest.t]')
|
||||||
|
if sys161_opts:
|
||||||
|
content = add_sys161_opts(content, sys161_opts)
|
||||||
|
|
||||||
|
with open('crash-%s.t' % char, 'w') as f:
|
||||||
|
f.write(content)
|
||||||
|
|
||||||
|
# now do the F version
|
||||||
|
content = template.replace('-template', '-%sF' % char)
|
||||||
|
if sys161_opts:
|
||||||
|
content = add_sys161_opts(content, sys161_opts)
|
||||||
|
with open('crash-%sF.t' % char, 'w') as f:
|
||||||
|
f.write(content)
|
||||||
|
|
||||||
|
for char in RANGE:
|
||||||
|
create_crash(char)
|
||||||
|
|
||||||
|
# Now do the 'all'
|
||||||
|
sys161_opts = \
|
||||||
|
'''
|
||||||
|
sys161:
|
||||||
|
ram: 2M
|
||||||
|
'''
|
||||||
|
create_crash('all', sys161_opts)
|
||||||
|
|
||||||
|
#p = subprocess.Popen('ls *.t', shell=True, stdout=subprocess.PIPE)
|
||||||
|
#stdout, stderr = p.communicate()
|
||||||
|
#files = stdout.strip().split('\n')
|
||||||
|
#
|
||||||
|
#for f in files:
|
||||||
|
# name, ext = os.path.splitext(f)
|
||||||
|
#
|
||||||
|
# new_file = name + 'F' + ext
|
||||||
|
# letters = name[name.index('-'):]
|
||||||
|
# subprocess.check_call('cp %s %s' % (f, new_file), shell=True)
|
||||||
|
# subprocess.check_call('''sed -i 's/%s/%sF/g' %s''' % (letters, letters, new_file), shell=True)
|
10
test161/tests/stability/faulter.t
Normal file
10
test161/tests/stability/faulter.t
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
---
|
||||||
|
name: "Faulter Test"
|
||||||
|
description:
|
||||||
|
Tests whether kill_curthread is implemented correctly.
|
||||||
|
Attempts to access an invalid memory address expecting the kernel
|
||||||
|
to gracefully kill the current process instead of panicking.
|
||||||
|
tags: [proc]
|
||||||
|
depends: [console]
|
||||||
|
---
|
||||||
|
p /testbin/faulter
|
17
test161/tests/stability/forkbomb.t
Normal file
17
test161/tests/stability/forkbomb.t
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
---
|
||||||
|
name: "Calm Like a Fork Bomb"
|
||||||
|
tags: [stability]
|
||||||
|
depends: [console,sys_fork]
|
||||||
|
sys161:
|
||||||
|
ram: 2M
|
||||||
|
monitor:
|
||||||
|
progresstimeout: 40.0
|
||||||
|
user:
|
||||||
|
enablemin: true
|
||||||
|
min: 0.001
|
||||||
|
max: 1.0
|
||||||
|
kernel:
|
||||||
|
enablemin: true
|
||||||
|
min: 0.01
|
||||||
|
---
|
||||||
|
p /testbin/forkbomb
|
14
test161/tests/stability/forktest-stability.t
Normal file
14
test161/tests/stability/forktest-stability.t
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
---
|
||||||
|
name: "Fork Stability Test"
|
||||||
|
description:
|
||||||
|
Runs forktest 5 times to check for synchronization issues.
|
||||||
|
tags: [stability]
|
||||||
|
depends: [shell]
|
||||||
|
sys161:
|
||||||
|
ram: 16M
|
||||||
|
---
|
||||||
|
$ /testbin/forktest
|
||||||
|
$ /testbin/forktest
|
||||||
|
$ /testbin/forktest
|
||||||
|
$ /testbin/forktest
|
||||||
|
$ /testbin/forktest
|
10
test161/tests/stability/randcall.t
Normal file
10
test161/tests/stability/randcall.t
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
---
|
||||||
|
name: "Randcall Test"
|
||||||
|
description: >
|
||||||
|
Invokes system calls with random arguments.
|
||||||
|
tags: [stability]
|
||||||
|
depends: [shell]
|
||||||
|
sys161:
|
||||||
|
ram: 16M
|
||||||
|
---
|
||||||
|
$ /testbin/randcall -f -c 100 -r 421 2
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user