]> git.proxmox.com Git - mirror_qemu.git/blobdiff - util/bitmap.c
vl: make sure char-pty message displayed by moving setbuf to the beginning
[mirror_qemu.git] / util / bitmap.c
index 687841dcec01cb850e40c442e4995dfcf70b372c..cb618c65a537f4fca7cf4e5ab814886cae105fd4 100644 (file)
@@ -9,11 +9,13 @@
  * Version 2.
  */
 
+#include "qemu/osdep.h"
 #include "qemu/bitops.h"
 #include "qemu/bitmap.h"
+#include "qemu/atomic.h"
 
 /*
- * bitmaps provide an array of bits, implemented using an an
+ * bitmaps provide an array of bits, implemented using 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.
@@ -36,9 +38,9 @@
  * endian architectures.
  */
 
-int slow_bitmap_empty(const unsigned long *bitmap, int bits)
+int slow_bitmap_empty(const unsigned long *bitmap, long bits)
 {
-    int k, lim = bits/BITS_PER_LONG;
+    long k, lim = bits/BITS_PER_LONG;
 
     for (k = 0; k < lim; ++k) {
         if (bitmap[k]) {
@@ -54,9 +56,9 @@ int slow_bitmap_empty(const unsigned long *bitmap, int bits)
     return 1;
 }
 
-int slow_bitmap_full(const unsigned long *bitmap, int bits)
+int slow_bitmap_full(const unsigned long *bitmap, long bits)
 {
-    int k, lim = bits/BITS_PER_LONG;
+    long k, lim = bits/BITS_PER_LONG;
 
     for (k = 0; k < lim; ++k) {
         if (~bitmap[k]) {
@@ -74,9 +76,9 @@ int slow_bitmap_full(const unsigned long *bitmap, int bits)
 }
 
 int slow_bitmap_equal(const unsigned long *bitmap1,
-                      const unsigned long *bitmap2, int bits)
+                      const unsigned long *bitmap2, long bits)
 {
-    int k, lim = bits/BITS_PER_LONG;
+    long k, lim = bits/BITS_PER_LONG;
 
     for (k = 0; k < lim; ++k) {
         if (bitmap1[k] != bitmap2[k]) {
@@ -94,9 +96,9 @@ int slow_bitmap_equal(const unsigned long *bitmap1,
 }
 
 void slow_bitmap_complement(unsigned long *dst, const unsigned long *src,
-                            int bits)
+                            long bits)
 {
-    int k, lim = bits/BITS_PER_LONG;
+    long k, lim = bits/BITS_PER_LONG;
 
     for (k = 0; k < lim; ++k) {
         dst[k] = ~src[k];
@@ -108,10 +110,10 @@ void slow_bitmap_complement(unsigned long *dst, const unsigned long *src,
 }
 
 int slow_bitmap_and(unsigned long *dst, const unsigned long *bitmap1,
-                    const unsigned long *bitmap2, int bits)
+                    const unsigned long *bitmap2, long bits)
 {
-    int k;
-    int nr = BITS_TO_LONGS(bits);
+    long k;
+    long nr = BITS_TO_LONGS(bits);
     unsigned long result = 0;
 
     for (k = 0; k < nr; k++) {
@@ -121,10 +123,10 @@ int slow_bitmap_and(unsigned long *dst, const unsigned long *bitmap1,
 }
 
 void slow_bitmap_or(unsigned long *dst, const unsigned long *bitmap1,
-                    const unsigned long *bitmap2, int bits)
+                    const unsigned long *bitmap2, long bits)
 {
-    int k;
-    int nr = BITS_TO_LONGS(bits);
+    long k;
+    long nr = BITS_TO_LONGS(bits);
 
     for (k = 0; k < nr; k++) {
         dst[k] = bitmap1[k] | bitmap2[k];
@@ -132,10 +134,10 @@ void slow_bitmap_or(unsigned long *dst, const unsigned long *bitmap1,
 }
 
 void slow_bitmap_xor(unsigned long *dst, const unsigned long *bitmap1,
-                     const unsigned long *bitmap2, int bits)
+                     const unsigned long *bitmap2, long bits)
 {
-    int k;
-    int nr = BITS_TO_LONGS(bits);
+    long k;
+    long nr = BITS_TO_LONGS(bits);
 
     for (k = 0; k < nr; k++) {
         dst[k] = bitmap1[k] ^ bitmap2[k];
@@ -143,10 +145,10 @@ void slow_bitmap_xor(unsigned long *dst, const unsigned long *bitmap1,
 }
 
 int slow_bitmap_andnot(unsigned long *dst, const unsigned long *bitmap1,
-                       const unsigned long *bitmap2, int bits)
+                       const unsigned long *bitmap2, long bits)
 {
-    int k;
-    int nr = BITS_TO_LONGS(bits);
+    long k;
+    long nr = BITS_TO_LONGS(bits);
     unsigned long result = 0;
 
     for (k = 0; k < nr; k++) {
@@ -155,15 +157,15 @@ int slow_bitmap_andnot(unsigned long *dst, const unsigned long *bitmap1,
     return result != 0;
 }
 
-#define BITMAP_FIRST_WORD_MASK(start) (~0UL << ((start) % BITS_PER_LONG))
-
-void bitmap_set(unsigned long *map, int start, int nr)
+void bitmap_set(unsigned long *map, long start, long nr)
 {
     unsigned long *p = map + BIT_WORD(start);
-    const int size = start + nr;
+    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);
 
+    assert(start >= 0 && nr >= 0);
+
     while (nr - bits_to_set >= 0) {
         *p |= mask_to_set;
         nr -= bits_to_set;
@@ -177,13 +179,54 @@ void bitmap_set(unsigned long *map, int start, int nr)
     }
 }
 
-void bitmap_clear(unsigned long *map, int start, int nr)
+void bitmap_set_atomic(unsigned long *map, long start, long nr)
 {
     unsigned long *p = map + BIT_WORD(start);
-    const int size = start + nr;
+    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);
+
+    assert(start >= 0 && nr >= 0);
+
+    /* First word */
+    if (nr - bits_to_set > 0) {
+        atomic_or(p, mask_to_set);
+        nr -= bits_to_set;
+        bits_to_set = BITS_PER_LONG;
+        mask_to_set = ~0UL;
+        p++;
+    }
+
+    /* Full words */
+    if (bits_to_set == BITS_PER_LONG) {
+        while (nr >= BITS_PER_LONG) {
+            *p = ~0UL;
+            nr -= BITS_PER_LONG;
+            p++;
+        }
+    }
+
+    /* Last word */
+    if (nr) {
+        mask_to_set &= BITMAP_LAST_WORD_MASK(size);
+        atomic_or(p, mask_to_set);
+    } else {
+        /* If we avoided the full barrier in atomic_or(), issue a
+         * barrier to account for the assignments in the while loop.
+         */
+        smp_mb();
+    }
+}
+
+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);
 
+    assert(start >= 0 && nr >= 0);
+
     while (nr - bits_to_clear >= 0) {
         *p &= ~mask_to_clear;
         nr -= bits_to_clear;
@@ -197,6 +240,64 @@ void bitmap_clear(unsigned long *map, int start, int nr)
     }
 }
 
+bool bitmap_test_and_clear_atomic(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);
+    unsigned long dirty = 0;
+    unsigned long old_bits;
+
+    assert(start >= 0 && nr >= 0);
+
+    /* First word */
+    if (nr - bits_to_clear > 0) {
+        old_bits = atomic_fetch_and(p, ~mask_to_clear);
+        dirty |= old_bits & mask_to_clear;
+        nr -= bits_to_clear;
+        bits_to_clear = BITS_PER_LONG;
+        mask_to_clear = ~0UL;
+        p++;
+    }
+
+    /* Full words */
+    if (bits_to_clear == BITS_PER_LONG) {
+        while (nr >= BITS_PER_LONG) {
+            if (*p) {
+                old_bits = atomic_xchg(p, 0);
+                dirty |= old_bits;
+            }
+            nr -= BITS_PER_LONG;
+            p++;
+        }
+    }
+
+    /* Last word */
+    if (nr) {
+        mask_to_clear &= BITMAP_LAST_WORD_MASK(size);
+        old_bits = atomic_fetch_and(p, ~mask_to_clear);
+        dirty |= old_bits & mask_to_clear;
+    } else {
+        if (!dirty) {
+            smp_mb();
+        }
+    }
+
+    return dirty != 0;
+}
+
+void bitmap_copy_and_clear_atomic(unsigned long *dst, unsigned long *src,
+                                  long nr)
+{
+    while (nr > 0) {
+        *dst = atomic_xchg(src, 0);
+        dst++;
+        src++;
+        nr -= BITS_PER_LONG;
+    }
+}
+
 #define ALIGN_MASK(x,mask)      (((x)+(mask))&~(mask))
 
 /**
@@ -212,10 +313,10 @@ void bitmap_clear(unsigned long *map, int start, int nr)
  * 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 int nr,
-                                        unsigned long align_mask)
+                                         unsigned long size,
+                                         unsigned long start,
+                                         unsigned long nr,
+                                         unsigned long align_mask)
 {
     unsigned long index, end, i;
 again:
@@ -237,9 +338,9 @@ again:
 }
 
 int slow_bitmap_intersects(const unsigned long *bitmap1,
-                           const unsigned long *bitmap2, int bits)
+                           const unsigned long *bitmap2, long bits)
 {
-    int k, lim = bits/BITS_PER_LONG;
+    long k, lim = bits/BITS_PER_LONG;
 
     for (k = 0; k < lim; ++k) {
         if (bitmap1[k] & bitmap2[k]) {
@@ -254,3 +355,50 @@ int slow_bitmap_intersects(const unsigned long *bitmap1,
     }
     return 0;
 }
+
+long slow_bitmap_count_one(const unsigned long *bitmap, long nbits)
+{
+    long k, lim = nbits / BITS_PER_LONG, result = 0;
+
+    for (k = 0; k < lim; k++) {
+        result += ctpopl(bitmap[k]);
+    }
+
+    if (nbits % BITS_PER_LONG) {
+        result += ctpopl(bitmap[k] & BITMAP_LAST_WORD_MASK(nbits));
+    }
+
+    return result;
+}
+
+static void bitmap_to_from_le(unsigned long *dst,
+                              const unsigned long *src, long nbits)
+{
+    long len = BITS_TO_LONGS(nbits);
+
+#ifdef HOST_WORDS_BIGENDIAN
+    long index;
+
+    for (index = 0; index < len; index++) {
+# if HOST_LONG_BITS == 64
+        dst[index] = bswap64(src[index]);
+# else
+        dst[index] = bswap32(src[index]);
+# endif
+    }
+#else
+    memcpy(dst, src, len * sizeof(unsigned long));
+#endif
+}
+
+void bitmap_from_le(unsigned long *dst, const unsigned long *src,
+                    long nbits)
+{
+    bitmap_to_from_le(dst, src, nbits);
+}
+
+void bitmap_to_le(unsigned long *dst, const unsigned long *src,
+                  long nbits)
+{
+    bitmap_to_from_le(dst, src, nbits);
+}