import
This commit is contained in:
10
qemu/util/Makefile.objs
Normal file
10
qemu/util/Makefile.objs
Normal file
@@ -0,0 +1,10 @@
|
||||
util-obj-y = cutils.o unicode.o qemu-timer-common.o
|
||||
util-obj-$(CONFIG_WIN32) += oslib-win32.o qemu-thread-win32.o
|
||||
util-obj-$(CONFIG_POSIX) += oslib-posix.o qemu-thread-posix.o
|
||||
util-obj-y += module.o
|
||||
util-obj-y += bitmap.o bitops.o
|
||||
util-obj-y += error.o
|
||||
util-obj-y += aes.o
|
||||
util-obj-y += qemu-option.o
|
||||
util-obj-y += crc32c.o
|
||||
util-obj-y += host-utils.o
|
||||
1652
qemu/util/aes.c
Normal file
1652
qemu/util/aes.c
Normal file
File diff suppressed because it is too large
Load Diff
256
qemu/util/bitmap.c
Normal file
256
qemu/util/bitmap.c
Normal file
@@ -0,0 +1,256 @@
|
||||
/*
|
||||
* Bitmap Module
|
||||
*
|
||||
* Stolen from linux/src/lib/bitmap.c
|
||||
*
|
||||
* Copyright (C) 2010 Corentin Chary
|
||||
*
|
||||
* This source code is licensed under the GNU General Public License,
|
||||
* Version 2.
|
||||
*/
|
||||
|
||||
#include "qemu/bitops.h"
|
||||
#include "qemu/bitmap.h"
|
||||
|
||||
/*
|
||||
* bitmaps provide an array of bits, implemented using an an
|
||||
* array of unsigned longs. The number of valid bits in a
|
||||
* given bitmap does _not_ need to be an exact multiple of
|
||||
* BITS_PER_LONG.
|
||||
*
|
||||
* The possible unused bits in the last, partially used word
|
||||
* of a bitmap are 'don't care'. The implementation makes
|
||||
* no particular effort to keep them zero. It ensures that
|
||||
* their value will not affect the results of any operation.
|
||||
* The bitmap operations that return Boolean (bitmap_empty,
|
||||
* for example) or scalar (bitmap_weight, for example) results
|
||||
* carefully filter out these unused bits from impacting their
|
||||
* results.
|
||||
*
|
||||
* These operations actually hold to a slightly stronger rule:
|
||||
* if you don't input any bitmaps to these ops that have some
|
||||
* unused bits set, then they won't output any set unused bits
|
||||
* in output bitmaps.
|
||||
*
|
||||
* The byte ordering of bitmaps is more natural on little
|
||||
* endian architectures.
|
||||
*/
|
||||
|
||||
int slow_bitmap_empty(const unsigned long *bitmap, long bits)
|
||||
{
|
||||
long k, lim = bits/BITS_PER_LONG;
|
||||
|
||||
for (k = 0; k < lim; ++k) {
|
||||
if (bitmap[k]) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (bits % BITS_PER_LONG) {
|
||||
if (bitmap[k] & BITMAP_LAST_WORD_MASK(bits)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int slow_bitmap_full(const unsigned long *bitmap, long bits)
|
||||
{
|
||||
long k, lim = bits/BITS_PER_LONG;
|
||||
|
||||
for (k = 0; k < lim; ++k) {
|
||||
if (~bitmap[k]) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (bits % BITS_PER_LONG) {
|
||||
if (~bitmap[k] & BITMAP_LAST_WORD_MASK(bits)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int slow_bitmap_equal(const unsigned long *bitmap1,
|
||||
const unsigned long *bitmap2, long bits)
|
||||
{
|
||||
long k, lim = bits/BITS_PER_LONG;
|
||||
|
||||
for (k = 0; k < lim; ++k) {
|
||||
if (bitmap1[k] != bitmap2[k]) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (bits % BITS_PER_LONG) {
|
||||
if ((bitmap1[k] ^ bitmap2[k]) & BITMAP_LAST_WORD_MASK(bits)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void slow_bitmap_complement(unsigned long *dst, const unsigned long *src,
|
||||
long bits)
|
||||
{
|
||||
long k, lim = bits/BITS_PER_LONG;
|
||||
|
||||
for (k = 0; k < lim; ++k) {
|
||||
dst[k] = ~src[k];
|
||||
}
|
||||
|
||||
if (bits % BITS_PER_LONG) {
|
||||
dst[k] = ~src[k] & BITMAP_LAST_WORD_MASK(bits);
|
||||
}
|
||||
}
|
||||
|
||||
int slow_bitmap_and(unsigned long *dst, const unsigned long *bitmap1,
|
||||
const unsigned long *bitmap2, long bits)
|
||||
{
|
||||
long k;
|
||||
long nr = BITS_TO_LONGS(bits);
|
||||
unsigned long result = 0;
|
||||
|
||||
for (k = 0; k < nr; k++) {
|
||||
result |= (dst[k] = bitmap1[k] & bitmap2[k]);
|
||||
}
|
||||
return result != 0;
|
||||
}
|
||||
|
||||
void slow_bitmap_or(unsigned long *dst, const unsigned long *bitmap1,
|
||||
const unsigned long *bitmap2, long bits)
|
||||
{
|
||||
long k;
|
||||
long nr = BITS_TO_LONGS(bits);
|
||||
|
||||
for (k = 0; k < nr; k++) {
|
||||
dst[k] = bitmap1[k] | bitmap2[k];
|
||||
}
|
||||
}
|
||||
|
||||
void slow_bitmap_xor(unsigned long *dst, const unsigned long *bitmap1,
|
||||
const unsigned long *bitmap2, long bits)
|
||||
{
|
||||
long k;
|
||||
long nr = BITS_TO_LONGS(bits);
|
||||
|
||||
for (k = 0; k < nr; k++) {
|
||||
dst[k] = bitmap1[k] ^ bitmap2[k];
|
||||
}
|
||||
}
|
||||
|
||||
int slow_bitmap_andnot(unsigned long *dst, const unsigned long *bitmap1,
|
||||
const unsigned long *bitmap2, long bits)
|
||||
{
|
||||
long k;
|
||||
long nr = BITS_TO_LONGS(bits);
|
||||
unsigned long result = 0;
|
||||
|
||||
for (k = 0; k < nr; k++) {
|
||||
result |= (dst[k] = bitmap1[k] & ~bitmap2[k]);
|
||||
}
|
||||
return result != 0;
|
||||
}
|
||||
|
||||
#define BITMAP_FIRST_WORD_MASK(start) (~0UL << ((start) % BITS_PER_LONG))
|
||||
|
||||
void bitmap_set(unsigned long *map, long start, long nr)
|
||||
{
|
||||
unsigned long *p = map + BIT_WORD(start);
|
||||
const long size = start + nr;
|
||||
int bits_to_set = BITS_PER_LONG - (start % BITS_PER_LONG);
|
||||
unsigned long mask_to_set = BITMAP_FIRST_WORD_MASK(start);
|
||||
|
||||
while (nr - bits_to_set >= 0) {
|
||||
*p |= mask_to_set;
|
||||
nr -= bits_to_set;
|
||||
bits_to_set = BITS_PER_LONG;
|
||||
mask_to_set = ~0UL;
|
||||
p++;
|
||||
}
|
||||
if (nr) {
|
||||
mask_to_set &= BITMAP_LAST_WORD_MASK(size);
|
||||
*p |= mask_to_set;
|
||||
}
|
||||
}
|
||||
|
||||
void bitmap_clear(unsigned long *map, long start, long nr)
|
||||
{
|
||||
unsigned long *p = map + BIT_WORD(start);
|
||||
const long size = start + nr;
|
||||
int bits_to_clear = BITS_PER_LONG - (start % BITS_PER_LONG);
|
||||
unsigned long mask_to_clear = BITMAP_FIRST_WORD_MASK(start);
|
||||
|
||||
while (nr - bits_to_clear >= 0) {
|
||||
*p &= ~mask_to_clear;
|
||||
nr -= bits_to_clear;
|
||||
bits_to_clear = BITS_PER_LONG;
|
||||
mask_to_clear = ~0UL;
|
||||
p++;
|
||||
}
|
||||
if (nr) {
|
||||
mask_to_clear &= BITMAP_LAST_WORD_MASK(size);
|
||||
*p &= ~mask_to_clear;
|
||||
}
|
||||
}
|
||||
|
||||
#define ALIGN_MASK(x,mask) (((x)+(mask))&~(mask))
|
||||
|
||||
/**
|
||||
* bitmap_find_next_zero_area - find a contiguous aligned zero area
|
||||
* @map: The address to base the search on
|
||||
* @size: The bitmap size in bits
|
||||
* @start: The bitnumber to start searching at
|
||||
* @nr: The number of zeroed bits we're looking for
|
||||
* @align_mask: Alignment mask for zero area
|
||||
*
|
||||
* The @align_mask should be one less than a power of 2; the effect is that
|
||||
* the bit offset of all zero areas this function finds is multiples of that
|
||||
* power of 2. A @align_mask of 0 means no alignment is required.
|
||||
*/
|
||||
unsigned long bitmap_find_next_zero_area(unsigned long *map,
|
||||
unsigned long size,
|
||||
unsigned long start,
|
||||
unsigned long nr,
|
||||
unsigned long align_mask)
|
||||
{
|
||||
unsigned long index, end, i;
|
||||
again:
|
||||
index = find_next_zero_bit(map, size, start);
|
||||
|
||||
/* Align allocation */
|
||||
index = ALIGN_MASK(index, align_mask);
|
||||
|
||||
end = index + nr;
|
||||
if (end > size) {
|
||||
return end;
|
||||
}
|
||||
i = find_next_bit(map, end, index);
|
||||
if (i < end) {
|
||||
start = i + 1;
|
||||
goto again;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
int slow_bitmap_intersects(const unsigned long *bitmap1,
|
||||
const unsigned long *bitmap2, long bits)
|
||||
{
|
||||
long k, lim = bits/BITS_PER_LONG;
|
||||
|
||||
for (k = 0; k < lim; ++k) {
|
||||
if (bitmap1[k] & bitmap2[k]) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (bits % BITS_PER_LONG) {
|
||||
if ((bitmap1[k] & bitmap2[k]) & BITMAP_LAST_WORD_MASK(bits)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
158
qemu/util/bitops.c
Normal file
158
qemu/util/bitops.c
Normal file
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
* Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
* Copyright (C) 2008 IBM Corporation
|
||||
* Written by Rusty Russell <rusty@rustcorp.com.au>
|
||||
* (Inspired by David Howell's find_next_bit implementation)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include "qemu/bitops.h"
|
||||
|
||||
#define BITOP_WORD(nr) ((nr) / BITS_PER_LONG)
|
||||
|
||||
/*
|
||||
* Find the next set bit in a memory region.
|
||||
*/
|
||||
unsigned long find_next_bit(const unsigned long *addr, unsigned long size,
|
||||
unsigned long offset)
|
||||
{
|
||||
const unsigned long *p = addr + BITOP_WORD(offset);
|
||||
unsigned long result = offset & ~(BITS_PER_LONG-1);
|
||||
unsigned long tmp;
|
||||
|
||||
if (offset >= size) {
|
||||
return size;
|
||||
}
|
||||
size -= result;
|
||||
offset %= BITS_PER_LONG;
|
||||
if (offset) {
|
||||
tmp = *(p++);
|
||||
tmp &= (~0UL << offset);
|
||||
if (size < BITS_PER_LONG) {
|
||||
goto found_first;
|
||||
}
|
||||
if (tmp) {
|
||||
goto found_middle;
|
||||
}
|
||||
size -= BITS_PER_LONG;
|
||||
result += BITS_PER_LONG;
|
||||
}
|
||||
while (size >= 4*BITS_PER_LONG) {
|
||||
unsigned long d1, d2, d3;
|
||||
tmp = *p;
|
||||
d1 = *(p+1);
|
||||
d2 = *(p+2);
|
||||
d3 = *(p+3);
|
||||
if (tmp) {
|
||||
goto found_middle;
|
||||
}
|
||||
if (d1 | d2 | d3) {
|
||||
break;
|
||||
}
|
||||
p += 4;
|
||||
result += 4*BITS_PER_LONG;
|
||||
size -= 4*BITS_PER_LONG;
|
||||
}
|
||||
while (size >= BITS_PER_LONG) {
|
||||
if ((tmp = *(p++))) {
|
||||
goto found_middle;
|
||||
}
|
||||
result += BITS_PER_LONG;
|
||||
size -= BITS_PER_LONG;
|
||||
}
|
||||
if (!size) {
|
||||
return result;
|
||||
}
|
||||
tmp = *p;
|
||||
|
||||
found_first:
|
||||
tmp &= (~0UL >> (BITS_PER_LONG - size));
|
||||
if (tmp == 0UL) { /* Are any bits set? */
|
||||
return result + size; /* Nope. */
|
||||
}
|
||||
found_middle:
|
||||
return result + ctzl(tmp);
|
||||
}
|
||||
|
||||
/*
|
||||
* This implementation of find_{first,next}_zero_bit was stolen from
|
||||
* Linus' asm-alpha/bitops.h.
|
||||
*/
|
||||
unsigned long find_next_zero_bit(const unsigned long *addr, unsigned long size,
|
||||
unsigned long offset)
|
||||
{
|
||||
const unsigned long *p = addr + BITOP_WORD(offset);
|
||||
unsigned long result = offset & ~(BITS_PER_LONG-1);
|
||||
unsigned long tmp;
|
||||
|
||||
if (offset >= size) {
|
||||
return size;
|
||||
}
|
||||
size -= result;
|
||||
offset %= BITS_PER_LONG;
|
||||
if (offset) {
|
||||
tmp = *(p++);
|
||||
tmp |= ~0UL >> (BITS_PER_LONG - offset);
|
||||
if (size < BITS_PER_LONG) {
|
||||
goto found_first;
|
||||
}
|
||||
if (~tmp) {
|
||||
goto found_middle;
|
||||
}
|
||||
size -= BITS_PER_LONG;
|
||||
result += BITS_PER_LONG;
|
||||
}
|
||||
while (size & ~(BITS_PER_LONG-1)) {
|
||||
if (~(tmp = *(p++))) {
|
||||
goto found_middle;
|
||||
}
|
||||
result += BITS_PER_LONG;
|
||||
size -= BITS_PER_LONG;
|
||||
}
|
||||
if (!size) {
|
||||
return result;
|
||||
}
|
||||
tmp = *p;
|
||||
|
||||
found_first:
|
||||
tmp |= ~0UL << size;
|
||||
if (tmp == ~0UL) { /* Are any bits zero? */
|
||||
return result + size; /* Nope. */
|
||||
}
|
||||
found_middle:
|
||||
return result + ctzl(~tmp);
|
||||
}
|
||||
|
||||
unsigned long find_last_bit(const unsigned long *addr, unsigned long size)
|
||||
{
|
||||
unsigned long words;
|
||||
unsigned long tmp;
|
||||
|
||||
/* Start at final word. */
|
||||
words = size / BITS_PER_LONG;
|
||||
|
||||
/* Partial final word? */
|
||||
if (size & (BITS_PER_LONG-1)) {
|
||||
tmp = (addr[words] & (~0UL >> (BITS_PER_LONG
|
||||
- (size & (BITS_PER_LONG-1)))));
|
||||
if (tmp) {
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
|
||||
while (words) {
|
||||
tmp = addr[--words];
|
||||
if (tmp) {
|
||||
found:
|
||||
return words * BITS_PER_LONG + BITS_PER_LONG - 1 - clzl(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
/* Not found */
|
||||
return size;
|
||||
}
|
||||
115
qemu/util/crc32c.c
Normal file
115
qemu/util/crc32c.c
Normal file
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Castagnoli CRC32C Checksum Algorithm
|
||||
*
|
||||
* Polynomial: 0x11EDC6F41
|
||||
*
|
||||
* Castagnoli93: Guy Castagnoli and Stefan Braeuer and Martin Herrman
|
||||
* "Optimization of Cyclic Redundancy-Check Codes with 24
|
||||
* and 32 Parity Bits",IEEE Transactions on Communication,
|
||||
* Volume 41, Number 6, June 1993
|
||||
*
|
||||
* Copyright (c) 2013 Red Hat, Inc.,
|
||||
*
|
||||
* Authors:
|
||||
* Jeff Cody <jcody@redhat.com>
|
||||
*
|
||||
* Based on the Linux kernel cryptographic crc32c module,
|
||||
*
|
||||
* Copyright (c) 2004 Cisco Systems, Inc.
|
||||
* Copyright (c) 2008 Herbert Xu <herbert@gondor.apana.org.au>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "qemu-common.h"
|
||||
#include "qemu/crc32c.h"
|
||||
|
||||
/*
|
||||
* This is the CRC-32C table
|
||||
* Generated with:
|
||||
* width = 32 bits
|
||||
* poly = 0x1EDC6F41
|
||||
* reflect input bytes = true
|
||||
* reflect output bytes = true
|
||||
*/
|
||||
|
||||
static const uint32_t crc32c_table[256] = {
|
||||
0x00000000L, 0xF26B8303L, 0xE13B70F7L, 0x1350F3F4L,
|
||||
0xC79A971FL, 0x35F1141CL, 0x26A1E7E8L, 0xD4CA64EBL,
|
||||
0x8AD958CFL, 0x78B2DBCCL, 0x6BE22838L, 0x9989AB3BL,
|
||||
0x4D43CFD0L, 0xBF284CD3L, 0xAC78BF27L, 0x5E133C24L,
|
||||
0x105EC76FL, 0xE235446CL, 0xF165B798L, 0x030E349BL,
|
||||
0xD7C45070L, 0x25AFD373L, 0x36FF2087L, 0xC494A384L,
|
||||
0x9A879FA0L, 0x68EC1CA3L, 0x7BBCEF57L, 0x89D76C54L,
|
||||
0x5D1D08BFL, 0xAF768BBCL, 0xBC267848L, 0x4E4DFB4BL,
|
||||
0x20BD8EDEL, 0xD2D60DDDL, 0xC186FE29L, 0x33ED7D2AL,
|
||||
0xE72719C1L, 0x154C9AC2L, 0x061C6936L, 0xF477EA35L,
|
||||
0xAA64D611L, 0x580F5512L, 0x4B5FA6E6L, 0xB93425E5L,
|
||||
0x6DFE410EL, 0x9F95C20DL, 0x8CC531F9L, 0x7EAEB2FAL,
|
||||
0x30E349B1L, 0xC288CAB2L, 0xD1D83946L, 0x23B3BA45L,
|
||||
0xF779DEAEL, 0x05125DADL, 0x1642AE59L, 0xE4292D5AL,
|
||||
0xBA3A117EL, 0x4851927DL, 0x5B016189L, 0xA96AE28AL,
|
||||
0x7DA08661L, 0x8FCB0562L, 0x9C9BF696L, 0x6EF07595L,
|
||||
0x417B1DBCL, 0xB3109EBFL, 0xA0406D4BL, 0x522BEE48L,
|
||||
0x86E18AA3L, 0x748A09A0L, 0x67DAFA54L, 0x95B17957L,
|
||||
0xCBA24573L, 0x39C9C670L, 0x2A993584L, 0xD8F2B687L,
|
||||
0x0C38D26CL, 0xFE53516FL, 0xED03A29BL, 0x1F682198L,
|
||||
0x5125DAD3L, 0xA34E59D0L, 0xB01EAA24L, 0x42752927L,
|
||||
0x96BF4DCCL, 0x64D4CECFL, 0x77843D3BL, 0x85EFBE38L,
|
||||
0xDBFC821CL, 0x2997011FL, 0x3AC7F2EBL, 0xC8AC71E8L,
|
||||
0x1C661503L, 0xEE0D9600L, 0xFD5D65F4L, 0x0F36E6F7L,
|
||||
0x61C69362L, 0x93AD1061L, 0x80FDE395L, 0x72966096L,
|
||||
0xA65C047DL, 0x5437877EL, 0x4767748AL, 0xB50CF789L,
|
||||
0xEB1FCBADL, 0x197448AEL, 0x0A24BB5AL, 0xF84F3859L,
|
||||
0x2C855CB2L, 0xDEEEDFB1L, 0xCDBE2C45L, 0x3FD5AF46L,
|
||||
0x7198540DL, 0x83F3D70EL, 0x90A324FAL, 0x62C8A7F9L,
|
||||
0xB602C312L, 0x44694011L, 0x5739B3E5L, 0xA55230E6L,
|
||||
0xFB410CC2L, 0x092A8FC1L, 0x1A7A7C35L, 0xE811FF36L,
|
||||
0x3CDB9BDDL, 0xCEB018DEL, 0xDDE0EB2AL, 0x2F8B6829L,
|
||||
0x82F63B78L, 0x709DB87BL, 0x63CD4B8FL, 0x91A6C88CL,
|
||||
0x456CAC67L, 0xB7072F64L, 0xA457DC90L, 0x563C5F93L,
|
||||
0x082F63B7L, 0xFA44E0B4L, 0xE9141340L, 0x1B7F9043L,
|
||||
0xCFB5F4A8L, 0x3DDE77ABL, 0x2E8E845FL, 0xDCE5075CL,
|
||||
0x92A8FC17L, 0x60C37F14L, 0x73938CE0L, 0x81F80FE3L,
|
||||
0x55326B08L, 0xA759E80BL, 0xB4091BFFL, 0x466298FCL,
|
||||
0x1871A4D8L, 0xEA1A27DBL, 0xF94AD42FL, 0x0B21572CL,
|
||||
0xDFEB33C7L, 0x2D80B0C4L, 0x3ED04330L, 0xCCBBC033L,
|
||||
0xA24BB5A6L, 0x502036A5L, 0x4370C551L, 0xB11B4652L,
|
||||
0x65D122B9L, 0x97BAA1BAL, 0x84EA524EL, 0x7681D14DL,
|
||||
0x2892ED69L, 0xDAF96E6AL, 0xC9A99D9EL, 0x3BC21E9DL,
|
||||
0xEF087A76L, 0x1D63F975L, 0x0E330A81L, 0xFC588982L,
|
||||
0xB21572C9L, 0x407EF1CAL, 0x532E023EL, 0xA145813DL,
|
||||
0x758FE5D6L, 0x87E466D5L, 0x94B49521L, 0x66DF1622L,
|
||||
0x38CC2A06L, 0xCAA7A905L, 0xD9F75AF1L, 0x2B9CD9F2L,
|
||||
0xFF56BD19L, 0x0D3D3E1AL, 0x1E6DCDEEL, 0xEC064EEDL,
|
||||
0xC38D26C4L, 0x31E6A5C7L, 0x22B65633L, 0xD0DDD530L,
|
||||
0x0417B1DBL, 0xF67C32D8L, 0xE52CC12CL, 0x1747422FL,
|
||||
0x49547E0BL, 0xBB3FFD08L, 0xA86F0EFCL, 0x5A048DFFL,
|
||||
0x8ECEE914L, 0x7CA56A17L, 0x6FF599E3L, 0x9D9E1AE0L,
|
||||
0xD3D3E1ABL, 0x21B862A8L, 0x32E8915CL, 0xC083125FL,
|
||||
0x144976B4L, 0xE622F5B7L, 0xF5720643L, 0x07198540L,
|
||||
0x590AB964L, 0xAB613A67L, 0xB831C993L, 0x4A5A4A90L,
|
||||
0x9E902E7BL, 0x6CFBAD78L, 0x7FAB5E8CL, 0x8DC0DD8FL,
|
||||
0xE330A81AL, 0x115B2B19L, 0x020BD8EDL, 0xF0605BEEL,
|
||||
0x24AA3F05L, 0xD6C1BC06L, 0xC5914FF2L, 0x37FACCF1L,
|
||||
0x69E9F0D5L, 0x9B8273D6L, 0x88D28022L, 0x7AB90321L,
|
||||
0xAE7367CAL, 0x5C18E4C9L, 0x4F48173DL, 0xBD23943EL,
|
||||
0xF36E6F75L, 0x0105EC76L, 0x12551F82L, 0xE03E9C81L,
|
||||
0x34F4F86AL, 0xC69F7B69L, 0xD5CF889DL, 0x27A40B9EL,
|
||||
0x79B737BAL, 0x8BDCB4B9L, 0x988C474DL, 0x6AE7C44EL,
|
||||
0xBE2DA0A5L, 0x4C4623A6L, 0x5F16D052L, 0xAD7D5351L
|
||||
};
|
||||
|
||||
|
||||
uint32_t crc32c(uint32_t crc, const uint8_t *data, unsigned int length)
|
||||
{
|
||||
while (length--) {
|
||||
crc = crc32c_table[(crc ^ *data++) & 0xFFL] ^ (crc >> 8);
|
||||
}
|
||||
return crc^0xffffffff;
|
||||
}
|
||||
|
||||
419
qemu/util/cutils.c
Normal file
419
qemu/util/cutils.c
Normal file
@@ -0,0 +1,419 @@
|
||||
/*
|
||||
* Simple C functions to supplement the C library
|
||||
*
|
||||
* Copyright (c) 2006 Fabrice Bellard
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#include "qemu-common.h"
|
||||
#include "qemu/host-utils.h"
|
||||
#include <math.h>
|
||||
#include <limits.h>
|
||||
#include <errno.h>
|
||||
|
||||
|
||||
void strpadcpy(char *buf, int buf_size, const char *str, char pad)
|
||||
{
|
||||
int len = qemu_strnlen(str, buf_size);
|
||||
memcpy(buf, str, len);
|
||||
memset(buf + len, pad, buf_size - len);
|
||||
}
|
||||
|
||||
void pstrcpy(char *buf, int buf_size, const char *str)
|
||||
{
|
||||
int c;
|
||||
char *q = buf;
|
||||
|
||||
if (buf_size <= 0)
|
||||
return;
|
||||
|
||||
for(;;) {
|
||||
c = *str++;
|
||||
if (c == 0 || q >= buf + buf_size - 1)
|
||||
break;
|
||||
*q++ = c;
|
||||
}
|
||||
*q = '\0';
|
||||
}
|
||||
|
||||
/* strcat and truncate. */
|
||||
char *pstrcat(char *buf, int buf_size, const char *s)
|
||||
{
|
||||
int len;
|
||||
len = strlen(buf);
|
||||
if (len < buf_size)
|
||||
pstrcpy(buf + len, buf_size - len, s);
|
||||
return buf;
|
||||
}
|
||||
|
||||
int strstart(const char *str, const char *val, const char **ptr)
|
||||
{
|
||||
const char *p, *q;
|
||||
p = str;
|
||||
q = val;
|
||||
while (*q != '\0') {
|
||||
if (*p != *q)
|
||||
return 0;
|
||||
p++;
|
||||
q++;
|
||||
}
|
||||
if (ptr)
|
||||
*ptr = p;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int stristart(const char *str, const char *val, const char **ptr)
|
||||
{
|
||||
const char *p, *q;
|
||||
p = str;
|
||||
q = val;
|
||||
while (*q != '\0') {
|
||||
if (qemu_toupper(*p) != qemu_toupper(*q))
|
||||
return 0;
|
||||
p++;
|
||||
q++;
|
||||
}
|
||||
if (ptr)
|
||||
*ptr = p;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* XXX: use host strnlen if available ? */
|
||||
int qemu_strnlen(const char *s, int max_len)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; i < max_len; i++) {
|
||||
if (s[i] == '\0') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
char *qemu_strsep(char **input, const char *delim)
|
||||
{
|
||||
char *result = *input;
|
||||
if (result != NULL) {
|
||||
char *p;
|
||||
|
||||
for (p = result; *p != '\0'; p++) {
|
||||
if (strchr(delim, *p)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (*p == '\0') {
|
||||
*input = NULL;
|
||||
} else {
|
||||
*p = '\0';
|
||||
*input = p + 1;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
time_t mktimegm(struct tm *tm)
|
||||
{
|
||||
time_t t;
|
||||
int y = tm->tm_year + 1900, m = tm->tm_mon + 1, d = tm->tm_mday;
|
||||
if (m < 3) {
|
||||
m += 12;
|
||||
y--;
|
||||
}
|
||||
t = 86400ULL * (d + (153 * m - 457) / 5 + 365 * y + y / 4 - y / 100 +
|
||||
y / 400 - 719469);
|
||||
t += 3600 * tm->tm_hour + 60 * tm->tm_min + tm->tm_sec;
|
||||
return t;
|
||||
}
|
||||
|
||||
int qemu_fls(int i)
|
||||
{
|
||||
return 32 - clz32(i);
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure data goes on disk, but if possible do not bother to
|
||||
* write out the inode just for timestamp updates.
|
||||
*
|
||||
* Unfortunately even in 2009 many operating systems do not support
|
||||
* fdatasync and have to fall back to fsync.
|
||||
*/
|
||||
int qemu_fdatasync(int fd)
|
||||
{
|
||||
#ifdef CONFIG_FDATASYNC
|
||||
return fdatasync(fd);
|
||||
#else
|
||||
return fsync(fd);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
/* Sets a specific flag */
|
||||
int fcntl_setfl(int fd, int flag)
|
||||
{
|
||||
int flags;
|
||||
|
||||
flags = fcntl(fd, F_GETFL);
|
||||
if (flags == -1)
|
||||
return -errno;
|
||||
|
||||
if (fcntl(fd, F_SETFL, flags | flag) == -1)
|
||||
return -errno;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int64_t suffix_mul(char suffix, int64_t unit)
|
||||
{
|
||||
switch (qemu_toupper(suffix)) {
|
||||
case STRTOSZ_DEFSUFFIX_B:
|
||||
return 1;
|
||||
case STRTOSZ_DEFSUFFIX_KB:
|
||||
return unit;
|
||||
case STRTOSZ_DEFSUFFIX_MB:
|
||||
return unit * unit;
|
||||
case STRTOSZ_DEFSUFFIX_GB:
|
||||
return unit * unit * unit;
|
||||
case STRTOSZ_DEFSUFFIX_TB:
|
||||
return unit * unit * unit * unit;
|
||||
case STRTOSZ_DEFSUFFIX_PB:
|
||||
return unit * unit * unit * unit * unit;
|
||||
case STRTOSZ_DEFSUFFIX_EB:
|
||||
return unit * unit * unit * unit * unit * unit;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert string to bytes, allowing either B/b for bytes, K/k for KB,
|
||||
* M/m for MB, G/g for GB or T/t for TB. End pointer will be returned
|
||||
* in *end, if not NULL. Return -ERANGE on overflow, Return -EINVAL on
|
||||
* other error.
|
||||
*/
|
||||
int64_t strtosz_suffix_unit(const char *nptr, char **end,
|
||||
const char default_suffix, int64_t unit)
|
||||
{
|
||||
int64_t retval = -EINVAL;
|
||||
char *endptr;
|
||||
unsigned char c;
|
||||
int mul_required = 0;
|
||||
double val, mul, integral, fraction;
|
||||
|
||||
errno = 0;
|
||||
val = strtod(nptr, &endptr);
|
||||
if (isnan(val) || endptr == nptr || errno != 0) {
|
||||
goto fail;
|
||||
}
|
||||
fraction = modf(val, &integral);
|
||||
if (fraction != 0) {
|
||||
mul_required = 1;
|
||||
}
|
||||
c = *endptr;
|
||||
mul = suffix_mul(c, unit);
|
||||
if (mul >= 0) {
|
||||
endptr++;
|
||||
} else {
|
||||
mul = suffix_mul(default_suffix, unit);
|
||||
assert(mul >= 0);
|
||||
}
|
||||
if (mul == 1 && mul_required) {
|
||||
goto fail;
|
||||
}
|
||||
if ((val * mul >= INT64_MAX) || val < 0) {
|
||||
retval = -ERANGE;
|
||||
goto fail;
|
||||
}
|
||||
retval = val * mul;
|
||||
|
||||
fail:
|
||||
if (end) {
|
||||
*end = endptr;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
int64_t strtosz_suffix(const char *nptr, char **end, const char default_suffix)
|
||||
{
|
||||
return strtosz_suffix_unit(nptr, end, default_suffix, 1024);
|
||||
}
|
||||
|
||||
int64_t strtosz(const char *nptr, char **end)
|
||||
{
|
||||
return strtosz_suffix(nptr, end, STRTOSZ_DEFSUFFIX_MB);
|
||||
}
|
||||
|
||||
/**
|
||||
* parse_uint:
|
||||
*
|
||||
* @s: String to parse
|
||||
* @value: Destination for parsed integer value
|
||||
* @endptr: Destination for pointer to first character not consumed
|
||||
* @base: integer base, between 2 and 36 inclusive, or 0
|
||||
*
|
||||
* Parse unsigned integer
|
||||
*
|
||||
* Parsed syntax is like strtoull()'s: arbitrary whitespace, a single optional
|
||||
* '+' or '-', an optional "0x" if @base is 0 or 16, one or more digits.
|
||||
*
|
||||
* If @s is null, or @base is invalid, or @s doesn't start with an
|
||||
* integer in the syntax above, set *@value to 0, *@endptr to @s, and
|
||||
* return -EINVAL.
|
||||
*
|
||||
* Set *@endptr to point right beyond the parsed integer (even if the integer
|
||||
* overflows or is negative, all digits will be parsed and *@endptr will
|
||||
* point right beyond them).
|
||||
*
|
||||
* If the integer is negative, set *@value to 0, and return -ERANGE.
|
||||
*
|
||||
* If the integer overflows unsigned long long, set *@value to
|
||||
* ULLONG_MAX, and return -ERANGE.
|
||||
*
|
||||
* Else, set *@value to the parsed integer, and return 0.
|
||||
*/
|
||||
int parse_uint(const char *s, unsigned long long *value, char **endptr,
|
||||
int base)
|
||||
{
|
||||
int r = 0;
|
||||
char *endp = (char *)s;
|
||||
unsigned long long val = 0;
|
||||
|
||||
if (!s) {
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
val = strtoull(s, &endp, base);
|
||||
if (errno) {
|
||||
r = -errno;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (endp == s) {
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* make sure we reject negative numbers: */
|
||||
while (isspace((unsigned char)*s)) {
|
||||
s++;
|
||||
}
|
||||
if (*s == '-') {
|
||||
val = 0;
|
||||
r = -ERANGE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
*value = val;
|
||||
*endptr = endp;
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* parse_uint_full:
|
||||
*
|
||||
* @s: String to parse
|
||||
* @value: Destination for parsed integer value
|
||||
* @base: integer base, between 2 and 36 inclusive, or 0
|
||||
*
|
||||
* Parse unsigned integer from entire string
|
||||
*
|
||||
* Have the same behavior of parse_uint(), but with an additional check
|
||||
* for additional data after the parsed number. If extra characters are present
|
||||
* after the parsed number, the function will return -EINVAL, and *@v will
|
||||
* be set to 0.
|
||||
*/
|
||||
int parse_uint_full(const char *s, unsigned long long *value, int base)
|
||||
{
|
||||
char *endp;
|
||||
int r;
|
||||
|
||||
r = parse_uint(s, value, &endp, base);
|
||||
if (r < 0) {
|
||||
return r;
|
||||
}
|
||||
if (*endp) {
|
||||
*value = 0;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int qemu_parse_fd(const char *param)
|
||||
{
|
||||
long fd;
|
||||
char *endptr;
|
||||
|
||||
errno = 0;
|
||||
fd = strtol(param, &endptr, 10);
|
||||
if (param == endptr /* no conversion performed */ ||
|
||||
errno != 0 /* not representable as long; possibly others */ ||
|
||||
*endptr != '\0' /* final string not empty */ ||
|
||||
fd < 0 /* invalid as file descriptor */ ||
|
||||
fd > INT_MAX /* not representable as int */) {
|
||||
return -1;
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
/* round down to the nearest power of 2*/
|
||||
int64_t pow2floor(int64_t value)
|
||||
{
|
||||
if (!is_power_of_2(value)) {
|
||||
value = 0x8000000000000000ULL >> clz64(value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/*
|
||||
* Implementation of ULEB128 (http://en.wikipedia.org/wiki/LEB128)
|
||||
* Input is limited to 14-bit numbers
|
||||
*/
|
||||
int uleb128_encode_small(uint8_t *out, uint32_t n)
|
||||
{
|
||||
g_assert(n <= 0x3fff);
|
||||
if (n < 0x80) {
|
||||
*out++ = n;
|
||||
return 1;
|
||||
} else {
|
||||
*out++ = (n & 0x7f) | 0x80;
|
||||
*out++ = n >> 7;
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
int uleb128_decode_small(const uint8_t *in, uint32_t *n)
|
||||
{
|
||||
if (!(*in & 0x80)) {
|
||||
*n = *in++;
|
||||
return 1;
|
||||
} else {
|
||||
*n = *in++ & 0x7f;
|
||||
/* we exceed 14 bit number */
|
||||
if (*in & 0x80) {
|
||||
return -1;
|
||||
}
|
||||
*n |= *in++ << 7;
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
169
qemu/util/error.c
Normal file
169
qemu/util/error.c
Normal file
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
* QEMU Error Objects
|
||||
*
|
||||
* Copyright IBM, Corp. 2011
|
||||
*
|
||||
* Authors:
|
||||
* Anthony Liguori <aliguori@us.ibm.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU LGPL, version 2. See
|
||||
* the COPYING.LIB file in the top-level directory.
|
||||
*/
|
||||
|
||||
#include "qemu-common.h"
|
||||
#include "qapi/error.h"
|
||||
|
||||
struct Error
|
||||
{
|
||||
char *msg;
|
||||
ErrorClass err_class;
|
||||
};
|
||||
|
||||
Error *error_abort;
|
||||
|
||||
void error_set(Error **errp, ErrorClass err_class, const char *fmt, ...)
|
||||
{
|
||||
Error *err;
|
||||
va_list ap;
|
||||
int saved_errno = errno;
|
||||
|
||||
if (errp == NULL) {
|
||||
return;
|
||||
}
|
||||
assert(*errp == NULL);
|
||||
|
||||
err = g_malloc0(sizeof(*err));
|
||||
|
||||
va_start(ap, fmt);
|
||||
err->msg = g_strdup_vprintf(fmt, ap);
|
||||
va_end(ap);
|
||||
err->err_class = err_class;
|
||||
|
||||
if (errp == &error_abort) {
|
||||
abort();
|
||||
}
|
||||
|
||||
*errp = err;
|
||||
|
||||
errno = saved_errno;
|
||||
}
|
||||
|
||||
void error_set_errno(Error **errp, int os_errno, ErrorClass err_class,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
Error *err;
|
||||
char *msg1;
|
||||
va_list ap;
|
||||
int saved_errno = errno;
|
||||
|
||||
if (errp == NULL) {
|
||||
return;
|
||||
}
|
||||
assert(*errp == NULL);
|
||||
|
||||
err = g_malloc0(sizeof(*err));
|
||||
|
||||
va_start(ap, fmt);
|
||||
msg1 = g_strdup_vprintf(fmt, ap);
|
||||
if (os_errno != 0) {
|
||||
err->msg = g_strdup_printf("%s: %s", msg1, strerror(os_errno));
|
||||
g_free(msg1);
|
||||
} else {
|
||||
err->msg = msg1;
|
||||
}
|
||||
va_end(ap);
|
||||
err->err_class = err_class;
|
||||
|
||||
if (errp == &error_abort) {
|
||||
abort();
|
||||
}
|
||||
|
||||
*errp = err;
|
||||
|
||||
errno = saved_errno;
|
||||
}
|
||||
|
||||
void error_setg_file_open(Error **errp, int os_errno, const char *filename)
|
||||
{
|
||||
error_setg_errno(errp, os_errno, "Could not open '%s'", filename);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
void error_set_win32(Error **errp, int win32_err, ErrorClass err_class,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
Error *err;
|
||||
char *msg1;
|
||||
va_list ap;
|
||||
|
||||
if (errp == NULL) {
|
||||
return;
|
||||
}
|
||||
assert(*errp == NULL);
|
||||
|
||||
err = g_malloc0(sizeof(*err));
|
||||
|
||||
va_start(ap, fmt);
|
||||
msg1 = g_strdup_vprintf(fmt, ap);
|
||||
if (win32_err != 0) {
|
||||
char *msg2 = g_win32_error_message(win32_err);
|
||||
err->msg = g_strdup_printf("%s: %s (error: %x)", msg1, msg2,
|
||||
(unsigned)win32_err);
|
||||
g_free(msg2);
|
||||
g_free(msg1);
|
||||
} else {
|
||||
err->msg = msg1;
|
||||
}
|
||||
va_end(ap);
|
||||
err->err_class = err_class;
|
||||
|
||||
if (errp == &error_abort) {
|
||||
// error_report("%s", error_get_pretty(err));
|
||||
abort();
|
||||
}
|
||||
|
||||
*errp = err;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
Error *error_copy(const Error *err)
|
||||
{
|
||||
Error *err_new;
|
||||
|
||||
err_new = g_malloc0(sizeof(*err));
|
||||
err_new->msg = g_strdup(err->msg);
|
||||
err_new->err_class = err->err_class;
|
||||
|
||||
return err_new;
|
||||
}
|
||||
|
||||
ErrorClass error_get_class(const Error *err)
|
||||
{
|
||||
return err->err_class;
|
||||
}
|
||||
|
||||
const char *error_get_pretty(Error *err)
|
||||
{
|
||||
return err->msg;
|
||||
}
|
||||
|
||||
void error_free(Error *err)
|
||||
{
|
||||
if (err) {
|
||||
g_free(err->msg);
|
||||
g_free(err);
|
||||
}
|
||||
}
|
||||
|
||||
void error_propagate(Error **dst_errp, Error *local_err)
|
||||
{
|
||||
if (local_err && dst_errp == &error_abort) {
|
||||
abort();
|
||||
} else if (dst_errp && !*dst_errp) {
|
||||
*dst_errp = local_err;
|
||||
} else if (local_err) {
|
||||
error_free(local_err);
|
||||
}
|
||||
}
|
||||
167
qemu/util/host-utils.c
Normal file
167
qemu/util/host-utils.c
Normal file
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* Utility compute operations used by translated code.
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
* Copyright (c) 2007 Aurelien Jarno
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include "qemu/host-utils.h"
|
||||
|
||||
#ifndef CONFIG_INT128
|
||||
/* Long integer helpers */
|
||||
static inline void mul64(uint64_t *plow, uint64_t *phigh,
|
||||
uint64_t a, uint64_t b)
|
||||
{
|
||||
typedef union {
|
||||
uint64_t ll;
|
||||
struct {
|
||||
#ifdef HOST_WORDS_BIGENDIAN
|
||||
uint32_t high, low;
|
||||
#else
|
||||
uint32_t low, high;
|
||||
#endif
|
||||
} l;
|
||||
} LL;
|
||||
LL rl, rm, rn, rh, a0, b0;
|
||||
uint64_t c;
|
||||
|
||||
a0.ll = a;
|
||||
b0.ll = b;
|
||||
|
||||
rl.ll = (uint64_t)a0.l.low * b0.l.low;
|
||||
rm.ll = (uint64_t)a0.l.low * b0.l.high;
|
||||
rn.ll = (uint64_t)a0.l.high * b0.l.low;
|
||||
rh.ll = (uint64_t)a0.l.high * b0.l.high;
|
||||
|
||||
c = (uint64_t)rl.l.high + rm.l.low + rn.l.low;
|
||||
rl.l.high = c;
|
||||
c >>= 32;
|
||||
c = c + rm.l.high + rn.l.high + rh.l.low;
|
||||
rh.l.low = c;
|
||||
rh.l.high += (uint32_t)(c >> 32);
|
||||
|
||||
*plow = rl.ll;
|
||||
*phigh = rh.ll;
|
||||
}
|
||||
|
||||
/* Unsigned 64x64 -> 128 multiplication */
|
||||
void mulu64 (uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b)
|
||||
{
|
||||
mul64(plow, phigh, a, b);
|
||||
}
|
||||
|
||||
/* Signed 64x64 -> 128 multiplication */
|
||||
void muls64 (uint64_t *plow, uint64_t *phigh, int64_t a, int64_t b)
|
||||
{
|
||||
uint64_t rh;
|
||||
|
||||
mul64(plow, &rh, a, b);
|
||||
|
||||
/* Adjust for signs. */
|
||||
if (b < 0) {
|
||||
rh -= a;
|
||||
}
|
||||
if (a < 0) {
|
||||
rh -= b;
|
||||
}
|
||||
*phigh = rh;
|
||||
}
|
||||
|
||||
/* Unsigned 128x64 division. Returns 1 if overflow (divide by zero or */
|
||||
/* quotient exceeds 64 bits). Otherwise returns quotient via plow and */
|
||||
/* remainder via phigh. */
|
||||
int divu128(uint64_t *plow, uint64_t *phigh, uint64_t divisor)
|
||||
{
|
||||
uint64_t dhi = *phigh;
|
||||
uint64_t dlo = *plow;
|
||||
unsigned i;
|
||||
uint64_t carry = 0;
|
||||
|
||||
if (divisor == 0) {
|
||||
return 1;
|
||||
} else if (dhi == 0) {
|
||||
*plow = dlo / divisor;
|
||||
*phigh = dlo % divisor;
|
||||
return 0;
|
||||
} else if (dhi > divisor) {
|
||||
return 1;
|
||||
} else {
|
||||
|
||||
for (i = 0; i < 64; i++) {
|
||||
carry = dhi >> 63;
|
||||
dhi = (dhi << 1) | (dlo >> 63);
|
||||
if (carry || (dhi >= divisor)) {
|
||||
dhi -= divisor;
|
||||
carry = 1;
|
||||
} else {
|
||||
carry = 0;
|
||||
}
|
||||
dlo = (dlo << 1) | carry;
|
||||
}
|
||||
|
||||
*plow = dlo;
|
||||
*phigh = dhi;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int divs128(int64_t *plow, int64_t *phigh, int64_t divisor)
|
||||
{
|
||||
int sgn_dvdnd = *phigh < 0;
|
||||
int sgn_divsr = divisor < 0;
|
||||
int overflow = 0;
|
||||
|
||||
if (sgn_dvdnd) {
|
||||
*plow = ~(*plow);
|
||||
*phigh = ~(*phigh);
|
||||
if (*plow == (int64_t)-1) {
|
||||
*plow = 0;
|
||||
(*phigh)++;
|
||||
} else {
|
||||
(*plow)++;
|
||||
}
|
||||
}
|
||||
|
||||
if (sgn_divsr) {
|
||||
divisor = 0 - divisor;
|
||||
}
|
||||
|
||||
overflow = divu128((uint64_t *)plow, (uint64_t *)phigh, (uint64_t)divisor);
|
||||
|
||||
if (sgn_dvdnd ^ sgn_divsr) {
|
||||
*plow = 0 - *plow;
|
||||
}
|
||||
|
||||
if (!overflow) {
|
||||
if ((*plow < 0) ^ (sgn_dvdnd ^ sgn_divsr)) {
|
||||
overflow = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return overflow;
|
||||
}
|
||||
#else
|
||||
// avoid empty object file
|
||||
void dummy_func(void);
|
||||
void dummy_func(void) {}
|
||||
#endif
|
||||
57
qemu/util/module.c
Normal file
57
qemu/util/module.c
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* QEMU Module Infrastructure
|
||||
*
|
||||
* Copyright IBM, Corp. 2009
|
||||
*
|
||||
* Authors:
|
||||
* Anthony Liguori <aliguori@us.ibm.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2. See
|
||||
* the COPYING file in the top-level directory.
|
||||
*
|
||||
* Contributions after 2012-01-13 are licensed under the terms of the
|
||||
* GNU GPL, version 2 or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include "qemu-common.h"
|
||||
#include "qemu/queue.h"
|
||||
|
||||
#include "uc_priv.h"
|
||||
|
||||
static void init_lists(struct uc_struct *uc)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MODULE_INIT_MAX; i++) {
|
||||
QTAILQ_INIT(&uc->init_type_list[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static ModuleTypeList *find_type(struct uc_struct *uc, module_init_type type)
|
||||
{
|
||||
ModuleTypeList *l;
|
||||
|
||||
init_lists(uc);
|
||||
|
||||
l = &uc->init_type_list[type];
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
static void module_load(module_init_type type)
|
||||
{
|
||||
}
|
||||
|
||||
void module_call_init(struct uc_struct *uc, module_init_type type)
|
||||
{
|
||||
ModuleTypeList *l;
|
||||
ModuleEntry *e;
|
||||
|
||||
module_load(type);
|
||||
l = find_type(uc, type);
|
||||
|
||||
QTAILQ_FOREACH(e, l, node) {
|
||||
e->init();
|
||||
}
|
||||
}
|
||||
213
qemu/util/oslib-posix.c
Normal file
213
qemu/util/oslib-posix.c
Normal file
@@ -0,0 +1,213 @@
|
||||
/*
|
||||
* os-posix-lib.c
|
||||
*
|
||||
* Copyright (c) 2003-2008 Fabrice Bellard
|
||||
* Copyright (c) 2010 Red Hat, Inc.
|
||||
*
|
||||
* QEMU library functions on POSIX which are shared between QEMU and
|
||||
* the QEMU tools.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/* The following block of code temporarily renames the daemon() function so the
|
||||
compiler does not see the warning associated with it in stdlib.h on OSX */
|
||||
#ifdef __APPLE__
|
||||
#define daemon qemu_fake_daemon_function
|
||||
#include <stdlib.h>
|
||||
#undef daemon
|
||||
extern int daemon(int, int);
|
||||
#endif
|
||||
|
||||
#if defined(__linux__) && (defined(__x86_64__) || defined(__arm__))
|
||||
/* Use 2 MiB alignment so transparent hugepages can be used by KVM.
|
||||
Valgrind does not support alignments larger than 1 MiB,
|
||||
therefore we need special code which handles running on Valgrind. */
|
||||
# define QEMU_VMALLOC_ALIGN (512 * 4096)
|
||||
#elif defined(__linux__) && defined(__s390x__)
|
||||
/* Use 1 MiB (segment size) alignment so gmap can be used by KVM. */
|
||||
# define QEMU_VMALLOC_ALIGN (256 * 4096)
|
||||
#else
|
||||
# define QEMU_VMALLOC_ALIGN getpagesize()
|
||||
#endif
|
||||
#define HUGETLBFS_MAGIC 0x958458f6
|
||||
|
||||
#include <termios.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <glib/gprintf.h>
|
||||
|
||||
#include "config-host.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include <sys/mman.h>
|
||||
#include <libgen.h>
|
||||
#include <setjmp.h>
|
||||
#include <sys/signal.h>
|
||||
|
||||
#ifdef CONFIG_LINUX
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/vfs.h>
|
||||
#endif
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
#include <sys/sysctl.h>
|
||||
#endif
|
||||
|
||||
int qemu_get_thread_id(void)
|
||||
{
|
||||
#if defined(__linux__)
|
||||
return syscall(SYS_gettid);
|
||||
#else
|
||||
return getpid();
|
||||
#endif
|
||||
}
|
||||
|
||||
int qemu_daemon(int nochdir, int noclose)
|
||||
{
|
||||
return daemon(nochdir, noclose);
|
||||
}
|
||||
|
||||
void *qemu_oom_check(void *ptr)
|
||||
{
|
||||
if (ptr == NULL) {
|
||||
fprintf(stderr, "Failed to allocate memory: %s\n", strerror(errno));
|
||||
abort();
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void *qemu_try_memalign(size_t alignment, size_t size)
|
||||
{
|
||||
void *ptr;
|
||||
|
||||
if (alignment < sizeof(void*)) {
|
||||
alignment = sizeof(void*);
|
||||
}
|
||||
|
||||
#if defined(_POSIX_C_SOURCE) && !defined(__sun__)
|
||||
int ret;
|
||||
ret = posix_memalign(&ptr, alignment, size);
|
||||
if (ret != 0) {
|
||||
errno = ret;
|
||||
ptr = NULL;
|
||||
}
|
||||
#elif defined(CONFIG_BSD)
|
||||
ptr = valloc(size);
|
||||
#else
|
||||
ptr = memalign(alignment, size);
|
||||
#endif
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void *qemu_memalign(size_t alignment, size_t size)
|
||||
{
|
||||
return qemu_oom_check(qemu_try_memalign(alignment, size));
|
||||
}
|
||||
|
||||
/* alloc shared memory pages */
|
||||
void *qemu_anon_ram_alloc(size_t size, uint64_t *alignment)
|
||||
{
|
||||
size_t align = QEMU_VMALLOC_ALIGN;
|
||||
size_t total = size + align - getpagesize();
|
||||
void *ptr = mmap(0, total, PROT_READ | PROT_WRITE,
|
||||
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
|
||||
size_t offset = QEMU_ALIGN_UP((uintptr_t)ptr, align) - (uintptr_t)ptr;
|
||||
|
||||
if (ptr == MAP_FAILED) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (alignment) {
|
||||
*alignment = align;
|
||||
}
|
||||
ptr += offset;
|
||||
total -= offset;
|
||||
|
||||
if (offset > 0) {
|
||||
munmap(ptr - offset, offset);
|
||||
}
|
||||
if (total > size) {
|
||||
munmap(ptr + size, total - size);
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void qemu_vfree(void *ptr)
|
||||
{
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
void qemu_anon_ram_free(void *ptr, size_t size)
|
||||
{
|
||||
if (ptr) {
|
||||
munmap(ptr, size);
|
||||
}
|
||||
}
|
||||
|
||||
void qemu_set_cloexec(int fd)
|
||||
{
|
||||
int f;
|
||||
f = fcntl(fd, F_GETFD);
|
||||
fcntl(fd, F_SETFD, f | FD_CLOEXEC);
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates a pipe with FD_CLOEXEC set on both file descriptors
|
||||
*/
|
||||
int qemu_pipe(int pipefd[2])
|
||||
{
|
||||
int ret;
|
||||
|
||||
#ifdef CONFIG_PIPE2
|
||||
ret = pipe2(pipefd, O_CLOEXEC);
|
||||
if (ret != -1 || errno != ENOSYS) {
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
ret = pipe(pipefd);
|
||||
if (ret == 0) {
|
||||
qemu_set_cloexec(pipefd[0]);
|
||||
qemu_set_cloexec(pipefd[1]);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
char *
|
||||
qemu_get_local_state_pathname(const char *relative_pathname)
|
||||
{
|
||||
return g_strdup_printf("%s/%s", CONFIG_QEMU_LOCALSTATEDIR,
|
||||
relative_pathname);
|
||||
}
|
||||
|
||||
void qemu_set_tty_echo(int fd, bool echo)
|
||||
{
|
||||
struct termios tty;
|
||||
|
||||
tcgetattr(fd, &tty);
|
||||
|
||||
if (echo) {
|
||||
tty.c_lflag |= ECHO | ECHONL | ICANON | IEXTEN;
|
||||
} else {
|
||||
tty.c_lflag &= ~(ECHO | ECHONL | ICANON | IEXTEN);
|
||||
}
|
||||
|
||||
tcsetattr(fd, TCSANOW, &tty);
|
||||
}
|
||||
421
qemu/util/oslib-win32.c
Normal file
421
qemu/util/oslib-win32.c
Normal file
@@ -0,0 +1,421 @@
|
||||
/*
|
||||
* os-win32.c
|
||||
*
|
||||
* Copyright (c) 2003-2008 Fabrice Bellard
|
||||
* Copyright (c) 2010 Red Hat, Inc.
|
||||
*
|
||||
* QEMU library functions for win32 which are shared between QEMU and
|
||||
* the QEMU tools.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* The implementation of g_poll (functions poll_rest, g_poll) at the end of
|
||||
* this file are based on code from GNOME glib-2 and use a different license,
|
||||
* see the license comment there.
|
||||
*/
|
||||
#include <windows.h>
|
||||
|
||||
#define G_OS_WIN32
|
||||
|
||||
#include <glib.h>
|
||||
#include <stdlib.h>
|
||||
#include "config-host.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "qemu/main-loop.h"
|
||||
// #include "trace.h"
|
||||
//#include "qemu/sockets.h"
|
||||
|
||||
/* this must come after including "trace.h" */
|
||||
#include <shlobj.h>
|
||||
|
||||
void *qemu_oom_check(void *ptr)
|
||||
{
|
||||
if (ptr == NULL) {
|
||||
fprintf(stderr, "Failed to allocate memory: %lu\n", GetLastError());
|
||||
abort();
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void *qemu_try_memalign(size_t alignment, size_t size)
|
||||
{
|
||||
void *ptr;
|
||||
|
||||
if (!size) {
|
||||
abort();
|
||||
}
|
||||
ptr = VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE);
|
||||
// trace_qemu_memalign(alignment, size, ptr);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void *qemu_memalign(size_t alignment, size_t size)
|
||||
{
|
||||
return qemu_oom_check(qemu_try_memalign(alignment, size));
|
||||
}
|
||||
|
||||
void *qemu_anon_ram_alloc(size_t size, uint64_t *align)
|
||||
{
|
||||
void *ptr;
|
||||
|
||||
/* FIXME: this is not exactly optimal solution since VirtualAlloc
|
||||
has 64Kb granularity, but at least it guarantees us that the
|
||||
memory is page aligned. */
|
||||
ptr = VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE);
|
||||
// trace_qemu_anon_ram_alloc(size, ptr);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void qemu_vfree(void *ptr)
|
||||
{
|
||||
// trace_qemu_vfree(ptr);
|
||||
if (ptr) {
|
||||
VirtualFree(ptr, 0, MEM_RELEASE);
|
||||
}
|
||||
}
|
||||
|
||||
void qemu_anon_ram_free(void *ptr, size_t size)
|
||||
{
|
||||
// trace_qemu_anon_ram_free(ptr, size);
|
||||
if (ptr) {
|
||||
VirtualFree(ptr, 0, MEM_RELEASE);
|
||||
}
|
||||
}
|
||||
|
||||
/* FIXME: add proper locking */
|
||||
struct tm *gmtime_r(const time_t *timep, struct tm *result)
|
||||
{
|
||||
struct tm *p = gmtime(timep);
|
||||
memset(result, 0, sizeof(*result));
|
||||
if (p) {
|
||||
*result = *p;
|
||||
p = result;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
/* FIXME: add proper locking */
|
||||
struct tm *localtime_r(const time_t *timep, struct tm *result)
|
||||
{
|
||||
struct tm *p = localtime(timep);
|
||||
memset(result, 0, sizeof(*result));
|
||||
if (p) {
|
||||
*result = *p;
|
||||
p = result;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
int socket_set_fast_reuse(int fd)
|
||||
{
|
||||
/* Enabling the reuse of an endpoint that was used by a socket still in
|
||||
* TIME_WAIT state is usually performed by setting SO_REUSEADDR. On Windows
|
||||
* fast reuse is the default and SO_REUSEADDR does strange things. So we
|
||||
* don't have to do anything here. More info can be found at:
|
||||
* http://msdn.microsoft.com/en-us/library/windows/desktop/ms740621.aspx */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
int inet_aton(const char *cp, struct in_addr *ia)
|
||||
{
|
||||
uint32_t addr = inet_addr(cp);
|
||||
if (addr == 0xffffffff) {
|
||||
return 0;
|
||||
}
|
||||
ia->s_addr = addr;
|
||||
return 1;
|
||||
}*/
|
||||
|
||||
void qemu_set_cloexec(int fd)
|
||||
{
|
||||
}
|
||||
|
||||
/* Offset between 1/1/1601 and 1/1/1970 in 100 nanosec units */
|
||||
#define _W32_FT_OFFSET (116444736000000000ULL)
|
||||
|
||||
int qemu_gettimeofday(qemu_timeval *tp)
|
||||
{
|
||||
union {
|
||||
unsigned long long ns100; /*time since 1 Jan 1601 in 100ns units */
|
||||
FILETIME ft;
|
||||
} _now;
|
||||
|
||||
if(tp) {
|
||||
GetSystemTimeAsFileTime (&_now.ft);
|
||||
tp->tv_usec=(long)((_now.ns100 / 10ULL) % 1000000ULL );
|
||||
tp->tv_sec= (long)((_now.ns100 - _W32_FT_OFFSET) / 10000000ULL);
|
||||
}
|
||||
/* Always return 0 as per Open Group Base Specifications Issue 6.
|
||||
Do not set errno on error. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
int qemu_get_thread_id(void)
|
||||
{
|
||||
return GetCurrentThreadId();
|
||||
}
|
||||
|
||||
char *
|
||||
qemu_get_local_state_pathname(const char *relative_pathname)
|
||||
{
|
||||
HRESULT result;
|
||||
char base_path[MAX_PATH+1] = "";
|
||||
|
||||
result = SHGetFolderPath(NULL, CSIDL_COMMON_APPDATA, NULL,
|
||||
/* SHGFP_TYPE_CURRENT */ 0, base_path);
|
||||
if (result != S_OK) {
|
||||
/* misconfigured environment */
|
||||
g_critical("CSIDL_COMMON_APPDATA unavailable: %ld", (long)result);
|
||||
abort();
|
||||
}
|
||||
return g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s", base_path,
|
||||
relative_pathname);
|
||||
}
|
||||
|
||||
void qemu_set_tty_echo(int fd, bool echo)
|
||||
{
|
||||
HANDLE handle = (HANDLE)_get_osfhandle(fd);
|
||||
DWORD dwMode = 0;
|
||||
|
||||
if (handle == INVALID_HANDLE_VALUE) {
|
||||
return;
|
||||
}
|
||||
|
||||
GetConsoleMode(handle, &dwMode);
|
||||
|
||||
if (echo) {
|
||||
SetConsoleMode(handle, dwMode | ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT);
|
||||
} else {
|
||||
SetConsoleMode(handle,
|
||||
dwMode & ~(ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The original implementation of g_poll from glib has a problem on Windows
|
||||
* when using timeouts < 10 ms.
|
||||
*
|
||||
* Whenever g_poll is called with timeout < 10 ms, it does a quick poll instead
|
||||
* of wait. This causes significant performance degradation of QEMU.
|
||||
*
|
||||
* The following code is a copy of the original code from glib/gpoll.c
|
||||
* (glib commit 20f4d1820b8d4d0fc4447188e33efffd6d4a88d8 from 2014-02-19).
|
||||
* Some debug code was removed and the code was reformatted.
|
||||
* All other code modifications are marked with 'QEMU'.
|
||||
*/
|
||||
|
||||
/*
|
||||
* gpoll.c: poll(2) abstraction
|
||||
* Copyright 1998 Owen Taylor
|
||||
* Copyright 2008 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
static int poll_rest(gboolean poll_msgs, HANDLE *handles, gint nhandles,
|
||||
GPollFD *fds, guint nfds, gint timeout)
|
||||
{
|
||||
DWORD ready;
|
||||
GPollFD *f;
|
||||
int recursed_result;
|
||||
|
||||
if (poll_msgs) {
|
||||
/* Wait for either messages or handles
|
||||
* -> Use MsgWaitForMultipleObjectsEx
|
||||
*/
|
||||
ready = MsgWaitForMultipleObjectsEx(nhandles, handles, timeout,
|
||||
QS_ALLINPUT, MWMO_ALERTABLE);
|
||||
|
||||
if (ready == WAIT_FAILED) {
|
||||
gchar *emsg = g_win32_error_message(GetLastError());
|
||||
g_warning("MsgWaitForMultipleObjectsEx failed: %s", emsg);
|
||||
g_free(emsg);
|
||||
}
|
||||
} else if (nhandles == 0) {
|
||||
/* No handles to wait for, just the timeout */
|
||||
if (timeout == INFINITE) {
|
||||
ready = WAIT_FAILED;
|
||||
} else {
|
||||
SleepEx(timeout, TRUE);
|
||||
ready = WAIT_TIMEOUT;
|
||||
}
|
||||
} else {
|
||||
/* Wait for just handles
|
||||
* -> Use WaitForMultipleObjectsEx
|
||||
*/
|
||||
ready =
|
||||
WaitForMultipleObjectsEx(nhandles, handles, FALSE, timeout, TRUE);
|
||||
if (ready == WAIT_FAILED) {
|
||||
gchar *emsg = g_win32_error_message(GetLastError());
|
||||
g_warning("WaitForMultipleObjectsEx failed: %s", emsg);
|
||||
g_free(emsg);
|
||||
}
|
||||
}
|
||||
|
||||
if (ready == WAIT_FAILED) {
|
||||
return -1;
|
||||
} else if (ready == WAIT_TIMEOUT || ready == WAIT_IO_COMPLETION) {
|
||||
return 0;
|
||||
} else if (poll_msgs && ready == WAIT_OBJECT_0 + nhandles) {
|
||||
for (f = fds; f < &fds[nfds]; ++f) {
|
||||
if (f->fd == G_WIN32_MSG_HANDLE && f->events & G_IO_IN) {
|
||||
f->revents |= G_IO_IN;
|
||||
}
|
||||
}
|
||||
|
||||
/* If we have a timeout, or no handles to poll, be satisfied
|
||||
* with just noticing we have messages waiting.
|
||||
*/
|
||||
if (timeout != 0 || nhandles == 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* If no timeout and handles to poll, recurse to poll them,
|
||||
* too.
|
||||
*/
|
||||
recursed_result = poll_rest(FALSE, handles, nhandles, fds, nfds, 0);
|
||||
return (recursed_result == -1) ? -1 : 1 + recursed_result;
|
||||
} else if (/* QEMU: removed the following unneeded statement which causes
|
||||
* a compiler warning: ready >= WAIT_OBJECT_0 && */
|
||||
ready < WAIT_OBJECT_0 + nhandles) {
|
||||
for (f = fds; f < &fds[nfds]; ++f) {
|
||||
if ((HANDLE) f->fd == handles[ready - WAIT_OBJECT_0]) {
|
||||
f->revents = f->events;
|
||||
}
|
||||
}
|
||||
|
||||
/* If no timeout and polling several handles, recurse to poll
|
||||
* the rest of them.
|
||||
*/
|
||||
if (timeout == 0 && nhandles > 1) {
|
||||
/* Remove the handle that fired */
|
||||
int i;
|
||||
if (ready < nhandles - 1) {
|
||||
for (i = ready - WAIT_OBJECT_0 + 1; i < nhandles; i++) {
|
||||
handles[i-1] = handles[i];
|
||||
}
|
||||
}
|
||||
nhandles--;
|
||||
recursed_result = poll_rest(FALSE, handles, nhandles, fds, nfds, 0);
|
||||
return (recursed_result == -1) ? -1 : 1 + recursed_result;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
gint g_poll(GPollFD *fds, guint nfds, gint timeout)
|
||||
{
|
||||
HANDLE handles[MAXIMUM_WAIT_OBJECTS];
|
||||
gboolean poll_msgs = FALSE;
|
||||
GPollFD *f;
|
||||
gint nhandles = 0;
|
||||
int retval;
|
||||
|
||||
for (f = fds; f < &fds[nfds]; ++f) {
|
||||
if (f->fd == G_WIN32_MSG_HANDLE && (f->events & G_IO_IN)) {
|
||||
poll_msgs = TRUE;
|
||||
} else if (f->fd > 0) {
|
||||
/* Don't add the same handle several times into the array, as
|
||||
* docs say that is not allowed, even if it actually does seem
|
||||
* to work.
|
||||
*/
|
||||
gint i;
|
||||
|
||||
for (i = 0; i < nhandles; i++) {
|
||||
if (handles[i] == (HANDLE) f->fd) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == nhandles) {
|
||||
if (nhandles == MAXIMUM_WAIT_OBJECTS) {
|
||||
g_warning("Too many handles to wait for!\n");
|
||||
break;
|
||||
} else {
|
||||
handles[nhandles++] = (HANDLE) f->fd;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (f = fds; f < &fds[nfds]; ++f) {
|
||||
f->revents = 0;
|
||||
}
|
||||
|
||||
if (timeout == -1) {
|
||||
timeout = INFINITE;
|
||||
}
|
||||
|
||||
/* Polling for several things? */
|
||||
if (nhandles > 1 || (nhandles > 0 && poll_msgs)) {
|
||||
/* First check if one or several of them are immediately
|
||||
* available
|
||||
*/
|
||||
retval = poll_rest(poll_msgs, handles, nhandles, fds, nfds, 0);
|
||||
|
||||
/* If not, and we have a significant timeout, poll again with
|
||||
* timeout then. Note that this will return indication for only
|
||||
* one event, or only for messages. We ignore timeouts less than
|
||||
* ten milliseconds as they are mostly pointless on Windows, the
|
||||
* MsgWaitForMultipleObjectsEx() call will timeout right away
|
||||
* anyway.
|
||||
*
|
||||
* Modification for QEMU: replaced timeout >= 10 by timeout > 0.
|
||||
*/
|
||||
if (retval == 0 && (timeout == INFINITE || timeout > 0)) {
|
||||
retval = poll_rest(poll_msgs, handles, nhandles,
|
||||
fds, nfds, timeout);
|
||||
}
|
||||
} else {
|
||||
/* Just polling for one thing, so no need to check first if
|
||||
* available immediately
|
||||
*/
|
||||
retval = poll_rest(poll_msgs, handles, nhandles, fds, nfds, timeout);
|
||||
}
|
||||
|
||||
if (retval == -1) {
|
||||
for (f = fds; f < &fds[nfds]; ++f) {
|
||||
f->revents = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
size_t getpagesize(void)
|
||||
{
|
||||
SYSTEM_INFO system_info;
|
||||
|
||||
GetSystemInfo(&system_info);
|
||||
return system_info.dwPageSize;
|
||||
}
|
||||
69
qemu/util/qemu-error.c
Normal file
69
qemu/util/qemu-error.c
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Error reporting
|
||||
*
|
||||
* Copyright (C) 2010 Red Hat Inc.
|
||||
*
|
||||
* Authors:
|
||||
* Markus Armbruster <armbru@redhat.com>,
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
static const char *progname;
|
||||
|
||||
/*
|
||||
* Set the program name for error_print_loc().
|
||||
*/
|
||||
void error_set_progname(const char *argv0)
|
||||
{
|
||||
const char *p = strrchr(argv0, '/');
|
||||
progname = p ? p + 1 : argv0;
|
||||
}
|
||||
|
||||
const char *error_get_progname(void)
|
||||
{
|
||||
return progname;
|
||||
}
|
||||
|
||||
/*
|
||||
* Print current location to current monitor if we have one, else to stderr.
|
||||
*/
|
||||
static void error_print_loc(void)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* Print an error message to current monitor if we have one, else to stderr.
|
||||
* Format arguments like vsprintf(). The result should not contain
|
||||
* newlines.
|
||||
* Prepend the current location and append a newline.
|
||||
* It's wrong to call this in a QMP monitor. Use qerror_report() there.
|
||||
*/
|
||||
void error_vreport(const char *fmt, va_list ap)
|
||||
{
|
||||
GTimeVal tv;
|
||||
gchar *timestr;
|
||||
|
||||
error_print_loc();
|
||||
error_vprintf(fmt, ap);
|
||||
error_printf("\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* Print an error message to current monitor if we have one, else to stderr.
|
||||
* Format arguments like sprintf(). The result should not contain
|
||||
* newlines.
|
||||
* Prepend the current location and append a newline.
|
||||
* It's wrong to call this in a QMP monitor. Use qerror_report() there.
|
||||
*/
|
||||
void error_report(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
error_vreport(fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
1128
qemu/util/qemu-option.c
Normal file
1128
qemu/util/qemu-option.c
Normal file
File diff suppressed because it is too large
Load Diff
454
qemu/util/qemu-thread-posix.c
Normal file
454
qemu/util/qemu-thread-posix.c
Normal file
@@ -0,0 +1,454 @@
|
||||
/*
|
||||
* Wrappers around mutex/cond/thread functions
|
||||
*
|
||||
* Copyright Red Hat, Inc. 2009
|
||||
*
|
||||
* Author:
|
||||
* Marcelo Tosatti <mtosatti@redhat.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <time.h>
|
||||
#include <signal.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
#ifdef __linux__
|
||||
#include <sys/syscall.h>
|
||||
#include <linux/futex.h>
|
||||
#endif
|
||||
#include "qemu/thread.h"
|
||||
#include "qemu/atomic.h"
|
||||
|
||||
static void error_exit(int err, const char *msg)
|
||||
{
|
||||
fprintf(stderr, "qemu: %s: %s\n", msg, strerror(err));
|
||||
abort();
|
||||
}
|
||||
|
||||
void qemu_mutex_init(QemuMutex *mutex)
|
||||
{
|
||||
int err;
|
||||
pthread_mutexattr_t mutexattr;
|
||||
|
||||
pthread_mutexattr_init(&mutexattr);
|
||||
pthread_mutexattr_settype(&mutexattr, PTHREAD_MUTEX_ERRORCHECK);
|
||||
err = pthread_mutex_init(&mutex->lock, &mutexattr);
|
||||
pthread_mutexattr_destroy(&mutexattr);
|
||||
if (err)
|
||||
error_exit(err, __func__);
|
||||
}
|
||||
|
||||
void qemu_mutex_destroy(QemuMutex *mutex)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = pthread_mutex_destroy(&mutex->lock);
|
||||
if (err)
|
||||
error_exit(err, __func__);
|
||||
}
|
||||
|
||||
void qemu_mutex_lock(QemuMutex *mutex)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = pthread_mutex_lock(&mutex->lock);
|
||||
if (err)
|
||||
error_exit(err, __func__);
|
||||
}
|
||||
|
||||
int qemu_mutex_trylock(QemuMutex *mutex)
|
||||
{
|
||||
return pthread_mutex_trylock(&mutex->lock);
|
||||
}
|
||||
|
||||
void qemu_mutex_unlock(QemuMutex *mutex)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = pthread_mutex_unlock(&mutex->lock);
|
||||
if (err)
|
||||
error_exit(err, __func__);
|
||||
}
|
||||
|
||||
void qemu_cond_init(QemuCond *cond)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = pthread_cond_init(&cond->cond, NULL);
|
||||
if (err)
|
||||
error_exit(err, __func__);
|
||||
}
|
||||
|
||||
void qemu_cond_destroy(QemuCond *cond)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = pthread_cond_destroy(&cond->cond);
|
||||
if (err)
|
||||
error_exit(err, __func__);
|
||||
}
|
||||
|
||||
void qemu_cond_signal(QemuCond *cond)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = pthread_cond_signal(&cond->cond);
|
||||
if (err)
|
||||
error_exit(err, __func__);
|
||||
}
|
||||
|
||||
void qemu_cond_broadcast(QemuCond *cond)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = pthread_cond_broadcast(&cond->cond);
|
||||
if (err)
|
||||
error_exit(err, __func__);
|
||||
}
|
||||
|
||||
void qemu_cond_wait(QemuCond *cond, QemuMutex *mutex)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = pthread_cond_wait(&cond->cond, &mutex->lock);
|
||||
if (err)
|
||||
error_exit(err, __func__);
|
||||
}
|
||||
|
||||
void qemu_sem_init(QemuSemaphore *sem, int init)
|
||||
{
|
||||
int rc;
|
||||
|
||||
#if defined(__APPLE__) || defined(__NetBSD__)
|
||||
rc = pthread_mutex_init(&sem->lock, NULL);
|
||||
if (rc != 0) {
|
||||
error_exit(rc, __func__);
|
||||
}
|
||||
rc = pthread_cond_init(&sem->cond, NULL);
|
||||
if (rc != 0) {
|
||||
error_exit(rc, __func__);
|
||||
}
|
||||
if (init < 0) {
|
||||
error_exit(EINVAL, __func__);
|
||||
}
|
||||
sem->count = init;
|
||||
#else
|
||||
rc = sem_init(&sem->sem, 0, init);
|
||||
if (rc < 0) {
|
||||
error_exit(errno, __func__);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void qemu_sem_destroy(QemuSemaphore *sem)
|
||||
{
|
||||
int rc;
|
||||
|
||||
#if defined(__APPLE__) || defined(__NetBSD__)
|
||||
rc = pthread_cond_destroy(&sem->cond);
|
||||
if (rc < 0) {
|
||||
error_exit(rc, __func__);
|
||||
}
|
||||
rc = pthread_mutex_destroy(&sem->lock);
|
||||
if (rc < 0) {
|
||||
error_exit(rc, __func__);
|
||||
}
|
||||
#else
|
||||
rc = sem_destroy(&sem->sem);
|
||||
if (rc < 0) {
|
||||
error_exit(errno, __func__);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void qemu_sem_post(QemuSemaphore *sem)
|
||||
{
|
||||
int rc;
|
||||
|
||||
#if defined(__APPLE__) || defined(__NetBSD__)
|
||||
pthread_mutex_lock(&sem->lock);
|
||||
if (sem->count == UINT_MAX) {
|
||||
rc = EINVAL;
|
||||
} else {
|
||||
sem->count++;
|
||||
rc = pthread_cond_signal(&sem->cond);
|
||||
}
|
||||
pthread_mutex_unlock(&sem->lock);
|
||||
if (rc != 0) {
|
||||
error_exit(rc, __func__);
|
||||
}
|
||||
#else
|
||||
rc = sem_post(&sem->sem);
|
||||
if (rc < 0) {
|
||||
error_exit(errno, __func__);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void compute_abs_deadline(struct timespec *ts, int ms)
|
||||
{
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
ts->tv_nsec = tv.tv_usec * 1000 + (ms % 1000) * 1000000;
|
||||
ts->tv_sec = tv.tv_sec + ms / 1000;
|
||||
if (ts->tv_nsec >= 1000000000) {
|
||||
ts->tv_sec++;
|
||||
ts->tv_nsec -= 1000000000;
|
||||
}
|
||||
}
|
||||
|
||||
int qemu_sem_timedwait(QemuSemaphore *sem, int ms)
|
||||
{
|
||||
int rc;
|
||||
struct timespec ts;
|
||||
|
||||
#if defined(__APPLE__) || defined(__NetBSD__)
|
||||
rc = 0;
|
||||
compute_abs_deadline(&ts, ms);
|
||||
pthread_mutex_lock(&sem->lock);
|
||||
while (sem->count == 0) {
|
||||
rc = pthread_cond_timedwait(&sem->cond, &sem->lock, &ts);
|
||||
if (rc == ETIMEDOUT) {
|
||||
break;
|
||||
}
|
||||
if (rc != 0) {
|
||||
error_exit(rc, __func__);
|
||||
}
|
||||
}
|
||||
if (rc != ETIMEDOUT) {
|
||||
--sem->count;
|
||||
}
|
||||
pthread_mutex_unlock(&sem->lock);
|
||||
return (rc == ETIMEDOUT ? -1 : 0);
|
||||
#else
|
||||
if (ms <= 0) {
|
||||
/* This is cheaper than sem_timedwait. */
|
||||
do {
|
||||
rc = sem_trywait(&sem->sem);
|
||||
} while (rc == -1 && errno == EINTR);
|
||||
if (rc == -1 && errno == EAGAIN) {
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
compute_abs_deadline(&ts, ms);
|
||||
do {
|
||||
rc = sem_timedwait(&sem->sem, &ts);
|
||||
} while (rc == -1 && errno == EINTR);
|
||||
if (rc == -1 && errno == ETIMEDOUT) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (rc < 0) {
|
||||
error_exit(errno, __func__);
|
||||
}
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void qemu_sem_wait(QemuSemaphore *sem)
|
||||
{
|
||||
int rc;
|
||||
|
||||
#if defined(__APPLE__) || defined(__NetBSD__)
|
||||
pthread_mutex_lock(&sem->lock);
|
||||
while (sem->count == 0) {
|
||||
rc = pthread_cond_wait(&sem->cond, &sem->lock);
|
||||
if (rc != 0) {
|
||||
error_exit(rc, __func__);
|
||||
}
|
||||
}
|
||||
--sem->count;
|
||||
pthread_mutex_unlock(&sem->lock);
|
||||
#else
|
||||
do {
|
||||
rc = sem_wait(&sem->sem);
|
||||
} while (rc == -1 && errno == EINTR);
|
||||
if (rc < 0) {
|
||||
error_exit(errno, __func__);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
#define futex(...) syscall(__NR_futex, __VA_ARGS__)
|
||||
|
||||
static inline void futex_wake(QemuEvent *ev, int n)
|
||||
{
|
||||
futex(ev, FUTEX_WAKE, n, NULL, NULL, 0);
|
||||
}
|
||||
|
||||
static inline void futex_wait(QemuEvent *ev, unsigned val)
|
||||
{
|
||||
futex(ev, FUTEX_WAIT, (int) val, NULL, NULL, 0);
|
||||
}
|
||||
#else
|
||||
static inline void futex_wake(QemuEvent *ev, int n)
|
||||
{
|
||||
pthread_mutex_lock(&ev->lock);
|
||||
if (n == 1) {
|
||||
pthread_cond_signal(&ev->cond);
|
||||
} else {
|
||||
pthread_cond_broadcast(&ev->cond);
|
||||
}
|
||||
pthread_mutex_unlock(&ev->lock);
|
||||
}
|
||||
|
||||
static inline void futex_wait(QemuEvent *ev, unsigned val)
|
||||
{
|
||||
pthread_mutex_lock(&ev->lock);
|
||||
if (ev->value == val) {
|
||||
pthread_cond_wait(&ev->cond, &ev->lock);
|
||||
}
|
||||
pthread_mutex_unlock(&ev->lock);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Valid transitions:
|
||||
* - free->set, when setting the event
|
||||
* - busy->set, when setting the event, followed by futex_wake
|
||||
* - set->free, when resetting the event
|
||||
* - free->busy, when waiting
|
||||
*
|
||||
* set->busy does not happen (it can be observed from the outside but
|
||||
* it really is set->free->busy).
|
||||
*
|
||||
* busy->free provably cannot happen; to enforce it, the set->free transition
|
||||
* is done with an OR, which becomes a no-op if the event has concurrently
|
||||
* transitioned to free or busy.
|
||||
*/
|
||||
|
||||
#define EV_SET 0
|
||||
#define EV_FREE 1
|
||||
#define EV_BUSY -1
|
||||
|
||||
void qemu_event_init(QemuEvent *ev, bool init)
|
||||
{
|
||||
#ifndef __linux__
|
||||
pthread_mutex_init(&ev->lock, NULL);
|
||||
pthread_cond_init(&ev->cond, NULL);
|
||||
#endif
|
||||
|
||||
ev->value = (init ? EV_SET : EV_FREE);
|
||||
}
|
||||
|
||||
void qemu_event_destroy(QemuEvent *ev)
|
||||
{
|
||||
#ifndef __linux__
|
||||
pthread_mutex_destroy(&ev->lock);
|
||||
pthread_cond_destroy(&ev->cond);
|
||||
#endif
|
||||
}
|
||||
|
||||
void qemu_event_set(QemuEvent *ev)
|
||||
{
|
||||
if (atomic_mb_read(&ev->value) != EV_SET) {
|
||||
if (atomic_xchg(&ev->value, EV_SET) == EV_BUSY) {
|
||||
/* There were waiters, wake them up. */
|
||||
futex_wake(ev, INT_MAX);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void qemu_event_reset(QemuEvent *ev)
|
||||
{
|
||||
if (atomic_mb_read(&ev->value) == EV_SET) {
|
||||
/*
|
||||
* If there was a concurrent reset (or even reset+wait),
|
||||
* do nothing. Otherwise change EV_SET->EV_FREE.
|
||||
*/
|
||||
atomic_or(&ev->value, EV_FREE);
|
||||
}
|
||||
}
|
||||
|
||||
void qemu_event_wait(QemuEvent *ev)
|
||||
{
|
||||
unsigned value;
|
||||
|
||||
value = atomic_mb_read(&ev->value);
|
||||
if (value != EV_SET) {
|
||||
if (value == EV_FREE) {
|
||||
/*
|
||||
* Leave the event reset and tell qemu_event_set that there
|
||||
* are waiters. No need to retry, because there cannot be
|
||||
* a concurent busy->free transition. After the CAS, the
|
||||
* event will be either set or busy.
|
||||
*/
|
||||
if (atomic_cmpxchg(&ev->value, EV_FREE, EV_BUSY) == EV_SET) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
futex_wait(ev, EV_BUSY);
|
||||
}
|
||||
}
|
||||
|
||||
void qemu_thread_create(QemuThread *thread, const char *name,
|
||||
void *(*start_routine)(void*),
|
||||
void *arg, int mode)
|
||||
{
|
||||
sigset_t set, oldset;
|
||||
int err;
|
||||
pthread_attr_t attr;
|
||||
|
||||
#if 0
|
||||
static int count = 0;
|
||||
count++;
|
||||
printf(">>> create thread %u\n", count);
|
||||
#endif
|
||||
|
||||
err = pthread_attr_init(&attr);
|
||||
if (err) {
|
||||
error_exit(err, __func__);
|
||||
}
|
||||
if (mode == QEMU_THREAD_DETACHED) {
|
||||
err = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
|
||||
if (err) {
|
||||
error_exit(err, __func__);
|
||||
}
|
||||
}
|
||||
|
||||
/* Leave signal handling to the iothread. */
|
||||
sigfillset(&set);
|
||||
pthread_sigmask(SIG_SETMASK, &set, &oldset);
|
||||
err = pthread_create(&thread->thread, &attr, start_routine, arg);
|
||||
if (err)
|
||||
error_exit(err, __func__);
|
||||
|
||||
pthread_sigmask(SIG_SETMASK, &oldset, NULL);
|
||||
|
||||
pthread_attr_destroy(&attr);
|
||||
}
|
||||
|
||||
void qemu_thread_get_self(QemuThread *thread)
|
||||
{
|
||||
thread->thread = pthread_self();
|
||||
}
|
||||
|
||||
bool qemu_thread_is_self(QemuThread *thread)
|
||||
{
|
||||
return pthread_equal(pthread_self(), thread->thread);
|
||||
}
|
||||
|
||||
void qemu_thread_exit(void *retval)
|
||||
{
|
||||
pthread_exit(retval);
|
||||
}
|
||||
|
||||
void *qemu_thread_join(QemuThread *thread)
|
||||
{
|
||||
int err;
|
||||
void *ret;
|
||||
|
||||
err = pthread_join(thread->thread, &ret);
|
||||
if (err) {
|
||||
error_exit(err, __func__);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
386
qemu/util/qemu-thread-win32.c
Normal file
386
qemu/util/qemu-thread-win32.c
Normal file
@@ -0,0 +1,386 @@
|
||||
/*
|
||||
* Win32 implementation for mutex/cond/thread functions
|
||||
*
|
||||
* Copyright Red Hat, Inc. 2010
|
||||
*
|
||||
* Author:
|
||||
* Paolo Bonzini <pbonzini@redhat.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*
|
||||
*/
|
||||
#include "qemu-common.h"
|
||||
#include "qemu/thread.h"
|
||||
#include <process.h>
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
|
||||
|
||||
static void error_exit(int err, const char *msg)
|
||||
{
|
||||
char *pstr;
|
||||
|
||||
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER,
|
||||
NULL, err, 0, (LPTSTR)&pstr, 2, NULL);
|
||||
fprintf(stderr, "qemu: %s: %s\n", msg, pstr);
|
||||
LocalFree(pstr);
|
||||
abort();
|
||||
}
|
||||
|
||||
void qemu_mutex_init(QemuMutex *mutex)
|
||||
{
|
||||
mutex->owner = 0;
|
||||
InitializeCriticalSection(&mutex->lock);
|
||||
}
|
||||
|
||||
void qemu_mutex_destroy(QemuMutex *mutex)
|
||||
{
|
||||
assert(mutex->owner == 0);
|
||||
DeleteCriticalSection(&mutex->lock);
|
||||
}
|
||||
|
||||
void qemu_mutex_lock(QemuMutex *mutex)
|
||||
{
|
||||
EnterCriticalSection(&mutex->lock);
|
||||
|
||||
/* Win32 CRITICAL_SECTIONs are recursive. Assert that we're not
|
||||
* using them as such.
|
||||
*/
|
||||
assert(mutex->owner == 0);
|
||||
mutex->owner = GetCurrentThreadId();
|
||||
}
|
||||
|
||||
int qemu_mutex_trylock(QemuMutex *mutex)
|
||||
{
|
||||
int owned;
|
||||
|
||||
owned = TryEnterCriticalSection(&mutex->lock);
|
||||
if (owned) {
|
||||
assert(mutex->owner == 0);
|
||||
mutex->owner = GetCurrentThreadId();
|
||||
}
|
||||
return !owned;
|
||||
}
|
||||
|
||||
void qemu_mutex_unlock(QemuMutex *mutex)
|
||||
{
|
||||
assert(mutex->owner == GetCurrentThreadId());
|
||||
mutex->owner = 0;
|
||||
LeaveCriticalSection(&mutex->lock);
|
||||
}
|
||||
|
||||
void qemu_cond_init(QemuCond *cond)
|
||||
{
|
||||
memset(cond, 0, sizeof(*cond));
|
||||
|
||||
cond->sema = CreateSemaphore(NULL, 0, LONG_MAX, NULL);
|
||||
if (!cond->sema) {
|
||||
error_exit(GetLastError(), __func__);
|
||||
}
|
||||
cond->continue_event = CreateEvent(NULL, /* security */
|
||||
FALSE, /* auto-reset */
|
||||
FALSE, /* not signaled */
|
||||
NULL); /* name */
|
||||
if (!cond->continue_event) {
|
||||
error_exit(GetLastError(), __func__);
|
||||
}
|
||||
}
|
||||
|
||||
void qemu_cond_destroy(QemuCond *cond)
|
||||
{
|
||||
BOOL result;
|
||||
result = CloseHandle(cond->continue_event);
|
||||
if (!result) {
|
||||
error_exit(GetLastError(), __func__);
|
||||
}
|
||||
cond->continue_event = 0;
|
||||
result = CloseHandle(cond->sema);
|
||||
if (!result) {
|
||||
error_exit(GetLastError(), __func__);
|
||||
}
|
||||
cond->sema = 0;
|
||||
}
|
||||
|
||||
void qemu_cond_signal(QemuCond *cond)
|
||||
{
|
||||
DWORD result;
|
||||
|
||||
/*
|
||||
* Signal only when there are waiters. cond->waiters is
|
||||
* incremented by pthread_cond_wait under the external lock,
|
||||
* so we are safe about that.
|
||||
*/
|
||||
if (cond->waiters == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Waiting threads decrement it outside the external lock, but
|
||||
* only if another thread is executing pthread_cond_broadcast and
|
||||
* has the mutex. So, it also cannot be decremented concurrently
|
||||
* with this particular access.
|
||||
*/
|
||||
cond->target = cond->waiters - 1;
|
||||
result = SignalObjectAndWait(cond->sema, cond->continue_event,
|
||||
INFINITE, FALSE);
|
||||
if (result == WAIT_ABANDONED || result == WAIT_FAILED) {
|
||||
error_exit(GetLastError(), __func__);
|
||||
}
|
||||
}
|
||||
|
||||
void qemu_cond_broadcast(QemuCond *cond)
|
||||
{
|
||||
BOOLEAN result;
|
||||
/*
|
||||
* As in pthread_cond_signal, access to cond->waiters and
|
||||
* cond->target is locked via the external mutex.
|
||||
*/
|
||||
if (cond->waiters == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
cond->target = 0;
|
||||
result = ReleaseSemaphore(cond->sema, cond->waiters, NULL);
|
||||
if (!result) {
|
||||
error_exit(GetLastError(), __func__);
|
||||
}
|
||||
|
||||
/*
|
||||
* At this point all waiters continue. Each one takes its
|
||||
* slice of the semaphore. Now it's our turn to wait: Since
|
||||
* the external mutex is held, no thread can leave cond_wait,
|
||||
* yet. For this reason, we can be sure that no thread gets
|
||||
* a chance to eat *more* than one slice. OTOH, it means
|
||||
* that the last waiter must send us a wake-up.
|
||||
*/
|
||||
WaitForSingleObject(cond->continue_event, INFINITE);
|
||||
}
|
||||
|
||||
void qemu_cond_wait(QemuCond *cond, QemuMutex *mutex)
|
||||
{
|
||||
/*
|
||||
* This access is protected under the mutex.
|
||||
*/
|
||||
cond->waiters++;
|
||||
|
||||
/*
|
||||
* Unlock external mutex and wait for signal.
|
||||
* NOTE: we've held mutex locked long enough to increment
|
||||
* waiters count above, so there's no problem with
|
||||
* leaving mutex unlocked before we wait on semaphore.
|
||||
*/
|
||||
qemu_mutex_unlock(mutex);
|
||||
WaitForSingleObject(cond->sema, INFINITE);
|
||||
|
||||
/* Now waiters must rendez-vous with the signaling thread and
|
||||
* let it continue. For cond_broadcast this has heavy contention
|
||||
* and triggers thundering herd. So goes life.
|
||||
*
|
||||
* Decrease waiters count. The mutex is not taken, so we have
|
||||
* to do this atomically.
|
||||
*
|
||||
* All waiters contend for the mutex at the end of this function
|
||||
* until the signaling thread relinquishes it. To ensure
|
||||
* each waiter consumes exactly one slice of the semaphore,
|
||||
* the signaling thread stops until it is told by the last
|
||||
* waiter that it can go on.
|
||||
*/
|
||||
if (InterlockedDecrement(&cond->waiters) == cond->target) {
|
||||
SetEvent(cond->continue_event);
|
||||
}
|
||||
|
||||
qemu_mutex_lock(mutex);
|
||||
}
|
||||
|
||||
void qemu_sem_init(QemuSemaphore *sem, int init)
|
||||
{
|
||||
/* Manual reset. */
|
||||
sem->sema = CreateSemaphore(NULL, init, LONG_MAX, NULL);
|
||||
}
|
||||
|
||||
void qemu_sem_destroy(QemuSemaphore *sem)
|
||||
{
|
||||
CloseHandle(sem->sema);
|
||||
}
|
||||
|
||||
void qemu_sem_post(QemuSemaphore *sem)
|
||||
{
|
||||
ReleaseSemaphore(sem->sema, 1, NULL);
|
||||
}
|
||||
|
||||
int qemu_sem_timedwait(QemuSemaphore *sem, int ms)
|
||||
{
|
||||
int rc = WaitForSingleObject(sem->sema, ms);
|
||||
if (rc == WAIT_OBJECT_0) {
|
||||
return 0;
|
||||
}
|
||||
if (rc != WAIT_TIMEOUT) {
|
||||
error_exit(GetLastError(), __func__);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void qemu_sem_wait(QemuSemaphore *sem)
|
||||
{
|
||||
if (WaitForSingleObject(sem->sema, INFINITE) != WAIT_OBJECT_0) {
|
||||
error_exit(GetLastError(), __func__);
|
||||
}
|
||||
}
|
||||
|
||||
void qemu_event_init(QemuEvent *ev, bool init)
|
||||
{
|
||||
/* Manual reset. */
|
||||
ev->event = CreateEvent(NULL, TRUE, init, NULL);
|
||||
}
|
||||
|
||||
void qemu_event_destroy(QemuEvent *ev)
|
||||
{
|
||||
CloseHandle(ev->event);
|
||||
}
|
||||
|
||||
void qemu_event_set(QemuEvent *ev)
|
||||
{
|
||||
SetEvent(ev->event);
|
||||
}
|
||||
|
||||
void qemu_event_reset(QemuEvent *ev)
|
||||
{
|
||||
ResetEvent(ev->event);
|
||||
}
|
||||
|
||||
void qemu_event_wait(QemuEvent *ev)
|
||||
{
|
||||
WaitForSingleObject(ev->event, INFINITE);
|
||||
}
|
||||
|
||||
struct QemuThreadData {
|
||||
/* Passed to win32_start_routine. */
|
||||
void *(*start_routine)(void *);
|
||||
void *arg;
|
||||
short mode;
|
||||
|
||||
/* Only used for joinable threads. */
|
||||
bool exited;
|
||||
void *ret;
|
||||
CRITICAL_SECTION cs;
|
||||
};
|
||||
|
||||
static __thread QemuThreadData *qemu_thread_data;
|
||||
|
||||
static unsigned __stdcall win32_start_routine(void *arg)
|
||||
{
|
||||
QemuThreadData *data = (QemuThreadData *) arg;
|
||||
void *(*start_routine)(void *) = data->start_routine;
|
||||
void *thread_arg = data->arg;
|
||||
|
||||
if (data->mode == QEMU_THREAD_DETACHED) {
|
||||
g_free(data);
|
||||
data = NULL;
|
||||
}
|
||||
qemu_thread_data = data;
|
||||
qemu_thread_exit(start_routine(thread_arg));
|
||||
abort();
|
||||
}
|
||||
|
||||
void qemu_thread_exit(void *arg)
|
||||
{
|
||||
QemuThreadData *data = qemu_thread_data;
|
||||
|
||||
if (data) {
|
||||
assert(data->mode != QEMU_THREAD_DETACHED);
|
||||
data->ret = arg;
|
||||
EnterCriticalSection(&data->cs);
|
||||
data->exited = true;
|
||||
LeaveCriticalSection(&data->cs);
|
||||
}
|
||||
_endthreadex(0);
|
||||
}
|
||||
|
||||
void *qemu_thread_join(QemuThread *thread)
|
||||
{
|
||||
QemuThreadData *data;
|
||||
void *ret;
|
||||
HANDLE handle;
|
||||
|
||||
data = thread->data;
|
||||
if (!data) {
|
||||
return NULL;
|
||||
}
|
||||
/*
|
||||
* Because multiple copies of the QemuThread can exist via
|
||||
* qemu_thread_get_self, we need to store a value that cannot
|
||||
* leak there. The simplest, non racy way is to store the TID,
|
||||
* discard the handle that _beginthreadex gives back, and
|
||||
* get another copy of the handle here.
|
||||
*/
|
||||
handle = qemu_thread_get_handle(thread);
|
||||
if (handle) {
|
||||
WaitForSingleObject(handle, INFINITE);
|
||||
CloseHandle(handle);
|
||||
}
|
||||
ret = data->ret;
|
||||
assert(data->mode != QEMU_THREAD_DETACHED);
|
||||
DeleteCriticalSection(&data->cs);
|
||||
g_free(data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void qemu_thread_create(QemuThread *thread, const char *name,
|
||||
void *(*start_routine)(void *),
|
||||
void *arg, int mode)
|
||||
{
|
||||
HANDLE hThread;
|
||||
struct QemuThreadData *data;
|
||||
|
||||
data = g_malloc(sizeof *data);
|
||||
data->start_routine = start_routine;
|
||||
data->arg = arg;
|
||||
data->mode = mode;
|
||||
data->exited = false;
|
||||
|
||||
if (data->mode != QEMU_THREAD_DETACHED) {
|
||||
InitializeCriticalSection(&data->cs);
|
||||
}
|
||||
|
||||
hThread = (HANDLE) _beginthreadex(NULL, 0, win32_start_routine,
|
||||
data, 0, &thread->tid);
|
||||
if (!hThread) {
|
||||
error_exit(GetLastError(), __func__);
|
||||
}
|
||||
CloseHandle(hThread);
|
||||
thread->data = (mode == QEMU_THREAD_DETACHED) ? NULL : data;
|
||||
}
|
||||
|
||||
void qemu_thread_get_self(QemuThread *thread)
|
||||
{
|
||||
thread->data = qemu_thread_data;
|
||||
thread->tid = GetCurrentThreadId();
|
||||
}
|
||||
|
||||
HANDLE qemu_thread_get_handle(QemuThread *thread)
|
||||
{
|
||||
QemuThreadData *data;
|
||||
HANDLE handle;
|
||||
|
||||
data = thread->data;
|
||||
if (!data) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
assert(data->mode != QEMU_THREAD_DETACHED);
|
||||
EnterCriticalSection(&data->cs);
|
||||
if (!data->exited) {
|
||||
handle = OpenThread(SYNCHRONIZE | THREAD_SUSPEND_RESUME, FALSE,
|
||||
thread->tid);
|
||||
} else {
|
||||
handle = NULL;
|
||||
}
|
||||
LeaveCriticalSection(&data->cs);
|
||||
return handle;
|
||||
}
|
||||
|
||||
bool qemu_thread_is_self(QemuThread *thread)
|
||||
{
|
||||
return GetCurrentThreadId() == thread->tid;
|
||||
}
|
||||
61
qemu/util/qemu-timer-common.c
Normal file
61
qemu/util/qemu-timer-common.c
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* QEMU System Emulator
|
||||
*
|
||||
* Copyright (c) 2003-2008 Fabrice Bellard
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#include "qemu/timer.h"
|
||||
|
||||
/***********************************************************/
|
||||
/* real time host monotonic timer */
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
int64_t clock_freq;
|
||||
|
||||
static void __attribute__((constructor)) init_get_clock(void)
|
||||
{
|
||||
LARGE_INTEGER freq;
|
||||
int ret;
|
||||
ret = QueryPerformanceFrequency(&freq);
|
||||
if (ret == 0) {
|
||||
fprintf(stderr, "Could not calibrate ticks\n");
|
||||
exit(1);
|
||||
}
|
||||
clock_freq = freq.QuadPart;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int use_rt_clock;
|
||||
|
||||
static void __attribute__((constructor)) init_get_clock(void)
|
||||
{
|
||||
use_rt_clock = 0;
|
||||
#ifdef CLOCK_MONOTONIC
|
||||
{
|
||||
struct timespec ts;
|
||||
if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
|
||||
use_rt_clock = 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
100
qemu/util/unicode.c
Normal file
100
qemu/util/unicode.c
Normal file
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Dealing with Unicode
|
||||
*
|
||||
* Copyright (C) 2013 Red Hat, Inc.
|
||||
*
|
||||
* Authors:
|
||||
* Markus Armbruster <armbru@redhat.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or
|
||||
* later. See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#include "qemu-common.h"
|
||||
|
||||
/**
|
||||
* mod_utf8_codepoint:
|
||||
* @s: string encoded in modified UTF-8
|
||||
* @n: maximum number of bytes to read from @s, if less than 6
|
||||
* @end: set to end of sequence on return
|
||||
*
|
||||
* Convert the modified UTF-8 sequence at the start of @s. Modified
|
||||
* UTF-8 is exactly like UTF-8, except U+0000 is encoded as
|
||||
* "\xC0\x80".
|
||||
*
|
||||
* If @n is zero or @s points to a zero byte, the sequence is invalid,
|
||||
* and @end is set to @s.
|
||||
*
|
||||
* If @s points to an impossible byte (0xFE or 0xFF) or a continuation
|
||||
* byte, the sequence is invalid, and @end is set to @s + 1
|
||||
*
|
||||
* Else, the first byte determines how many continuation bytes are
|
||||
* expected. If there are fewer, the sequence is invalid, and @end is
|
||||
* set to @s + 1 + actual number of continuation bytes. Else, the
|
||||
* sequence is well-formed, and @end is set to @s + 1 + expected
|
||||
* number of continuation bytes.
|
||||
*
|
||||
* A well-formed sequence is valid unless it encodes a codepoint
|
||||
* outside the Unicode range U+0000..U+10FFFF, one of Unicode's 66
|
||||
* noncharacters, a surrogate codepoint, or is overlong. Except the
|
||||
* overlong sequence "\xC0\x80" is valid.
|
||||
*
|
||||
* Conversion succeeds if and only if the sequence is valid.
|
||||
*
|
||||
* Returns: the Unicode codepoint on success, -1 on failure.
|
||||
*/
|
||||
int mod_utf8_codepoint(const char *s, size_t n, char **end)
|
||||
{
|
||||
static int min_cp[5] = { 0x80, 0x800, 0x10000, 0x200000, 0x4000000 };
|
||||
const unsigned char *p;
|
||||
unsigned byte, mask, len, i;
|
||||
int cp;
|
||||
|
||||
if (n == 0 || *s == 0) {
|
||||
/* empty sequence */
|
||||
*end = (char *)s;
|
||||
return -1;
|
||||
}
|
||||
|
||||
p = (const unsigned char *)s;
|
||||
byte = *p++;
|
||||
if (byte < 0x80) {
|
||||
cp = byte; /* one byte sequence */
|
||||
} else if (byte >= 0xFE) {
|
||||
cp = -1; /* impossible bytes 0xFE, 0xFF */
|
||||
} else if ((byte & 0x40) == 0) {
|
||||
cp = -1; /* unexpected continuation byte */
|
||||
} else {
|
||||
/* multi-byte sequence */
|
||||
len = 0;
|
||||
for (mask = 0x80; byte & mask; mask >>= 1) {
|
||||
len++;
|
||||
}
|
||||
assert(len > 1 && len < 7);
|
||||
cp = byte & (mask - 1);
|
||||
for (i = 1; i < len; i++) {
|
||||
byte = i < n ? *p : 0;
|
||||
if ((byte & 0xC0) != 0x80) {
|
||||
cp = -1; /* continuation byte missing */
|
||||
goto out;
|
||||
}
|
||||
p++;
|
||||
cp <<= 6;
|
||||
cp |= byte & 0x3F;
|
||||
}
|
||||
if (cp > 0x10FFFF) {
|
||||
cp = -1; /* beyond Unicode range */
|
||||
} else if ((cp >= 0xFDD0 && cp <= 0xFDEF)
|
||||
|| (cp & 0xFFFE) == 0xFFFE) {
|
||||
cp = -1; /* noncharacter */
|
||||
} else if (cp >= 0xD800 && cp <= 0xDFFF) {
|
||||
cp = -1; /* surrogate code point */
|
||||
} else if (cp < min_cp[len - 2] && !(cp == 0 && len == 2)) {
|
||||
cp = -1; /* overlong, not \xC0\x80 */
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
*end = (char *)p;
|
||||
return cp;
|
||||
}
|
||||
Reference in New Issue
Block a user