]> rtime.felk.cvut.cz Git - l4.git/commitdiff
update
authorl4check <l4check@d050ee49-bd90-4346-b210-929a50b99cfc>
Fri, 7 Jun 2013 07:57:24 +0000 (07:57 +0000)
committerl4check <l4check@d050ee49-bd90-4346-b210-929a50b99cfc>
Fri, 7 Jun 2013 07:57:24 +0000 (07:57 +0000)
git-svn-id: http://svn.tudos.org/repos/oc/tudos/trunk@56 d050ee49-bd90-4346-b210-929a50b99cfc

145 files changed:
kernel/fiasco/src/Makeconf
kernel/fiasco/src/abi/amd64/kip-amd64.cpp
kernel/fiasco/src/abi/arm/kip-arm.cpp
kernel/fiasco/src/abi/ia32/kip-ia32.cpp
kernel/fiasco/src/abi/kip.cpp
kernel/fiasco/src/abi/ppc32/kip-ppc32.cpp
kernel/fiasco/src/abi/sparc/kip-sparc.cpp
kernel/fiasco/src/boot/amd64/Makerules.BOOT.amd64
kernel/fiasco/src/boot/ia32/Makerules.BOOT.ia32
kernel/fiasco/src/drivers/arm/processor-arm.cpp
kernel/fiasco/src/jdb/arm/jdb-arm.cpp
kernel/fiasco/src/jdb/arm/jdb_kern_info-cpu-arm.cpp
kernel/fiasco/src/kern/app_cpu_thread.cpp
kernel/fiasco/src/kern/arm/Makerules.KERNEL
kernel/fiasco/src/kern/arm/bsp/bcm2835/pic-arm-bcm2835.cpp
kernel/fiasco/src/kern/arm/bsp/exynos/pic-arm-gic-exynos.cpp
kernel/fiasco/src/kern/arm/bsp/exynos/platform_control-arm-exynos.cpp
kernel/fiasco/src/kern/arm/bsp/imx/pic-arm-imx.cpp
kernel/fiasco/src/kern/arm/bsp/integrator/pic-arm-integrator.cpp
kernel/fiasco/src/kern/arm/bsp/kirkwood/pic-arm-kirkwood.cpp
kernel/fiasco/src/kern/arm/bsp/omap/pic-arm-omap3.cpp
kernel/fiasco/src/kern/arm/bsp/pxa-sa/pic-arm-pxa_sa1100.cpp
kernel/fiasco/src/kern/arm/bsp/s3c/pic-arm-s3c2410.cpp
kernel/fiasco/src/kern/arm/gic.cpp
kernel/fiasco/src/kern/arm/ivt.S
kernel/fiasco/src/kern/arm/kern_lib_page.cpp
kernel/fiasco/src/kern/arm/kip_init.cpp
kernel/fiasco/src/kern/arm/kmem.cpp
kernel/fiasco/src/kern/arm/kmem_alloc-arm.cpp
kernel/fiasco/src/kern/arm/mem_unit.cpp
kernel/fiasco/src/kern/arm/thread-arm.cpp
kernel/fiasco/src/kern/arm/timer-arm.cpp
kernel/fiasco/src/kern/arm/vmem_alloc-arch.cpp
kernel/fiasco/src/kern/cascade_irq.cpp
kernel/fiasco/src/kern/config.cpp
kernel/fiasco/src/kern/context.cpp
kernel/fiasco/src/kern/cpu.cpp
kernel/fiasco/src/kern/ia32/64/main-ia32-64.cpp
kernel/fiasco/src/kern/ia32/io_apic.cpp
kernel/fiasco/src/kern/ia32/irq_chip_pic.cpp
kernel/fiasco/src/kern/ia32/irq_msi.cpp
kernel/fiasco/src/kern/ia32/kip_init-ia32.cpp
kernel/fiasco/src/kern/ia32/timer-pit.cpp
kernel/fiasco/src/kern/ia32/timer-rtc.cpp
kernel/fiasco/src/kern/icu_helper.cpp
kernel/fiasco/src/kern/irq.cpp
kernel/fiasco/src/kern/irq_chip.cpp
kernel/fiasco/src/kern/irq_controller.cpp
kernel/fiasco/src/kern/kernel_uart.cpp
kernel/fiasco/src/kern/ppc32/Makerules.KERNEL
kernel/fiasco/src/kern/ppc32/bsp/mpc52xx/pic-mpc52xx.cpp
kernel/fiasco/src/kern/ppc32/kip_init.cpp
kernel/fiasco/src/kern/ppc32/timer-decr-ppc32.cpp
kernel/fiasco/src/kern/rcupdate.cpp
kernel/fiasco/src/kern/scheduler.cpp
kernel/fiasco/src/kern/sparc/Makerules.KERNEL
kernel/fiasco/src/kern/sparc/bsp/leon3/pic-sparc-leon3.cpp
kernel/fiasco/src/kern/sparc/kip_init.cpp
kernel/fiasco/src/kern/sparc/timer-decr-sparc.cpp
kernel/fiasco/src/kern/thread_object.cpp
kernel/fiasco/src/kern/timer-hpet.cpp
kernel/fiasco/src/kern/timer_tick-broadcast.cpp
kernel/fiasco/src/kern/timer_tick-single-vector.cpp
kernel/fiasco/src/kern/timer_tick.cpp
kernel/fiasco/src/kern/ux/Makerules.KERNEL
kernel/fiasco/src/kern/ux/timer-ux.cpp
kernel/fiasco/src/kern/vlog.cpp
kernel/fiasco/src/lib/libk/bitmap.cpp
l4/mk/Makeconf
l4/mk/defconfig/config.arm-rv
l4/mk/lib.mk
l4/mk/platforms/tegra3.conf [new file with mode: 0644]
l4/pkg/Makefile
l4/pkg/bootstrap/server/src/Makefile.platform
l4/pkg/bootstrap/server/src/platform/tegra3.cc [new file with mode: 0644]
l4/pkg/bootstrap/server/src/region.cc
l4/pkg/bootstrap/server/src/region.h
l4/pkg/bootstrap/server/src/startup.cc
l4/pkg/cxx/lib/tl/include/Makefile
l4/pkg/cxx/lib/tl/include/bitfield
l4/pkg/cxx/lib/tl/include/type_traits
l4/pkg/cxx/lib/tl/include/unique_ptr [new file with mode: 0644]
l4/pkg/drivers-frst/of/include/of.h
l4/pkg/drivers-frst/uart/src/uart_sa1000.cc
l4/pkg/examples/sys/aliens/main.c
l4/pkg/examples/sys/singlestep/main.c
l4/pkg/examples/sys/start-with-exc/main.c
l4/pkg/examples/sys/utcb-ipc/main.c
l4/pkg/io/config/arm-omap3.devs
l4/pkg/io/doc/example.io
l4/pkg/io/doc/example_pci.io
l4/pkg/l4sys/include/ARCH-amd64/__kip-arch.h [new file with mode: 0644]
l4/pkg/l4sys/include/ARCH-arm/__kip-arch.h [new file with mode: 0644]
l4/pkg/l4sys/include/ARCH-ppc32/__kip-arch.h [new file with mode: 0644]
l4/pkg/l4sys/include/ARCH-sparc/__kip-arch.h [new file with mode: 0644]
l4/pkg/l4sys/include/ARCH-x86/__kip-arch.h [new file with mode: 0644]
l4/pkg/l4sys/include/kip.h
l4/pkg/l4sys/include/types.h
l4/pkg/l4sys/include/utcb.h
l4/pkg/l4util/include/ARCH-x86/port_io.h
l4/pkg/l4util/include/mb_info.h
l4/pkg/libgcc/lib/ARCH-arm/l4-atomic.c
l4/pkg/libstdc++-headers/include/bits/gthr-posix.h
l4/pkg/libvcpu/include/vcpu
l4/pkg/libvcpu/include/vcpu.h
l4/pkg/plr/Makefile
l4/pkg/plr/doc/threadini.sh
l4/pkg/plr/ex/Makefile
l4/pkg/plr/ex/large_malloc/main.cc
l4/pkg/plr/ex/pthread_mutex/main.c
l4/pkg/plr/ex/superpages/Makefile [new file with mode: 0644]
l4/pkg/plr/ex/superpages/main.cc [new file with mode: 0644]
l4/pkg/plr/include/cpuid.h [new file with mode: 0644]
l4/pkg/plr/include/perf.h [new file with mode: 0644]
l4/pkg/plr/lib/Makefile
l4/pkg/plr/lib/libperfcnt/Makefile [new file with mode: 0644]
l4/pkg/plr/lib/libperfcnt/pcnt.c [new file with mode: 0644]
l4/pkg/plr/lib/libperfcnt/perfcnt.diff [new file with mode: 0644]
l4/pkg/plr/server/src/app_loading
l4/pkg/plr/server/src/app_loading.cc
l4/pkg/plr/server/src/cpuid.h
l4/pkg/plr/server/src/fault_handlers/observers.h
l4/pkg/plr/server/src/fault_handlers/pagefault.cc
l4/pkg/plr/server/src/fault_handlers/print_vcpu_state.cc
l4/pkg/plr/server/src/fault_handlers/syscalls.cc
l4/pkg/plr/server/src/memory
l4/pkg/plr/server/src/memory.cc
l4/pkg/plr/tools/Makefile [new file with mode: 0644]
l4/pkg/plr/tools/perfmon/Makefile [new file with mode: 0644]
l4/pkg/plr/tools/perfmon/main.cc [new file with mode: 0644]
l4/pkg/sqlite/lib/README
l4/pkg/sqlite/lib/contrib/configure
l4/pkg/sqlite/lib/contrib/configure.ac
l4/pkg/sqlite/lib/contrib/shell.c
l4/pkg/sqlite/lib/contrib/sqlite3.c
l4/pkg/sqlite/lib/contrib/sqlite3.h
l4/pkg/sqlite/lib/contrib/sqlite3ext.h
l4/pkg/uclibc/lib/contrib/uclibc/include/features.h
l4/pkg/uclibc/lib/libpthread/src/Makefile
l4/pkg/uclibc/lib/uclibc/ARCH-amd64/include/bits/uClibc_config.h
l4/pkg/uclibc/lib/uclibc/ARCH-arm/include/bits/uClibc_config.h
l4/pkg/uclibc/lib/uclibc/ARCH-ppc32/include/bits/uClibc_config.h
l4/pkg/uclibc/lib/uclibc/ARCH-sparc/include/bits/uClibc_config.h
l4/pkg/uclibc/lib/uclibc/ARCH-x86/include/bits/uClibc_config.h
l4/pkg/uclibc/lib/uclibc/contrib_files.mk

index 75ca8806e69cb679b63db2cfbdb465039be38caf..9483be92787e37041ace5e3056b9077998a97fd9 100644 (file)
@@ -171,6 +171,8 @@ OK_MESSAGE      ?=
 
 COMP_MESSAGE_NOOPT ?= $(COMP_MESSAGE)
 
+ADD_CONFIGFILE   = $(VERBOSE)$(OBJCOPY) --add-section .debug.fiasco_config=globalconfig.out $(1)
+
 ifneq ($(VERBOSE),)
 MOVE_IF_CHANGE += -q
 endif
index 9400e83a7288366ba62e0bdefaf2e289c1d223df..70ada111163b955f4ea8deee29d71d8d9c28891d 100644 (file)
@@ -9,6 +9,11 @@ INTERFACE [amd64]:
 EXTENSION class Kip
 {
 public:
+  struct Platform_info
+  {
+    char name[16];
+    Unsigned32 is_mp;
+  };
 
   /* 0x00 */
   Mword      magic;
@@ -66,6 +71,7 @@ public:
   Mword      _res8[2];
 
   /* 0x1E0 */
-  Unsigned32 __reserved[20];
+  Platform_info platform_info;
+  Unsigned32 __reserved[3];
 };
 
index 05dfdae27aeacdbcf066bc2e86f9880bc286dc76..77a25388c474972970d990cb0224c0eeac430d31 100644 (file)
@@ -11,8 +11,16 @@ EXTENSION class Kip
 public:
   struct Platform_info
   {
-    Unsigned32 cpuid;
-    Unsigned32 mp;
+    char name[16];
+    Unsigned32 is_mp;
+    struct
+    {
+      struct
+      {
+        Unsigned32 MIDR, CTR, ID_MMFR0, ID_ISAR0;
+      } cpuinfo;
+    } arch;
+    Unsigned32 pad[3];
   };
 
   /* 0x00 */
@@ -70,7 +78,6 @@ public:
 
   /* 0xF0 */
   Platform_info platform_info;
-  Unsigned32 __reserved[18];
 };
 
 //---------------------------------------------------------------------------
index f60bfa85f5beac33580aa33cefca4157bd2e5155..28e349454c9f4c3f63463691d842e7dae1d99be5 100644 (file)
@@ -13,6 +13,11 @@ INTERFACE [ia32 || ux]:
 EXTENSION class Kip
 {
 public:
+  struct Platform_info
+  {
+    char name[16];
+    Unsigned32 is_mp;
+  };
 
   /* 0x00 */
   Mword      magic;
@@ -68,7 +73,8 @@ public:
   Unsigned32 _res8[2];
 
   /* 0xF0 */
-  Unsigned32 __reserved[20];
+  Platform_info platform_info;
+  Unsigned32 __reserved[3];
 };
 
 //---------------------------------------------------------------------------
index 0a6e4e4c59e451a748ffdfee74c206275659695d..b7687f7027b94f011e1e664fe9c8a575c4869ef5 100644 (file)
@@ -146,6 +146,8 @@ void Kip::init_global_kip(Kip *kip)
 {
   global_kip = kip;
 
+  kip->platform_info.is_mp = Config::Max_num_cpus > 1;
+
   // check that the KIP has actually been set up
   //assert(kip->sigma0_ip && kip->root_ip && kip->user_ptr);
 }
index c740a92d8162b75c5e3a7e6f2076ec768e20f2b9..8c0a55010ed1573c2ae7f4465b92dec47c09b473 100644 (file)
@@ -9,6 +9,11 @@ INTERFACE [ppc32]:
 EXTENSION class Kip
 {
 public:
+  struct Platform_info
+  {
+    char name[16];
+    Unsigned32 is_mp;
+  };
 
   /* 0x00 */
   Mword      magic;
@@ -64,7 +69,8 @@ public:
   Unsigned32 _res8[2];
 
   /* 0xF0 */
-  Unsigned32 __reserved[20];
+  Platform_info platform_info;
+  Unsigned32 __reserved[3];
 };
 
 //---------------------------------------------------------------------------
index 352e0a987786376aed709da3c2101bca2faac438..fd5b15371cb2dca8781b3c6aea0929361064a174 100644 (file)
@@ -9,6 +9,11 @@ INTERFACE [sparc]:
 EXTENSION class Kip
 {
 public:
+  struct Platform_info
+  {
+    char name[16];
+    Unsigned32 is_mp;
+  };
 
   /* 0x00 */
   Mword      magic;
@@ -64,7 +69,8 @@ public:
   Unsigned32 _res8[2];
 
   /* 0xF0 */
-  Unsigned32 __reserved[20];
+  Platform_info platform_info;
+  Unsigned32 __reserved[3];
 };
 
 //---------------------------------------------------------------------------
index 2039c3a33f4ec2c4c119392d59a2763ebbdddb8a..a4385f8bce944f58727532713daf8086b37a26a3 100644 (file)
@@ -29,6 +29,7 @@ $(KERNEL):    kernel.amd64.lds boot_img.o $(CRT0) $(OBJ_KERNEL) $(JDB) $(LIBK) $(KE
                $(LINK_MESSAGE)
                $(VERBOSE)$(LD) -m elf_x86_64 -N -T $< -gc-sections \
                -o $@ $(filter-out $<,$+) $(LIBGCC) $(KERNEL_UNRES_SYMS)
+               $(call ADD_CONFIGFILE,$@)
 
 # '$(RM) main' should be removed later - Late 2012
 $(BOOT): $(KERNEL)
index 3e0600cb1cc23ad6527334a09a37f97d08e1ae00..5b0c31a3167f1e02d4ff15c4157f63c70ac03faf 100644 (file)
@@ -35,6 +35,7 @@ $(KERNEL):    kernel.ia32.lds boot_img.o $(CRT0) $(OBJ_KERNEL) $(JDB) $(LIBK) $(KER
                $(VERBOSE)$(LD) -m $(LD_EMULATION) -N -o $@ \
                   -T $< -gc-sections $(filter-out $<,$+) \
                   $(KERNEL_UNRES_SYMS)
+               $(call ADD_CONFIGFILE,$@)
 
 # '$(RM) main' should be removed later - Late 2012
 $(BOOT): $(KERNEL)
index 41598371a2e3f3bfc945f46aa41a0ef96b6adbd4..2dcfdd16950c609f5d82422b51dcfc8054b86c13 100644 (file)
@@ -233,7 +233,9 @@ IMPLEMENTATION[arm && (armca8 || armca9)]:
 
 IMPLEMENT static inline
 void Proc::pause()
-{}
+{
+  asm("yield");
+}
 
 IMPLEMENT static inline
 void Proc::halt()
index 0f989b72b9b06b0dfb91467809c8ff988757284c..a6933e31fcf9e79fe7900f2dbaf8e5b35e1f3d31 100644 (file)
@@ -173,7 +173,7 @@ Jdb::access_mem_task(Address virt, Space * task)
         {
           pte.create_page(Phys_mem_addr(cxx::mask_lsb(phys, pte.page_order())),
                           Page::Attr(Page::Rights::RW()));
-          pte.write_back_if(true);
+          pte.write_back_if(true, Mem_unit::Asid_kernel);
         }
 
       Mem_unit::tlb_flush();
index 74c8a9982407f0ac1ab3ef0d022d2b4406692a2e..52b8527a0a86128a38837233fa7a68e83bc678a6 100644 (file)
@@ -36,6 +36,7 @@ Jdb_kern_info_cpu::mrc(Mword insn)
   char *m = reinterpret_cast<char *>(jdb_mrc_insn);
   *reinterpret_cast<Mword *>(m) = insn;
   Mem_unit::flush_cache(m, m);
+  Mem::isb();
   return jdb_mrc_insn(0);
 }
 
@@ -112,7 +113,6 @@ Jdb_kern_info_cpu::show()
        cp_vals[i].show(val);
     }
 
-
   printf("Main ID:                                       %08lx\n", mrc(15, 0,  0,  0, 0));
   printf("Cache type:                                    %08lx\n", mrc(15, 0,  0,  0, 1));
   printf("TCM Status:                                    %08lx\n", mrc(15, 0,  0,  0, 2));
index 4ad65e1cfa8b398a7fd7ceae879e1765a9df718f..ce70d1207cbe53436ece66c0ddd68a35b8b03129 100644 (file)
@@ -33,7 +33,10 @@ Kernel_thread *
 App_cpu_thread::may_be_create(Cpu_number cpu, bool cpu_never_seen_before)
 {
   if (!cpu_never_seen_before)
-    return static_cast<Kernel_thread *>(kernel_context(cpu));
+    {
+      kernel_context(cpu)->reset_kernel_sp();
+      return static_cast<Kernel_thread *>(kernel_context(cpu));
+    }
 
   Kernel_thread *t = new (Ram_quota::root) App_cpu_thread;
   assert (t);
index 1d88bc6ce423eab510ded4d8b79c393424e52b17..3ab5530128e040158c91109c5dfe59db25433fce 100644 (file)
@@ -1,4 +1,5 @@
 # -*- makefile -*-
+# vim:se ft=make:
 
 ivt.o: $(TCBOFFSET)
 tramp-mp.o: $(TCBOFFSET)
@@ -17,6 +18,10 @@ $(KERNEL).image: kernel.arm.lds $(CRT0) bootstrap.$(KERNEL).o $(OBJ_KERNEL_noboo
        $(LINK_MESSAGE)
        $(VERBOSE)$(LD) $(LDFLAGS) -N -defsym kernel_load_addr=$(CONFIG_KERNEL_LOAD_ADDR) \
           -T $< -o $@ $(filter-out $<,$+)
+       $(call ADD_CONFIGFILE,$@)
+       $(VERBOSE)if [ -n "$$($(NM) -C bootstrap.o | grep "         U " | grep -vE 'Mem_layout::__ph_to_pm|_start_kernel|kernel_page_directory|kernel_lpae_dir|my_kernel_info_page')" ]; then \
+         echo "bootstrap.o contains unknown unresolved symbols."; exit 1; \
+       fi
 
 $(KERNEL): $(KERNEL).image
        $(LINK_MESSAGE)
index 2f24e09e07764d7b1f24ed94fc65850149866222..20ed280272e7ef56bc00f04d18a0cee7f874e736 100644 (file)
@@ -25,7 +25,8 @@ public:
     Disable_Basic_IRQs = 0x24,
   };
 
-  unsigned set_mode(Mword, unsigned) { return Irq_base::Trigger_level; }
+  int set_mode(Mword, Mode) { return 0; }
+  bool is_edge_triggered(Mword) const { return false; }
   void set_cpu(Mword, Cpu_number) {}
   void ack(Mword) { /* ack is empty */ }
 };
index 6f6dd76a0dcc952039c3d2212f5500944d5d5a47..dafa817ba7f360a5cff0f1d0e56f0ced9adc5482 100644 (file)
@@ -75,21 +75,24 @@ public:
   { Io::clear<Mword>(1 << (pin & 7), _gpio_base + MASK + offs(pin)); }
 
   void set_cpu(Mword, Cpu_number) {}
-  unsigned set_mode(Mword pin, unsigned m)
+  int set_mode(Mword pin, Mode m)
   {
     unsigned v;
 
-    m &= ~1;
+    if (m.wakeup())
+      return -L4_err::EInval;
 
-    switch (m)
+    if (!m.set_mode())
+      return 0;
+
+    switch (m.flow_type())
     {
-      default: m = Irq_base::Trigger_level | Irq_base::Polarity_low;
-               /* Fall-through */
-      case Irq_base::Trigger_level | Irq_base::Polarity_low:  v = 0; break;
-      case Irq_base::Trigger_level | Irq_base::Polarity_high: v = 1; break;
-      case Irq_base::Trigger_edge  | Irq_base::Polarity_low:  v = 2; break;
-      case Irq_base::Trigger_edge  | Irq_base::Polarity_high: v = 3; break;
-      case Irq_base::Trigger_edge  | Irq_base::Polarity_both: v = 4; break;
+      default:
+      case Irq_chip::Mode::Trigger_level | Irq_chip::Mode::Polarity_low:  v = 0; break;
+      case Irq_chip::Mode::Trigger_level | Irq_chip::Mode::Polarity_high: v = 1; break;
+      case Irq_chip::Mode::Trigger_edge  | Irq_chip::Mode::Polarity_low:  v = 2; break;
+      case Irq_chip::Mode::Trigger_edge  | Irq_chip::Mode::Polarity_high: v = 3; break;
+      case Irq_chip::Mode::Trigger_edge  | Irq_chip::Mode::Polarity_both: v = 4; break;
     };
 
     Mword a = _gpio_base + INTCON + offs(pin);
@@ -97,8 +100,18 @@ public:
     v <<= pin * 4;
     Io::write<Mword>((Io::read<Mword>(a) & ~(7 << (pin * 4))) | v, a);
 
-    return m;
+    return 0;
   }
+
+  bool is_edge_triggered(Mword pin) const
+  {
+    unsigned v;
+    Mword a = _gpio_base + INTCON + offs(pin);
+    pin = pin % 8;
+    v = (Io::read<Mword>(a) >> (pin * 4)) & 7;
+    return v & 6;
+  }
+
   unsigned pending() { return Io::read<Mword>(_gpio_base + 0xb08); }
 
 private:
@@ -118,7 +131,8 @@ private:
 public:
   explicit Gpio_wakeup_chip(Address physbase)
   : Irq_chip_gen(32),
-    Mmio_register_block(Kmem::mmio_remap(physbase))
+    Mmio_register_block(Kmem::mmio_remap(physbase)),
+    _wakeup(0)
   {}
 
   void mask(Mword pin)
@@ -133,20 +147,29 @@ public:
   { modify<Mword>(0, 1 << (pin & 7), MASK + offs(pin)); }
   void set_cpu(Mword, Cpu_number) {}
 
-  unsigned set_mode(Mword pin, unsigned m)
+  int set_mode(Mword pin, Mode m)
   {
     unsigned v;
-    m &= ~1;
 
-    switch (m)
+    if (m.set_wakeup() && m.clear_wakeup())
+      return -L4_err::EInval;
+
+    if (m.set_wakeup())
+      _wakeup |= 1 << pin;
+    else if (m.clear_wakeup())
+      _wakeup &= ~(1 << pin);
+
+    if (!m.set_mode())
+      return 0;
+
+    switch (m.flow_type())
     {
-      default: m = Irq_base::Trigger_level | Irq_base::Polarity_low;
-               /* Fall-through */
-      case Irq_base::Trigger_level | Irq_base::Polarity_low:  v = 0; break;
-      case Irq_base::Trigger_level | Irq_base::Polarity_high: v = 1; break;
-      case Irq_base::Trigger_edge  | Irq_base::Polarity_low:  v = 2; break;
-      case Irq_base::Trigger_edge  | Irq_base::Polarity_high: v = 3; break;
-      case Irq_base::Trigger_edge  | Irq_base::Polarity_both: v = 4; break;
+      default:
+      case Irq_chip::Mode::Trigger_level | Irq_chip::Mode::Polarity_low:  v = 0; break;
+      case Irq_chip::Mode::Trigger_level | Irq_chip::Mode::Polarity_high: v = 1; break;
+      case Irq_chip::Mode::Trigger_edge  | Irq_chip::Mode::Polarity_low:  v = 2; break;
+      case Irq_chip::Mode::Trigger_edge  | Irq_chip::Mode::Polarity_high: v = 3; break;
+      case Irq_chip::Mode::Trigger_edge  | Irq_chip::Mode::Polarity_both: v = 4; break;
     };
 
     Mword a = INTCON + offs(pin);
@@ -154,7 +177,16 @@ public:
     v <<= pin * 4;
     modify<Mword>(v, 7UL << (pin * 4), a);
 
-    return m;
+    return 0;
+  }
+
+  bool is_edge_triggered(Mword pin) const
+  {
+    unsigned v;
+    Mword a = INTCON + offs(pin);
+    pin = pin % 8;
+    v = (read<Mword>(a) >> (pin * 4)) & 7;
+    return v & 6;
   }
 
   unsigned pending01() const // debug only
@@ -167,6 +199,8 @@ public:
     return read<Unsigned8>(PEND + 8) | (static_cast<unsigned>(read<Unsigned8>(PEND + 12)) << 8);
   }
 
+  Unsigned32 _wakeup;
+
 private:
   enum {
     INTCON = 0xe00,
@@ -212,8 +246,11 @@ public:
 
   void set_cpu(Mword, Cpu_number) {}
 
-  unsigned set_mode(Mword, unsigned)
-  { return Irq_base::Trigger_level; }
+  int set_mode(Mword, Mode)
+  { return 0; }
+
+  bool is_edge_triggered(Mword) const
+  { return false; }
 
   void unmask(Mword i)
   { write<Mword>(1UL << (i & 31), offset(i / 8) + Enable_set); }
@@ -274,7 +311,7 @@ public:
   : _wu_gpio(gc), _pin(pin)
   { set_hit(&handler_wrapper<Gpio_cascade_wu01_irq>); }
 
-  void switch_mode(unsigned) {}
+  void switch_mode(bool) {}
 
   void handle(Upstream_irq const *u)
   {
@@ -299,7 +336,7 @@ public:
   : _wu_gpio(gc)
   { set_hit(&handler_wrapper<Gpio_cascade_wu23_irq>); }
 
-  void switch_mode(unsigned) {}
+  void switch_mode(bool) {}
 
 private:
   Gpio_wakeup_chip *_wu_gpio;
@@ -326,7 +363,7 @@ public:
   : _eint_gc(g), _special(special)
   { set_hit(&handler_wrapper<Gpio_cascade_xab_irq>); }
 
-  void switch_mode(unsigned) {}
+  void switch_mode(bool) {}
 
 private:
   Gpio_eint_chip *_eint_gc;
@@ -366,7 +403,7 @@ public:
   : _combiner_nr(nr), _child(chld)
   { set_hit(&handler_wrapper<Combiner_cascade_irq>); }
 
-  void switch_mode(unsigned) {}
+  void switch_mode(bool) {}
   unsigned irq_nr_base() const { return _combiner_nr * 8; }
 
 private:
@@ -566,6 +603,8 @@ public:
     return Irq();
   }
 
+  Unsigned32 wakeup_irq_eint_mask() { return _wu_gc->_wakeup; }
+
 private:
   friend void irq_handler();
   friend class Pic;
@@ -710,7 +749,7 @@ public:
            cxx::int_value<Cpu_number>(current_cpu()));
   }
 private:
-  void switch_mode(unsigned) {}
+  void switch_mode(bool) {}
 };
 
 DEFINE_PER_CPU static Per_cpu<Static_object<Check_irq0> > _check_irq0;
index 2a993bdf1f8ecbcf7cffe49b864e566287c1d75d..d3f186cf8ccf35bc8d431e7e1f7417ed3686047b 100644 (file)
@@ -132,31 +132,19 @@ PUBLIC static
 void
 Platform_control::setup_cpu_start_vector(Cpu_phys_id cpu, Mword phys_reset_vector)
 {
-  if ((Platform::is_4210() && Platform::subrev() == 0)
-      || Platform::is_4412())
-    {
-      printf("AP bootup sysram\n");
+  unsigned long b = Mem_layout::Sysram_phys_base;
 
-      unsigned o = 0;
-      if (Platform::is_4412())
-        o = (Platform::running_ns() ? 0x2f01c : 0)
-            + cxx::int_value<Cpu_phys_id>(cpu) * 4;
+  if (Platform::running_ns())
+    b += Platform::is_4210() ? 0x1f01c : 0x2f01c;
+  else if (Platform::is_4210() && Platform::subrev() == 0x11)
+    b = Mem_layout::Pmu_phys_base + 0x814;
+  else if (Platform::is_4210() && Platform::subrev() == 0)
+    b += 0x5000;
 
-      set_one_vector(Mem_layout::Sysram_phys_base + o,
-                     phys_reset_vector);
-    }
-  else if (Platform::is_5250())
-    {
-      unsigned o = Platform::running_ns() ? 0x2f01c : 0;
-      set_one_vector(Mem_layout::Sysram_phys_base + o,
-                     phys_reset_vector);
-    }
-  else
-    {
-      printf("AP bootup inform\n");
-      set_one_vector(Mem_layout::Pmu_phys_base + 0x814,
-                     phys_reset_vector);
-    }
+  if (Platform::is_4412())
+    b += cxx::int_value<Cpu_phys_id>(cpu) * 4;
+
+  set_one_vector(b, phys_reset_vector);
 }
 
 
index d7341cdbf7036b2be3ddfee4d3309b0c210536b2..07b87529abe4089fe9ee161d71a22f943f127869 100644 (file)
@@ -51,7 +51,8 @@ private:
     INTCTL_NIDIS = 1 << 22, // Normal Interrupt Disable
   };
 public:
-  unsigned set_mode(Mword, unsigned) { return Irq_base::Trigger_level; }
+  int set_mode(Mword, Mode) { return 0; }
+  bool is_edge_triggered(Mword) const { return false; }
   void set_cpu(Mword, Cpu_number) {}
   void ack(Mword) { /* ack is empty */ }
 };
index fe90cf93ceb1c96f091e28698b3877e3c35f73bc..3a6bc6d8694b903cf6aa8310a7319833e821c75c 100644 (file)
@@ -24,7 +24,8 @@ private:
   };
 
 public:
-  unsigned set_mode(Mword, unsigned) { return Irq_base::Trigger_level; }
+  int set_mode(Mword, Mode) { return 0; }
+  bool is_edge_triggered(Mword) const { return false; }
   void set_cpu(Mword, Cpu_number) {}
   void ack(Mword) { /* ack is empty */ }
 };
index 64837a06dc7d82e431ded06de6bc8769da1aa9ed..3b379232b0c41d1b19318306022efa6cd6803a17 100644 (file)
@@ -41,7 +41,8 @@ public:
     modify<Unsigned32>(1 << Bridge_int_num, 0, Main_Irq_mask_low_reg);
   }
 
-  unsigned set_mode(Mword, unsigned) { return Irq_base::Trigger_level; }
+  int set_mode(Mword, Mode) { return 0; }
+  bool is_edge_triggered(Mword) const { return false; }
   void set_cpu(Mword, Cpu_number) {}
   void ack(Mword) { /* ack is empty */ }
 };
index 1e2496155ba935644f65bbb357b344e296e29064..7952684a6a53a9ff98c66712d2906a1157feab7f 100644 (file)
@@ -57,7 +57,8 @@ private:
     INTCPS_ILRm_base         = 0x100,
   };
 public:
-  unsigned set_mode(Mword, unsigned) { return Irq_base::Trigger_level; }
+  int set_mode(Mword, Mode) { return 0; }
+  bool is_edge_triggered(Mword) const { return false; }
   void set_cpu(Mword, Cpu_number) {}
 };
 
index b9ff15da296b84d1b07842d498b64f36e373d610..646e2a9f4bd5bd830fef229a9b4d94cbc6a747a7 100644 (file)
@@ -45,7 +45,8 @@ IMPLEMENTATION [arm && (sa1100 || pxa)]:
 class Chip : public Irq_chip_gen, private Mmio_register_block
 {
 public:
-  unsigned set_mode(Mword, unsigned) { return Irq_base::Trigger_level; }
+  int set_mode(Mword, Mode) { return 0; }
+  bool is_edge_triggered(Mword) const { return false; }
   void set_cpu(Mword, Cpu_number) {}
   void ack(Mword) { /* ack is empty */ }
 };
index ec51488db6fd5bf4f73bcab52f6f69f1506e381d..356b4f5e02c787d0cceb1ea25bf957d2e46f43f0 100644 (file)
@@ -87,7 +87,8 @@ class S3c_chip : public Irq_chip_gen, Mmio_register_block
   };
 
 public:
-  unsigned set_mode(Mword, unsigned) { return Irq_base::Trigger_level; }
+  int set_mode(Mword, Mode) { return 0; }
+  bool is_edge_triggered(Mword) const { return false; }
   void set_cpu(Mword, Cpu_number) {}
 };
 
index c43ebcb3b7cf995b5b917f03df2f623fde97b84a..d7b0631fff04dccddf1e894e284e6fb199193b35 100644 (file)
@@ -280,9 +280,16 @@ Gic::unmask(Mword pin)
 }
 
 PUBLIC
-unsigned
-Gic::set_mode(Mword, unsigned)
-{ return Irq_base::Trigger_level; }
+int
+Gic::set_mode(Mword, Mode)
+{
+  return 0;
+}
+
+PUBLIC
+bool
+Gic::is_edge_triggered(Mword) const
+{ return false; }
 
 PUBLIC inline
 void
index cc0c563d376875d003b221c6fa7067f3ec7bb16e..b9eaf2d8fe01eb76285ef50f2d5fb16c791b8eff 100644 (file)
@@ -914,7 +914,7 @@ monitor_vector_base:
 mon_enter_secure mon_undef_entry,      6, 4
 mon_enter_secure mon_swi_entry,        1, 0
 mon_enter_secure mon_inst_abort_entry, 2, 4
-mon_enter_secure mon_data_abort_entry, 3, 4
+mon_enter_secure mon_data_abort_entry, 3, 8
 mon_enter_secure mon_irq_entry,        4, 4
 mon_enter_secure mon_fiq_entry,        5, 4
 
index 7969847c1bf47d11cc964d2b5580232aafbedcf7..315d6f4b4b61fceab8ca65863901ecc4e3a76b9e 100644 (file)
@@ -31,7 +31,7 @@ void Kern_lib_page::init()
 
   pte.create_page(Phys_mem_addr((Address)&kern_lib_start - Mem_layout::Map_base
           + Mem_layout::Sdram_phys_base), Page::Attr(Page::Rights::URX(), Page::Type::Normal(), Page::Kern::Global()));
-  pte.write_back_if(true);
+  pte.write_back_if(true, Mem_unit::Asid_kernel);
 }
 
 //---------------------------------------------------------------------------
index 0503b5a8b7c5c447fe4470fb6c82f60825e43989..c1e324e12cd1073463d976938bbf6279ff824995 100644 (file)
@@ -56,7 +56,7 @@ namespace KIP_namespace
        /* A0/140 */ 0, 0, 0, 0,
        /* B0/160 */ {},
        /* E0/1C0 */ 0, 0, {},
-       /* F0/1D0 */ {0, 0}, {},
+       /* F0/1D0 */ {"", 0, {{0, 0, 0, 0}}, {}},
       },
       {}
     };
@@ -69,6 +69,13 @@ void Kip_init::init()
   Kip::init_global_kip(kinfo);
   kinfo->add_mem_region(Mem_desc(0, Mem_layout::User_max - 1,
                         Mem_desc::Conventional, true));
-  asm volatile("mrc p15, 0, %0, c0, c0, 0" : "=r" (kinfo->platform_info.cpuid));
-  kinfo->platform_info.mp = Config::Max_num_cpus > 1;
+
+  asm("mrc p15, 0, %0, c0, c0, 0" : "=r" (kinfo->platform_info.arch.cpuinfo.MIDR));
+  asm("mrc p15, 0, %0, c0, c0, 1" : "=r" (kinfo->platform_info.arch.cpuinfo.CTR));
+
+  if (((kinfo->platform_info.arch.cpuinfo.MIDR >> 16) & 0xf) < 7)
+    return;
+
+  asm("mrc p15, 0, %0, c0, c1, 4" : "=r" (kinfo->platform_info.arch.cpuinfo.ID_MMFR0));
+  asm("mrc p15, 0, %0, c0, c2, 0" : "=r" (kinfo->platform_info.arch.cpuinfo.ID_ISAR0));
 }
index c0cf9a619d2d03256f8c2c8cacd4d5117d13d09c..916ab6af8c0a275b3e8aec040dbf3e0bba69bb5c 100644 (file)
@@ -53,8 +53,7 @@ Kmem::mmio_remap(Address phys)
   m.create_page(Phys_mem_addr(phys_page), Page::Attr(Page::Rights::RWX(), Page::Type::Uncached(),
                 Page::Kern::Global()));
 
-  m.write_back_if(true);
-
+  m.write_back_if(true, Mem_unit::Asid_kernel);
   add_pmem(phys_page, dm, Config::SUPERPAGE_SIZE);
 
   return phys_to_pmem(phys);
index 7c526628b11ef65602149e298ce70cb80bceda69..748af72dd25cbc4ddcac999477d4da1d8304c348 100644 (file)
@@ -20,7 +20,7 @@ Kmem_alloc::map_pmem(unsigned long phy, unsigned long size)
     {
       auto pte = Kmem_space::kdir()->walk(Virt_addr(next_map + i), Pdir::Super_level);
       pte.create_page(Phys_mem_addr(phy + i), Page::Attr(Page::Rights::RW()));
-      pte.write_back_if(true);
+      pte.write_back_if(true, Mem_unit::Asid_kernel);
     }
   Mem_layout::add_pmem(phy, next_map, size);
   next_map += size;
index 19ec4451f007e343e7ce7198601fbe1f67617e87..0f09f5e4c0b93ae82ca3aa94a82c28b411d16ff6 100644 (file)
@@ -8,6 +8,7 @@ class Mem_unit : public Mmu< Mem_layout::Cache_flush_area >
 public:
   enum : Mword
   {
+    Asid_kernel  = 0UL,
     Asid_invalid = ~0UL
   };
 
index e890feecbd651ff1b10faf085b8c55bb2786f724..8c7f760fde323685ac5c9713a8dd5327e3c415a8 100644 (file)
@@ -705,7 +705,7 @@ public:
   Thread_remote_rq_irq()
   { set_hit(&handler_wrapper<Thread_remote_rq_irq>); }
 
-  void switch_mode(unsigned) {}
+  void switch_mode(bool) {}
 };
 
 class Thread_glbl_remote_rq_irq : public Irq_base
@@ -718,7 +718,7 @@ public:
   Thread_glbl_remote_rq_irq()
   { set_hit(&handler_wrapper<Thread_glbl_remote_rq_irq>); }
 
-  void switch_mode(unsigned) {}
+  void switch_mode(bool) {}
 };
 
 class Thread_debug_ipi : public Irq_base
@@ -734,7 +734,7 @@ public:
   Thread_debug_ipi()
   { set_hit(&handler_wrapper<Thread_debug_ipi>); }
 
-  void switch_mode(unsigned) {}
+  void switch_mode(bool) {}
 };
 
 class Thread_timer_tick_ipi : public Irq_base
@@ -752,7 +752,7 @@ public:
   Thread_timer_tick_ipi()
   { set_hit(&handler_wrapper<Thread_timer_tick_ipi>); }
 
-  void switch_mode(unsigned) {}
+  void switch_mode(bool) {}
 };
 
 
index 356e570b907e82d1957e1de52ffb3e88cb12cc66..7611ae75f4b693721c4126aa44a4949a88d6ba82 100644 (file)
@@ -1,9 +1,12 @@
 INTERFACE [arm]:
 
+#include "irq_chip.h"
+
 EXTENSION class Timer
 {
 public:
-  static unsigned irq_mode() { return 0; }
+  static Irq_chip::Mode irq_mode()
+  { return Irq_chip::Mode::F_raising_edge; }
 
 private:
   static inline void update_one_shot(Unsigned64 wakeup);
index 8daa490d3f00df0725dc4ff899f11a66945ee516..f58d4ebc16b6cc024d02cc16056cd7b98778436c 100644 (file)
@@ -38,7 +38,7 @@ void *Vmem_alloc::page_alloc(void *address, Zero_fill zf, unsigned mode)
     r |= Page::Rights::U();
 
   pte.create_page(Phys_mem_addr(page), Page::Attr(r, Page::Type::Normal(), Page::Kern::Global()));
-  pte.write_back_if(true);
+  pte.write_back_if(true, Mem_unit::Asid_kernel);
   Mem_unit::dtlb_flush(address);
 
   if (zf == ZERO_FILL)
index 7d8b1cc011ac8156c23358bb4408095fa2716ee8..64a433d5b9a9df126f8fdfb4bc057494bf5306b8 100644 (file)
@@ -16,7 +16,7 @@ public:
   }
 
   Irq_chip_icu *child() const { return _child; }
-  void switch_mode(unsigned) {}
+  void switch_mode(bool) {}
 
 private:
   Irq_chip_icu *_child;
index 47e36bc94962767a395f3a1b09b2dbe96c8d8de4..aa61013fb44570560b3694f79c41727fbb308152 100644 (file)
@@ -27,7 +27,7 @@ INTERFACE:
 
 #define GREETING_COLOR_ANSI_OFF    "\033[0m"
 
-#define FIASCO_KERNEL_SUBVERSION 1
+#define FIASCO_KERNEL_SUBVERSION 2
 
 class Config
 {
index 7879e36ef68b7f3aaa24ca4a18a6b6b416d26ba0..66451fa80232f2c4cc485d9e78878cb5ae149c1f 100644 (file)
@@ -459,6 +459,13 @@ Context::Context()
   set_cpu_of(this, Cpu::invalid());
 }
 
+PUBLIC inline
+void
+Context::reset_kernel_sp()
+{
+  _kernel_sp = reinterpret_cast<Mword*>(regs());
+}
+
 PUBLIC inline
 void
 Context::spill_fpu_if_owner()
@@ -1358,8 +1365,9 @@ Context::Drq_q::handle_requests(Drop_mode drop)
       need_resched |= execute_request(r, drop, false);
     }
 }
+
 /**
- * \biref Forced dequeue from lock wait queue, or DRQ queue.
+ * \brief Forced dequeue from lock wait queue, or DRQ queue.
  */
 PRIVATE
 void
index 6ac7780c04cbedec68ed6b1c9bc84bd1357fd557..8fdc9104e7e0648c7c69be1bb78abe9656b3e309 100644 (file)
@@ -79,8 +79,6 @@ Cpu::online_mask()
 // --------------------------------------------------------------------------
 IMPLEMENTATION [mp]:
 
-#include "kdb_ke.h"
-
 IMPLEMENT inline
 Cpu_number
 Cpu::id() const
@@ -96,13 +94,12 @@ void
 Cpu::set_online(bool o)
 {
   if (o)
-    _online_mask.set(_id);
+    _online_mask.atomic_set(_id);
   else
-    _online_mask.clear(_id);
+    _online_mask.atomic_clear(_id);
 }
 
-
-IMPLEMENT static inline NEEDS["kdb_ke.h"]
+IMPLEMENT static inline
 bool
 Cpu::online(Cpu_number _cpu)
 { return _online_mask.get(_cpu); }
index ef756f5b1c957d905014a625ebde3583068d5e93..69e5d58e533ff2cdb641b8073112855ba9e6f16f 100644 (file)
@@ -70,8 +70,8 @@ main_switch_ap_cpu_stack(Kernel_thread *kernel)
 
   // switch to stack of kernel thread and bootstrap the kernel
   asm volatile
-    (" mov %%rsi, %%rsp        \n\t"   // switch stack
+    (" mov %[rsp], %%rsp       \n\t"   // switch stack
      " call call_ap_bootstrap  \n\t"   // bootstrap kernel thread
      :  "=a" (dummy), "=c" (dummy), "=d" (dummy)
-     : "a"(kernel), "S" (kernel->init_stack()));
+     : "D"(kernel), [rsp]"r" (kernel->init_stack()));
 }
index 603697eab9f269a7ab8a246db10ab5ce7ce3994c..247bc8efb368329a51ae7c5975acf8a16c635c99 100644 (file)
@@ -56,7 +56,7 @@ private:
   } __attribute__((packed));
 
   Apic *_apic;
-  Spin_lock<> _l;
+  mutable Spin_lock<> _l;
   unsigned _offset;
   Io_apic *_next;
 
@@ -159,7 +159,7 @@ Io_apic::Io_apic(Io_apic::Apic *addr, unsigned irqs, unsigned gsi_base)
 
 PUBLIC inline NEEDS["kdb_ke.h", "lock_guard.h"]
 Io_apic_entry
-Io_apic::read_entry(unsigned i)
+Io_apic::read_entry(unsigned i) const
 {
   auto g = lock_guard(_l);
   Io_apic_entry e;
@@ -406,32 +406,40 @@ Io_apic::set_cpu(Mword irq, Cpu_number cpu)
 }
 
 static inline
-Mword to_io_apic_trigger(unsigned mode)
+Mword to_io_apic_trigger(Irq_chip::Mode mode)
 {
-  return (mode & Irq_base::Trigger_level)
-            ? Io_apic_entry::Level
-            : Io_apic_entry::Edge;
+  return mode.level_triggered()
+         ? Io_apic_entry::Level
+         : Io_apic_entry::Edge;
 }
 
 static inline
-Mword to_io_apic_polarity(unsigned mode)
+Mword to_io_apic_polarity(Irq_chip::Mode mode)
 {
-  return (mode & Irq_base::Polarity_low)
-             ? Io_apic_entry::Low_active
-             : Io_apic_entry::High_active;
+  return mode.polarity() == Irq_chip::Mode::Polarity_high
+         ? Io_apic_entry::High_active
+         : Io_apic_entry::Low_active;
 }
 
-PUBLIC unsigned
-Io_apic::set_mode(Mword pin, unsigned mode)
+PUBLIC int
+Io_apic::set_mode(Mword pin, Mode mode)
 {
-  if ((mode & Irq_base::Polarity_mask) == Irq_base::Polarity_both)
-    mode = Irq_base::Polarity_low;
+  if (!mode.set_mode())
+    return 0;
 
   Io_apic_entry e = read_entry(pin);
   e.polarity() = to_io_apic_polarity(mode);
   e.trigger() = to_io_apic_trigger(mode);
   write_entry(pin, e);
-  return mode;
+  return 0;
+}
+
+PUBLIC
+bool
+Io_apic::is_edge_triggered(Mword pin) const
+{
+  Io_apic_entry e = read_entry(pin);
+  return e.trigger() == Io_apic_entry::Edge;
 }
 
 PUBLIC
index 439079e65ab2eb83298dad1b01e3584215e945cd..d72f300b230fac2ca52ee1d0e3efc4724e74222b 100644 (file)
@@ -68,9 +68,14 @@ Irq_chip_ia32_pic::ack(Mword irq)
 }
 
 PUBLIC
-unsigned
-Irq_chip_ia32_pic::set_mode(Mword, unsigned)
-{ return Irq_base::Trigger_level | Irq_base::Polarity_low; }
+int
+Irq_chip_ia32_pic::set_mode(Mword, Mode)
+{ return 0; }
+
+PUBLIC
+bool
+Irq_chip_ia32_pic::is_edge_triggered(Mword) const
+{ return false; }
 
 PUBLIC
 void
index 4372efc6ca23ed07eca58b28b728a6586feebebb..dc641b5bac68cdbd542992ecb4cedde7dfa4a95f 100644 (file)
@@ -57,9 +57,13 @@ Irq_chip_msi::msg(Mword pin)
   return 0;
 }
 
-PUBLIC unsigned
-Irq_chip_msi::set_mode(Mword, unsigned)
-{ return Irq_base::Trigger_edge | Irq_base::Polarity_low; }
+PUBLIC int
+Irq_chip_msi::set_mode(Mword, Mode)
+{ return 0; }
+
+PUBLIC bool
+Irq_chip_msi::is_edge_triggered(Mword) const
+{ return true; }
 
 PUBLIC void
 Irq_chip_msi::set_cpu(Mword, Cpu_number)
index ab9f5e52e44f5879a43a48f6f44218bf076d463b..a86d74acf2b43ac43528864eba7045f2664ed17b 100644 (file)
@@ -77,7 +77,7 @@ namespace KIP_namespace
        /* A0/140 */ 0, 0, 0, 0,
        /* B0/160 */ {},
        /* E0/1C0 */ 0, 0, {},
-       /* F0/1D0 */ {},
+       /* F0/1D0 */ {"", 0}, {},
       },
       {}
     };
index 6b05ec1907a2f3a1d7f85537c961ffa3d1de7d0f..9c3b81c767ad68be1df50f505998f0d3d7d8b06f 100644 (file)
@@ -1,6 +1,9 @@
-IMPLEMENTATION[{ia32,amd64}-pit_timer]:
+INTERFACE [{ia32,amd64}-pit_timer]:
 
 #include "irq_chip.h"
+
+IMPLEMENTATION[{ia32,amd64}-pit_timer]:
+
 #include "pit.h"
 
 #include <cstdio>
@@ -19,8 +22,8 @@ PUBLIC static inline
 unsigned Timer::irq() { return 0; }
 
 PUBLIC static inline NEEDS["irq_chip.h"]
-unsigned Timer::irq_mode()
-{ return Irq_base::Trigger_edge | Irq_base::Polarity_high; }
+Irq_chip::Mode Timer::irq_mode()
+{ return Irq_chip::Mode::F_raising_edge; }
 
 PUBLIC static inline
 void
index 03643f99d1c8e85ba13f423a4d3a530cc3bb78db..d12aae786a21539177c990591d99f209927866fc 100644 (file)
@@ -1,6 +1,9 @@
-IMPLEMENTATION[{ia32,amd64}-rtc_timer]:
+INTERFACE [{ia32,amd64}-rtc_timer]:
 
 #include "irq_chip.h"
+
+IMPLEMENTATION[{ia32,amd64}-rtc_timer]:
+
 #include "rtc.h"
 #include "pit.h"
 
@@ -12,8 +15,8 @@ PUBLIC static inline
 unsigned Timer::irq() { return 8; }
 
 PUBLIC static inline NEEDS["irq_chip.h"]
-unsigned Timer::irq_mode()
-{ return Irq_base::Trigger_edge | Irq_base::Polarity_high; }
+Irq_chip::Mode Timer::irq_mode()
+{ return Irq_chip::Mode::F_raising_edge; }
 
 IMPLEMENT
 void
index 842ea7fe3337881f46be465a8d4d31b69ae187e4..975dd284bb3acd60dfbf7e72714706e16b9bafbe 100644 (file)
@@ -169,16 +169,8 @@ Icu_h<REAL_ICU>::icu_invoke(L4_obj_ref, L4_fpage::Rights /*rights*/,
 
     case Op_set_mode:
       if (tag.words() >= 3)
-       {
-         Irq_base *irq = this_icu()->icu_get_irq(utcb->values[1]);
-
-         if (irq)
-           {
-             irq->set_mode(utcb->values[2]);
-             return Kobject_iface::commit_result(0);
-           }
-       }
-
+        return this_icu()->icu_set_mode(utcb->values[1],
+                                        Irq_chip::Mode(utcb->values[2]));
       return Kobject_iface::commit_result(-L4_err::EInval);
 
     default:
index 32c57db766cc0e43d5d5cdd17fef89f4e3cdd9eb..6dc6b8b1f54553b58b4bdbde3657047f886e7fc8 100644 (file)
@@ -72,8 +72,9 @@ private:
 class Irq_muxer : public Kobject_h<Irq_muxer, Irq>, private Irq_chip
 {
 public:
-  unsigned set_mode(Mword, unsigned mode) { return mode; }
-  void switch_mode(unsigned)
+  int set_mode(Mword, Irq_chip::Mode) { return 0; }
+  bool is_edge_triggered(Mword) const { return false; }
+  void switch_mode(bool)
   {
     // the irq object is assumed to be always handled as
     // level triggered
@@ -238,7 +239,6 @@ Irq_muxer::sys_attach(L4_msg_tag const &tag, Utcb const *utcb, Syscall_frame * /
   L4_snd_item_iter snd_items(utcb, tag.words());
 
   Irq *irq = 0;
-  unsigned mode = utcb->values[0] >> 16;
 
   if (tag.items() == 0)
     return commit_result(-L4_err::EInval);
@@ -255,10 +255,6 @@ Irq_muxer::sys_attach(L4_msg_tag const &tag, Utcb const *utcb, Syscall_frame * /
   if (!irq)
     return commit_result(-L4_err::EInval);
 
-  if (mode & Set_irq_mode)
-    printf("DEPRECATED SET IRQ MODE\n");
-    //pin()->set_mode(mode);
-
   irq->unbind();
 
   if (!irq->masked())
@@ -378,12 +374,9 @@ Irq_sender::Irq_sender(Ram_quota *q = 0)
 
 PUBLIC
 void
-Irq_sender::switch_mode(unsigned mode)
+Irq_sender::switch_mode(bool is_edge_triggered)
 {
-  if ((mode & Trigger_mask) == Trigger_edge)
-    hit_func = &hit_edge_irq;
-  else
-    hit_func = &hit_level_irq;
+  hit_func = is_edge_triggered ? &hit_edge_irq : &hit_level_irq;
 }
 
 PUBLIC
@@ -587,14 +580,8 @@ Irq_sender::sys_attach(L4_msg_tag const &tag, Utcb const *utcb, Syscall_frame *
   if (tag.items() == 0)
     {
       // detach
-      if (mode & Set_irq_mode)
-       printf("DEPRECATED SET IRQ MODE\n");
-       //pin()->set_mode(mode);
-      else
-       {
-         free(_irq_thread);
-         _irq_id = ~0UL;
-       }
+      free(_irq_thread);
+      _irq_id = ~0UL;
       return commit_result(0);
     }
 
@@ -612,8 +599,6 @@ Irq_sender::sys_attach(L4_msg_tag const &tag, Utcb const *utcb, Syscall_frame *
 
   if (alloc(thread))
     {
-      if (mode & Set_irq_mode)
-       printf("DEPRECATED SET IRQ MODE\n");
       _irq_id = utcb->values[1];
       return commit_result(0);
     }
index 6c6b0bfff093df99f1b543464413980c48b42065..98d83c87b71017b6a5305c6bd6650dd4058280bf 100644 (file)
@@ -1,5 +1,7 @@
 INTERFACE:
 
+#include <cxx/bitfield>
+
 #include "types.h"
 
 class Irq_base;
@@ -20,6 +22,42 @@ private:
 class Irq_chip
 {
 public:
+  struct Mode
+  {
+    Mode() = default;
+    explicit Mode(unsigned m) : raw(m) {}
+
+    enum Flow_type
+    {
+      Set_irq_mode  = 0x1,
+      Trigger_edge  = 0x0,
+      Trigger_level = 0x2,
+      Trigger_mask  = 0x2,
+
+      Polarity_high = 0x0,
+      Polarity_low  = 0x4,
+      Polarity_both = 0x8,
+      Polarity_mask = 0xc,
+
+      F_level_high   = Set_irq_mode | Trigger_level | Polarity_high,
+      F_level_low    = Set_irq_mode | Trigger_level | Polarity_low,
+      F_raising_edge = Set_irq_mode | Trigger_edge  | Polarity_high,
+      F_falling_edge = Set_irq_mode | Trigger_edge  | Polarity_low,
+      F_both_edges   = Set_irq_mode | Trigger_edge  | Polarity_both
+    };
+
+    Mode(Flow_type ft) : raw(ft) {}
+
+    unsigned raw;
+    CXX_BITFIELD_MEMBER(0, 0, set_mode, raw);
+    CXX_BITFIELD_MEMBER_UNSHIFTED(1, 3, flow_type, raw);
+    CXX_BITFIELD_MEMBER_UNSHIFTED(1, 1, level_triggered, raw);
+    CXX_BITFIELD_MEMBER_UNSHIFTED(2, 3, polarity, raw);
+    CXX_BITFIELD_MEMBER(4, 5, wakeup, raw);
+    CXX_BITFIELD_MEMBER(4, 4, set_wakeup, raw);
+    CXX_BITFIELD_MEMBER(5, 5, clear_wakeup, raw);
+  };
+
   virtual void mask(Mword pin) = 0;
   virtual void unmask(Mword pin) = 0;
   virtual void ack(Mword pin) = 0;
@@ -28,7 +66,8 @@ public:
   /**
    * Set the trigger mode and polarity.
    */
-  virtual unsigned set_mode(Mword pin, unsigned) = 0;
+  virtual int set_mode(Mword pin, Mode) = 0;
+  virtual bool is_edge_triggered(Mword pin) const = 0;
 
   /**
    * Set the target CPU.
@@ -52,7 +91,8 @@ public:
   void ack(Mword) {}
 
   void set_cpu(Mword, Cpu_number) {}
-  unsigned set_mode(Mword, unsigned mode) { return mode; }
+  int set_mode(Mword, Mode) { return 0; }
+  bool is_edge_triggered(Mword) const { return true; }
 
   char const *chip_type() const { return "Soft"; }
 
@@ -92,20 +132,7 @@ public:
     F_enabled = 1,
   };
 
-  enum Mode
-  {
-    Set_irq_mode  = 0x1,
-    Trigger_edge  = 0x0,
-    Trigger_level = 0x2,
-    Trigger_mask  = 0x2,
-
-    Polarity_high = 0x0,
-    Polarity_low  = 0x4,
-    Polarity_both = 0x8,
-    Polarity_mask = 0xc,
-  };
-
-  Irq_base() : _flags(Trigger_level), _next(0)
+  Irq_base() : _flags(0), _next(0)
   {
     Irq_chip_soft::sw_chip.bind(this, 0, true);
     mask();
@@ -128,14 +155,6 @@ public:
   void unmask() { if (__unmask()) _chip->unmask(_pin); }
   void ack() { _chip->ack(_pin); }
 
-
-  void set_mode(unsigned m)
-  {
-    unsigned mode = _chip->set_mode(_pin, m);
-    _flags = (_flags & ~0xe) | (mode & 0xe);
-    switch_mode(mode);
-  }
-
   void set_cpu(Cpu_number cpu) { _chip->set_cpu(_pin, cpu); }
 
   unsigned get_mode() const
@@ -150,7 +169,7 @@ public:
   bool __unmask() { bool o = masked(); _flags |= F_enabled; return o; }
 
   void set_hit(Hit_func f) { hit_func = f; }
-  virtual void switch_mode(unsigned mode) = 0;
+  virtual void switch_mode(bool is_edge_triggered) = 0;
   virtual ~Irq_base() = 0;
 
 protected:
@@ -222,7 +241,8 @@ Irq_chip::bind(Irq_base *irq, Mword pin, bool ctor = false)
   if (ctor)
     return;
 
-  irq->set_mode(irq->get_mode());
+  irq->switch_mode(is_edge_triggered(pin));
+
   if (irq->masked())
     mask(pin);
   else
index c2eeb65071952a7f16defddf52d2fe411e61cd4d..741c72e220318afa3733cd7f30ed7ae70a054b1a 100644 (file)
@@ -53,6 +53,24 @@ Icu::icu_bind_irq(Irq *irq, unsigned irqnum)
   return commit_result(0);
 }
 
+PUBLIC inline NEEDS["irq_mgr.h"]
+L4_msg_tag
+Icu::icu_set_mode(Mword pin, Irq_chip::Mode mode)
+{
+  Irq_mgr::Irq i = Irq_mgr::mgr->chip(pin);
+
+  if (!i.chip)
+    return commit_result(-L4_err::ENodev);
+
+  int r = i.chip->set_mode(i.pin, mode);
+
+  Irq_base *irq = i.chip->irq(i.pin);
+  if (irq)
+    irq->switch_mode(i.chip->is_edge_triggered(i.pin));
+
+  return commit_result(r);
+}
+
 
 PUBLIC inline NEEDS["irq_mgr.h"]
 void
index 0d573239266549f3117b3979ea3df467a5746978..724f67d06b9c280b12503a5227dc968523e18644 100644 (file)
@@ -103,7 +103,7 @@ class Kuart_irq : public Irq_base
 {
 public:
   Kuart_irq() { hit_func = &handler_wrapper<Kuart_irq>; }
-  void switch_mode(unsigned) {}
+  void switch_mode(bool) {}
   void handle(Upstream_irq const *ui)
   {
     mask_and_ack();
index c50ef6e6940ab8af7d2ca3bd2cdae4510777e0f8..1269364247ac7b3f4c2a640096a6b5940a649821 100644 (file)
@@ -17,6 +17,7 @@ phys_mem.o: $(TCBOFFSET)
 $(KERNEL).image: $(srcdir)/kernel.ppc32.ld $(CRT0) $(OBJ_KERNEL) $(LIBK) $(LIBDISASM) libdrivers.a $(ABI) $(LIBUART) $(CXXLIB) $(MINILIBC) libgluedriverslibc.a 
        $(LINK_MESSAGE)
        $(VERBOSE)$(LD) $(LDFLAGS) -N -T $< -o $@ $(filter-out $<,$+) $(LIBGCC)
+       $(call ADD_CONFIGFILE,$@)
 
 $(KERNEL): $(KERNEL).image
        $(LINK_MESSAGE)
index 05e4c2f68534c131543c4fd660ba4aabe2943eb8..f74b9231bac6852a0cf487fb2fbb59ade93a02ac 100644 (file)
@@ -83,7 +83,8 @@ class Chip : public Irq_chip_gen
 {
 public:
   Chip() : Irq_chip_gen(Pic::IRQ_MAX) {}
-  unsigned set_mode(Mword, unsigned) { return Irq_base::Trigger_level; }
+  int set_mode(Mword, Mode) { return 0; }
+  bool is_edge_triggered(Mword) const { return false; }
   void set_cpu(Mword, Cpu_number) {}
 };
 
index 1d5f6d72b7f2a719ea4677605c69183ca9963113..ae7e4dad7675e2e0f699d16b274241f548d57d0b 100644 (file)
@@ -51,7 +51,7 @@ namespace KIP_namespace
        /* A0/140 */ 0, 0, 0, 0,
        /* B0/160 */ {},
        /* E0/1C0 */ 0, 0, {},
-       /* F0/1D0 */ {},
+       /* F0/1D0 */ {"", 0}, {},
       },
       {}
     };
index 976ee94707e08f1c976abc1eb5c96c8cf2e01e9c..92c43f080f17e2b80d6e82717623077b089d7abb 100644 (file)
@@ -1,6 +1,9 @@
 /**
  * PowerPC timer using internal decrementer
  */
+INTERFACE [ppc32]:
+
+#include "irq_chip.h"
 
 IMPLEMENTATION [ppc32]:
 
@@ -30,10 +33,10 @@ unsigned
 Timer::irq()
 { return 0; }
 
-PUBLIC static inline
-unsigned
+PUBLIC static inline NEEDS["irq_chip.h"]
+Irq_chip::Mode
 Timer::irq_mode()
-{ return 0; }
+{ return Irq_chip::Mode::F_raising_edge; }
 
 PUBLIC static inline
 void
index b8bb68fa0140b9893ef5917f0dcb34af53688d1e..51052978f109eed77ced51e3c71949c30511f701 100644 (file)
@@ -300,17 +300,33 @@ Rcu_glbl::start_batch()
     }
 }
 
+PUBLIC
+void
+Rcu_data::enter_idle(Rcu_glbl *rgp)
+{
+  if (EXPECT_TRUE(!_idle))
+    {
+      _idle = true;
+
+      auto guard = lock_guard(rgp->_lock);
+      rgp->_active_cpus.clear(_cpu);
+
+      if (_q_batch != rgp->_current || _pending)
+        {
+          _q_batch = rgp->_current;
+          _pending = 0;
+          rgp->cpu_quiet(_cpu);
+          assert (!pending(rgp));
+        }
+    }
+}
+
 PUBLIC static inline
 void
 Rcu::enter_idle(Cpu_number cpu)
 {
   Rcu_data *rdp = &_rcu_data.cpu(cpu);
-  if (EXPECT_TRUE(!rdp->_idle))
-    {
-      rdp->_idle = true;
-      auto guard = lock_guard(rcu()->_lock);
-      rcu()->_active_cpus.clear(cpu);
-    }
+  rdp->enter_idle(rcu());
 }
 
 PUBLIC static inline
index 9959d9dbd46a1293e250f6468952eb8ba92c19e8..f717c30f451ca44b6412aef19d59345e3ced37c0 100644 (file)
@@ -199,6 +199,18 @@ Scheduler::icu_bind_irq(Irq *irq_o, unsigned irqnum)
   return commit_result(0);
 }
 
+PUBLIC
+L4_msg_tag
+Scheduler::icu_set_mode(Mword pin, Irq_chip::Mode)
+{
+  if (pin != 0)
+    return commit_result(-L4_err::EInval);
+
+  if (_irq)
+    _irq->switch_mode(true);
+  return commit_result(0);
+}
+
 PUBLIC inline
 void
 Scheduler::trigger_hotplug_event()
index 38e155f6ceb37a2cb0cad7692f7ed7861050213c..29ec00c365a21da9ddae536e12c95debaf8f1982 100644 (file)
@@ -10,6 +10,7 @@ $(KERNEL).image: $(srcdir)/kernel.sparc.ld $(CRT0) $(OBJ_KERNEL) $(JDB) $(LIBK)
        $(LINK_MESSAGE)
        $(VERBOSE)$(LD) $(LDFLAGS) -N -defsym kernel_load_addr=$(CONFIG_KERNEL_LOAD_ADDR) \
          -T $< -o $@ $(filter-out $<,$+) $(LIBGCC)
+       $(call ADD_CONFIGFILE,$@)
 
 $(KERNEL): $(KERNEL).image
        $(LINK_MESSAGE)
index 3a8c11478df2b076bc85cd210d30b05cde2fd29c..f9275102ae37401e20dc942f0b2a010845209215 100644 (file)
@@ -82,7 +82,8 @@ class Chip : public Irq_chip_gen
 {
 public:
   Chip() : Irq_chip_gen(Pic::IRQ_MAX) {}
-  unsigned set_mode(Mword, unsigned) { return Irq_base::Trigger_level; }
+  int set_mode(Mword, Mode) { return 0; }
+  bool is_edge_triggered(Mword) const { return false; }
   void set_cpu(Mword, Cpu_number) {}
 };
 
index ec31871f35a224fffa9fda4f05024611f40afad2..c7e5733a798b03fc9bc1a893c3fcca5378e2aa56 100644 (file)
@@ -51,7 +51,7 @@ namespace KIP_namespace
        /* A0/140 */ 0, 0, 0, 0,
        /* B0/160 */ {},
        /* E0/1C0 */ 0, 0, {},
-       /* F0/1D0 */ {},
+       /* F0/1D0 */ {"", 0}, {},
       },
       {}
     };
index 100d229a19c65da65b73c1c2991da5379291bc29..049042f8cd31becf17f9433ff0762dbe36851ef2 100644 (file)
@@ -1,6 +1,9 @@
 /**
- * PowerPC timer using internal decrementer
+ * Sparc timer
  */
+INTERFACE [sparc]:
+
+#include "irq_chip.h"
 
 IMPLEMENTATION [sparc]:
 
@@ -30,10 +33,10 @@ unsigned
 Timer::irq()
 { return 0; }
 
-PUBLIC static inline
-unsigned
+PUBLIC static inline NEEDS["irq_chip.h"]
+Irq_chip::Mode
 Timer::irq_mode()
-{ return 0; }
+{ return Irq_chip::Mode::F_raising_edge; }
 
 PUBLIC static inline
 void
index 4c24387417a91c4d818d97c453732022e65a42fa..6d6fa049aaf7a6b7b1db2080e0e1d7f947daeff6 100644 (file)
@@ -176,7 +176,7 @@ Thread_object::sys_vcpu_resume(L4_msg_tag const &tag, Utcb *utcb)
   Vcpu_state *vcpu = vcpu_state().access(true);
 
   L4_obj_ref user_task = vcpu->user_task;
-  if (user_task.valid())
+  if (user_task.valid() && user_task.op() == 0)
     {
       L4_fpage::Rights task_rights = L4_fpage::Rights(0);
       Task *task = Kobject::dcast<Task*>(s->lookup_local(user_task.cap(),
@@ -188,7 +188,7 @@ Thread_object::sys_vcpu_resume(L4_msg_tag const &tag, Utcb *utcb)
       if (task != vcpu_user_space())
         vcpu_set_user_space(task);
 
-      vcpu->user_task = L4_obj_ref();
+      reinterpret_cast<Mword &>(vcpu->user_task) |= L4_obj_ref::Ipc_send;
     }
   else if (user_task.op() == L4_obj_ref::Ipc_reply)
     vcpu_set_user_space(0);
index 2e573d7ab52f9f39eefbd3954fc8ffc48d916ca2..69b5a31bbd03efe9cd91473503b10e699b899f45 100644 (file)
@@ -1,5 +1,7 @@
 INTERFACE [hpet_timer]:
 
+#include "irq_chip.h"
+
 EXTENSION class Timer
 {
   static int hpet_irq;
@@ -10,7 +12,6 @@ IMPLEMENTATION [hpet_timer]:
 #include "config.h"
 #include "cpu.h"
 #include "hpet.h"
-#include "irq_chip.h"
 #include "logdefs.h"
 #include "pit.h"
 #include "std_macros.h"
@@ -22,8 +23,8 @@ int Timer::hpet_irq;
 PUBLIC static inline int Timer::irq() { return hpet_irq; }
 
 PUBLIC static inline NEEDS["irq_chip.h"]
-unsigned Timer::irq_mode()
-{ return Irq_base::Trigger_level | Irq_base::Polarity_low; }
+Irq_chip::Mode Timer::irq_mode()
+{ return Irq_chip::Mode::F_level_low; }
 
 IMPLEMENT
 void
index bb4fe98a85fc53c5a7ef11b7343ab2c970e9c174..5246d52ef253a0f0ec000d44e93f6712649b2f50 100644 (file)
@@ -26,7 +26,7 @@ Timer_tick::setup(Cpu_number cpu)
       else
         printf("Timer is at IRQ %d\n", Timer::irq());
 
-      _glbl_timer->set_mode(Timer::irq_mode());
+      _glbl_timer->chip()->set_mode(_glbl_timer->pin(), Timer::irq_mode());
     }
 }
 
index 951c45285db3f35964131b387e1df045720b21fb..38200552568003f38023856b7dc7801226e83f8d 100644 (file)
@@ -25,7 +25,7 @@ Timer_tick::setup(Cpu_number cpu)
   if (!allocate_irq(_glbl_timer, Timer::irq()))
     panic("Could not allocate scheduling IRQ %d\n", Timer::irq());
 
-  _glbl_timer->set_mode(Timer::irq_mode());
+  _glbl_timer->chip()->set_mode(_glbl_timer->pin(), Timer::irq_mode());
 }
 
 IMPLEMENT
index cf708d38391c905f49534d2102e85f84b9e24263..9d99e6f303cc5965d987613e61ded7db120bffe9 100644 (file)
@@ -32,7 +32,7 @@ protected:
 
 private:
   // we do not support triggering modes
-  void switch_mode(unsigned) {}
+  void switch_mode(bool) {}
 };
 
 // ------------------------------------------------------------------------
index cbc0b468fa769fce8f9ae02853fd08122d9990cd..a2eacfa37a0d3654fcd772a250d16dc1da78ef62 100644 (file)
@@ -39,6 +39,7 @@ $(KERNEL):    kernel.ux.lds $(OBJ_KERNEL) $(MINILIBC) $(LIBK) $(KERNEL_EXTRA_LIBS)
                  if [ "$$preinit_array_start" != "$$preinit_array_end" ]; then \
                    echo "preinit_array content appeared, check linker symbols"; \
                  fi
+               $(call ADD_CONFIGFILE,$@)
 
 irq0.o:                irq0.c
                $(COMP_MESSAGE)
index 334ce42bdde06e985b4b29a866396ec1b18a8c8b..9b27fba690f980069808977cce1603e3d4e2f9e3 100644 (file)
@@ -1,6 +1,8 @@
 // ------------------------------------------------------------------------
 INTERFACE[ux]:
 
+#include "irq_chip.h"
+
 EXTENSION class Timer
 {
 private:
@@ -16,7 +18,6 @@ IMPLEMENTATION[ux]:
 #include <sys/types.h>
 #include "boot_info.h"
 #include "initcalls.h"
-#include "irq_chip.h"
 #include "irq_mgr.h"
 #include "pic.h"
 
@@ -24,9 +25,10 @@ PUBLIC static inline NEEDS["pic.h"]
 unsigned
 Timer::irq() { return Pic::Irq_timer; }
 
-PUBLIC static inline
-unsigned
-Timer::irq_mode() { return 0; }
+PUBLIC static inline NEEDS["irq_chip.h"]
+Irq_chip::Mode
+Timer::irq_mode()
+{ return Irq_chip::Mode::F_raising_edge; }
 
 IMPLEMENT FIASCO_INIT_CPU
 void
index 18318830de364e8dddd39360e5cc336d749c3de4..f1b1dfeda9c043adf2c1ef08d0881aff81b49854 100644 (file)
@@ -160,6 +160,17 @@ Vlog::icu_bind_irq(Irq *irq_o, unsigned irqnum)
   return commit_result(0);
 }
 
+PUBLIC
+L4_msg_tag
+Vlog::icu_set_mode(Mword pin, Irq_chip::Mode)
+{
+  if (pin != 0)
+    return commit_result(-L4_err::EInval);
+
+  if (_irq)
+    _irq->switch_mode(true);
+  return commit_result(0);
+}
 
 PRIVATE inline NOEXPORT
 L4_msg_tag
index e92c6119ca13ca4c1b23fc5413623651243dd647..3e630f7bed243a3b0d2746c0abf9855f863ab2f4 100644 (file)
@@ -2,42 +2,47 @@ INTERFACE:
 
 #include "atomic.h"
 
-template< bool LARGE >
+template< bool LARGE, unsigned BITS >
 class Bitmap_base;
 
 // Implementation for bitmaps bigger than sizeof(unsigned long) * 8
 // Derived classes have to make sure to provide the storage space for
 // holding the bitmap.
-template<>
-class Bitmap_base< true >
+template<unsigned BITS>
+class Bitmap_base< true, BITS >
 {
 public:
+  enum {
+    Bpl      = sizeof(unsigned long) * 8,
+    Nr_elems = (BITS + Bpl - 1) / Bpl,
+  };
+
   void bit(unsigned long bit, bool on)
   {
     unsigned long idx = bit / Bpl;
     unsigned long b   = bit % Bpl;
-    _bits()[idx] = (_bits()[idx] & ~(1UL << b)) | ((unsigned long)on << b);
+    _bits[idx] = (_bits[idx] & ~(1UL << b)) | ((unsigned long)on << b);
   }
 
   void clear_bit(unsigned long bit)
   {
     unsigned long idx = bit / Bpl;
     unsigned long b   = bit % Bpl;
-    _bits()[idx] &= ~(1UL << b);
+    _bits[idx] &= ~(1UL << b);
   }
 
   void set_bit(unsigned long bit)
   {
     unsigned long idx = bit / Bpl;
     unsigned long b   = bit % Bpl;
-    _bits()[idx] |= (1UL << b);
+    _bits[idx] |= (1UL << b);
   }
 
   unsigned long operator [] (unsigned long bit) const
   {
     unsigned long idx = bit / Bpl;
     unsigned long b   = bit % Bpl;
-    return _bits()[idx] & (1UL << b);
+    return _bits[idx] & (1UL << b);
   }
 
   bool atomic_get_and_clear(unsigned long bit)
@@ -45,11 +50,15 @@ public:
     unsigned long idx = bit / Bpl;
     unsigned long b   = bit % Bpl;
     unsigned long v;
+
+    if (!(_bits[idx] & (1UL << b)))
+      return false;
+
     do
       {
-        v = _bits()[idx];
+        v = _bits[idx];
       }
-    while (!mp_cas(&_bits()[idx], v, v & ~(1UL << b)));
+    while (!mp_cas(&_bits[idx], v, v & ~(1UL << b)));
 
     return v & (1UL << b);
   }
@@ -58,122 +67,159 @@ public:
   {
     unsigned long idx = bit / Bpl;
     unsigned long b   = bit % Bpl;
-    atomic_mp_or(&_bits()[idx], 1UL << b);
+    atomic_mp_or(&_bits[idx], 1UL << b);
   }
 
   void atomic_clear_bit(unsigned long bit)
   {
     unsigned long idx = bit / Bpl;
     unsigned long b   = bit % Bpl;
-    atomic_mp_and(&_bits()[idx], ~(1UL << b));
+    atomic_mp_and(&_bits[idx], ~(1UL << b));
   }
 
-protected:
-  enum
+  void clear_all()
   {
-    Bpl      = sizeof(unsigned long) * 8,
-  };
+    for (unsigned i = 0; i < Nr_elems; ++i)
+      _bits[i] = 0;
+  }
+
+  bool is_empty() const
+  {
+    for (unsigned i = 0; i < Nr_elems; ++i)
+      if (_bits[i])
+       return false;
+    return true;
+  }
+
+  void atomic_or(Bitmap_base const &r)
+  {
+    for (unsigned i = 0; i < Nr_elems; ++i)
+      atomic_mp_or(&_bits[i], r._bits[i]);
+  }
 
+protected:
   Bitmap_base() {}
   Bitmap_base(Bitmap_base const &) = delete;
   Bitmap_base &operator = (Bitmap_base const &) = delete;
 
-private:
-  unsigned long *_bits()
-  { return reinterpret_cast<unsigned long *>(this); }
 
-  unsigned long const *_bits() const
-  { return reinterpret_cast<unsigned long const *>(this); }
+  void _or(Bitmap_base const &r)
+  {
+    for (unsigned i = 0; i < Nr_elems; ++i)
+      _bits[i] |= r._bits[i];
+  }
+
+  void _copy(Bitmap_base const &s)
+  { __builtin_memcpy(_bits, s._bits, Nr_elems * sizeof(_bits[0])); }
+
+  unsigned long _bits[Nr_elems];
 };
 
 // Implementation for a bitmap up to sizeof(unsigned long) * 8 bits
-template<>
-class Bitmap_base<false>
+template<unsigned BITS>
+class Bitmap_base<false, BITS>
 {
 public:
   void bit(unsigned long bit, bool on)
   {
-    _bits[0] = (_bits[0] & ~(1UL << bit)) | ((unsigned long)on << bit);
+    _bits = (_bits & ~(1UL << bit)) | ((unsigned long)on << bit);
   }
 
   void clear_bit(unsigned long bit)
   {
-    _bits[0] &= ~(1UL << bit);
+    _bits &= ~(1UL << bit);
   }
 
   void set_bit(unsigned long bit)
   {
-    _bits[0] |= 1UL << bit;
+    _bits |= 1UL << bit;
   }
 
   unsigned long operator [] (unsigned long bit) const
   {
-    return _bits[0] & (1UL << bit);
+    return _bits & (1UL << bit);
   }
 
   bool atomic_get_and_clear(unsigned long bit)
   {
+    if (!(_bits & (1UL << bit)))
+      return false;
+
     unsigned long v;
     do
       {
-        v = _bits[0];
+        v = _bits;
       }
-    while (!mp_cas(&_bits[0], v, v & ~(1UL << bit)));
+    while (!mp_cas(&_bits, v, v & ~(1UL << bit)));
 
     return v & (1UL << bit);
   }
 
   void atomic_set_bit(unsigned long bit)
   {
-    atomic_mp_or(&_bits[0], 1UL << bit);
+    atomic_mp_or(&_bits, 1UL << bit);
   }
 
   void atomic_clear_bit(unsigned long bit)
   {
-    atomic_mp_and(&_bits[0], ~(1UL << bit));
+    atomic_mp_and(&_bits, ~(1UL << bit));
   }
 
+  void clear_all()
+  {
+    _bits = 0;
+  }
+
+  bool is_empty() const
+  {
+    return !_bits;
+  }
+
+  void atomic_or(Bitmap_base const &r)
+  {
+    atomic_mp_or(&_bits, r._bits);
+  }
+
+
+
 protected:
   enum
   {
     Bpl      = sizeof(unsigned long) * 8,
+    Nr_elems = 1,
   };
-  unsigned long _bits[1];
+  unsigned long _bits;
 
   Bitmap_base() {}
   Bitmap_base(Bitmap_base const &) = delete;
   Bitmap_base &operator = (Bitmap_base const &) = delete;
-};
 
-template<int BITS>
-class Bitmap : public Bitmap_base< (BITS > sizeof(unsigned long) * 8) >
-{
-public:
-  void clear_all()
+  void _or(Bitmap_base const &r)
   {
-    for (unsigned i = 0; i < Nr_elems; ++i)
-      _bits[i] = 0;
+    _bits |= r._bits;
   }
 
-  bool is_empty() const
-  {
-    for (unsigned i = 0; i < Nr_elems; ++i)
-      if (_bits[i])
-       return false;
-    return true;
-  }
+  void _copy(Bitmap_base const &s)
+  { _bits = s._bits; }
+};
 
+template<int BITS>
+class Bitmap : public Bitmap_base< (BITS > sizeof(unsigned long) * 8), BITS >
+{
+public:
   Bitmap() {}
   Bitmap(Bitmap const &o)
-  { __builtin_memcpy(_bits, o._bits, sizeof(_bits)); }
+  { this->_copy(o); }
 
   Bitmap &operator = (Bitmap const &o)
-  { __builtin_memcpy(_bits, o._bits, sizeof(_bits)); return *this; }
+  {
+    this->_copy(o);
+    return *this;
+  }
 
-private:
-  enum {
-    Bpl      = sizeof(unsigned long) * 8,
-    Nr_elems = (BITS + Bpl - 1) / Bpl,
-  };
-  unsigned long _bits[Nr_elems];
+  Bitmap &operator |= (Bitmap const &o)
+  {
+    this->_or(o);
+    return *this;
+  }
 };
index c96e3f73a72194904f076815bc6f6abfe2d62fa6..14ec24792bd97a72ffad481df1aed11e40dac7ff 100644 (file)
@@ -673,7 +673,7 @@ generate_pcfile =                                                            \
        ;echo "Version: 0"                                         >> $(2)   \
        ;echo "Description: L4 library"                            >> $(2)   \
        $(if $(3),;echo "Cflags: $(addprefix -I\$${incdir}/,$(3))" >> $(2))  \
-       $(if $(4),;echo "Libs: $(sort $(4))"                       >> $(2))  \
+       $(if $(4),;echo "Libs: $(4)"                               >> $(2))  \
        $(if $(5),;echo "Requires: $(5)"                           >> $(2))  \
        $(if $(BID_GEN_CONTROL),;echo "Provides: $(1)"             >> $(PKGDIR)/Control) \
        $(if $(BID_GEN_CONTROL),;echo "Requires: $(5)"             >> $(PKGDIR)/Control) ;
index df93e75ff71f1fb76b095330e1d35e61e3f9c5c2..6d956556c6a59a158e047d535901c31c797a2d9c 100644 (file)
@@ -40,6 +40,7 @@ CONFIG_PLATFORM_TYPE_rv=y
 # CONFIG_PLATFORM_TYPE_rv_vexpress is not set
 # CONFIG_PLATFORM_TYPE_rv_vexpress_a15 is not set
 # CONFIG_PLATFORM_TYPE_tegra2 is not set
+# CONFIG_PLATFORM_TYPE_tegra3 is not set
 # CONFIG_PLATFORM_TYPE_custom is not set
 CONFIG_PLATFORM_TYPE="rv"
 # CONFIG_USE_DROPS_STDDIR is not set
index 3b18efa13c7a1a211cf63c9e5541cc678b83dcff..36081112e6876e1a52a6e0784c1f9928973a4b0a 100644 (file)
@@ -96,7 +96,6 @@ PC_FILES     := $(foreach pcfile,$(PC_FILENAMES),$(OBJ_BASE)/pc/$(pcfile).pc)
 get_cont = $(if $($(1)_$(2)),$($(1)_$(2)),$($(1)))
 
 $(OBJ_BASE)/pc/%.pc: $(GENERAL_D_LOC)
-       $(if $(filter-out -l%,$(call get_cont,PC_LIBS,$*)),$(error PC_LIBS contains invalid library list: $(call get_cont,PC_LIBS,$*); Only -l statements allowed.),@true)
        $(VERBOSE)$(call generate_pcfile,$*,$@,$(call get_cont,CONTRIB_INCDIR,$*),$(call get_cont,PC_LIBS,$*),$(call get_cont,REQUIRES_LIBS,$*))
 
 all:: $(PC_FILES)
diff --git a/l4/mk/platforms/tegra3.conf b/l4/mk/platforms/tegra3.conf
new file mode 100644 (file)
index 0000000..3948d7b
--- /dev/null
@@ -0,0 +1,4 @@
+PLATFORM_NAME        = "Nvidia Tegra 3"
+PLATFORM_ARCH        = arm
+PLATFORM_RAM_BASE    = 0x80000000
+PLATFORM_RAM_SIZE_MB = 1022
index b035bf7d5dedf774e4a47724530d719c97fae26e..ca2196a50e5926bff9cbac7231200a0622b04f70 100644 (file)
@@ -131,7 +131,7 @@ depcheck:
          echo ==========================================================;     \
          echo "Deleting all pkgs in build-dir";                               \
          $(RM) -r $(OBJ_BASE)/lib $(OBJ_BASE)/bin $(OBJ_BASE)/include         \
-                  $(OBJ_BASE)/pc;                                             \
+                  $(OBJ_BASE)/pc $(OBJ_BASE)/pkg/.Package.deps;               \
          $(if $(CHECK_FULL),$(RM) -r $(OBJ_BASE)/pkg;,)                       \
          echo "Done";                                                         \
          echo ----------------------------------------------------------;     \
index 26341e6535179ecac014b0a3159b71bea5f074e2..cb30800d2752d0a21fdbf2c9bace191941c597fa 100644 (file)
@@ -12,6 +12,7 @@ SUPPORT_CC_arm-omap3_am33xx    := platform/omap.cc
 SUPPORT_CC_arm-beagleboard     := platform/omap.cc
 SUPPORT_CC_arm-pandaboard      := platform/omap.cc
 SUPPORT_CC_arm-tegra2          := platform/tegra2.cc
+SUPPORT_CC_arm-tegra3          := platform/tegra3.cc
 SUPPORT_CC_arm-imx21           := platform/imx.cc
 DEFAULT_RELOC_arm-imx21        := 0x00200000  # because of blob
 SUPPORT_CC_arm-imx35           := platform/imx.cc
diff --git a/l4/pkg/bootstrap/server/src/platform/tegra3.cc b/l4/pkg/bootstrap/server/src/platform/tegra3.cc
new file mode 100644 (file)
index 0000000..f4c92bc
--- /dev/null
@@ -0,0 +1,42 @@
+/*!
+ * \file
+ * \brief  Support for Tegra 3 platforms
+ *
+ * \date   2013
+ * \author Adam Lackorzynski <adam@os.inf.tu-dresden.de>
+ *
+ */
+/*
+ * (c) 2013 Author(s)
+ *     economic rights: Technische Universität Dresden (Germany)
+ *
+ * This file is part of TUD:OS and distributed under the terms of the
+ * GNU General Public License 2.
+ * Please see the COPYING-GPL-2 file for details.
+ */
+
+#include "support.h"
+#include <l4/drivers/uart_pxa.h>
+
+namespace {
+class Platform_arm_tegra3 : public Platform_single_region_ram
+{
+  bool probe() { return true; }
+
+  void init()
+  {
+    static L4::Uart_16550 _uart(25459200);
+    unsigned long uart_addr;
+    switch (2) {
+      case 0: uart_addr = 0x70006000;
+      case 2: uart_addr = 0x70006200;
+    };
+    static L4::Io_register_block_mmio r(uart_addr, 2);
+    _uart.startup(&r);
+    _uart.change_mode(3, 115200);
+    set_stdio_uart(&_uart);
+  }
+};
+}
+
+REGISTER_PLATFORM(Platform_arm_tegra3);
index 77543fe9aee79d69a948fe0d8aa7b5023f53ed71..2ebe2c3daa4647499b9e020d8b73fc8e1a96f62d 100644 (file)
@@ -116,11 +116,30 @@ Region_list::add(Region const &region, bool may_overlap)
       return;
     }
 
+  if (mem.begin() > _address_limit)
+    {
+      printf("  Dropping '%s' region ", _name);
+      mem.print();
+      printf(" due to %lld MB address limit\n", _address_limit >> 20);
+      return;
+    }
+
+  if (mem.end() >= _address_limit)
+    {
+      printf("  Limiting '%s' region ", _name);
+      mem.print();
+      mem.end(_address_limit - 1);
+      printf(" to ");
+      mem.print();
+      printf(" due to %lld MB address limit\n", _address_limit >> 20);
+
+    }
+
   if (_combined_size >= _max_combined_size)
     {
       printf("  Dropping '%s' region ", _name);
       mem.print();
-      printf(" due to %lld MB limit\n", _max_combined_size >> 20);
+      printf(" due to %lld MB size limit\n", _max_combined_size >> 20);
       return;
     }
 
@@ -131,7 +150,7 @@ Region_list::add(Region const &region, bool may_overlap)
       mem.end(mem.begin() + _max_combined_size - _combined_size - 1);
       printf(" to ");
       mem.print();
-      printf(" due to %lld MB limit\n", _max_combined_size >> 20);
+      printf(" due to %lld MB size limit\n", _max_combined_size >> 20);
     }
 
   add_nolimitcheck(mem, may_overlap);
index 8a20eeb8de3f627d0827374c7d3eafde146bc865..6677f8891e1be7d01d725761508c0b01df3e1c65 100644 (file)
@@ -126,12 +126,14 @@ public:
    */
   void init(Region *store, unsigned size,
             const char *name,
-            unsigned long long max_combined_size = ~0ULL)
+            unsigned long long max_combined_size = ~0ULL,
+            unsigned long long address_limit = ~0ULL)
   {
     _reg = _end = store;
     _max = _reg + size;
     _name = name;
     _max_combined_size = max_combined_size;
+    _address_limit = address_limit;
     _combined_size = 0;
   }
 
@@ -180,6 +182,7 @@ protected:
 
   const char *_name;
   unsigned long long _max_combined_size;
+  unsigned long long _address_limit;
   unsigned long long _combined_size;
 
 private:
index e6db7bf4e4e6e9f54aa10483a56919cabd502666..d1110f66e31841cfc0c8688e0acf986007193b8f 100644 (file)
@@ -64,7 +64,7 @@ static Region __regs[300];
 
 /* management of conventional memory regions */
 static Region_list ram;
-static Region __ram[8];
+static Region __ram[16];
 
 #if defined(ARCH_x86) || defined(ARCH_amd64)
 static l4util_mb_vbe_mode_t __mb_vbe;
@@ -252,34 +252,36 @@ check_arg(l4util_mb_info_t *mbi, const char *arg)
  * Calculate the maximum memory limit in MB.
  *
  * The limit is the highes physical address where conventional RAM is allowed.
- *
- * If available the '-maxmem=xx' command line option is used.
- * If not then the memory is limited to 3 GB IA32 and unlimited on other
- * systems.
+ * The memory is limited to 3 GB IA32 and unlimited on other systems.
  */
 static
 unsigned long
-get_memory_limit(l4util_mb_info_t *mbi)
+get_memory_max_address()
 {
-  unsigned long arch_limit = ~0UL;
 #if defined(ARCH_x86)
   /* Limit memory, we cannot really handle more right now. In fact, the
    * problem is roottask. It maps as many superpages/pages as it gets.
    * After that, the remaining pages are mapped using l4sigma0_map_anypage()
    * with a receive window of L4_WHOLE_ADDRESS_SPACE. In response Sigma0
    * could deliver pages beyond the 3GB user space limit. */
-  arch_limit = 3024UL << 20;
+  return 3024UL << 20;
 #endif
 
+  return ~0UL;
+}
+
+/*
+ * If available the '-maxmem=xx' command line option is used.
+ */
+static
+unsigned long
+get_memory_max_size(l4util_mb_info_t *mbi)
+{
   /* maxmem= parameter? */
   if (char *c = check_arg(mbi, "-maxmem="))
-    {
-      unsigned long l = strtoul(c + 8, NULL, 10) << 20;
-      if (l < arch_limit)
-       return l;
-    }
+    return strtoul(c + 8, NULL, 10) << 20;
 
-  return arch_limit;
+  return ~0UL;
 }
 
 static int
@@ -616,7 +618,7 @@ add_elf_regions(l4util_mb_info_t *mbi, l4_umword_t module,
   l4_addr_t entry;
   int r;
   const char *error_msg;
-  l4util_mb_mod_t *mb_mod = (l4util_mb_mod_t*)mbi->mods_addr;
+  l4util_mb_mod_t *mb_mod = (l4util_mb_mod_t*)(unsigned long)mbi->mods_addr;
 
   assert(module < mbi->mods_count);
 
@@ -864,13 +866,13 @@ relocate_mbi(l4util_mb_info_t *src_mbi, unsigned long* start,
   /* copy command lines of modules */
   for (unsigned i = 0; i < dst_mbi->mods_count; i++)
     {
-      char *n = dup_cmdline(src_mbi, i, &p, (char const *)(mods[i].cmdline));
+      char *n = dup_cmdline(src_mbi, i, &p, (char const *)(unsigned long)mods[i].cmdline);
       if (n)
          mods[i].cmdline = (l4_addr_t) n;
     }
   *end = (l4_addr_t)p;
 
-  printf("  Relocated mbi to [%p-%p]\n", mbi_start, (void*)(*end));
+  printf("  Relocated mbi to [%p-%p]\n", mbi_start, (void *)(*end));
   regions.add(Region::n((unsigned long)mbi_start,
                         ((unsigned long)*end) + 0xfe,
                         ".Multiboot info", Region::Root),
@@ -1143,7 +1145,7 @@ startup(l4util_mb_info_t *mbi, l4_umword_t flag,
 
   regions.init(__regs, sizeof(__regs) / sizeof(__regs[0]), "regions");
   ram.init(__ram, sizeof(__ram) / sizeof(__ram[0]), "RAM",
-           get_memory_limit(mbi));
+           get_memory_max_size(mbi), get_memory_max_address());
 
 #ifdef ARCH_amd64
   // add the page-table on which we're running in 64bit mode
@@ -1279,7 +1281,7 @@ startup(l4util_mb_info_t *mbi, l4_umword_t flag,
   if (!mb_info)
     panic("could not copy multiboot info to memory below 4MB");
 
-  mb_mod = (l4util_mb_mod_t*)mb_info->mods_addr;
+  mb_mod = (l4util_mb_mod_t *)(unsigned long)mb_info->mods_addr;
 
   /* --- Shouldn't touch original Multiboot parameters after here. -- */
 
index 2a4e20030471b2bd7c318667884837e2ddd60af0..d29a5bd999ed477ae6c08dc718519d27168548a1 100644 (file)
@@ -24,6 +24,7 @@ EXTRA_TARGET := \
   type_traits \
   type_list \
   bitfield \
+  unique_ptr \
   utils
 
 include $(L4DIR)/mk/include.mk
index deed009221555d6c54cf34a244a4d5da9a2e1ff7..acab1a7819f584fef189f5248b223bb77b5c45eb 100644 (file)
@@ -188,10 +188,10 @@ public:
     Bits_type get() const { return Bitfield::get(v); }
     T get_unshifted() const { return Bitfield::get_unshifted(v); }
 
-    void set(Bits_type val) { v = Bitfield::set(v, val); }
-    void set_dirty(Bits_type val) { v = Bitfield::set_dirty(v, val); }
-    void set_unshifted(Shift_type val) { v = Bitfield::set_unshifted(v, val); }
-    void set_unshifted_dirty(Shift_type val) { v = Bitfield::set_unshifted_dirty(v, val); }
+    void set(Bits_type val) __restrict__ { v = Bitfield::set(v, val); }
+    void set_dirty(Bits_type val) __restrict__ { v = Bitfield::set_dirty(v, val); }
+    void set_unshifted(Shift_type val) __restrict__ { v = Bitfield::set_unshifted(v, val); }
+    void set_unshifted_dirty(Shift_type val) __restrict__ { v = Bitfield::set_unshifted_dirty(v, val); }
   };
 
   /** Internal helper type */
@@ -201,7 +201,7 @@ public:
   public:
     Value(TT t) : Value_base<TT>(t) {}
     operator Bits_type () const { return this->get(); }
-    Value &operator = (Bits_type val) { this->set(val); return *this; }
+    Value &operator = (Bits_type val) __restrict__ { this->set(val); return *this; }
   };
 
   /** Internal helper type */
@@ -211,7 +211,7 @@ public:
   public:
     Value_unshifted(TT t) : Value_base<TT>(t) {}
     operator Shift_type () const { return this->get_unshifted(); }
-    Value_unshifted &operator = (Shift_type val) { this->set_unshifted(val); return *this; }
+    Value_unshifted &operator = (Shift_type val) __restrict__ { this->set_unshifted(val); return *this; }
   };
 
   /** Reference type to access the bits inside a raw bit field. */
@@ -235,6 +235,14 @@ public:
   name ## _bfm_t::Ref name() { return data_member; } \
   /** @} */
 
+#define CXX_BITFIELD_MEMBER_RO(LSB, MSB, name, data_member) \
+  /** @{ */ \
+  /** \brief Type to access the \a name bits (LSB to MSB) of \a data_member. */ \
+  typedef cxx::Bitfield<decltype(data_member), LSB, MSB> name ## _bfm_t; \
+  /** \brief Get the \a name bits (LSB to MSB) of \a data_member. */ \
+  name ## _bfm_t::Val name() const { return data_member; } \
+  /** @} */
+
 #define CXX_BITFIELD_MEMBER_UNSHIFTED(LSB, MSB, name, data_member) \
   /** @{ */ \
   /** \brief Type to access the \a name bits (LSB to MSB) of \a data_member. */ \
@@ -245,5 +253,11 @@ public:
   name ## _bfm_t::Ref_unshifted name() { return data_member; } \
   /** @} */
 
+#define CXX_BITFIELD_MEMBER_UNSHIFTED_RO(LSB, MSB, name, data_member) \
+  /** @{ */ \
+  /** \brief Type to access the \a name bits (LSB to MSB) of \a data_member. */ \
+  typedef cxx::Bitfield<decltype(data_member), LSB, MSB> name ## _bfm_t; \
+  /** \brief Get the \a name bits (LSB to MSB) of \a data_member. */ \
+  name ## _bfm_t::Val_unshifted name() const { return data_member; } \
+  /** @} */
 }
-
index da8fd0a57a50f705087408296d1c806bfd6c0b0f..20ab06525278ecb0a9bc29288a31d82f241531f5 100644 (file)
@@ -22,6 +22,8 @@
 
 #pragma once
 
+#pragma GCC system_header
+
 #include "bits/type_traits.h"
 
 
@@ -55,13 +57,17 @@ template< typename T > struct remove_cv;
 
 template< typename T > struct remove_pointer;
 
+template< typename T > struct remove_extent;
+
+template< typename T > struct remove_all_extents;
+
 
 
 template< typename, typename >
-struct is_same : public false_type {};
+struct is_same : false_type {};
 
 template< typename T >
-struct is_same<T, T> : public true_type {};
+struct is_same<T, T> : true_type {};
 
 template< typename T >
 struct remove_reference { typedef T type; };
@@ -90,7 +96,27 @@ template< typename T, typename I >
 struct __remove_pointer_h<T, I*> { typedef I type; };
 
 template< typename  T >
-struct remove_pointer : public __remove_pointer_h<T, typename remove_cv<T>::type> {};
+struct remove_pointer : __remove_pointer_h<T, typename remove_cv<T>::type> {};
+
+
+template< typename T >
+struct remove_extent { typedef T type; };
+
+template< typename T >
+struct remove_extent<T[]> { typedef T type; };
+
+template< typename T, unsigned long N >
+struct remove_extent<T[N]> { typedef T type; };
+
+
+template< typename T >
+struct remove_all_extents { typedef T type; };
+
+template< typename T >
+struct remove_all_extents<T[]> { typedef typename remove_all_extents<T>::type type; };
+
+template< typename T, unsigned long N >
+struct remove_all_extents<T[N]> { typedef typename remove_all_extents<T>::type type; };
 
 #ifdef __GXX_EXPERIMENTAL_CXX0X__
 #if CXX_GCC_VERSION >= 405
@@ -126,10 +152,10 @@ template< typename T >
 struct enable_if<true, T> { typedef T type; };
 
 template< typename T >
-struct is_const : public false_type {};
+struct is_const : false_type {};
 
 template< typename T >
-struct is_const<T const> : public true_type {};
+struct is_const<T const> : true_type {};
 
 template< bool, typename, typename >
 struct conditional;
@@ -144,21 +170,21 @@ template<typename T>
 struct is_enum : integral_constant<bool, __is_enum(T)> {};
 
 
-template< typename T > struct is_integral : public false_type {};
+template< typename T > struct is_integral : false_type {};
 
-template<> struct is_integral<bool> : public true_type {};
+template<> struct is_integral<bool> : true_type {};
 
-template<> struct is_integral<char> : public true_type {};
-template<> struct is_integral<signed char> : public true_type {};
-template<> struct is_integral<unsigned char> : public true_type {};
-template<> struct is_integral<short> : public true_type {};
-template<> struct is_integral<unsigned short> : public true_type {};
-template<> struct is_integral<int> : public true_type {};
-template<> struct is_integral<unsigned int> : public true_type {};
-template<> struct is_integral<long> : public true_type {};
-template<> struct is_integral<unsigned long> : public true_type {};
-template<> struct is_integral<long long> : public true_type {};
-template<> struct is_integral<unsigned long long> : public true_type {};
+template<> struct is_integral<char> : true_type {};
+template<> struct is_integral<signed char> : true_type {};
+template<> struct is_integral<unsigned char> : true_type {};
+template<> struct is_integral<short> : true_type {};
+template<> struct is_integral<unsigned short> : true_type {};
+template<> struct is_integral<int> : true_type {};
+template<> struct is_integral<unsigned int> : true_type {};
+template<> struct is_integral<long> : true_type {};
+template<> struct is_integral<unsigned long> : true_type {};
+template<> struct is_integral<long long> : true_type {};
+template<> struct is_integral<unsigned long long> : true_type {};
 
 template< typename T, bool = is_integral<T>::value || is_enum<T>::value >
 struct __is_signed_helper : integral_constant<bool, static_cast<bool>(T(-1) < T(0))> {};
@@ -170,6 +196,16 @@ template< typename T >
 struct is_signed : __is_signed_helper<T> {};
 
 
+template< typename >
+struct is_array : false_type {};
+
+template< typename T >
+struct is_array<T[]> : true_type {};
+
+template< typename T, unsigned long N >
+struct is_array<T[N]> : true_type {};
+
+
 template< int SIZE, bool SIGN = false, bool = true > struct int_type_for_size;
 
 template<> struct int_type_for_size<sizeof(char), true, true>
@@ -210,6 +246,27 @@ struct underlying_type<T, typename enable_if<is_enum<T>::value>::type >
   typedef typename int_type_for_size<sizeof(T), is_signed<T>::value>::type type;
 };
 
+template< typename T > struct make_signed;
+template<> struct make_signed<char>          { typedef signed char type; };
+template<> struct make_signed<unsigned char> { typedef signed char type; };
+template<> struct make_signed<signed char>   { typedef signed char type; };
+template<> struct make_signed<unsigned int>      { typedef signed int type; };
+template<> struct make_signed<signed int>        { typedef signed int type; };
+template<> struct make_signed<unsigned long int> { typedef signed long int type; };
+template<> struct make_signed<signed long int>   { typedef signed long int type; };
+template<> struct make_signed<unsigned long long int> { typedef signed long long int type; };
+template<> struct make_signed<signed long long int>   { typedef signed long long int type; };
+
+template< typename T > struct make_unsigned;
+template<> struct make_unsigned<char>          { typedef unsigned char type; };
+template<> struct make_unsigned<unsigned char> { typedef unsigned char type; };
+template<> struct make_unsigned<signed char>   { typedef unsigned char type; };
+template<> struct make_unsigned<unsigned int>      { typedef unsigned int type; };
+template<> struct make_unsigned<signed int>        { typedef unsigned int type; };
+template<> struct make_unsigned<unsigned long int> { typedef unsigned long int type; };
+template<> struct make_unsigned<signed long int>   { typedef unsigned long int type; };
+template<> struct make_unsigned<unsigned long long int> { typedef unsigned long long int type; };
+template<> struct make_unsigned<signed long long int>   { typedef unsigned long long int type; };
 
 }
 
diff --git a/l4/pkg/cxx/lib/tl/include/unique_ptr b/l4/pkg/cxx/lib/tl/include/unique_ptr
new file mode 100644 (file)
index 0000000..c295827
--- /dev/null
@@ -0,0 +1,104 @@
+#pragma once
+
+#include "type_traits"
+
+namespace cxx
+{
+
+template< typename T >
+struct default_delete
+{
+  default_delete() {}
+
+  template< typename U >
+  default_delete(default_delete<U> const &) {}
+
+  void operator () (T *p) const
+  { delete p; }
+};
+
+template< typename T >
+struct default_delete<T[]>
+{
+  default_delete() {}
+
+  void operator () (T *p)
+  { delete [] p; }
+};
+
+template< typename T, typename T_Del = default_delete<T> >
+class unique_ptr
+{
+private:
+  struct _unspec;
+  typedef _unspec* _unspec_ptr_type;
+
+public:
+  typedef typename cxx::remove_extent<T>::type element_type;
+  typedef element_type *pointer;
+  typedef element_type &reference;
+  typedef T_Del deleter_type;
+
+  unique_ptr() : _ptr(pointer()) {}
+
+  explicit unique_ptr(pointer p) : _ptr(p) {}
+
+  unique_ptr(unique_ptr &&o) : _ptr(o.release()) {}
+
+  ~unique_ptr() { reset(); }
+
+  unique_ptr &operator = (unique_ptr &&o)
+  {
+    reset(o.release());
+    return *this;
+  }
+
+  unique_ptr &operator = (_unspec_ptr_type)
+  {
+    reset();
+    return *this;
+  }
+
+  element_type &operator * () const { return *get(); }
+  pointer operator -> () const { return get(); }
+
+  pointer get() const { return _ptr; }
+
+  operator _unspec_ptr_type () const
+  { return reinterpret_cast<_unspec_ptr_type>(get()); }
+
+  pointer release()
+  {
+    pointer r = _ptr;
+    _ptr = 0;
+    return r;
+  }
+
+  void reset(pointer p = pointer())
+  {
+    if (p != get())
+      {
+        deleter_type()(get());
+        _ptr = p;
+      }
+  }
+
+  typename cxx::enable_if<cxx::is_array<T>::value, reference>::type
+  operator [] (unsigned long idx) const
+  { return _ptr[idx]; }
+
+
+  unique_ptr(unique_ptr const &) = delete;
+  unique_ptr &operator = (unique_ptr const &) = delete;
+
+
+private:
+  pointer _ptr;
+};
+
+template< typename T >
+unique_ptr<T>
+make_unique_ptr(T *p)
+{ return unique_ptr<T>(p); }
+
+}
index b72339172bc2af9163c94c73da9a56038e9eb212..fb7c03cc0ab39551d9ef73b06810b7c5540c3029 100644 (file)
@@ -38,7 +38,7 @@ protected:
     } of_item_t;
 
   /* methods */
-  unsigned prom_call(const char *service, int nargs, int nret, ...) const
+  unsigned long prom_call(const char *service, int nargs, int nret, ...) const
     {
       struct prom_args args = prom_args(service, nargs, nret);
       va_list list;
index 55b531d16117cc65b399ecd7b23dda1d86c239f7..859f138f87e6eccf5bbfdb8cb4c9768705113708 100644 (file)
@@ -88,7 +88,7 @@ namespace L4
   bool Uart_sa1000::startup(Io_register_block const *regs)
   {
     _regs = regs;
-    _regs->write<unsigned int>(UTSR0, ~0UL); // clear pending status bits
+    _regs->write<unsigned int>(UTSR0, ~0U); // clear pending status bits
     _regs->write<unsigned int>(UTCR3, UTCR3_RXE | UTCR3_TXE); //enable transmitter and receiver
     return true;
   }
index 50ce555182466324b371f16ee1c0c55360fe2b37..32354393473453272baf2b75d8b1d7f45aa42437 100644 (file)
@@ -69,7 +69,7 @@ int main(void)
   l4_touch_rw(alien_thread_stack, sizeof(alien_thread_stack));
 
   tag = l4_factory_create_thread(l4re_env()->factory, alien);
-  if (l4_msgtag_has_error(tag))
+  if (l4_error(tag))
     return 1;
 
   l4_debugger_set_object_name(alien, "alienth");
@@ -80,16 +80,21 @@ int main(void)
   l4_thread_control_bind((l4_utcb_t *)l4re_env()->first_free_utcb, L4RE_THIS_TASK_CAP);
   l4_thread_control_alien(1);
   tag = l4_thread_control_commit(alien);
-  if (l4_msgtag_has_error(tag))
+  if (l4_error(tag))
     return 2;
 
   tag = l4_thread_ex_regs(alien,
                           (l4_umword_t)alien_thread,
                           (l4_umword_t)alien_thread_stack + sizeof(alien_thread_stack),
                           0);
-  if (l4_msgtag_has_error(tag))
+  if (l4_error(tag))
     return 3;
 
+  l4_sched_param_t sp = l4_sched_param(1, 0);
+  tag = l4_scheduler_run_thread(l4re_env()->scheduler, alien, &sp);
+  if (l4_error(tag))
+    return 4;
+
 #ifdef MEASURE
   l4_calibrate_tsc(l4re_kip());
 #endif
index be8c8ab9de9e4b5895c5cda45a03be2507df3e84..f28477068eef657a0fcd6f5e89c304f4fb0e982c 100644 (file)
@@ -76,7 +76,7 @@ int main(void)
   l4_touch_ro(thread_func, 1);
 
   tag = l4_factory_create_thread(l4re_env()->factory, th);
-  if (l4_msgtag_has_error(tag))
+  if (l4_error(tag))
     return 1;
 
   l4_thread_control_start();
@@ -86,20 +86,25 @@ int main(void)
                           L4RE_THIS_TASK_CAP);
   l4_thread_control_alien(1);
   tag = l4_thread_control_commit(th);
-  if (l4_msgtag_has_error(tag))
+  if (l4_error(tag))
     return 2;
 
   tag = l4_thread_ex_regs(th, (l4_umword_t)thread_func,
                           (l4_umword_t)thread_stack + sizeof(thread_stack),
                           0);
-  if (l4_msgtag_has_error(tag))
+  if (l4_error(tag))
     return 3;
 
+  l4_sched_param_t sp = l4_sched_param(1, 0);
+  tag = l4_scheduler_run_thread(l4re_env()->scheduler, th, &sp);
+  if (l4_error(tag))
+    return 4;
+
   /* Pager/Exception loop */
   if (l4_msgtag_has_error(tag = l4_ipc_receive(th, u, L4_IPC_NEVER)))
     {
       printf("l4_ipc_receive failed");
-      return 4;
+      return 5;
     }
   memcpy(&exc, l4_utcb_exc(), sizeof(exc));
   mr0 = l4_utcb_mr()->mr[0];
index c292b7596aa4712fcac7d4ad2acdf8b0c4768d70..48820217cef9f3a85eec61f7e62adaa9095c8b2f 100644 (file)
@@ -62,19 +62,19 @@ int main(void)
   l4_exc_regs_t *e = l4_utcb_exc_u(u);
   l4_msgtag_t tag;
   int err;
-  extern char _start[], _end[], _etext[];
+  extern char _start[], _end[], _sdata[];
 
   if (l4_is_invalid_cap(t1))
     return 1;
 
   /* Prevent pagefaults of our new thread because we do not want to
    * implement a pager as well. */
-  l4_touch_ro(_start, _end - _start + 1);
-  l4_touch_rw(_etext, _end - _etext);
+  l4_touch_ro(_start, _sdata - _start + 1);
+  l4_touch_rw(_sdata, _end - _sdata);
 
   /* Create the thread using our default factory */
   tag = l4_factory_create_thread(l4re_env()->factory, t1);
-  if (l4_msgtag_has_error(tag))
+  if (l4_error(tag))
     return 1;
 
   /* Setup the thread by setting the pager and task. */
@@ -84,7 +84,7 @@ int main(void)
   l4_thread_control_bind((l4_utcb_t *)l4re_env()->first_free_utcb,
                           L4RE_THIS_TASK_CAP);
   tag = l4_thread_control_commit(t1);
-  if (l4_msgtag_has_error(tag))
+  if (l4_error(tag))
     return 2;
 
   /* Start the thread by finally setting instruction and stack pointer */
@@ -92,9 +92,15 @@ int main(void)
                           (l4_umword_t)thread,
                           (l4_umword_t)thread_stack + sizeof(thread_stack),
                           L4_THREAD_EX_REGS_TRIGGER_EXCEPTION);
-  if (l4_msgtag_has_error(tag))
+  if (l4_error(tag))
     return 3;
 
+  l4_sched_param_t sp = l4_sched_param(1, 0);
+  tag = l4_scheduler_run_thread(l4re_env()->scheduler, t1, &sp);
+  if (l4_error(tag))
+    return 4;
+
+
   /* Receive initial exception from just started thread */
   tag = l4_ipc_receive(t1, u, L4_IPC_NEVER);
   if ((err = l4_ipc_error(tag, u)))
index ecb381574d4fae0edff89146eee5249ba26bea5b..2272891165a92ac7049ce4b7add7edda3a545161 100644 (file)
@@ -77,7 +77,7 @@ int main(void)
     return 1;
 
   tag = l4_factory_create_thread(l4re_env()->factory, thread2_cap);
-  if (l4_msgtag_has_error(tag))
+  if (l4_error(tag))
     return 1;
 
   l4_thread_control_start();
@@ -86,15 +86,20 @@ int main(void)
   l4_thread_control_bind((l4_utcb_t *)l4re_env()->first_free_utcb,
                           L4RE_THIS_TASK_CAP);
   tag = l4_thread_control_commit(thread2_cap);
-  if (l4_msgtag_has_error(tag))
+  if (l4_error(tag))
     return 2;
 
   tag = l4_thread_ex_regs(thread2_cap,
                           (l4_umword_t)thread2,
                           (l4_umword_t)(stack2 + sizeof(stack2)), 0);
-  if (l4_msgtag_has_error(tag))
+  if (l4_error(tag))
     return 3;
 
+  l4_sched_param_t sp = l4_sched_param(1, 0);
+  tag = l4_scheduler_run_thread(l4re_env()->scheduler, thread2_cap, &sp);
+  if (l4_error(tag))
+    return 4;
+
   thread1();
 
   return 0;
index 3db96fec8804785eb8bcff4c8cb29627ae439c79..45273591b5a0b390b97fdebacd23552262546b2e 100644 (file)
@@ -29,7 +29,7 @@ Io.hw_add_devices
 
   gpio = Hw.Device
   {
-    hid = "GPIO"; -- FIXME: should be "OMAP GPIO" or something
+    hid = "omap3-gpio";
     Res.mmio(0x48004000, 0x48004fff);
     Res.mmio(0x48310000, 0x48310fff);
     Res.mmio(0x49050000, 0x49050fff);
@@ -47,7 +47,7 @@ Io.hw_add_devices
 
   i2c1 = Hw.Device
   {
-    hid = "I2C";  -- FIXME: this should be "OMAP I2C" or smoething
+    hid = "omap3-i2c";
     Res.mmio(0x48070000, 0x48070fff);
   }
 }
index b22844dddf737df255c52e0ee7f30db432d56bc2..bbf8fdcba7f17c35fb1788c2f22a7934ebcd1901 100644 (file)
@@ -1,33 +1,34 @@
-# Example configuration for io
+-- Example configuration for io
 
-# Configure 2 platform device to be known to io
-hw-root
+-- Configure two platform devices to be known to io
+Io.hw_add_devices
 {
-  FOODEVICE => new Device()
+  FOODEVICE = Io.Hw.Device
   {
-    .hid = "FOODEVICE";
-    new-res Irq(17);
-    new-res Mmio(0x6f000000 .. 0x6f007fff);
-  }
+    hid = "FOODEVICE";
+    Io.Res.irq(17);
+    Io.Res.mmio(0x6f000000, 0x6f007fff);
+  },
 
-  BARDEVICE => new Device()
+  BARDEVICE = Io.Hw.Device
   {
-    .hid = "BARDEVICE";
-    new-res Irq(19);
-    new-res Irq(20);
-    new-res Mmio(0x6f100000 .. 0x6f100fff);
+    hid = "BARDEVICE";
+    Io.Res.irq(19);
+    Io.Res.irq(20);
+    Io.Res.mmio(0x6f100000, 0x6f100fff);
   }
 }
 
-# Create a virtual bus for a client and give access to FOODEVICE
-client1 => new System_bus()
-{
-  dev => wrap(hw-root.FOODEVICE);
-}
 
-# Create a virtual bus for another client and give it access to
-# BARDEVICE
-client2 => new System_bus()
+Io.add_vbusses
 {
-  dev => wrap(hw-root.BARDEVICE);
+-- Create a virtual bus for a client and give access to FOODEVICE
+  client1 = Vi.System_bus(function ()
+    dev = wrap(hw:match("FOODEVICE"));
+  end),
+
+-- Create a virtual bus for another client and give it access to BARDEVICE
+  client2 = Vi.System_bus(function ()
+    dev = wrap(hw:match("BARDEVICE"));
+  end)
 }
index 68b2e8aaafdc8ee27b934c9d3f3504dcf77e8a1f..47561eef097c888136513ffb1647255a4cfeed56 100644 (file)
@@ -1,8 +1,12 @@
-# This is a configuration snippet for PCI device selection
+-- This is a configuration snippet for PCI device selection
 
-pciclient => new System_bus()
+Io.add_vbusses
 {
-  pci_storage[] => wrap(hw-root.match("PCI/CC_01"));
-  pci_net[] => wrap(hw-root.match("PCI/CC_02"));
-  pci_mm[] => wrap(hw-root.match("PCI/CC_04"))
+  pciclient = Vi.System_bus(function ()
+    PCI = Vi.PCI_bus(function ()
+      pci_mm      = wrap(hw:match("PCI/CC_04"));
+      pci_net     = wrap(hw:match("PCI/CC_02"));
+      pci_storage = wrap(hw:match("PCI/CC_01"));
+    end)
+  end)
 }
diff --git a/l4/pkg/l4sys/include/ARCH-amd64/__kip-arch.h b/l4/pkg/l4sys/include/ARCH-amd64/__kip-arch.h
new file mode 100644 (file)
index 0000000..ede2457
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * (c) 2013 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
+ *     economic rights: Technische Universität Dresden (Germany)
+ *
+ * This file is part of TUD:OS and distributed under the terms of the
+ * GNU General Public License 2.
+ * Please see the COPYING-GPL-2 file for details.
+ *
+ * As a special exception, you may use this file as part of a free software
+ * library without restriction.  Specifically, if other files instantiate
+ * templates or use macros or inline functions from this file, or you compile
+ * this file and link it with other files to produce an executable, this
+ * file does not by itself cause the resulting executable to be covered by
+ * the GNU General Public License.  This exception does not however
+ * invalidate any other reasons why the executable file might be covered by
+ * the GNU General Public License.
+ */
+#pragma once
+
+struct l4_kip_platform_info_arch
+{};
diff --git a/l4/pkg/l4sys/include/ARCH-arm/__kip-arch.h b/l4/pkg/l4sys/include/ARCH-arm/__kip-arch.h
new file mode 100644 (file)
index 0000000..291e9ff
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * (c) 2013 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
+ *     economic rights: Technische Universität Dresden (Germany)
+ *
+ * This file is part of TUD:OS and distributed under the terms of the
+ * GNU General Public License 2.
+ * Please see the COPYING-GPL-2 file for details.
+ *
+ * As a special exception, you may use this file as part of a free software
+ * library without restriction.  Specifically, if other files instantiate
+ * templates or use macros or inline functions from this file, or you compile
+ * this file and link it with other files to produce an executable, this
+ * file does not by itself cause the resulting executable to be covered by
+ * the GNU General Public License.  This exception does not however
+ * invalidate any other reasons why the executable file might be covered by
+ * the GNU General Public License.
+ */
+#pragma once
+
+/**
+ * \internal
+ * Do not expose as any interface yet as this assumes equality over all CPUs
+ * which will not be true along the way.
+ */
+struct l4_kip_platform_info_arch
+{
+  struct
+  {
+    l4_uint32_t MIDR, CTR, ID_MMFR0, ID_ISAR0;
+  } cpuinfo;
+};
+
diff --git a/l4/pkg/l4sys/include/ARCH-ppc32/__kip-arch.h b/l4/pkg/l4sys/include/ARCH-ppc32/__kip-arch.h
new file mode 100644 (file)
index 0000000..ede2457
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * (c) 2013 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
+ *     economic rights: Technische Universität Dresden (Germany)
+ *
+ * This file is part of TUD:OS and distributed under the terms of the
+ * GNU General Public License 2.
+ * Please see the COPYING-GPL-2 file for details.
+ *
+ * As a special exception, you may use this file as part of a free software
+ * library without restriction.  Specifically, if other files instantiate
+ * templates or use macros or inline functions from this file, or you compile
+ * this file and link it with other files to produce an executable, this
+ * file does not by itself cause the resulting executable to be covered by
+ * the GNU General Public License.  This exception does not however
+ * invalidate any other reasons why the executable file might be covered by
+ * the GNU General Public License.
+ */
+#pragma once
+
+struct l4_kip_platform_info_arch
+{};
diff --git a/l4/pkg/l4sys/include/ARCH-sparc/__kip-arch.h b/l4/pkg/l4sys/include/ARCH-sparc/__kip-arch.h
new file mode 100644 (file)
index 0000000..ede2457
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * (c) 2013 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
+ *     economic rights: Technische Universität Dresden (Germany)
+ *
+ * This file is part of TUD:OS and distributed under the terms of the
+ * GNU General Public License 2.
+ * Please see the COPYING-GPL-2 file for details.
+ *
+ * As a special exception, you may use this file as part of a free software
+ * library without restriction.  Specifically, if other files instantiate
+ * templates or use macros or inline functions from this file, or you compile
+ * this file and link it with other files to produce an executable, this
+ * file does not by itself cause the resulting executable to be covered by
+ * the GNU General Public License.  This exception does not however
+ * invalidate any other reasons why the executable file might be covered by
+ * the GNU General Public License.
+ */
+#pragma once
+
+struct l4_kip_platform_info_arch
+{};
diff --git a/l4/pkg/l4sys/include/ARCH-x86/__kip-arch.h b/l4/pkg/l4sys/include/ARCH-x86/__kip-arch.h
new file mode 100644 (file)
index 0000000..ede2457
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * (c) 2013 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
+ *     economic rights: Technische Universität Dresden (Germany)
+ *
+ * This file is part of TUD:OS and distributed under the terms of the
+ * GNU General Public License 2.
+ * Please see the COPYING-GPL-2 file for details.
+ *
+ * As a special exception, you may use this file as part of a free software
+ * library without restriction.  Specifically, if other files instantiate
+ * templates or use macros or inline functions from this file, or you compile
+ * this file and link it with other files to produce an executable, this
+ * file does not by itself cause the resulting executable to be covered by
+ * the GNU General Public License.  This exception does not however
+ * invalidate any other reasons why the executable file might be covered by
+ * the GNU General Public License.
+ */
+#pragma once
+
+struct l4_kip_platform_info_arch
+{};
index 2b3df1a9259e18655a55c7a88e93a2c128aef5c7..c17f7c29ad3466604e76b987210dfcd2aed2f2e7 100644 (file)
@@ -4,7 +4,7 @@
  * \ingroup l4_api
  */
 /*
- * (c) 2008-2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
+ * (c) 2008-2013 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
  *               Alexander Warg <warg@os.inf.tu-dresden.de>
  *     economic rights: Technische Universität Dresden (Germany)
  *
 #include <l4/sys/compiler.h>
 #include <l4/sys/l4int.h>
 
+#include <l4/sys/__kip-arch.h>
+
 /**
  * \internal
  */
 struct l4_kip_platform_info
 {
-  l4_umword_t cpuid;     ///< reserved \internal
-  l4_umword_t mp;        ///< reserved \internal
-  char        name[16];
+  char                             name[16];
+  l4_uint32_t                      is_mp;
+  struct l4_kip_platform_info_arch arch;
 };
 
 #if L4_MWORD_BITS == 32
@@ -42,9 +44,6 @@ struct l4_kip_platform_info
 #  include <l4/sys/__kip-64bit.h>
 #endif
 
-
-
-
 /**
  * \addtogroup l4_kip_api
  *
index cd51bb3909449166e5d01197fa2b1b81e8a673c3..ae2118eb00848303f58ef9181026a658266d1891 100644 (file)
@@ -5,7 +5,7 @@
  * \ingroup l4_api
  */
 /*
- * (c) 2008-2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
+ * (c) 2008-2013 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
  *               Alexander Warg <warg@os.inf.tu-dresden.de>,
  *               Björn Döbel <doebel@os.inf.tu-dresden.de>,
  *               Torsten Frenzel <frenzel@os.inf.tu-dresden.de>
@@ -413,3 +413,6 @@ L4_INLINE unsigned l4_msgtag_is_sigma0(l4_msgtag_t t) L4_NOTHROW
 
 L4_INLINE unsigned l4_msgtag_is_io_page_fault(l4_msgtag_t t) L4_NOTHROW
 { return l4_msgtag_label(t) == L4_PROTO_IO_PAGE_FAULT; }
+
+#include <l4/sys/__l4_fpage.h>
+#include <l4/sys/__timeout.h>
index eec61c90676ce6fedd7db881c051ba3983001fd0..13feb53b30cae38521c6cfdbee2f172b3bca4017 100644 (file)
@@ -79,7 +79,14 @@ typedef struct l4_utcb_t l4_utcb_t;
  */
 typedef struct l4_msg_regs_t
 {
+#if defined(__STRICT_ANSI__) && (__STDC_VERSION__ < 201112L)
   l4_umword_t mr[L4_UTCB_GENERIC_DATA_SIZE]; /**< Message registers */
+#else
+  union {
+    l4_umword_t mr[L4_UTCB_GENERIC_DATA_SIZE]; /**< Message registers */
+    l4_uint64_t mr64[L4_UTCB_GENERIC_DATA_SIZE / (sizeof(l4_uint64_t)/sizeof(l4_umword_t))]; /**< Message registers 64bit alias*/
+  };
+#endif
 } l4_msg_regs_t;
 
 /**
@@ -292,6 +299,16 @@ l4_timeout_s l4_timeout_abs_u(l4_kernel_clock_t pint, int br,
 L4_INLINE
 l4_timeout_s l4_timeout_abs(l4_kernel_clock_t pint, int br) L4_NOTHROW;
 
+/**
+ * \brief Get index into 64bit message registers alias from native-sized index.
+ * \ingroup l4_timeout_api
+ *
+ * \param idx  Index to native-sized message register
+ * \return Index to 64bit message register alias
+ */
+L4_INLINE
+unsigned l4_utcb_mr64_idx(unsigned idx) L4_NOTHROW;
+
 /**************************************************************************
  * Implementations
  **************************************************************************/
@@ -362,6 +379,9 @@ L4_INLINE
 l4_timeout_s l4_timeout_abs(l4_kernel_clock_t val, int pos) L4_NOTHROW
 { return l4_timeout_abs_u(val, pos, l4_utcb()); }
 
+L4_INLINE unsigned l4_utcb_mr64_idx(unsigned idx) L4_NOTHROW
+{ return idx / (sizeof(l4_uint64_t) / sizeof(l4_umword_t)); }
+
 __END_DECLS
 
 #endif /* ! _L4_SYS_UTCB_H */
index 6b86fd6d6c200c347ed4eec59a7e4ffd44e95507..facfe3a7a732cd84e6a6ad4c49c3caa14fa5955a 100644 (file)
@@ -27,7 +27,6 @@
 /* L4 includes */
 #include <l4/sys/l4int.h>
 #include <l4/sys/compiler.h>
-#include <l4/sys/types.h>
 
 /*****************************************************************************
  *** Prototypes
index ca486e0c622a749dfc635bfed10c050c8208d095..45819fdffe833d744841593b3dba7ce490004744 100644 (file)
@@ -50,8 +50,8 @@ typedef struct __attribute__((packed))
 } l4util_mb_addr_range_t;
 
 #define l4util_mb_for_each_mmap_entry(i, mbi) \
-  for (i = (l4util_mb_addr_range_t *) mbi->mmap_addr; \
-       (unsigned long)i < mbi->mmap_addr + mbi->mmap_length; \
+  for (i = (l4util_mb_addr_range_t *)(unsigned long)mbi->mmap_addr; \
+       (unsigned long)i < (unsigned long)mbi->mmap_addr + mbi->mmap_length; \
        i = (l4util_mb_addr_range_t *)((unsigned long)i + mmap->struct_size + sizeof (mmap->struct_size)))
 
 /** usable memory "Type", all others are reserved.  */
index 954724f36f2a32a80c50ac12a34e6748107d0770..87898bbcac43415be4d426742c47585adf7663b6 100644 (file)
@@ -42,14 +42,13 @@ static inline  void __kernel_dmb(void)
   extern char const __L4_KIP_ADDR__[];
   l4_kernel_info_t *k = (l4_kernel_info_t *)__L4_KIP_ADDR__;
 
-  static_assert(   (offsetof(l4_kernel_info_t, platform_info.cpuid) & 0xf) == 0
-                && (offsetof(l4_kernel_info_t, platform_info.mp) & 0xf)
-                    == sizeof(k->platform_info.cpuid),
-                "No proper alignment");
+  static_assert(   (offsetof(l4_kernel_info_t, platform_info.is_mp) == 0x100)
+                && (offsetof(l4_kernel_info_t, platform_info.arch.cpuinfo.MIDR) == 0x104),
+                "Changed KIP layout, adapt");
 
-  if (k->platform_info.mp)
+  if (k->platform_info.is_mp)
     {
-      unsigned arch = (k->platform_info.cpuid >> 16) & 0xf;
+      unsigned arch = (k->platform_info.arch.cpuinfo.MIDR >> 16) & 0xf;
       if (arch == 0xf)
         asm volatile(".inst 0xf57ff05f" : : : "memory");
       else if (arch == 0x7)
index 9e9b2e4d5c34cd67083fbd904c96e4f680628226..4c4fdb294715ee8198f3b2f8d9735b71267a68db 100644 (file)
@@ -90,24 +90,9 @@ typedef struct timespec __gthread_time_t;
 # ifndef __gthrw_pragma
 #  define __gthrw_pragma(pragma)
 # endif
-// by AW11     ---->
-# if __GNUC__ < 4
-#  error Unsupported GCC version >= 4.0 required
-# elif __GNUC__ > 4 || __GNUC_MINOR__ >= 2
-#  define __GXX_AW11_WEAK_ALIAS_LINKAGE static
-# else
-#  define __GXX_AW11_WEAK_ALIAS_LINKAGE extern
-# endif
-// end by AW11 <----
-# ifndef AW11_CHANGED_THIS // for gcc 4.1
-# define __gthrw2(name,name2,type) \
-  __GXX_AW11_WEAK_ALIAS_LINKAGE __typeof(type) name __attribute__ ((__weakref__(#name2))); \
-  __gthrw_pragma(weak type)
-# else
 # define __gthrw2(name,name2,type) \
   static __typeof(type) name __attribute__ ((__weakref__(#name2))); \
   __gthrw_pragma(weak type)
-# endif
 # define __gthrw_(name) __gthrw_ ## name
 #else
 # define __gthrw2(name,name2,type)
index 197e3088afa24cecf37ee0a4253e37f2e4798026..8e480b4b17b005839da361f4117cd802de73909c 100644 (file)
@@ -125,7 +125,8 @@ public:
    * \param do_event_work_cb Call-back function that is called in case an
    *                         event (such as an interrupt) is pending.
    * \param setup_ipc        Call-back function that is called before an
-   *                         IPC operation is called.
+   *                         IPC operation is called, and before event
+   *                         delivery is enabled.
    */
   void irq_enable(l4_utcb_t *utcb, l4vcpu_event_hndl_t do_event_work_cb,
                   l4vcpu_setup_ipc_t setup_ipc) throw()
@@ -139,7 +140,8 @@ public:
    * \param do_event_work_cb Call-back function that is called in case an
    *                         event (such as an interrupt) is pending.
    * \param setup_ipc        Call-back function that is called before an
-   *                         IPC operation is called.
+   *                         IPC operation is called, and before event
+   *                         delivery is enabled.
    */
   void irq_restore(Irq_state s, l4_utcb_t *utcb,
                    l4vcpu_event_hndl_t do_event_work_cb,
index 2311e860838bdedb558f061066dde66c4d81fac7..751051fd4ec535b5f3373163d18a819bea41f6dc 100644 (file)
@@ -92,7 +92,8 @@ l4vcpu_irq_disable_save(l4_vcpu_state_t *vcpu) L4_NOTHROW;
  * \param do_event_work_cb Call-back function that is called in case an
  *                         event (such as an interrupt) is pending.
  * \param setup_ipc        Function call-back that is called right before
- *                         any IPC operation.
+ *                         any IPC operation, and before event delivery is
+ *                         enabled.
  */
 L4_CV L4_INLINE
 void
@@ -111,7 +112,8 @@ l4vcpu_irq_enable(l4_vcpu_state_t *vcpu, l4_utcb_t *utcb,
  *                         event (such as an interrupt) is pending after
  *                         enabling.
  * \param setup_ipc        Function call-back that is called right before
- *                         any IPC operation.
+ *                         any IPC operation, and before event delivery is
+ *                         enabled.
  */
 L4_CV L4_INLINE
 void
@@ -266,6 +268,12 @@ l4vcpu_irq_enable(l4_vcpu_state_t *vcpu, l4_utcb_t *utcb,
                   l4vcpu_event_hndl_t do_event_work_cb,
                   l4vcpu_setup_ipc_t setup_ipc) L4_NOTHROW
 {
+  if (!(vcpu->state & L4_VCPU_F_IRQ))
+    {
+      setup_ipc(utcb);
+      l4_barrier();
+    }
+
   while (1)
     {
       vcpu->state |= L4_VCPU_F_IRQ;
index 0c402eb601ecd48bea667901adcd71826ff4079b..d4e3eb2ee6c5666acbb58eab2e78afde5d7ed41e 100644 (file)
@@ -8,8 +8,9 @@ L4DIR   ?= $(PKGDIR)/../..
 
 SYSTEMS = x86-l4f
 
-TARGET = include server lib ex
+TARGET = include server lib ex tools
 
 ex : lib server
+tools : ex
 
 include $(L4DIR)/mk/subdir.mk
index 253b4a460efcccecf0a6c11acc171412a3c4c4c3..1f165bf5f0238e98bc1a6adafc20cc1d3bf24ac3 100755 (executable)
@@ -1,10 +1,14 @@
 #!/bin/bash
 
+nothreads=$(nm $1 | grep pthread_mutex_lock | grep ' w pthread');
+
 echo "# Auto-generated for '$1'"
 echo ""
 echo "[general]"
 echo "   page_fault_handling = rw"
-echo "  threads             = yes"
+if [ -z "$nothreads" ]; then
+       echo "  threads             = yes"
+fi
 echo "  intercept_kip       = yes"
 echo "#  redundancy          = none"
 echo "#  redundancy          = dual"
@@ -20,16 +24,15 @@ echo "#  log                 = all"
 
 echo ""
 
-echo "[threads]"
-
-function_list="__pthread_lock __pthread_unlock pthread_mutex_lock pthread_mutex_unlock"
-
-for f in $function_list; do
-       nm $1 | grep -E "\ $f" | sed -re "s/([0-9a-f]+) [TW] ($f(_rep)?)/  \2 = 0x\1/" | sed -re "s/[_]*pthread_//g"
-done
-
+if [ -z "$nothreads" ]; then
+       echo "[threads]"
+       function_list="__pthread_lock __pthread_unlock pthread_mutex_lock pthread_mutex_unlock"
+       for f in $function_list; do
+               nm $1 | grep -E "\ $f" | sed -re "s/([0-9a-f]+) [TW] ($f(_rep)?)/  \2 = 0x\1/" | sed -re "s/[_]*pthread_//g"
+       done
+       echo ""
+fi
 
-echo ""
 echo "[kip-time]"
 for v in libc_backend_rt_clock_gettime mono_clock_gettime; do
        echo -n "  "; nm $1 | grep $v |  sed -re 's/([0-9a-f]+) [wWtT] (.*)/\2 = 0x\1/g';
index aeb7891440d28fab45c1406ce1e91ff6c49bb4c7..eac8410f075f72bad544fb81d5b24a5dba0be52c 100644 (file)
@@ -1,12 +1,6 @@
 PKGDIR ?= ..
 L4DIR  ?= $(PKGDIR)/../..
 
-TARGET = serial_client \
-         trap+emulate \
-         hello \
-         large_malloc \
-         pthread_hello \
-         pthread_mutex \
-         eventbuf
+TARGET = $(wildcard [a-z]*)
 
 include $(L4DIR)/mk/subdir.mk
index bbb461885a3fdcfda45718335385d2df4668f0c1..3cf552a7f7ee13e7a20089784cb2566ad4f9deb7 100644 (file)
 #include <errno.h>
 
 #include <l4/util/util.h>
-#include <l4/re/env.h>
+#include <l4/re/env>
+#include <l4/re/mem_alloc>
+#include <l4/re/rm>
+#include <l4/re/util/cap_alloc>
 #include <l4/sys/kdebug.h>
 
 #include "log"
@@ -31,7 +34,9 @@ static inline long long US(struct timeval& tv)
        return tv.tv_sec * 1000000 + tv.tv_usec;
 }
 
-int main(void)
+static void
+__attribute__((used))
+malloc_test()
 {
        l4_umword_t sizes[NUM_SIZES] = {
                      1024 * 1024, // 1 MB
@@ -65,7 +70,55 @@ int main(void)
                       US(ttouch)  - US(tmalloc),
                       US(tfree)   - US(ttouch));
        }
+}
+
+
+static void rm_test()
+{
+       unsigned size = 400 * 1024 * 1024; // 800 MB
+       unsigned flags = 0; //L4Re::Mem_alloc::Super_pages | L4Re::Mem_alloc::Continuous;
+
+       printf("Start RM test. %lx\n", flags);
+
+       L4::Cap<L4Re::Dataspace> dscap = L4Re::Util::cap_alloc.alloc<L4Re::Dataspace>();
+       L4::Cap<L4Re::Dataspace> dscap2;
+       printf("DS: %lx\n", dscap.cap());
+       int error = L4Re::Env::env()->mem_alloc()->alloc(size, dscap, flags);
+       if (error) {
+               enter_kdebug("alloc fail");
+       }
+
+       l4_addr_t a = 0;
+       error = L4Re::Env::env()->rm()->attach(&a, size, L4Re::Rm::Search_addr, dscap, 0);
+       printf("Attached to %p\n", (void*)a);
+
+       l4_touch_rw((void*)a, size);
+
+       //L4Re::Env::env()->rm()->detach(a, &dscap2);
+       //L4Re::Env::env()->mem_alloc()->free(dscap);
+
+       printf("End RM test.\n");
+}
+
+
+int main(int argc, char **argv)
+{
+       int max_rounds = 2;
+       struct timeval start, stop;
+       if (argc > 1) {
+               max_rounds = strtol(argv[1], 0, 0);
+       }
+
+       l4_sleep(2000);
+
+       gettimeofday(&start, 0);
+       for (unsigned i = 0; i < max_rounds; ++i) {
+               //malloc_test();
+               rm_test();
+       }
+       gettimeofday(&stop, 0);
+       printf("Difference: %lld Âµs\n", US(stop) - US(start));
+
 
-       enter_kdebug("I am done.");
        return 0;
 }
index 4587a8fa7b26fbea48d9d1e5f0f7dc91d8490388..c4b2d50e1dde83e85f6e00a3963a151a0b2c3c5d 100644 (file)
@@ -26,8 +26,8 @@ pthread_mutex_t mtx;
 
 #define NUM_THREADS 2
 
-static const unsigned print_iterations = 1000;
-static const unsigned inc_iterations   = 10000 / NUM_THREADS;
+static const unsigned print_iterations = 100;
+static const unsigned inc_iterations   = 1000 / NUM_THREADS;
 
 static
 void *thread(void *data)
diff --git a/l4/pkg/plr/ex/superpages/Makefile b/l4/pkg/plr/ex/superpages/Makefile
new file mode 100644 (file)
index 0000000..5a6d162
--- /dev/null
@@ -0,0 +1,14 @@
+PKGDIR ?=      ../../..
+L4DIR ?=       $(PKGDIR)/..
+
+SYSTEMS = x86-l4f
+
+TARGET = romain_superpages
+SRC_CC = main.cc
+
+REQUIRES_LIBS = libstdc++
+
+CXXFLAGS += -I$(SRC_DIR)/../../server/src/
+include $(L4DIR)/mk/prog.mk
+
+#LDFLAGS += -lpthread_rep -luc_c -levbuf_c
diff --git a/l4/pkg/plr/ex/superpages/main.cc b/l4/pkg/plr/ex/superpages/main.cc
new file mode 100644 (file)
index 0000000..c9dc55b
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * superpages/main.cc --
+ *
+ *     Test usage of superpages for mapping memory
+ *
+ * (c) 2013 Björn Döbel <doebel@os.inf.tu-dresden.de>,
+ *     economic rights: Technische Universität Dresden (Germany)
+ * This file is part of TUD:OS and distributed under the terms of the
+ * GNU General Public License 2.
+ * Please see the COPYING-GPL-2 file for details.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <sys/time.h>
+#include <errno.h>
+
+#include <l4/util/util.h>
+#include <l4/re/env.h>
+#include <l4/sys/kdebug.h>
+#include <l4/re/env>
+#include <l4/re/rm>
+#include <l4/re/dataspace>
+#include <l4/re/mem_alloc>
+#include <l4/re/util/cap_alloc>
+
+/*
+ */
+static inline long long US(struct timeval& tv)
+{
+       return tv.tv_sec * 1000000 + tv.tv_usec;
+}
+
+
+static void map_without_superpage()
+{
+       l4_umword_t size = 1 << 22;
+       L4::Cap<L4Re::Dataspace> dscap = L4Re::Util::cap_alloc.alloc<L4Re::Dataspace>();
+       long r = L4Re::Env::env()->mem_alloc()->alloc(size, dscap,
+                                                     L4Re::Mem_alloc::Super_pages);
+       printf("alloc: %ld\n", r);
+
+       l4_addr_t start = 0;
+       r = L4Re::Env::env()->rm()->attach(&start, size, L4Re::Rm::Search_addr,
+                                          dscap, 0, 22);
+       printf("attach: %ld addr %lx\n", r, start);
+
+       memset((void*)start, 5, size);
+}
+
+
+static void map_with_superpage()
+{
+       l4_umword_t size = 1 << 22;
+       L4::Cap<L4Re::Dataspace> dscap = L4Re::Util::cap_alloc.alloc<L4Re::Dataspace>();
+       // Hint: note the combined use of Super_pages and Continuous!
+       long r = L4Re::Env::env()->mem_alloc()->alloc(size, dscap,
+                                                     L4Re::Mem_alloc::Super_pages |
+                                                     L4Re::Mem_alloc::Continuous);
+       printf("alloc: %ld\n", r);
+
+       l4_addr_t start = 0;
+       r = L4Re::Env::env()->rm()->attach(&start, size, L4Re::Rm::Search_addr,
+                                          dscap, 0, 22);
+       printf("attach: %ld addr %lx\n", r, start);
+
+       memset((void*)start, 5, size);
+}
+
+
+int main(void)
+{
+       map_with_superpage();
+       map_without_superpage();
+
+       return 0;
+}
diff --git a/l4/pkg/plr/include/cpuid.h b/l4/pkg/plr/include/cpuid.h
new file mode 100644 (file)
index 0000000..8f6d914
--- /dev/null
@@ -0,0 +1,108 @@
+#pragma once
+
+#include <l4/sys/types.h>
+#include "constants.h"
+
+struct CPU_id
+{
+    l4_umword_t fiasco_id;
+    l4_umword_t apic_id;
+
+    CPU_id(l4_umword_t a=0xf00, l4_umword_t b=0xf00)
+        : fiasco_id(a), apic_id(b)
+    {}
+
+    static bool comp_apic(CPU_id const& i1, CPU_id const& i2)
+    { return i1.apic_id < i2.apic_id; }
+};
+
+class CPUID
+{
+public:
+
+    enum {
+        MAXID     = 0x00,
+        FMS_flags = 0x01,
+        CACHES_o  = 0x02,
+        PSN       = 0x03,
+        CACHES_n  = 0x04,
+        MON       = 0x05,
+        POWER     = 0x06,
+        FLAGS     = 0x07,
+        DCA       = 0x08,
+        PEMO      = 0x0A,
+        TOPOLOGY  = 0x0B,
+        XSTATE    = 0x0D,
+    };
+
+    /* Perform CPUID */
+    static unsigned cpuid(l4_umword_t code, l4_umword_t* a, l4_umword_t* b,
+                          l4_umword_t *c, l4_umword_t *d)
+    {
+        asm volatile ("cpuid"
+         : "=a"(*a), "=b"(*b), "=c"(*c), "=d"(*d)
+         : "a" (code), "b" (*b), "c" (*c), "d" (*d));
+        return *a;
+    }
+
+
+    /*
+     * Check if CPU supports CPUID.
+     *
+     * From http://wiki.osdev.org/CPUID
+     */
+     static bool have_cpuid()
+     {
+        l4_umword_t ret;
+        asm volatile (
+            "pushf\t\n"
+            "pop %%eax\t\n"
+            "mov %%eax, %%ecx\t\n"
+            "xor $0x200000, %%eax\t\n"
+            "push %%eax\t\n"
+            "popf\t\n"
+            "pushf\t\n"
+            "pop %%eax\t\n"
+            "xor %%ecx, %%eax\t\n"
+            "shr $21, %%eax\t\n"
+            "and $1, %%eax\t\n"
+            "push %%ecx\t\n"
+            "popf\t\n"
+            : "=a" (ret));
+
+        return (ret == 1);
+    }
+
+
+    static CPU_id current_apicid(unsigned fiascoID)
+    {
+        CPU_id ret;
+        l4_umword_t a,b,c,d;
+        a = 0; b = 0; c = 0; d = 0;
+        a = CPUID::cpuid(CPUID::TOPOLOGY, &a, &b, &c, &d);
+        ret.fiasco_id = fiascoID;
+        ret.apic_id   = d;
+        return ret;
+    }
+
+
+    static l4_umword_t num_cpus()
+    {
+        if (CPUID::max_cpuid() < CPUID::TOPOLOGY) {
+            return Romain::MAX_CPUS;
+        }
+        l4_umword_t a,b,c,d;
+        a = 0; b = 0; c = 1; d = 0;
+        a = CPUID::cpuid(CPUID::TOPOLOGY, &a, &b, &c, &d);
+        return b;
+    }
+
+
+
+    static l4_umword_t max_cpuid()
+    {
+        l4_umword_t a, b, c, d;
+        a = b = c = d = 0;
+        return CPUID::cpuid(CPUID::MAXID, &a, &b, &c, &d);
+    }
+};
diff --git a/l4/pkg/plr/include/perf.h b/l4/pkg/plr/include/perf.h
new file mode 100644 (file)
index 0000000..14ab611
--- /dev/null
@@ -0,0 +1,12 @@
+#pragma once
+#include <l4/sys/compiler.h>
+#include <l4/sys/types.h>
+
+EXTERN_C_BEGIN
+/* Configure counters -> setup is in lib/perfcnt/perfcnt.c */
+void perfconf(void);
+/* Read and print counters */
+void perfread(void);
+void perfread2(l4_uint64_t *v1,l4_uint64_t *v2,l4_uint64_t *v3,l4_uint64_t *v4);
+
+EXTERN_C_END
index 896578197152eadb9eefcf3cad99087beed65781..eac8410f075f72bad544fb81d5b24a5dba0be52c 100644 (file)
@@ -1,6 +1,6 @@
 PKGDIR ?= ..
 L4DIR  ?= $(PKGDIR)/../..
 
-TARGET = libpthread_romain libuu libevbuf_c
+TARGET = $(wildcard [a-z]*)
 
 include $(L4DIR)/mk/subdir.mk
diff --git a/l4/pkg/plr/lib/libperfcnt/Makefile b/l4/pkg/plr/lib/libperfcnt/Makefile
new file mode 100644 (file)
index 0000000..d3f95e4
--- /dev/null
@@ -0,0 +1,13 @@
+PKGDIR?= ../..
+L4DIR ?= $(PKGDIR)/../..
+
+# the name of your library
+TARGET = libpcnt.a
+
+PC_FILENAME = libpcnt
+
+# list your .c or .cc files here
+SRC_C  = pcnt.c 
+SRC_CC  =
+
+include $(L4DIR)/mk/lib.mk
diff --git a/l4/pkg/plr/lib/libperfcnt/pcnt.c b/l4/pkg/plr/lib/libperfcnt/pcnt.c
new file mode 100644 (file)
index 0000000..8064e51
--- /dev/null
@@ -0,0 +1,105 @@
+#include <l4/sys/types.h>
+#include <l4/sys/thread.h>
+#include <stdio.h>
+#include <l4/re/env.h>
+#include <l4/plr/perf.h>
+
+enum {
+    THREAD_PERF_OP = 12,
+       SETUP_PERF     = 0x5E,
+       READ_PERF      = 0xAE,
+};
+
+enum {
+       /* Cache events */
+       L1I_MISSES_U  = 0x02,
+       L1I_MISSES_E  = 0x80,
+       L3_MISSES_U   = 0x41,
+       L3_MISSES_E   = 0x2E,
+       L2_MISSES_U   = 0x02,
+       L2_MISSES_E   = 0x24,
+       
+       /* TLB events */
+       ITLB_MISSES_U = 0x01,
+       ITLB_MISSES_E = 0x85,
+       DTLB_MISSES_U = 0x01,
+       DTLB_MISSES_E = 0x49,
+
+       /* Runtime events */
+       CLK_UNHALTED_THR_U = 0x00,
+       CLK_UNHALTED_THR_E = 0x3C,
+       CLK_UNHALTED_REF_U = 0x01,
+       CLK_UNHALTED_REF_E = 0x3C,
+
+       USR_FLAG      = (1 << 16),
+       OS_FLAG       = (1 << 17),
+       ENABLE_FLAG   = (1 << 22),
+};
+
+static void perfcall(l4_umword_t op, l4_umword_t arg1, l4_umword_t arg2,
+                     l4_umword_t arg3, l4_umword_t arg4)
+{
+       l4_msg_regs_t* mr = l4_utcb_mr_u(l4_utcb());
+       mr->mr[1] = THREAD_PERF_OP;
+       mr->mr[2] = op;
+       mr->mr[3] = arg1;
+       mr->mr[4] = arg2;
+       mr->mr[5] = arg3;
+       mr->mr[6] = arg4;
+
+       l4_thread_stats_time_u(l4re_global_env->main_thread, l4_utcb());
+}
+
+void perfconf(void)
+{
+       l4_umword_t ev1, ev2, ev3, ev4;
+       
+       ev1  = 0;
+       //ev1  = CLK_UNHALTED_REF_E & 0xFF;
+       //ev1 |= ((CLK_UNHALTED_REF_U & 0xFF) << 8);
+       //ev1 |= USR_FLAG;
+       //ev1 |= OS_FLAG;
+       //ev1 |= ENABLE_FLAG;
+       
+       ev2  = 0;
+    //ev2  = CLK_UNHALTED_THR_E & 0xFF;
+    //ev2 |= ((CLK_UNHALTED_THR_U & 0xFF) << 8);
+    //ev2 |= OS_FLAG;
+    //ev2 |= ENABLE_FLAG;
+
+       ev3 = 0;
+       ev3 = L2_MISSES_E & 0xFF;
+       ev3 |= ((L2_MISSES_E & 0xFF) << 8);
+       ev3 |= USR_FLAG;
+       ev3 |= OS_FLAG;
+       ev3 |= ENABLE_FLAG;
+
+       ev4 = 0;
+       ev4 = L3_MISSES_E & 0xFF;
+       ev4 |= ((L3_MISSES_U & 0xFF) << 8);
+       ev4 |= USR_FLAG;
+       ev4 |= OS_FLAG;
+       ev4 |= ENABLE_FLAG;
+       
+       perfcall(SETUP_PERF, ev1, ev2, ev3, ev4);
+}
+
+void perfread2(l4_uint64_t *v1,l4_uint64_t *v2,l4_uint64_t *v3,l4_uint64_t *v4)
+{
+       perfcall(READ_PERF, 0, 0, 0, 0);
+
+       l4_msg_regs_t *mr = l4_utcb_mr_u(l4_utcb());
+       *v1 = mr->mr[0] | ( (l4_uint64_t)mr->mr[1] << 32 );
+       *v2 = mr->mr[2] | ( (l4_uint64_t)mr->mr[3] << 32 );
+       *v3 = mr->mr[4] | ( (l4_uint64_t)mr->mr[5] << 32 );
+       *v4 = mr->mr[6] | ( (l4_uint64_t)mr->mr[7] << 32 );
+}
+
+void perfread(void)
+{
+       l4_uint64_t v1, v2, v3, v4;
+       perfread2(&v1, &v2, &v3, &v4);
+
+       printf("READ %016llx %016llx %016llx %016llx\n", v1, v2, v3, v4);
+}
+
diff --git a/l4/pkg/plr/lib/libperfcnt/perfcnt.diff b/l4/pkg/plr/lib/libperfcnt/perfcnt.diff
new file mode 100644 (file)
index 0000000..a596daf
--- /dev/null
@@ -0,0 +1,65 @@
+diff --git a/src/kern/thread_object.cpp b/src/kern/thread_object.cpp
+index 4c24387..7efc871 100644
+--- a/src/kern/thread_object.cpp
++++ b/src/kern/thread_object.cpp
+@@ -681,6 +681,60 @@ Thread_object::sys_thread_stats(L4_msg_tag const &/*tag*/, Utcb *utcb)
+     drq(handle_sys_thread_stats_remote, &value, 0, Drq::Any_ctxt);
+   else
+     {
++        if (utcb->values[1] == 12)
++              {
++                //printf("KERN STATS TIME ");
++                //printf("%lx %lx %lx\n", utcb->values[2], utcb->values[3], utcb->values[4]);
++                if (utcb->values[2] == 0x1E) // TEST
++                  {
++                        Mword a, b, c, d;
++
++                        a = 0; b = 0; c = 0; d = 0;
++                        asm volatile ("cpuid"
++                            : "=a" (a), "=b" (b), "=c" (c), "=d" (d)
++                            : "a" (a), "b" (b), "c" (c), "d" (d)
++                        );
++                        //printf("::CPUID.MAX: %08lx\n", a);
++
++                        a = 0x0A;
++                        asm volatile ("cpuid"
++                            : "=a" (a), "=b" (b), "=c" (c), "=d" (d)
++                            : "a" (a), "b" (b), "c" (c), "d" (d)
++                        );
++                        //printf("::Perfmon capabilities:\n");
++                        //printf("::A %08lx B %08lx C %08lx D %08lx\n", a, b, c, d);
++                      }
++                else if (utcb->values[2] == 0x5E) // SETUP
++                  {
++                        //printf("SETUP\n");
++                        Cpu::wrmsr(utcb->values[3], 0x186);
++                        Cpu::wrmsr(utcb->values[4], 0x187);
++                        Cpu::wrmsr(utcb->values[5], 0x188);
++                        Cpu::wrmsr(utcb->values[6], 0x189);
++
++                        Cpu::wrmsr(0, 0xC1);
++                        Cpu::wrmsr(0, 0xC2);
++                        Cpu::wrmsr(0, 0xC3);
++                        Cpu::wrmsr(0, 0xC4);
++                  }
++                else if (utcb->values[2] == 0xAE) // READ
++                      {
++                        //printf("READ\n");
++                        Unsigned64 v1, v2, v3, v4;
++                        v1 = Cpu::rdmsr(0xC1);
++                        v2 = Cpu::rdmsr(0xC2);
++                        v3 = Cpu::rdmsr(0xC3);
++                        v4 = Cpu::rdmsr(0xC4);
++                        utcb->values[0] = v1 & 0xFFFFFFFF;
++                        utcb->values[1] = (v1 >> 32) & 0xFFFFFFFF;
++                        utcb->values[2] = v2 & 0xFFFFFFFF;
++                        utcb->values[3] = (v2 >> 32) & 0xFFFFFFFF;
++                        utcb->values[4] = v3 & 0xFFFFFFFF;
++                        utcb->values[5] = (v3 >> 32) & 0xFFFFFFFF;
++                        utcb->values[6] = v4 & 0xFFFFFFFF;
++                        utcb->values[7] = (v4 >> 32) & 0xFFFFFFFF;
++                      }
++              }
+       // Respect the fact that the consumed time is only updated on context switch
+       if (this == current())
+         update_consumed_time();
index 640091b9be6e4f91675b5889124d32c49a42be4a..c3dfa4e2486417e23510e0c07cd15ae344751b74 100644 (file)
@@ -86,7 +86,7 @@ class App_model : public Ldr::Base_app_model<Romain::App_stack>
                                            unsigned flags, char const *what, l4_addr_t local_start = 0,
                                            bool shared = false);
                l4_addr_t    local_attach_ds(Const_dataspace ds, unsigned long size,
-                                            unsigned long offset) const;
+                                            unsigned long offset, l4_umword_t address_hint = 0) const;
                void         local_detach_ds(l4_addr_t addr, unsigned long /*size*/) const;
                int          prog_reserve_area(l4_addr_t *start, unsigned long size,
                                               unsigned flags, unsigned char align);
@@ -106,8 +106,8 @@ class App_model : public Ldr::Base_app_model<Romain::App_stack>
                void init_prog()
                {
                        push_trampoline();
-                       push_argv_strings();
                        push_env_strings();
+                       push_argv_strings();
                }
 
                static Dataspace local_kip_ds()
@@ -153,18 +153,29 @@ class App_model : public Ldr::Base_app_model<Romain::App_stack>
                        _trampoline_remote = (l4_addr_t)_stack.relocate(_stack.ptr());
                }
 
-               void push_env_strings() { /* nothing */ }
+               void push_env_strings()
+               {
+                       char **p = environ;
+                       while (*p) {
+                               printf("ENV: %s\n", *p);
+                               _remote_env[_env_count++] = _stack.push_str(*p, strlen(*p));
+                               p++;
+                       }
+               }
 
 
                void push_envp()
                {
                        _stack.push(0UL);
-                       _stack.push(0UL);
+                       for (unsigned i = 0; i < _env_count; ++i) {
+                               _stack.push_local_ptr(_remote_env[i]);
+                       }
                }
 
 
                void push_argv()
                {
+                       _stack.push(0UL);
                        for (unsigned i = _argc; i > 0; --i) {
                                _stack.push_local_ptr(_remote_argv[i-1]);
                        }
@@ -182,6 +193,8 @@ class App_model : public Ldr::Base_app_model<Romain::App_stack>
                unsigned         _argc;            // app argc
                char const     **_argv;            // app argv
                char const     *_remote_argv[32];  // XXX
+               char const     *_remote_env[32];   // XXX
+               unsigned         _env_count;       //
                Dataspace        _utcb_area;       // XXX: this is per thread!
 
                /*
@@ -201,7 +214,7 @@ class App_model : public Ldr::Base_app_model<Romain::App_stack>
        public:
                App_model(char const *filename, unsigned argc, char const **argv)
                        : _binary_ds(Romain::App_model::open_file(filename)),
-                         _argc(argc), _argv(argv),
+                         _argc(argc), _argv(argv), _env_count(0),
                      _trampoline_local(0), _trampoline_remote(0),
                      _lockinfo_local(0), _lockinfo_remote(0)
                {
@@ -214,6 +227,7 @@ class App_model : public Ldr::Base_app_model<Romain::App_stack>
                        prog_info()->kip            = 0xdeadbeef;
 
                        memset(_remote_argv, 0, sizeof(_remote_argv));
+                       memset(_remote_env, 0, sizeof(_remote_env));
                }
 
                Const_dataspace binary()      const { return _binary_ds; }
index 83b40dc4c943e48a871ba50f0b7ec66d1f0af189..0c232ed5543f375a405d8fa218e93779f092c1b4 100644 (file)
@@ -38,7 +38,8 @@ Romain::App_model::Const_dataspace Romain::App_model::open_file(char const *name
 
 l4_addr_t Romain::App_model::local_attach_ds(Romain::App_model::Const_dataspace ds,
                                              unsigned long size,
-                                             unsigned long offset) const
+                                             unsigned long offset,
+                                             l4_umword_t address_hint) const
 {
        Romain::Rm_guard r(rm(), 0); // we always init stuff for instance 0,
        // rest is paged in lazily
@@ -62,6 +63,9 @@ l4_addr_t Romain::App_model::local_attach_ds(Romain::App_model::Const_dataspace
        }
        Romain::Region_handler handler(ds, L4_INVALID_CAP, offset, 0,
                                    Romain::Region(0, 0));
+       if (address_hint != 0) {
+               handler.alignToAddressAndSize(address_hint, size);
+       }
        l4_addr_t ret = (l4_addr_t)rm()->attach_locally((void*)0, size, &handler, flags);
        return ret;
 }
@@ -97,7 +101,8 @@ Romain::App_model::Dataspace Romain::App_model::alloc_app_stack()
              << std::hex << (void*)_stack.ptr();
 #endif
        Romain::App_model::Dataspace ds = this->alloc_ds(_stack.stack_size());
-       char *addr = reinterpret_cast<char*>(this->local_attach_ds(ds, _stack.stack_size(), 0));
+       char *addr = reinterpret_cast<char*>(this->local_attach_ds(ds, _stack.stack_size(),
+                                                                                                                          0, _stack.target_addr()));
        MSG() << "attached app stack: " << (void*)addr;
        _local_stack_address = l4_addr_t(addr);
 
index e896277d4b5776460a43f9306d2d5c0095af52c9..8f6d91485a3d19ac967a029042397ffe42aa6157 100644 (file)
@@ -30,7 +30,7 @@ public:
         POWER     = 0x06,
         FLAGS     = 0x07,
         DCA       = 0x08,
-        PEMO      = 0x09,
+        PEMO      = 0x0A,
         TOPOLOGY  = 0x0B,
         XSTATE    = 0x0D,
     };
@@ -105,4 +105,4 @@ public:
         a = b = c = d = 0;
         return CPUID::cpuid(CPUID::MAXID, &a, &b, &c, &d);
     }
-};
\ No newline at end of file
+};
index 7cd2acad9fbf64cb4f4f6d713f5242961fb02562..e8ec015d862e9ee8d000d8ed5df37cd8a3133bb0 100644 (file)
@@ -104,7 +104,8 @@ namespace Romain
                /*******************************************
                 * Thread-related system calls
                 *******************************************/
-               void handle_task(Romain::App_instance*, Romain::App_thread*, Romain::App_model*);
+               Romain::Observer::ObserverReturnVal
+                       handle_task(Romain::App_instance*, Romain::App_thread*, Romain::App_model*);
        };
 
 
index 14d4798a3833ecab1ab424ec6957c1161fe93f85..b18df2cb79f4f46468225fc567b67d2f2a9e0ff1 100644 (file)
@@ -24,6 +24,7 @@
 
 #include <l4/sys/kdebug.h>
 #include <l4/util/bitops.h>
+#include <algorithm>
 
 extern l4_addr_t __libc_l4_gettime;
 
@@ -82,10 +83,8 @@ l4_umword_t Romain::PageFaultObserver::fit_alignment(Romain::Region const* local
                }
        }
 
-       return align;
-
-       /* XXX: Use this if you want to test the single-page-mapping version. */
-       //return L4_PAGESHIFT;
+       // XXX: tweak here if you want < 4MB mappings
+       return std::min(align, 22UL);
 }
 
 Romain::Observer::ObserverReturnVal
@@ -124,12 +123,7 @@ Romain::PageFaultObserver::notify(Romain::App_instance *i, Romain::App_thread *t
                /*
                 * Lazily establish region handlers for replicas
                 */
-               MSGt(t) << "[" << std::hex
-                       << n->second.local_region(i->id()).start() << " - "
-                       << n->second.local_region(i->id()).end() << "] ==> "
-                       << "[" << n->first.start() << " - "
-                       << n->first.end() << "]";
-               MSGt(t) << "   DS " << std::hex <<  n->second.memory(i->id()).cap();
+               MSGt(t) << Romain::Region_map::print_mapping(n, i->id());
 
                if (write_pf && (always_readonly() ||
                                (n->second.writable() == Romain::Region_handler::Read_only_emulate_write))) {
@@ -158,6 +152,7 @@ Romain::PageFaultObserver::notify(Romain::App_instance *i, Romain::App_thread *t
                        l4_addr_t offset_in_region          = l4_trunc_page(pfa - remote->start());
                        l4_addr_t remotebase                = remote->start() + offset_in_region;
                        unsigned pageflags                  = rh->is_ro() ? L4_FPAGE_RO : L4_FPAGE_RW;
+                       l4_umword_t last_align = 0;
 
                        for (l4_umword_t instID = 0;
                             instID < Romain::_the_instance_manager->instance_count();
@@ -166,6 +161,9 @@ Romain::PageFaultObserver::notify(Romain::App_instance *i, Romain::App_thread *t
                                a->rm()->lazy_map_region(n, instID, write_pf);
 
                                Romain::Region const * localregion  = &rh->local_region(instID);
+
+                               MSGt(t) << Romain::Region_map::print_mapping(n, instID);
+                               MSGt(t) << "rh.alignment() = " << std::dec << rh->alignment();
                                /*
                                 * We try to map the largest possible flexpage to reduce the
                                 * total number of mappings.
@@ -196,6 +194,16 @@ Romain::PageFaultObserver::notify(Romain::App_instance *i, Romain::App_thread *t
                                }
                                MSGt(t) << "fitting align " << align;
 
+                               if (instID > 0) {
+                                       if (align != last_align) {
+                                               ERROR() << "Mapping with diverging alignments!";
+                                               ERROR() << Romain::Region_map::print_mapping(n, instID);
+                                               ERROR() << "align: " << align << " but last was " << last_align;
+                                               enter_kdebug("Align!");
+                                       }
+                               }
+                               last_align = align;
+
                                /* Calculate the map base addresses for the given alignment */
                                l4_addr_t localbase = localregion->start() + offset_in_region;
                                localbase  = localbase  - (localbase  & ((1 << align) - 1));
index f871daaad964f39d7642433dbd44758c8e667fe7..9816ed0610f79ac1c785aa07fc9585a4d7ee92a2 100644 (file)
@@ -25,6 +25,11 @@ Romain::PrintVCPUStateObserver::notify(Romain::App_instance *,
                                        Romain::App_model *)
 {
        t->print_vcpu_state();
+       l4_utcb_t *utcb = reinterpret_cast<l4_utcb_t*>(t->remote_utcb());
+       l4_msg_regs_t *regs = l4_utcb_mr_u(utcb);
+       INFO() << "UTCB::MR " << std::hex << regs->mr[0] << " " << regs->mr[1] << " "
+              << regs->mr[2] << " " << regs->mr[3];
+       
        return Romain::Observer::Continue;
 }
 
index e59714175f413250440d748e595e854f08bbb3f7..5304e92cc6fa836e6f9decc2f7c617ef414e2cf1 100644 (file)
@@ -18,6 +18,7 @@
 
 #include "observers.h"
 
+#include <l4/re/rm-sys.h>
 #include <l4/re/util/region_mapping_svr>
 #include <l4/sys/segment.h>
 #include <l4/sys/consts.h>
@@ -118,8 +119,7 @@ Romain::SyscallObserver::notify(Romain::App_instance *i,
 
                        case L4_PROTO_TASK:
                                if ((t->vcpu()->r()->dx & ~0xF) == L4RE_THIS_TASK_CAP) {
-                                       handle_task(i, t, a);
-                                       retval = Romain::Observer::Finished;
+                                       retval = handle_task(i, t, a);
                                } else {
                                        nullhandler.proxy_syscall(i, t, tg, a);
                                        retval = Romain::Observer::Replicatable;
@@ -154,7 +154,8 @@ Romain::SyscallObserver::notify(Romain::App_instance *i,
 
                                        Romain::_the_instance_manager->show_stats();
                                        
-                                       if (1) enter_kdebug("*#^");
+                                       if (0) enter_kdebug("*#^");
+                                       else l4_sleep_forever();
 
                                        nullhandler.proxy_syscall(i, t, tg, a);
                                        retval = Romain::Observer::Replicatable;
@@ -184,7 +185,9 @@ Romain::SyscallObserver::notify(Romain::App_instance *i,
        } else if (t->vcpu()->r()->err == 0x152) { // INT $42
                INFO() << "[" << std::hex << (unsigned)t->vcpu() <<  "] INT 42 ("
                           << t->vcpu()->r()->ip << ")";
+               t->vcpu()->print_state();
                t->vcpu()->r()->ip += 2;
+               Romain::Log::logFlags = Romain::Log::All;
                retval = Romain::Observer::Replicatable;
        } else {
                t->vcpu()->print_state();
@@ -278,7 +281,7 @@ Romain::RegionManagingHandler::handle(Romain::App_instance* i,
 
 
 Romain::Observer::ObserverReturnVal
-Romain::ThreadHandler::handle(Romain::App_instance *,
+Romain::ThreadHandler::handle(Romain::App_instance *i,
                               Romain::App_thread* t,
                               Romain::Thread_group * tg,
                               Romain::App_model *am)
@@ -347,18 +350,25 @@ Romain::ThreadHandler::handle(Romain::App_instance *,
 }
 
 
-void Romain::SyscallObserver::handle_task(Romain::App_instance* i,
+Romain::Observer::ObserverReturnVal
+Romain::SyscallObserver::handle_task(Romain::App_instance* i,
                                           Romain::App_thread*   t,
                                           Romain::App_model*    a)
 {
        l4_utcb_t   *utcb = reinterpret_cast<l4_utcb_t*>(t->remote_utcb());
        l4_umword_t    op = l4_utcb_mr_u(utcb)->mr[0] & L4_THREAD_OPCODE_MASK;
+       Romain::Observer::ObserverReturnVal ret = Romain::Observer::Finished;
+
        switch(op) {
                case L4_TASK_UNMAP_OP:
-#if 0
-                       MSGt(t) << "unmap";
-                       i->unmap(l4_utcb_mr_u(utcb)->mr[2]);
-#endif
+                       {
+                               l4_fpage_t fp;
+                               fp.raw = l4_utcb_mr_u(utcb)->mr[2];
+                               MSGt(t) << "Task::unmap(p = " << std::hex
+                                       << l4_fpage_page(fp) << ", sz = " << l4_fpage_size(fp) << ")";
+                               i->vcpu_task()->unmap(fp, L4_FP_ALL_SPACES, utcb);
+                       }
+                       //t->vcpu()->r()->ax = 0;
                        break;
                case L4_TASK_CAP_INFO_OP:
                        nullhandler.proxy_syscall(i,t,0,a);
@@ -371,6 +381,8 @@ void Romain::SyscallObserver::handle_task(Romain::App_instance* i,
                        enter_kdebug("unknown task op?");
                        break;
        }
+
+       return ret;
 }
 
 
index c592fda762b110a2008edf029d245f37297f6543..89c387decc67a6b7f720293816ac37814cb6d1a7 100644 (file)
@@ -20,6 +20,7 @@
 
 #include <cstdlib>
 #include <vector>
+#include <sstream>
 
 #include <l4/re/env>
 #include <l4/sys/kip>
@@ -182,7 +183,7 @@ namespace Romain
                        {
                                for (unsigned i = 0; i < o.local_region_count(); ++i) {
                                        _local_regions[i] = o.local_region(i);
-                                       _mem[i]           = o.memory(i);
+                                       _mem[i]           = o.local_memory(i);
                                }
                        }
 
@@ -226,9 +227,10 @@ namespace Romain
                        }
 
                        //DS const &memory() const throw() { return _mem; }
-                       DS const &   memory(unsigned idx = 0) const throw() { return _mem[idx]; }
-                       void         memory(unsigned idx, DS const & m)     { _mem[idx] = m; }
+                       l4_cap_idx_t memory() const throw()                 { return _cap; }
                        l4_cap_idx_t client_cap_idx() const throw()         { return _cap; }
+                       DS const &   local_memory(unsigned idx) const throw()  { return _mem[idx]; }
+                       void         local_memory(unsigned idx, DS const & m)  { _mem[idx] = m; }
                        l4_addr_t    offset() const throw()                 { return _offs; }
                        void         offset(l4_addr_t o)                    { _offs = o; }
                        l4_addr_t    is_ro() const throw()                  { return _flags & L4Re::Rm::Read_only; }
@@ -399,7 +401,7 @@ namespace Romain
                                memcpy((void*)a, (void*)r.local_region(orig_id).start(), size);
 
                                r.set_local_region(inst_id, Romain::Region(a, a+size-1));
-                               r.memory(inst_id, mem);
+                               r.local_memory(inst_id, mem);
 
                                return true;
                        }
@@ -412,7 +414,7 @@ namespace Romain
                        allocate_ds(L4::Cap<L4Re::Dataspace> *cap, unsigned size)
                        {
                                unsigned long flags = 0;
-                               if (size >= L4_SUPERPAGESIZE) {
+                               if (size >= (L4_SUPERPAGESIZE >> 2)) { // use super pages from 1 MB...
                                        flags |= L4Re::Mem_alloc::Super_pages;
                                        flags |= L4Re::Mem_alloc::Continuous;
                                }
@@ -509,6 +511,29 @@ namespace Romain
                        void *attach(void* addr, unsigned long size, Romain::Region_handler const &hdlr,
                                     unsigned flags = None, unsigned char align=L4_PAGESHIFT, bool shared = false);
 
+                       l4_addr_t attach_area(l4_addr_t addr, unsigned long size, unsigned flags = None,
+                                             unsigned char align = L4_PAGESHIFT) throw()
+                       {
+                               DEBUG() << "attach_area(" << std::hex << addr << ", " << size << ", " << flags << ")";
+                               return Base::attach_area(addr, size, flags, align);
+                       }
+
+
+                       bool detach_area(l4_addr_t addr) throw()
+                       {
+                               DEBUG() << "detach_area(" << std::hex << addr << ")";
+                               return Base::detach_area(addr);
+                       }
+
+                       Base::Node find(Base::Key_type const& k) const throw()
+                       {
+                               Base::Node n = Base::find(k);
+                               DEBUG() << GREEN << "find(" << std::hex << k.start() << "): " << NOCOLOR
+                                       << "addr " << (n ? n->first.start() : 0xF00)
+                                       << " memcap " << (n ? n->second.client_cap_idx() : 0xF00);
+                               return n;
+                       }
+
                        int detach(void* addr, unsigned long size, unsigned flags,
                        L4Re::Util::Region* reg, Romain::Region_handler* h);
 
@@ -526,6 +551,19 @@ namespace Romain
                                        }
                                }
                        }
+
+
+                       static char const* print_mapping(Node n, l4_umword_t id)
+                       {
+                               std::stringstream s;
+                               s << "[" << std::hex << n->second.local_region(id).start()
+                                 << " - " << n->second.local_region(id).end() << "] ==> "
+                                 << "[" << n->first.start() << " - " << n->first.end() << "]";
+                               s << std::endl;
+                               s << "   DS " << std::hex <<  n->second.local_memory(id).cap();
+
+                               return s.str().c_str();
+                       }
        };
 
 
@@ -548,6 +586,7 @@ namespace Romain
                        }
 
 
-                       static l4_umword_t find_res(L4::Cap<void> const &ds) { return ds.cap(); }
+                       //static l4_umword_t find_res(L4::Cap<void> const &ds) { return ds.cap(); }
+                       static l4_umword_t find_res(l4_cap_idx_t cap) { return cap; }
        };
 }
index 01a89676fad4d13355ed4273254079a105732cab..eb79ed635da9a4aa3670ec0bf3f662e2de97efdc 100644 (file)
@@ -42,10 +42,16 @@ void Romain::Region_ops::unmap(Region_handler const *h, l4_addr_t vaddr,
 
 void Romain::Region_ops::free(Region_handler const *h, l4_addr_t start, unsigned long size)
 {
-       (void)h;
-       (void)start;
-       (void)size;
-       enter_kdebug("ops::free");
+       if ((h->flags() & L4Re::Rm::Reserved))
+               return;
+
+       if (h->flags() & L4Re::Rm::Pager)
+               return;
+
+       L4::Cap<L4Re::Dataspace> ds(h->client_cap_idx());
+       ds->clear(h->offset() + start, size);
+       
+       //enter_kdebug("ops::free");
 }
 
 
@@ -161,7 +167,7 @@ void *Romain::Region_map::attach_locally(void* addr, unsigned long size,
                                          unsigned flags, unsigned char align)
 {
        long r; (void)addr;
-       Romain::Region_handler::Dataspace const *ds = &hdlr->memory(0);
+       Romain::Region_handler::Dataspace const *ds = &hdlr->local_memory(0);
        L4Re::Dataspace::Stats dsstat;
        (*ds)->info(&dsstat);
 
@@ -246,7 +252,7 @@ void *Romain::Region_map::attach_locally(void* addr, unsigned long size,
                page_base = 0;
                /*
                 * XXX: If we copied the dataspace above, what happens to the
-                *      original DS that was passed in? Shoudln't it be released?
+                *      original DS that was passed in? Shouldn't it be released?
                 *
                 *      No. It might still be attached elsewhere. Perhaps decrement
                 *      some refcnt? XXX check
@@ -280,7 +286,8 @@ void *Romain::Region_map::attach(void* addr, unsigned long size,
 {
        void *ret = 0;
 
-       DEBUG() << std::hex << addr << " " << size << " " << (int)align;
+       MSG() << std::hex << addr << " " << size << " " << (int)align << " " << flags;
+       MSG() << "cap " << std::hex << hdlr.client_cap_idx();
 
        /*
         * XXX: the only reason for this Region_handler to exist is to copy
@@ -295,14 +302,25 @@ void *Romain::Region_map::attach(void* addr, unsigned long size,
         * the remote address and can then during local attaching make sure
         * that the memory alignment of the local mapping matches the remote
         * alignment. This allows us to play mapping tricks later.
+        * 
+        * Note, we can only do this if the Search_addr flag is set, otherwise
+        * we might hurt the client's expectations about the mem region.
         */
-       if ((size > L4_SUPERPAGESIZE) and (align < L4_LOG2_SUPERPAGESIZE)) {
+       if ((flags & L4Re::Rm::Search_addr) and 
+           !(flags & L4Re::Rm::In_area) and
+           (size > L4_SUPERPAGESIZE) and
+           (align < L4_LOG2_SUPERPAGESIZE)) {
                align = L4_LOG2_SUPERPAGESIZE;
                size  = l4_round_size(size, L4_SUPERPAGESHIFT);
        }
+       
 
        ret = Base::attach(addr, size, _handler, flags, align);
-       DEBUG() << "Base::attach = " << std::hex << ret;
+       MSG() << "Base::attach = " << std::hex << ret << " hdlr.offs: " << _handler.offset();
+       if (ret == (void*)~0UL) {
+               INFO() << std::hex << addr << " " << size << " " << (int)align << " " << flags;
+               enter_kdebug("Attach error");
+       }
 
        /*
         * The node is now present in the region map. This means we now need
@@ -338,17 +356,56 @@ void *Romain::Region_map::attach(void* addr, unsigned long size,
 
 
 
-#if 1
-int Romain::Region_map::detach(void* addr, unsigned long size, unsigned flags,
-                              L4Re::Util::Region* reg, Romain::Region_handler* h)
+int Romain::Region_map::detach(void* /* IN */ addr, unsigned long /* IN */ size,
+                               unsigned /* IN */ flags,
+                               L4Re::Util::Region* /* OUT */ reg,
+                               Romain::Region_handler* /* OUT */ h)
 {
-       MSG() << "addr " << std::hex << l4_addr_t(addr) << " " << size
-             << " " << flags;
-       MSG() << "active instance: " << _active_instance;
-       //enter_kdebug("detach");
-       return -1;
+       /* First, do a lookup for the handler, because Base::Detach() will not always
+        * return the handler node, but we need it for detach later.
+        */
+       l4_addr_t srch = (l4_addr_t)addr;
+       Romain::Region_handler hd = Base::find(Region(srch, srch + size - 1))->second;
+       MSG() << "Client cap: " << std::hex << hd.client_cap_idx();
+       if (hd.client_cap_idx() == L4_INVALID_CAP) {
+               enter_kdebug("invalid cap!");
+       }
+
+       MSG() << std::hex << "Base::detach(" << (l4_addr_t)addr << " " << size << " " << flags << ")";
+       MSG() << std::hex << find((l4_addr_t)addr)->second.client_cap_idx();
+       int ret = Base::detach(addr, size, flags, reg, h);
+       MSG() << std::hex << "Base::detach(): " << ret << " r.start: " << reg->start() << " " << reg->size();
+
+       /*
+        * Iterate over replicas and detach() the replicas' mappings within
+        * the master AS.
+        */
+       for (unsigned idx = 0; idx < hd.local_region_count(); ++idx) {
+               if (hd.local_region(idx).start() == 0) {
+                       continue;
+               }
+
+               MSG() << "[" << std::hex
+                         << hd.local_region(idx).start() << " - "
+                         << hd.local_region(idx).end() << "] ==> "
+                         << "[" << reg->start() << " - "
+                         << reg->end() << "]";
+
+               L4::Cap<L4Re::Dataspace> memcap;
+               int r = L4Re::Env::env()->rm()->detach(hd.local_region(idx).start(),
+                                                      hd.local_region(idx).size(),
+                                                                                          &memcap, L4Re::This_task);
+               MSG() << "detached locally: " << r << " cap: " << std::hex << memcap.cap();
+
+               if (!hd.writable()) {
+                       /* For read-only regions, we only need to detach once */
+                       break;
+               }
+       }
+
+       return ret;
 }
-#endif
+
 
 bool Romain::Region_map::lazy_map_region(Romain::Region_map::Base::Node &n, unsigned inst, bool iswritepf)
 {
@@ -356,10 +413,10 @@ bool Romain::Region_map::lazy_map_region(Romain::Region_map::Base::Node &n, unsi
        if (n->second.local_region(inst).start())
                return false;
 
-       DEBUGf(Romain::Log::Memory) << "start " <<  n->second.local_region(inst).start();
-       DEBUGf(Romain::Log::Memory) << "replica without yet established mapping.";
-       DEBUGf(Romain::Log::Memory) << "ro: " << n->second.is_ro();
-       DEBUGf(Romain::Log::Memory) << "shared: " << (n->second.shared() ? "true" : "false");
+       MSG() << "start " <<  n->second.local_region(inst).start();
+       MSG() << "replica without yet established mapping.";
+       MSG() << "ro: " << n->second.is_ro();
+       MSG() << "shared: " << (n->second.shared() ? "true" : "false");
 
        /*
         * As we found a node, we know there exists at least one replica
@@ -377,17 +434,17 @@ bool Romain::Region_map::lazy_map_region(Romain::Region_map::Base::Node &n, unsi
         * Case 1: region is read-only -> we share the mapping from
         *         the first node, because it was already established.
         */
-       
        if (n->second.is_ro() or rh->shared()) {
                /*
                 * XXX: Why is setting local_region and memory split up?
                 */
                rh->set_local_region(inst, n->second.local_region(existing));
-               rh->memory(inst, n->second.memory(existing));
+               rh->local_memory(inst, n->second.local_memory(existing));
        } else {
-                       DEBUGf(Romain::Log::Memory) << "Copying existing mapping.";
+                       MSG() << "Copying existing mapping.";
                        bool b = copy_existing_mapping(*rh, existing, inst, iswritepf);
                        _check(!b, "error creating rw copy");
        }
        return true;
 }
+
diff --git a/l4/pkg/plr/tools/Makefile b/l4/pkg/plr/tools/Makefile
new file mode 100644 (file)
index 0000000..c62713a
--- /dev/null
@@ -0,0 +1,6 @@
+PKGDIR ?= ..
+L4DIR  ?= $(PKGDIR)/../..
+
+TARGET = perfmon
+
+include $(L4DIR)/mk/subdir.mk
diff --git a/l4/pkg/plr/tools/perfmon/Makefile b/l4/pkg/plr/tools/perfmon/Makefile
new file mode 100644 (file)
index 0000000..db11755
--- /dev/null
@@ -0,0 +1,14 @@
+PKGDIR ?=      ../../..
+L4DIR ?=       $(PKGDIR)/..
+
+SYSTEMS = x86-l4f
+
+TARGET = perfmon_romain
+SRC_CC = main.cc
+
+REQUIRES_LIBS = libstdc++ libpcnt libpthread
+
+CXXFLAGS += -I$(SRC_DIR)/../../server/src/
+include $(L4DIR)/mk/prog.mk
+
+#LDFLAGS += -lpthread_rep -luc_c -levbuf_c
diff --git a/l4/pkg/plr/tools/perfmon/main.cc b/l4/pkg/plr/tools/perfmon/main.cc
new file mode 100644 (file)
index 0000000..936e9c1
--- /dev/null
@@ -0,0 +1,235 @@
+#include <l4/plr/perf.h>
+#include <l4/plr/cpuid.h>
+#include <l4/sys/debugger.h>
+#include <l4/sys/scheduler>
+#include <l4/sys/thread>
+#include <l4/re/error_helper>
+#include <l4/re/env>
+#include <l4/util/util.h>
+#include <l4/util/rdtsc.h>
+#include <pthread-l4.h>
+
+#include <cstdlib>
+#include <cstdio>
+#include <iostream>
+#include <vector>
+#include <algorithm>
+
+enum {
+       MAX_CPUS = 32
+};
+
+using L4Re::chksys;
+
+/*
+ * Map logical (=sequential) CPU numbers to the topology of the underlying
+ * platform.
+ *
+ * Background: Fiasco.OC uses sequential CPU numbers to assign threads to CPUs. These
+ *             numbers are assigned during bootup and their order depends on the order
+ *             in which booted CPUs come up. This means, assigning two threads to CPUs
+ *             0 and 1 can in one case mean that they are running on the same core in
+ *             different hyperthreads, while in the next run, they run on the different
+ *             physical CPUs (or even NUMA domains, if we had those).
+ *
+ *             The purpose of this map is to make the assignment less surprising, e.g.,
+ *             for the same platform, assigning to two specific CPU IDs should always
+ *             lead to the same performance.
+ */
+class LogicalCPUMap
+{
+       protected:
+       std::vector<CPU_id> _fiasco_cpus;
+       unsigned            _cpus;
+
+       static void* topology_scanner(void* data)
+       {
+               l4_debugger_set_object_name(pthread_getl4cap(pthread_self()), "romain::topscan");
+               LogicalCPUMap *m = reinterpret_cast<LogicalCPUMap*>(data);
+               L4::Cap<L4::Thread> thread(pthread_getl4cap(pthread_self()));
+
+               for (unsigned cpu = 0; cpu < m->num_cpus(); ++cpu) {
+                       l4_sched_param_t sp = l4_sched_param(2);
+                       sp.affinity = l4_sched_cpu_set(cpu, 0);
+                       chksys(L4Re::Env::env()->scheduler()->run_thread(thread, sp));
+
+                       m->_fiasco_cpus[cpu] = CPUID::current_apicid(cpu);
+               }
+               return 0;
+       }
+
+
+       void scan_topology()
+       {
+               /* Check if we can perform a topology query. */
+               if (CPUID::max_cpuid() < CPUID::TOPOLOGY) {
+                       std::cout << "CPU does not provide topology information\n";
+                       return;
+               }
+
+               pthread_t p;
+               int ret = pthread_create(&p, 0, LogicalCPUMap::topology_scanner, this);
+               if (ret != 0) {
+                       std::cout << "error creating topology scanner\n";
+                       exit(1);
+               }
+               ret = pthread_join(p, 0);
+
+               for (unsigned i = CPUID::num_cpus(); i < MAX_CPUS; ++i) {
+                       _fiasco_cpus[i].apic_id = 0xDEADBEEF;
+               }
+
+               std::cout << "Topology scan completed.\n";
+       }
+
+
+       void print_map()
+       {
+               std::cout << "Virtual to Fiasco CPU map\n";
+
+               for (unsigned i = 0; i < CPUID::num_cpus(); ++i) {
+                       std::cout << "virt# " << i << " fiasco# " << _fiasco_cpus[i].fiasco_id
+                                     << " apic# " << std::hex << _fiasco_cpus[i].apic_id << "\n";
+               }
+       }
+
+       public:
+               LogicalCPUMap(unsigned max = MAX_CPUS)
+                       : _fiasco_cpus(max), _cpus(max)
+               {
+                       /* Default: identity mapping if nothing else works */
+                       for (unsigned i = 0; i < MAX_CPUS; ++i) {
+                               _fiasco_cpus[i].fiasco_id = i;
+                               _fiasco_cpus[i].apic_id   = i;
+                       }
+
+                       if (CPUID::have_cpuid()) {
+                               _cpus = CPUID::num_cpus();
+                               scan_topology();
+                               std::sort(_fiasco_cpus.begin(), _fiasco_cpus.end(), CPU_id::comp_apic);
+                               print_map();
+                       }
+
+                       //enter_kdebug("cpu");
+
+               }
+
+               unsigned logicalToCPU(unsigned log) const
+               {
+                       std::cout << log << " -> " << _fiasco_cpus[log].fiasco_id << "\n";
+                       return _fiasco_cpus[log].fiasco_id;
+               }
+
+               unsigned num_cpus() const { return _cpus; }
+};
+
+
+class CounterLog
+{
+       struct perf_entry {
+               l4_uint64_t timestamp;
+               l4_uint64_t v1, v2, v3, v4;
+       };
+       
+       LogicalCPUMap const *map;
+
+       unsigned             entr;
+       perf_entry          *thelog;
+       unsigned             logIndex;
+
+       public:
+
+               LogicalCPUMap const * cpu_map() { return map; }
+               unsigned entries() { return entr; }
+
+               void loginit()
+               {
+                       L4::Cap<L4::Thread> thread(pthread_getl4cap(pthread_self()));
+
+                       /* #1: Setup counters. */
+                       for (unsigned cpu = 0; cpu < map->num_cpus(); ++cpu) {
+                               l4_sched_param_t sp = l4_sched_param(2);
+                               sp.affinity = l4_sched_cpu_set(cpu, 0);
+                               chksys(L4Re::Env::env()->scheduler()->run_thread(thread, sp));
+                               perfconf();
+                       }
+               }
+
+               void *logwork()
+               {
+                       L4::Cap<L4::Thread> thread(pthread_getl4cap(pthread_self()));
+                       /* #2 Counter read loop */
+                       for (unsigned cpu = 0; cpu < map->num_cpus(); ++cpu) {
+                               l4_sched_param_t sp = l4_sched_param(4);
+                               sp.affinity = l4_sched_cpu_set(cpu, 0);
+                               chksys(L4Re::Env::env()->scheduler()->run_thread(thread, sp));
+
+                               perf_entry *ent = &thelog[logIndex * map->num_cpus() + cpu];
+                               ent->timestamp = l4_rdtsc();
+                               perfread2(&ent->v1, &ent->v2, &ent->v3, &ent->v4);
+                       }
+
+                       ++logIndex;
+
+                       return 0;
+               }
+
+               CounterLog(LogicalCPUMap const *m, unsigned entries)
+                       : map(m), entr(entries), logIndex(0)
+               {
+                       thelog = new perf_entry[m->num_cpus() * entries];
+                       l4_touch_rw(thelog, m->num_cpus() * entries * sizeof(perf_entry));
+
+                       loginit();
+               }
+
+
+               void dump()
+               {
+                       for (unsigned i = 0; i < map->num_cpus(); ++i) {
+                               std::cout << "\033[33;1m======== CPU " << i << " =====\033[0m\n";
+                               l4_uint64_t tsc_base = thelog[i].timestamp;
+                               for (unsigned ent = 0; ent < entr; ++ent) {
+                                       perf_entry * e = &thelog[ent * map->num_cpus() + i];
+                                       printf("%016lld %16lld %16lld %16lld %16lld\n",
+                                              e->timestamp - tsc_base, e->v1, e->v2, e->v3, e->v4);
+                               }
+                       }
+               }
+};
+
+
+int main(int argc, char **argv)
+{
+       unsigned sleepInterval = 2000;
+       unsigned numEntries    = 200;
+       LogicalCPUMap *map;
+       CounterLog    *log;
+
+       std::cout << "===== Perf Mon ====\n";
+       l4_sleep(2000); // wait for bootup to complete (XXX)
+
+       if (argc > 1) {
+               numEntries = strtol(argv[1], 0, 10);
+       }
+
+       if (argc > 2) {
+               sleepInterval = strtol(argv[2], 0, 10) * 1000;
+       }
+
+       map = new LogicalCPUMap();
+       log = new CounterLog(map, numEntries);
+       std::cout << std::dec << "   Loops " << numEntries << ", interval "
+                 << sleepInterval << " ms. CPUs: " << map->num_cpus() << "\n";
+
+       for (unsigned i = 0; i < numEntries; ++i) {
+               log->logwork();
+               l4_sleep(sleepInterval);
+       }
+
+       std::cout << "\033[33;1mPerfmon done. Dump.\033[0m\n";
+
+       log->dump();
+
+       return 0;
+}
index dbcee742996178ccc719d8432c291af7460c6dd2..02b30c1f8aa29cf503c6194fef30be70358bad2b 100644 (file)
@@ -1,7 +1,7 @@
 
 
 The contrib directory contains the nearly unmodified contents of
-sqlite-autoconf-3071602.tar.gz
+sqlite-autoconf-3071700.tar.gz
 
-The current change is to undef HAVE_POSIX_FALLOCATE in case of uclibc
+The current modification is to undef HAVE_POSIX_FALLOCATE in case of uclibc
 because uclibc does not have it.
index 568b9b8cfadfee893b47b8a3d2f587b80df5a85a..f27217f98b544d49ed64a177ac9bcae593f4a32e 100755 (executable)
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for sqlite 3.7.16.2.
+# Generated by GNU Autoconf 2.69 for sqlite 3.7.17.
 #
 # Report bugs to <http://www.sqlite.org>.
 #
@@ -734,8 +734,8 @@ MAKEFLAGS=
 # Identity of this package.
 PACKAGE_NAME='sqlite'
 PACKAGE_TARNAME='sqlite'
-PACKAGE_VERSION='3.7.16.2'
-PACKAGE_STRING='sqlite 3.7.16.2'
+PACKAGE_VERSION='3.7.17'
+PACKAGE_STRING='sqlite 3.7.17'
 PACKAGE_BUGREPORT='http://www.sqlite.org'
 PACKAGE_URL=''
 
@@ -1455,7 +1455,7 @@ if test "$ac_init_help" = "long"; then
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures sqlite 3.7.16.2 to adapt to many kinds of systems.
+\`configure' configures sqlite 3.7.17 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1525,7 +1525,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of sqlite 3.7.16.2:";;
+     short | recursive ) echo "Configuration of sqlite 3.7.17:";;
    esac
   cat <<\_ACEOF
 
@@ -1635,7 +1635,7 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-sqlite configure 3.7.16.2
+sqlite configure 3.7.17
 generated by GNU Autoconf 2.69
 
 Copyright (C) 2012 Free Software Foundation, Inc.
@@ -2255,7 +2255,7 @@ cat >config.log <<_ACEOF
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by sqlite $as_me 3.7.16.2, which was
+It was created by sqlite $as_me 3.7.17, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   $ $0 $@
@@ -2924,7 +2924,7 @@ fi
 
 # Define the identity of the package.
  PACKAGE='sqlite'
- VERSION='3.7.16.2'
+ VERSION='3.7.17'
 
 
 cat >>confdefs.h <<_ACEOF
@@ -20493,7 +20493,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by sqlite $as_me 3.7.16.2, which was
+This file was extended by sqlite $as_me 3.7.17, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -20550,7 +20550,7 @@ _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
 ac_cs_version="\\
-sqlite config.status 3.7.16.2
+sqlite config.status 3.7.17
 configured by $0, generated by GNU Autoconf 2.69,
   with options \\"\$ac_cs_config\\"
 
index 9980d4edbf913b78cfe294713223acfa74a97a80..93ff04c151d71cf925ef32de1bb90311fd94c0d6 100644 (file)
@@ -8,7 +8,7 @@
 #
 
 AC_PREREQ(2.61)
-AC_INIT(sqlite, 3.7.16.2, http://www.sqlite.org)
+AC_INIT(sqlite, 3.7.17, http://www.sqlite.org)
 AC_CONFIG_SRCDIR([sqlite3.c])
 
 # Use automake.
index c6d7fa3d536605324a19a07ac8c9c08d8b356db0..1be2871fed9a1fdf1df7198e11253600ecba76cc 100644 (file)
@@ -1480,18 +1480,6 @@ static void open_db(struct callback_data *p){
     }
 #ifndef SQLITE_OMIT_LOAD_EXTENSION
     sqlite3_enable_load_extension(p->db, 1);
-#endif
-#ifdef SQLITE_ENABLE_REGEXP
-    {
-      extern int sqlite3_add_regexp_func(sqlite3*);
-      sqlite3_add_regexp_func(db);
-    }
-#endif
-#ifdef SQLITE_ENABLE_SPELLFIX
-    {
-      extern int sqlite3_spellfix1_register(sqlite3*);
-      sqlite3_spellfix1_register(db);
-    }
 #endif
   }
 }
@@ -1552,6 +1540,43 @@ static int booleanValue(char *zArg){
   return 0;
 }
 
+/*
+** Interpret zArg as an integer value, possibly with suffixes.
+*/
+static sqlite3_int64 integerValue(const char *zArg){
+  sqlite3_int64 v = 0;
+  static const struct { char *zSuffix; int iMult; } aMult[] = {
+    { "KiB", 1024 },
+    { "MiB", 1024*1024 },
+    { "GiB", 1024*1024*1024 },
+    { "KB",  1000 },
+    { "MB",  1000000 },
+    { "GB",  1000000000 },
+    { "K",   1000 },
+    { "M",   1000000 },
+    { "G",   1000000000 },
+  };
+  int i;
+  int isNeg = 0;
+  if( zArg[0]=='-' ){
+    isNeg = 1;
+    zArg++;
+  }else if( zArg[0]=='+' ){
+    zArg++;
+  }
+  while( isdigit(zArg[0]) ){
+    v = v*10 + zArg[0] - '0';
+    zArg++;
+  }
+  for(i=0; i<sizeof(aMult)/sizeof(aMult[0]); i++){
+    if( sqlite3_stricmp(aMult[i].zSuffix, zArg)==0 ){
+      v *= aMult[i].iMult;
+      break;
+    }
+  }
+  return isNeg? -v : v;
+}
+
 /*
 ** Close an output file, assuming it is not stderr or stdout
 */
@@ -2253,8 +2278,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
           "   SELECT sql, type, tbl_name, name, rowid FROM sqlite_temp_master) "
           "WHERE lower(tbl_name) LIKE shellstatic()"
           "  AND type!='meta' AND sql NOTNULL "
-          "ORDER BY substr(type,2,1), "
-                  " CASE type WHEN 'view' THEN rowid ELSE name END",
+          "ORDER BY rowid",
           callback, &data, &zErrMsg);
         zShellStatic = 0;
       }
@@ -2265,8 +2289,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
          "     FROM sqlite_master UNION ALL"
          "   SELECT sql, type, tbl_name, name, rowid FROM sqlite_temp_master) "
          "WHERE type!='meta' AND sql NOTNULL AND name NOT LIKE 'sqlite_%'"
-         "ORDER BY substr(type,2,1),"
-                  " CASE type WHEN 'view' THEN rowid ELSE name END",
+         "ORDER BY rowid",
          callback, &data, &zErrMsg
       );
     }
@@ -2388,9 +2411,9 @@ static int do_meta_command(char *zLine, struct callback_data *p){
       for(i=0; i<nPrintRow; i++){
         for(j=i; j<nRow; j+=nPrintRow){
           char *zSp = j<nPrintRow ? "" : "  ";
-          printf("%s%-*s", zSp, maxlen, azResult[j] ? azResult[j] : "");
+          fprintf(p->out, "%s%-*s", zSp, maxlen, azResult[j] ? azResult[j] : "");
         }
-        printf("\n");
+        fprintf(p->out, "\n");
       }
     }
     for(ii=0; ii<nRow; ii++) sqlite3_free(azResult[ii]);
@@ -2447,7 +2470,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
           if( nArg==3 ){
             int opt = (int)strtol(azArg[2], 0, 0);        
             rc = sqlite3_test_control(testctrl, p->db, opt);
-            printf("%d (0x%08x)\n", rc, rc);
+            fprintf(p->out, "%d (0x%08x)\n", rc, rc);
           } else {
             fprintf(stderr,"Error: testctrl %s takes a single int option\n",
                     azArg[1]);
@@ -2460,7 +2483,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
         case SQLITE_TESTCTRL_PRNG_RESET:
           if( nArg==2 ){
             rc = sqlite3_test_control(testctrl);
-            printf("%d (0x%08x)\n", rc, rc);
+            fprintf(p->out, "%d (0x%08x)\n", rc, rc);
           } else {
             fprintf(stderr,"Error: testctrl %s takes no options\n", azArg[1]);
           }
@@ -2469,9 +2492,9 @@ static int do_meta_command(char *zLine, struct callback_data *p){
         /* sqlite3_test_control(int, uint) */
         case SQLITE_TESTCTRL_PENDING_BYTE:        
           if( nArg==3 ){
-            unsigned int opt = (unsigned int)atoi(azArg[2]);        
+            unsigned int opt = (unsigned int)integerValue(azArg[2]);        
             rc = sqlite3_test_control(testctrl, opt);
-            printf("%d (0x%08x)\n", rc, rc);
+            fprintf(p->out, "%d (0x%08x)\n", rc, rc);
           } else {
             fprintf(stderr,"Error: testctrl %s takes a single unsigned"
                            " int option\n", azArg[1]);
@@ -2484,7 +2507,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
           if( nArg==3 ){
             int opt = atoi(azArg[2]);        
             rc = sqlite3_test_control(testctrl, opt);
-            printf("%d (0x%08x)\n", rc, rc);
+            fprintf(p->out, "%d (0x%08x)\n", rc, rc);
           } else {
             fprintf(stderr,"Error: testctrl %s takes a single int option\n",
                             azArg[1]);
@@ -2497,7 +2520,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
           if( nArg==3 ){
             const char *opt = azArg[2];        
             rc = sqlite3_test_control(testctrl, opt);
-            printf("%d (0x%08x)\n", rc, rc);
+            fprintf(p->out, "%d (0x%08x)\n", rc, rc);
           } else {
             fprintf(stderr,"Error: testctrl %s takes a single char * option\n",
                             azArg[1]);
@@ -2542,7 +2565,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
   }else
 
   if( c=='v' && strncmp(azArg[0], "version", n)==0 ){
-    printf("SQLite %s %s\n" /*extra-version-info*/,
+    fprintf(p->out, "SQLite %s %s\n" /*extra-version-info*/,
         sqlite3_libversion(), sqlite3_sourceid());
   }else
 
@@ -2552,7 +2575,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
     if( p->db ){
       sqlite3_file_control(p->db, zDbName, SQLITE_FCNTL_VFSNAME, &zVfsName);
       if( zVfsName ){
-        printf("%s\n", zVfsName);
+        fprintf(p->out, "%s\n", zVfsName);
         sqlite3_free(zVfsName);
       }
     }
@@ -2561,7 +2584,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
 #if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_WHERETRACE)
   if( c=='w' && strncmp(azArg[0], "wheretrace", n)==0 ){
     extern int sqlite3WhereTrace;
-    sqlite3WhereTrace = atoi(azArg[1]);
+    sqlite3WhereTrace = booleanValue(azArg[1]);
   }else
 #endif
 
@@ -2747,6 +2770,10 @@ static int process_input(struct callback_data *p, FILE *in){
       free(zSql);
       zSql = 0;
       nSql = 0;
+    }else if( zSql && _all_whitespace(zSql) ){
+      free(zSql);
+      zSql = 0;
+      nSql = 0;
     }
   }
   if( zSql ){
@@ -2882,6 +2909,7 @@ static const char zOptions[] =
   "   -interactive         force interactive I/O\n"
   "   -line                set output mode to 'line'\n"
   "   -list                set output mode to 'list'\n"
+  "   -mmap N              default mmap size set to N\n"
 #ifdef SQLITE_ENABLE_MULTIPLEX
   "   -multiplex           enable the multiplexor VFS\n"
 #endif
@@ -3001,12 +3029,7 @@ int main(int argc, char **argv){
       sqlite3_int64 szHeap;
 
       zSize = cmdline_option_value(argc, argv, ++i);
-      szHeap = atoi(zSize);
-      for(j=0; (c = zSize[j])!=0; j++){
-        if( c=='M' ){ szHeap *= 1000000; break; }
-        if( c=='K' ){ szHeap *= 1000; break; }
-        if( c=='G' ){ szHeap *= 1000000000; break; }
-      }
+      szHeap = integerValue(zSize);
       if( szHeap>0x7fff0000 ) szHeap = 0x7fff0000;
       sqlite3_config(SQLITE_CONFIG_HEAP, malloc((int)szHeap), (int)szHeap, 64);
 #endif
@@ -3026,6 +3049,9 @@ int main(int argc, char **argv){
       extern int sqlite3_multiple_initialize(const char*,int);
       sqlite3_multiplex_initialize(0, 1);
 #endif
+    }else if( strcmp(z,"-mmap")==0 ){
+      sqlite3_int64 sz = integerValue(cmdline_option_value(argc,argv,++i));
+      sqlite3_config(SQLITE_CONFIG_MMAP_SIZE, sz, sz);
     }else if( strcmp(z,"-vfs")==0 ){
       sqlite3_vfs *pVfs = sqlite3_vfs_find(cmdline_option_value(argc,argv,++i));
       if( pVfs ){
@@ -3111,6 +3137,8 @@ int main(int argc, char **argv){
       stdin_is_interactive = 0;
     }else if( strcmp(z,"-heap")==0 ){
       i++;
+    }else if( strcmp(z,"-mmap")==0 ){
+      i++;
     }else if( strcmp(z,"-vfs")==0 ){
       i++;
 #ifdef SQLITE_ENABLE_VFSTRACE
@@ -3128,7 +3156,7 @@ int main(int argc, char **argv){
       z = cmdline_option_value(argc,argv,++i);
       if( z[0]=='.' ){
         rc = do_meta_command(z, &data);
-        if( rc && bail_on_error ) return rc;
+        if( rc && bail_on_error ) return rc==2 ? 0 : rc;
       }else{
         open_db(&data);
         rc = shell_exec(data.db, z, shell_callback, &data, &zErrMsg);
@@ -3152,6 +3180,7 @@ int main(int argc, char **argv){
     */
     if( zFirstCmd[0]=='.' ){
       rc = do_meta_command(zFirstCmd, &data);
+      if( rc==2 ) rc = 0;
     }else{
       open_db(&data);
       rc = shell_exec(data.db, zFirstCmd, shell_callback, &data, &zErrMsg);
index ca12d7e0a25851aa93bbb72b7c26bc4833f16469..42d330811ee2fb02d67eff3e3a3520b0c45fd916 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
 ** This file is an amalgamation of many separate C source files from SQLite
-** version 3.7.16.2.  By combining all the individual C code files into this 
+** version 3.7.17.  By combining all the individual C code files into this 
 ** single large file, the entire code can be compiled as a single translation
 ** unit.  This allows many compilers to do optimizations that would not be
 ** possible if the files were compiled separately.  Performance improvements
 ** We support that for legacy.
 */
 #if !defined(SQLITE_THREADSAFE)
-#if defined(THREADSAFE)
-# define SQLITE_THREADSAFE THREADSAFE
-#else
-# define SQLITE_THREADSAFE 1 /* IMP: R-07272-22309 */
-#endif
+# if defined(THREADSAFE)
+#   define SQLITE_THREADSAFE THREADSAFE
+# else
+#   define SQLITE_THREADSAFE 1 /* IMP: R-07272-22309 */
+# endif
 #endif
 
 /*
@@ -678,9 +678,9 @@ extern "C" {
 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
 ** [sqlite_version()] and [sqlite_source_id()].
 */
-#define SQLITE_VERSION        "3.7.16.2"
-#define SQLITE_VERSION_NUMBER 3007016
-#define SQLITE_SOURCE_ID      "2013-04-12 11:52:43 cbea02d93865ce0e06789db95fd9168ebac970c7"
+#define SQLITE_VERSION        "3.7.17"
+#define SQLITE_VERSION_NUMBER 3007017
+#define SQLITE_SOURCE_ID      "2013-05-20 00:56:22 118a3b35693b134d56ebd780123b7fd6f1497668"
 
 /*
 ** CAPI3REF: Run-Time Library Version Numbers
@@ -996,6 +996,8 @@ SQLITE_API int sqlite3_exec(
 #define SQLITE_FORMAT      24   /* Auxiliary database format error */
 #define SQLITE_RANGE       25   /* 2nd parameter to sqlite3_bind out of range */
 #define SQLITE_NOTADB      26   /* File opened that is not a database file */
+#define SQLITE_NOTICE      27   /* Notifications from sqlite3_log() */
+#define SQLITE_WARNING     28   /* Warnings from sqlite3_log() */
 #define SQLITE_ROW         100  /* sqlite3_step() has another row ready */
 #define SQLITE_DONE        101  /* sqlite3_step() has finished executing */
 /* end-of-error-codes */
@@ -1046,6 +1048,7 @@ SQLITE_API int sqlite3_exec(
 #define SQLITE_IOERR_SHMMAP            (SQLITE_IOERR | (21<<8))
 #define SQLITE_IOERR_SEEK              (SQLITE_IOERR | (22<<8))
 #define SQLITE_IOERR_DELETE_NOENT      (SQLITE_IOERR | (23<<8))
+#define SQLITE_IOERR_MMAP              (SQLITE_IOERR | (24<<8))
 #define SQLITE_LOCKED_SHAREDCACHE      (SQLITE_LOCKED |  (1<<8))
 #define SQLITE_BUSY_RECOVERY           (SQLITE_BUSY   |  (1<<8))
 #define SQLITE_CANTOPEN_NOTEMPDIR      (SQLITE_CANTOPEN | (1<<8))
@@ -1065,6 +1068,8 @@ SQLITE_API int sqlite3_exec(
 #define SQLITE_CONSTRAINT_TRIGGER      (SQLITE_CONSTRAINT | (7<<8))
 #define SQLITE_CONSTRAINT_UNIQUE       (SQLITE_CONSTRAINT | (8<<8))
 #define SQLITE_CONSTRAINT_VTAB         (SQLITE_CONSTRAINT | (9<<8))
+#define SQLITE_NOTICE_RECOVER_WAL      (SQLITE_NOTICE | (1<<8))
+#define SQLITE_NOTICE_RECOVER_ROLLBACK (SQLITE_NOTICE | (2<<8))
 
 /*
 ** CAPI3REF: Flags For File Open Operations
@@ -1304,6 +1309,9 @@ struct sqlite3_io_methods {
   void (*xShmBarrier)(sqlite3_file*);
   int (*xShmUnmap)(sqlite3_file*, int deleteFlag);
   /* Methods above are valid for version 2 */
+  int (*xFetch)(sqlite3_file*, sqlite3_int64 iOfst, int iAmt, void **pp);
+  int (*xUnfetch)(sqlite3_file*, sqlite3_int64 iOfst, void *p);
+  /* Methods above are valid for version 3 */
   /* Additional methods may be added in future releases */
 };
 
@@ -1440,7 +1448,8 @@ struct sqlite3_io_methods {
 ** it is able to override built-in [PRAGMA] statements.
 **
 ** <li>[[SQLITE_FCNTL_BUSYHANDLER]]
-** ^This file-control may be invoked by SQLite on the database file handle
+** ^The [SQLITE_FCNTL_BUSYHANDLER]
+** file-control may be invoked by SQLite on the database file handle
 ** shortly after it is opened in order to provide a custom VFS with access
 ** to the connections busy-handler callback. The argument is of type (void **)
 ** - an array of two (void *) values. The first (void *) actually points
@@ -1451,13 +1460,24 @@ struct sqlite3_io_methods {
 ** current operation.
 **
 ** <li>[[SQLITE_FCNTL_TEMPFILENAME]]
-** ^Application can invoke this file-control to have SQLite generate a
+** ^Application can invoke the [SQLITE_FCNTL_TEMPFILENAME] file-control
+** to have SQLite generate a
 ** temporary filename using the same algorithm that is followed to generate
 ** temporary filenames for TEMP tables and other internal uses.  The
 ** argument should be a char** which will be filled with the filename
 ** written into memory obtained from [sqlite3_malloc()].  The caller should
 ** invoke [sqlite3_free()] on the result to avoid a memory leak.
 **
+** <li>[[SQLITE_FCNTL_MMAP_SIZE]]
+** The [SQLITE_FCNTL_MMAP_SIZE] file control is used to query or set the
+** maximum number of bytes that will be used for memory-mapped I/O.
+** The argument is a pointer to a value of type sqlite3_int64 that
+** is an advisory maximum number of bytes in the file to memory map.  The
+** pointer is overwritten with the old value.  The limit is not changed if
+** the value originally pointed to is negative, and so the current limit 
+** can be queried by passing in a pointer to a negative number.  This
+** file-control is used internally to implement [PRAGMA mmap_size].
+**
 ** </ul>
 */
 #define SQLITE_FCNTL_LOCKSTATE               1
@@ -1476,6 +1496,7 @@ struct sqlite3_io_methods {
 #define SQLITE_FCNTL_PRAGMA                 14
 #define SQLITE_FCNTL_BUSYHANDLER            15
 #define SQLITE_FCNTL_TEMPFILENAME           16
+#define SQLITE_FCNTL_MMAP_SIZE              18
 
 /*
 ** CAPI3REF: Mutex Handle
@@ -2142,7 +2163,9 @@ struct sqlite3_mem_methods {
 ** page cache implementation into that object.)^ </dd>
 **
 ** [[SQLITE_CONFIG_LOG]] <dt>SQLITE_CONFIG_LOG</dt>
-** <dd> ^The SQLITE_CONFIG_LOG option takes two arguments: a pointer to a
+** <dd> The SQLITE_CONFIG_LOG option is used to configure the SQLite
+** global [error log].
+** (^The SQLITE_CONFIG_LOG option takes two arguments: a pointer to a
 ** function with a call signature of void(*)(void*,int,const char*), 
 ** and a pointer to void. ^If the function pointer is not NULL, it is
 ** invoked by [sqlite3_log()] to process each logging event.  ^If the
@@ -2188,12 +2211,12 @@ struct sqlite3_mem_methods {
 ** <dt>SQLITE_CONFIG_PCACHE and SQLITE_CONFIG_GETPCACHE
 ** <dd> These options are obsolete and should not be used by new code.
 ** They are retained for backwards compatibility but are now no-ops.
-** </dl>
+** </dd>
 **
 ** [[SQLITE_CONFIG_SQLLOG]]
 ** <dt>SQLITE_CONFIG_SQLLOG
 ** <dd>This option is only available if sqlite is compiled with the
-** SQLITE_ENABLE_SQLLOG pre-processor macro defined. The first argument should
+** [SQLITE_ENABLE_SQLLOG] pre-processor macro defined. The first argument should
 ** be a pointer to a function of type void(*)(void*,sqlite3*,const char*, int).
 ** The second should be of type (void*). The callback is invoked by the library
 ** in three separate circumstances, identified by the value passed as the
@@ -2203,7 +2226,23 @@ struct sqlite3_mem_methods {
 ** fourth parameter is 1, then the SQL statement that the third parameter
 ** points to has just been executed. Or, if the fourth parameter is 2, then
 ** the connection being passed as the second parameter is being closed. The
-** third parameter is passed NULL In this case.
+** third parameter is passed NULL In this case.  An example of using this
+** configuration option can be seen in the "test_sqllog.c" source file in
+** the canonical SQLite source tree.</dd>
+**
+** [[SQLITE_CONFIG_MMAP_SIZE]]
+** <dt>SQLITE_CONFIG_MMAP_SIZE
+** <dd>SQLITE_CONFIG_MMAP_SIZE takes two 64-bit integer (sqlite3_int64) values
+** that are the default mmap size limit (the default setting for
+** [PRAGMA mmap_size]) and the maximum allowed mmap size limit.
+** The default setting can be overridden by each database connection using
+** either the [PRAGMA mmap_size] command, or by using the
+** [SQLITE_FCNTL_MMAP_SIZE] file control.  The maximum allowed mmap size
+** cannot be changed at run-time.  Nor may the maximum allowed mmap size
+** exceed the compile-time maximum mmap size set by the
+** [SQLITE_MAX_MMAP_SIZE] compile-time option.  
+** If either argument to this option is negative, then that argument is
+** changed to its compile-time default.
 ** </dl>
 */
 #define SQLITE_CONFIG_SINGLETHREAD  1  /* nil */
@@ -2227,6 +2266,7 @@ struct sqlite3_mem_methods {
 #define SQLITE_CONFIG_GETPCACHE2   19  /* sqlite3_pcache_methods2* */
 #define SQLITE_CONFIG_COVERING_INDEX_SCAN 20  /* int */
 #define SQLITE_CONFIG_SQLLOG       21  /* xSqllog, void* */
+#define SQLITE_CONFIG_MMAP_SIZE    22  /* sqlite3_int64, sqlite3_int64 */
 
 /*
 ** CAPI3REF: Database Connection Configuration Options
@@ -3060,6 +3100,9 @@ SQLITE_API int sqlite3_set_authorizer(
 ** as each triggered subprogram is entered.  The callbacks for triggers
 ** contain a UTF-8 SQL comment that identifies the trigger.)^
 **
+** The [SQLITE_TRACE_SIZE_LIMIT] compile-time option can be used to limit
+** the length of [bound parameter] expansion in the output of sqlite3_trace().
+**
 ** ^The callback function registered by sqlite3_profile() is invoked
 ** as each SQL statement finishes.  ^The profile callback contains
 ** the original statement text and an estimate of wall-clock time
@@ -3598,7 +3641,8 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
 ** <li>
 ** ^If the database schema changes, instead of returning [SQLITE_SCHEMA] as it
 ** always used to do, [sqlite3_step()] will automatically recompile the SQL
-** statement and try to run it again.
+** statement and try to run it again. As many as [SQLITE_MAX_SCHEMA_RETRY]
+** retries will occur before sqlite3_step() gives up and returns an error.
 ** </li>
 **
 ** <li>
@@ -3802,6 +3846,9 @@ typedef struct sqlite3_context sqlite3_context;
 ** parameter [SQLITE_LIMIT_VARIABLE_NUMBER] (default value: 999).
 **
 ** ^The third argument is the value to bind to the parameter.
+** ^If the third parameter to sqlite3_bind_text() or sqlite3_bind_text16()
+** or sqlite3_bind_blob() is a NULL pointer then the fourth parameter
+** is ignored and the end result is the same as sqlite3_bind_null().
 **
 ** ^(In those routines that have a fourth argument, its value is the
 ** number of bytes in the parameter.  To be clear: the value is the
@@ -4758,7 +4805,7 @@ SQLITE_API void sqlite3_set_auxdata(sqlite3_context*, int N, void*, void (*)(voi
 ** the content before returning.
 **
 ** The typedef is necessary to work around problems in certain
-** C++ compilers.  See ticket #2191.
+** C++ compilers.
 */
 typedef void (*sqlite3_destructor_type)(void*);
 #define SQLITE_STATIC      ((sqlite3_destructor_type)0)
@@ -5557,11 +5604,20 @@ SQLITE_API int sqlite3_table_column_metadata(
 ** ^This interface loads an SQLite extension library from the named file.
 **
 ** ^The sqlite3_load_extension() interface attempts to load an
-** SQLite extension library contained in the file zFile.
+** [SQLite extension] library contained in the file zFile.  If
+** the file cannot be loaded directly, attempts are made to load
+** with various operating-system specific extensions added.
+** So for example, if "samplelib" cannot be loaded, then names like
+** "samplelib.so" or "samplelib.dylib" or "samplelib.dll" might
+** be tried also.
 **
 ** ^The entry point is zProc.
-** ^zProc may be 0, in which case the name of the entry point
-** defaults to "sqlite3_extension_init".
+** ^(zProc may be 0, in which case SQLite will try to come up with an
+** entry point name on its own.  It first tries "sqlite3_extension_init".
+** If that does not work, it constructs a name "sqlite3_X_init" where the
+** X is consists of the lower-case equivalent of all ASCII alphabetic
+** characters in the filename from the last "/" to the first following
+** "." and omitting any initial "lib".)^
 ** ^The sqlite3_load_extension() interface returns
 ** [SQLITE_OK] on success and [SQLITE_ERROR] if something goes wrong.
 ** ^If an error occurs and pzErrMsg is not 0, then the
@@ -5587,11 +5643,11 @@ SQLITE_API int sqlite3_load_extension(
 ** CAPI3REF: Enable Or Disable Extension Loading
 **
 ** ^So as not to open security holes in older applications that are
-** unprepared to deal with extension loading, and as a means of disabling
-** extension loading while evaluating user-entered SQL, the following API
+** unprepared to deal with [extension loading], and as a means of disabling
+** [extension loading] while evaluating user-entered SQL, the following API
 ** is provided to turn the [sqlite3_load_extension()] mechanism on and off.
 **
-** ^Extension loading is off by default. See ticket #1863.
+** ^Extension loading is off by default.
 ** ^Call the sqlite3_enable_load_extension() routine with onoff==1
 ** to turn extension loading on and call it with onoff==0 to turn
 ** it back off again.
@@ -5603,7 +5659,7 @@ SQLITE_API int sqlite3_enable_load_extension(sqlite3 *db, int onoff);
 **
 ** ^This interface causes the xEntryPoint() function to be invoked for
 ** each new [database connection] that is created.  The idea here is that
-** xEntryPoint() is the entry point for a statically linked SQLite extension
+** xEntryPoint() is the entry point for a statically linked [SQLite extension]
 ** that is to be automatically loaded into all new database connections.
 **
 ** ^(Even though the function prototype shows that xEntryPoint() takes
@@ -7383,10 +7439,25 @@ SQLITE_API int sqlite3_unlock_notify(
 SQLITE_API int sqlite3_stricmp(const char *, const char *);
 SQLITE_API int sqlite3_strnicmp(const char *, const char *, int);
 
+/*
+** CAPI3REF: String Globbing
+*
+** ^The [sqlite3_strglob(P,X)] interface returns zero if string X matches
+** the glob pattern P, and it returns non-zero if string X does not match
+** the glob pattern P.  ^The definition of glob pattern matching used in
+** [sqlite3_strglob(P,X)] is the same as for the "X GLOB P" operator in the
+** SQL dialect used by SQLite.  ^The sqlite3_strglob(P,X) function is case
+** sensitive.
+**
+** Note that this routine returns zero on a match and non-zero if the strings
+** do not match, the same as [sqlite3_stricmp()] and [sqlite3_strnicmp()].
+*/
+SQLITE_API int sqlite3_strglob(const char *zGlob, const char *zStr);
+
 /*
 ** CAPI3REF: Error Logging Interface
 **
-** ^The [sqlite3_log()] interface writes a message into the error log
+** ^The [sqlite3_log()] interface writes a message into the [error log]
 ** established by the [SQLITE_CONFIG_LOG] option to [sqlite3_config()].
 ** ^If logging is enabled, the zFormat string and subsequent arguments are
 ** used with [sqlite3_snprintf()] to generate the final output string.
@@ -8071,6 +8142,7 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*);
 */
 #ifndef SQLITE_TEMP_STORE
 # define SQLITE_TEMP_STORE 1
+# define SQLITE_TEMP_STORE_xc 1  /* Exclude from ctime.c */
 #endif
 
 /*
@@ -8218,6 +8290,49 @@ SQLITE_PRIVATE const int sqlite3one;
 # define EIGHT_BYTE_ALIGNMENT(X)   ((((char*)(X) - (char*)0)&7)==0)
 #endif
 
+/*
+** Disable MMAP on platforms where it is known to not work
+*/
+#if defined(__OpenBSD__) || defined(__QNXNTO__)
+# undef SQLITE_MAX_MMAP_SIZE
+# define SQLITE_MAX_MMAP_SIZE 0
+#endif
+
+/*
+** Default maximum size of memory used by memory-mapped I/O in the VFS
+*/
+#ifdef __APPLE__
+# include <TargetConditionals.h>
+# if TARGET_OS_IPHONE
+#   undef SQLITE_MAX_MMAP_SIZE
+#   define SQLITE_MAX_MMAP_SIZE 0
+# endif
+#endif
+#ifndef SQLITE_MAX_MMAP_SIZE
+# if defined(__linux__) \
+  || defined(_WIN32) \
+  || (defined(__APPLE__) && defined(__MACH__)) \
+  || defined(__sun)
+#   define SQLITE_MAX_MMAP_SIZE 0x7fff0000  /* 2147418112 */
+# else
+#   define SQLITE_MAX_MMAP_SIZE 0
+# endif
+# define SQLITE_MAX_MMAP_SIZE_xc 1 /* exclude from ctime.c */
+#endif
+
+/*
+** The default MMAP_SIZE is zero on all platforms.  Or, even if a larger
+** default MMAP_SIZE is specified at compile-time, make sure that it does
+** not exceed the maximum mmap size.
+*/
+#ifndef SQLITE_DEFAULT_MMAP_SIZE
+# define SQLITE_DEFAULT_MMAP_SIZE 0
+# define SQLITE_DEFAULT_MMAP_SIZE_xc 1  /* Exclude from ctime.c */
+#endif
+#if SQLITE_DEFAULT_MMAP_SIZE>SQLITE_MAX_MMAP_SIZE
+# undef SQLITE_DEFAULT_MMAP_SIZE
+# define SQLITE_DEFAULT_MMAP_SIZE SQLITE_MAX_MMAP_SIZE
+#endif
 
 /*
 ** An instance of the following structure is used to store the busy-handler
@@ -8439,6 +8554,7 @@ SQLITE_PRIVATE int sqlite3BtreeOpen(
 
 SQLITE_PRIVATE int sqlite3BtreeClose(Btree*);
 SQLITE_PRIVATE int sqlite3BtreeSetCacheSize(Btree*,int);
+SQLITE_PRIVATE int sqlite3BtreeSetMmapLimit(Btree*,sqlite3_int64);
 SQLITE_PRIVATE int sqlite3BtreeSetSafetyLevel(Btree*,int,int,int);
 SQLITE_PRIVATE int sqlite3BtreeSyncDisabled(Btree*);
 SQLITE_PRIVATE int sqlite3BtreeSetPageSize(Btree *p, int nPagesize, int nReserve, int eFix);
@@ -8515,6 +8631,7 @@ SQLITE_PRIVATE int sqlite3BtreeNewDb(Btree *p);
 #define BTREE_TEXT_ENCODING       5
 #define BTREE_USER_VERSION        6
 #define BTREE_INCR_VACUUM         7
+#define BTREE_APPLICATION_ID      8
 
 /*
 ** Values that may be OR'd together to form the second argument of an
@@ -9139,6 +9256,12 @@ typedef struct PgHdr DbPage;
 #define PAGER_JOURNALMODE_MEMORY      4   /* In-memory journal file */
 #define PAGER_JOURNALMODE_WAL         5   /* Use write-ahead logging */
 
+/*
+** Flags that make up the mask passed to sqlite3PagerAcquire().
+*/
+#define PAGER_ACQUIRE_NOCONTENT     0x01  /* Do not load data from disk */
+#define PAGER_ACQUIRE_READONLY      0x02  /* Read-only page is acceptable */
+
 /*
 ** The remainder of this file contains the declarations of the functions
 ** that make up the Pager sub-system API. See source code comments for 
@@ -9163,6 +9286,7 @@ SQLITE_PRIVATE void sqlite3PagerSetBusyhandler(Pager*, int(*)(void *), void *);
 SQLITE_PRIVATE int sqlite3PagerSetPagesize(Pager*, u32*, int);
 SQLITE_PRIVATE int sqlite3PagerMaxPageCount(Pager*, int);
 SQLITE_PRIVATE void sqlite3PagerSetCachesize(Pager*, int);
+SQLITE_PRIVATE void sqlite3PagerSetMmapLimit(Pager *, sqlite3_int64);
 SQLITE_PRIVATE void sqlite3PagerShrink(Pager*);
 SQLITE_PRIVATE void sqlite3PagerSetSafetyLevel(Pager*,int,int,int);
 SQLITE_PRIVATE int sqlite3PagerLockingMode(Pager *, int);
@@ -9309,6 +9433,8 @@ struct PgHdr {
 #define PGHDR_REUSE_UNLIKELY    0x010  /* A hint that reuse is unlikely */
 #define PGHDR_DONT_WRITE        0x020  /* Do not write content to disk */
 
+#define PGHDR_MMAP              0x040  /* This is an mmap page object */
+
 /* Initialize and shutdown the page cache subsystem */
 SQLITE_PRIVATE int sqlite3PcacheInitialize(void);
 SQLITE_PRIVATE void sqlite3PcacheShutdown(void);
@@ -9520,14 +9646,6 @@ SQLITE_PRIVATE void sqlite3PCacheSetDefault(void);
 # define SQLITE_OS_WINRT 0
 #endif
 
-/*
-** When compiled for WinCE or WinRT, there is no concept of the current
-** directory.
- */
-#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT
-# define SQLITE_CURDIR 1
-#endif
-
 /* If the SET_FULLSYNC macro is not defined above, then make it
 ** a no-op
 */
@@ -9680,6 +9798,8 @@ SQLITE_PRIVATE int sqlite3OsShmMap(sqlite3_file *,int,int,int,void volatile **);
 SQLITE_PRIVATE int sqlite3OsShmLock(sqlite3_file *id, int, int, int);
 SQLITE_PRIVATE void sqlite3OsShmBarrier(sqlite3_file *id);
 SQLITE_PRIVATE int sqlite3OsShmUnmap(sqlite3_file *id, int);
+SQLITE_PRIVATE int sqlite3OsFetch(sqlite3_file *id, i64, int, void **);
+SQLITE_PRIVATE int sqlite3OsUnfetch(sqlite3_file *, i64, void *);
 
 
 /* 
@@ -9919,6 +10039,7 @@ struct sqlite3 {
   int nDb;                      /* Number of backends currently in use */
   int flags;                    /* Miscellaneous flags. See below */
   i64 lastRowid;                /* ROWID of most recent insert (see above) */
+  i64 szMmap;                   /* Default mmap_size setting */
   unsigned int openFlags;       /* Flags passed to sqlite3_vfs.xOpen() */
   int errCode;                  /* Most recent error code (SQLITE_*) */
   int errMask;                  /* & result codes with this before returning */
@@ -11155,6 +11276,8 @@ struct NameContext {
 #define NC_HasAgg    0x02    /* One or more aggregate functions seen */
 #define NC_IsCheck   0x04    /* True if resolving names in a CHECK constraint */
 #define NC_InAggFunc 0x08    /* True if analyzing arguments to an agg func */
+#define NC_AsMaybe   0x10    /* Resolve to AS terms of the result set only
+                             ** if no other resolution is available */
 
 /*
 ** An instance of the following structure contains all information
@@ -11590,6 +11713,8 @@ struct Sqlite3Config {
   void *pHeap;                      /* Heap storage space */
   int nHeap;                        /* Size of pHeap[] */
   int mnReq, mxReq;                 /* Min and max heap requests sizes */
+  sqlite3_int64 szMmap;             /* mmap() space per open file */
+  sqlite3_int64 mxMmap;             /* Maximum value for szMmap */
   void *pScratch;                   /* Scratch memory */
   int szScratch;                    /* Size of each scratch buffer */
   int nScratch;                     /* Number of scratch buffers */
@@ -11624,6 +11749,7 @@ struct Walker {
   int (*xSelectCallback)(Walker*,Select*);  /* Callback for SELECTs */
   Parse *pParse;                            /* Parser context.  */
   int walkerDepth;                          /* Number of subqueries */
+  u8 bSelectDepthFirst;                     /* Do subqueries first */
   union {                                   /* Extra data for callback */
     NameContext *pNC;                          /* Naming context */
     int i;                                     /* Integer value */
@@ -12127,6 +12253,12 @@ SQLITE_PRIVATE void sqlite3Error(sqlite3*, int, const char*,...);
 SQLITE_PRIVATE void *sqlite3HexToBlob(sqlite3*, const char *z, int n);
 SQLITE_PRIVATE u8 sqlite3HexToInt(int h);
 SQLITE_PRIVATE int sqlite3TwoPartName(Parse *, Token *, Token *, Token **);
+
+#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) || \
+    defined(SQLITE_DEBUG_OS_TRACE)
+SQLITE_PRIVATE const char *sqlite3ErrName(int);
+#endif
+
 SQLITE_PRIVATE const char *sqlite3ErrStr(int);
 SQLITE_PRIVATE int sqlite3ReadSchema(Parse *pParse);
 SQLITE_PRIVATE CollSeq *sqlite3FindCollSeq(sqlite3*,u8 enc, const char*,int);
@@ -12611,6 +12743,8 @@ SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config = {
    (void*)0,                  /* pHeap */
    0,                         /* nHeap */
    0, 0,                      /* mnHeap, mxHeap */
+   SQLITE_DEFAULT_MMAP_SIZE,  /* szMmap */
+   SQLITE_MAX_MMAP_SIZE,      /* mxMmap */
    (void*)0,                  /* pScratch */
    0,                         /* szScratch */
    0,                         /* nScratch */
@@ -12734,15 +12868,15 @@ static const char * const azCompileOpt[] = {
 #ifdef SQLITE_COVERAGE_TEST
   "COVERAGE_TEST",
 #endif
-#ifdef SQLITE_CURDIR
-  "CURDIR",
-#endif
 #ifdef SQLITE_DEBUG
   "DEBUG",
 #endif
 #ifdef SQLITE_DEFAULT_LOCKING_MODE
   "DEFAULT_LOCKING_MODE=" CTIMEOPT_VAL(SQLITE_DEFAULT_LOCKING_MODE),
 #endif
+#if defined(SQLITE_DEFAULT_MMAP_SIZE) && !defined(SQLITE_DEFAULT_MMAP_SIZE_xc)
+  "DEFAULT_MMAP_SIZE=" CTIMEOPT_VAL(SQLITE_DEFAULT_MMAP_SIZE),
+#endif
 #ifdef SQLITE_DISABLE_DIRSYNC
   "DISABLE_DIRSYNC",
 #endif
@@ -12833,6 +12967,9 @@ static const char * const azCompileOpt[] = {
 #ifdef SQLITE_LOCK_TRACE
   "LOCK_TRACE",
 #endif
+#if defined(SQLITE_MAX_MMAP_SIZE) && !defined(SQLITE_MAX_MMAP_SIZE_xc)
+  "MAX_MMAP_SIZE=" CTIMEOPT_VAL(SQLITE_MAX_MMAP_SIZE),
+#endif
 #ifdef SQLITE_MAX_SCHEMA_RETRY
   "MAX_SCHEMA_RETRY=" CTIMEOPT_VAL(SQLITE_MAX_SCHEMA_RETRY),
 #endif
@@ -12890,11 +13027,6 @@ static const char * const azCompileOpt[] = {
 #ifdef SQLITE_OMIT_CHECK
   "OMIT_CHECK",
 #endif
-/* // redundant
-** #ifdef SQLITE_OMIT_COMPILEOPTION_DIAGS
-**   "OMIT_COMPILEOPTION_DIAGS",
-** #endif
-*/
 #ifdef SQLITE_OMIT_COMPLETE
   "OMIT_COMPLETE",
 #endif
@@ -13036,13 +13168,13 @@ static const char * const azCompileOpt[] = {
 #ifdef SQLITE_TCL
   "TCL",
 #endif
-#ifdef SQLITE_TEMP_STORE
+#if defined(SQLITE_TEMP_STORE) && !defined(SQLITE_TEMP_STORE_xc)
   "TEMP_STORE=" CTIMEOPT_VAL(SQLITE_TEMP_STORE),
 #endif
 #ifdef SQLITE_TEST
   "TEST",
 #endif
-#ifdef SQLITE_THREADSAFE
+#if defined(SQLITE_THREADSAFE)
   "THREADSAFE=" CTIMEOPT_VAL(SQLITE_THREADSAFE),
 #endif
 #ifdef SQLITE_USE_ALLOCA
@@ -13068,8 +13200,11 @@ SQLITE_API int sqlite3_compileoption_used(const char *zOptName){
   /* Since ArraySize(azCompileOpt) is normally in single digits, a
   ** linear search is adequate.  No need for a binary search. */
   for(i=0; i<ArraySize(azCompileOpt); i++){
-    if(   (sqlite3StrNICmp(zOptName, azCompileOpt[i], n)==0)
-       && ( (azCompileOpt[i][n]==0) || (azCompileOpt[i][n]=='=') ) ) return 1;
+    if( sqlite3StrNICmp(zOptName, azCompileOpt[i], n)==0
+     && sqlite3CtypeMap[(unsigned char)azCompileOpt[i][n]]==0
+    ){
+      return 1;
+    }
   }
   return 0;
 }
@@ -13126,6 +13261,14 @@ SQLITE_API const char *sqlite3_compileoption_get(int N){
 #ifndef _VDBEINT_H_
 #define _VDBEINT_H_
 
+/*
+** The maximum number of times that a statement will try to reparse
+** itself before giving up and returning SQLITE_SCHEMA.
+*/
+#ifndef SQLITE_MAX_SCHEMA_RETRY
+# define SQLITE_MAX_SCHEMA_RETRY 50
+#endif
+
 /*
 ** SQL is translated into a sequence of instructions to be
 ** executed by a virtual machine.  Each instruction is an instance
@@ -15092,6 +15235,26 @@ SQLITE_PRIVATE int sqlite3OsShmMap(
   return id->pMethods->xShmMap(id, iPage, pgsz, bExtend, pp);
 }
 
+#if SQLITE_MAX_MMAP_SIZE>0
+/* The real implementation of xFetch and xUnfetch */
+SQLITE_PRIVATE int sqlite3OsFetch(sqlite3_file *id, i64 iOff, int iAmt, void **pp){
+  DO_OS_MALLOC_TEST(id);
+  return id->pMethods->xFetch(id, iOff, iAmt, pp);
+}
+SQLITE_PRIVATE int sqlite3OsUnfetch(sqlite3_file *id, i64 iOff, void *p){
+  return id->pMethods->xUnfetch(id, iOff, p);
+}
+#else
+/* No-op stubs to use when memory-mapped I/O is disabled */
+SQLITE_PRIVATE int sqlite3OsFetch(sqlite3_file *id, i64 iOff, int iAmt, void **pp){
+  *pp = 0;
+  return SQLITE_OK;
+}
+SQLITE_PRIVATE int sqlite3OsUnfetch(sqlite3_file *id, i64 iOff, void *p){
+  return SQLITE_OK;
+}
+#endif
+
 /*
 ** The next group of routines are convenience wrappers around the
 ** VFS methods.
@@ -22852,7 +23015,7 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){
 /* #include <time.h> */
 #include <sys/time.h>
 #include <errno.h>
-#ifndef SQLITE_OMIT_WAL
+#if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0
 #include <sys/mman.h>
 #endif
 
@@ -22951,6 +23114,11 @@ struct unixFile {
   const char *zPath;                  /* Name of the file */
   unixShm *pShm;                      /* Shared memory segment information */
   int szChunk;                        /* Configured by FCNTL_CHUNK_SIZE */
+  int nFetchOut;                      /* Number of outstanding xFetch refs */
+  sqlite3_int64 mmapSize;             /* Usable size of mapping at pMapRegion */
+  sqlite3_int64 mmapSizeActual;       /* Actual size of mapping at pMapRegion */
+  sqlite3_int64 mmapSizeMax;          /* Configured FCNTL_MMAP_SIZE value */
+  void *pMapRegion;                   /* Memory mapped region */
 #ifdef __QNXNTO__
   int sectorSize;                     /* Device sector size */
   int deviceCharacteristics;          /* Precomputed device characteristics */
@@ -22975,7 +23143,9 @@ struct unixFile {
   unsigned char transCntrChng;   /* True if the transaction counter changed */
   unsigned char dbUpdate;        /* True if any part of database file changed */
   unsigned char inNormalWrite;   /* True if in a normal write operation */
+
 #endif
+
 #ifdef SQLITE_TEST
   /* In test mode, increase the size of this structure a bit so that 
   ** it is larger than the struct CrashFile defined in test6.c.
@@ -22999,6 +23169,7 @@ struct unixFile {
 #define UNIXFILE_DELETE      0x20     /* Delete on close */
 #define UNIXFILE_URI         0x40     /* Filename might have query parameters */
 #define UNIXFILE_NOLOCK      0x80     /* Do no file locking */
+#define UNIXFILE_WARNED    0x0100     /* verifyDbFile() warnings have been issued */
 
 /*
 ** Include code that is common to all os_*.c files
@@ -23240,6 +23411,17 @@ SQLITE_API int sqlite3_open_file_count = 0;
 #define threadid 0
 #endif
 
+/*
+** HAVE_MREMAP defaults to true on Linux and false everywhere else.
+*/
+#if !defined(HAVE_MREMAP)
+# if defined(__linux__) && defined(_GNU_SOURCE)
+#  define HAVE_MREMAP 1
+# else
+#  define HAVE_MREMAP 0
+# endif
+#endif
+
 /*
 ** Different Unix systems declare open() in different ways.  Same use
 ** open(const char*,int,mode_t).  Others use open(const char*,int,...).
@@ -23371,6 +23553,19 @@ static struct unix_syscall {
   { "fchown",       (sqlite3_syscall_ptr)posixFchown,     0 },
 #define osFchown    ((int(*)(int,uid_t,gid_t))aSyscall[20].pCurrent)
 
+  { "mmap",       (sqlite3_syscall_ptr)mmap,     0 },
+#define osMmap ((void*(*)(void*,size_t,int,int,int,off_t))aSyscall[21].pCurrent)
+
+  { "munmap",       (sqlite3_syscall_ptr)munmap,          0 },
+#define osMunmap ((void*(*)(void*,size_t))aSyscall[22].pCurrent)
+
+#if HAVE_MREMAP
+  { "mremap",       (sqlite3_syscall_ptr)mremap,          0 },
+#else
+  { "mremap",       (sqlite3_syscall_ptr)0,               0 },
+#endif
+#define osMremap ((void*(*)(void*,size_t,size_t,int,...))aSyscall[23].pCurrent)
+
 }; /* End of the overrideable system calls */
 
 /*
@@ -23702,7 +23897,6 @@ static int sqliteErrorFromPosixError(int posixError, int sqliteIOErr) {
 }
 
 
-
 /******************************************************************************
 ****************** Begin Unique File ID Utility Used By VxWorks ***************
 **
@@ -24038,7 +24232,6 @@ static int unixLogErrorAtLine(
   zErr = strerror(iErrno);
 #endif
 
-  assert( errcode!=SQLITE_OK );
   if( zPath==0 ) zPath = "";
   sqlite3_log(errcode,
       "os_unix.c:%d: (%d) %s(%s) - %s",
@@ -24204,6 +24397,50 @@ static int findInodeInfo(
 }
 
 
+/*
+** Check a unixFile that is a database.  Verify the following:
+**
+** (1) There is exactly one hard link on the file
+** (2) The file is not a symbolic link
+** (3) The file has not been renamed or unlinked
+**
+** Issue sqlite3_log(SQLITE_WARNING,...) messages if anything is not right.
+*/
+static void verifyDbFile(unixFile *pFile){
+  struct stat buf;
+  int rc;
+  if( pFile->ctrlFlags & UNIXFILE_WARNED ){
+    /* One or more of the following warnings have already been issued.  Do not
+    ** repeat them so as not to clutter the error log */
+    return;
+  }
+  rc = osFstat(pFile->h, &buf);
+  if( rc!=0 ){
+    sqlite3_log(SQLITE_WARNING, "cannot fstat db file %s", pFile->zPath);
+    pFile->ctrlFlags |= UNIXFILE_WARNED;
+    return;
+  }
+  if( buf.st_nlink==0 && (pFile->ctrlFlags & UNIXFILE_DELETE)==0 ){
+    sqlite3_log(SQLITE_WARNING, "file unlinked while open: %s", pFile->zPath);
+    pFile->ctrlFlags |= UNIXFILE_WARNED;
+    return;
+  }
+  if( buf.st_nlink>1 ){
+    sqlite3_log(SQLITE_WARNING, "multiple links to file: %s", pFile->zPath);
+    pFile->ctrlFlags |= UNIXFILE_WARNED;
+    return;
+  }
+  if( pFile->pInode!=0
+   && ((rc = osStat(pFile->zPath, &buf))!=0
+       || buf.st_ino!=pFile->pInode->fileId.ino)
+  ){
+    sqlite3_log(SQLITE_WARNING, "file renamed while open: %s", pFile->zPath);
+    pFile->ctrlFlags |= UNIXFILE_WARNED;
+    return;
+  }
+}
+
+
 /*
 ** This routine checks if there is a RESERVED lock held on the specified
 ** file by this or any other process. If such a lock is held, set *pResOut
@@ -24734,9 +24971,13 @@ end_unlock:
 ** the requested locking level, this routine is a no-op.
 */
 static int unixUnlock(sqlite3_file *id, int eFileLock){
+  assert( eFileLock==SHARED_LOCK || ((unixFile *)id)->nFetchOut==0 );
   return posixUnlock(id, eFileLock, 0);
 }
 
+static int unixMapfile(unixFile *pFd, i64 nByte);
+static void unixUnmapfile(unixFile *pFd);
+
 /*
 ** This function performs the parts of the "close file" operation 
 ** common to all locking schemes. It closes the directory and file
@@ -24749,6 +24990,7 @@ static int unixUnlock(sqlite3_file *id, int eFileLock){
 */
 static int closeUnixFile(sqlite3_file *id){
   unixFile *pFile = (unixFile*)id;
+  unixUnmapfile(pFile);
   if( pFile->h>=0 ){
     robust_close(pFile, pFile->h, __LINE__);
     pFile->h = -1;
@@ -24775,6 +25017,7 @@ static int closeUnixFile(sqlite3_file *id){
 static int unixClose(sqlite3_file *id){
   int rc = SQLITE_OK;
   unixFile *pFile = (unixFile *)id;
+  verifyDbFile(pFile);
   unixUnlock(id, NO_LOCK);
   unixEnterMutex();
 
@@ -26006,6 +26249,8 @@ static int unixRead(
   unixFile *pFile = (unixFile *)id;
   int got;
   assert( id );
+  assert( offset>=0 );
+  assert( amt>0 );
 
   /* If this is a database file (not a journal, master-journal or temp
   ** file), the bytes in the locking range should never be read or written. */
@@ -26016,6 +26261,23 @@ static int unixRead(
   );
 #endif
 
+#if SQLITE_MAX_MMAP_SIZE>0
+  /* Deal with as much of this read request as possible by transfering
+  ** data from the memory mapping using memcpy().  */
+  if( offset<pFile->mmapSize ){
+    if( offset+amt <= pFile->mmapSize ){
+      memcpy(pBuf, &((u8 *)(pFile->pMapRegion))[offset], amt);
+      return SQLITE_OK;
+    }else{
+      int nCopy = pFile->mmapSize - offset;
+      memcpy(pBuf, &((u8 *)(pFile->pMapRegion))[offset], nCopy);
+      pBuf = &((u8 *)pBuf)[nCopy];
+      amt -= nCopy;
+      offset += nCopy;
+    }
+  }
+#endif
+
   got = seekAndRead(pFile, offset, pBuf, amt);
   if( got==amt ){
     return SQLITE_OK;
@@ -26031,46 +26293,59 @@ static int unixRead(
 }
 
 /*
-** Seek to the offset in id->offset then read cnt bytes into pBuf.
-** Return the number of bytes actually read.  Update the offset.
-**
-** To avoid stomping the errno value on a failed write the lastErrno value
-** is set before returning.
+** Attempt to seek the file-descriptor passed as the first argument to
+** absolute offset iOff, then attempt to write nBuf bytes of data from
+** pBuf to it. If an error occurs, return -1 and set *piErrno. Otherwise, 
+** return the actual number of bytes written (which may be less than
+** nBuf).
 */
-static int seekAndWrite(unixFile *id, i64 offset, const void *pBuf, int cnt){
-  int got;
-#if (!defined(USE_PREAD) && !defined(USE_PREAD64))
-  i64 newOffset;
-#endif
-  assert( cnt==(cnt&0x1ffff) );
-  cnt &= 0x1ffff;
+static int seekAndWriteFd(
+  int fd,                         /* File descriptor to write to */
+  i64 iOff,                       /* File offset to begin writing at */
+  const void *pBuf,               /* Copy data from this buffer to the file */
+  int nBuf,                       /* Size of buffer pBuf in bytes */
+  int *piErrno                    /* OUT: Error number if error occurs */
+){
+  int rc = 0;                     /* Value returned by system call */
+
+  assert( nBuf==(nBuf&0x1ffff) );
+  nBuf &= 0x1ffff;
   TIMER_START;
+
 #if defined(USE_PREAD)
-  do{ got = osPwrite(id->h, pBuf, cnt, offset); }while( got<0 && errno==EINTR );
+  do{ rc = osPwrite(fd, pBuf, nBuf, iOff); }while( rc<0 && errno==EINTR );
 #elif defined(USE_PREAD64)
-  do{ got = osPwrite64(id->h, pBuf, cnt, offset);}while( got<0 && errno==EINTR);
+  do{ rc = osPwrite64(fd, pBuf, nBuf, iOff);}while( rc<0 && errno==EINTR);
 #else
   do{
-    newOffset = lseek(id->h, offset, SEEK_SET);
-    SimulateIOError( newOffset-- );
-    if( newOffset!=offset ){
-      if( newOffset == -1 ){
-        ((unixFile*)id)->lastErrno = errno;
-      }else{
-        ((unixFile*)id)->lastErrno = 0;
-      }
+    i64 iSeek = lseek(fd, iOff, SEEK_SET);
+    SimulateIOError( iSeek-- );
+
+    if( iSeek!=iOff ){
+      if( piErrno ) *piErrno = (iSeek==-1 ? errno : 0);
       return -1;
     }
-    got = osWrite(id->h, pBuf, cnt);
-  }while( got<0 && errno==EINTR );
+    rc = osWrite(fd, pBuf, nBuf);
+  }while( rc<0 && errno==EINTR );
 #endif
+
   TIMER_END;
-  if( got<0 ){
-    ((unixFile*)id)->lastErrno = errno;
-  }
+  OSTRACE(("WRITE   %-3d %5d %7lld %llu\n", fd, rc, iOff, TIMER_ELAPSED));
 
-  OSTRACE(("WRITE   %-3d %5d %7lld %llu\n", id->h, got, offset, TIMER_ELAPSED));
-  return got;
+  if( rc<0 && piErrno ) *piErrno = errno;
+  return rc;
+}
+
+
+/*
+** Seek to the offset in id->offset then read cnt bytes into pBuf.
+** Return the number of bytes actually read.  Update the offset.
+**
+** To avoid stomping the errno value on a failed write the lastErrno value
+** is set before returning.
+*/
+static int seekAndWrite(unixFile *id, i64 offset, const void *pBuf, int cnt){
+  return seekAndWriteFd(id->h, offset, pBuf, cnt, &id->lastErrno);
 }
 
 
@@ -26120,6 +26395,23 @@ static int unixWrite(
   }
 #endif
 
+#if SQLITE_MAX_MMAP_SIZE>0
+  /* Deal with as much of this write request as possible by transfering
+  ** data from the memory mapping using memcpy().  */
+  if( offset<pFile->mmapSize ){
+    if( offset+amt <= pFile->mmapSize ){
+      memcpy(&((u8 *)(pFile->pMapRegion))[offset], pBuf, amt);
+      return SQLITE_OK;
+    }else{
+      int nCopy = pFile->mmapSize - offset;
+      memcpy(&((u8 *)(pFile->pMapRegion))[offset], pBuf, nCopy);
+      pBuf = &((u8 *)pBuf)[nCopy];
+      amt -= nCopy;
+      offset += nCopy;
+    }
+  }
+#endif
+
   while( amt>0 && (wrote = seekAndWrite(pFile, offset, pBuf, amt))>0 ){
     amt -= wrote;
     offset += wrote;
@@ -26402,6 +26694,14 @@ static int unixTruncate(sqlite3_file *id, i64 nByte){
     }
 #endif
 
+    /* If the file was just truncated to a size smaller than the currently
+    ** mapped region, reduce the effective mapping size as well. SQLite will
+    ** use read() and write() to access data beyond this point from now on.  
+    */
+    if( nByte<pFile->mmapSize ){
+      pFile->mmapSize = nByte;
+    }
+
     return SQLITE_OK;
   }
 }
@@ -26490,6 +26790,19 @@ static int fcntlSizeHint(unixFile *pFile, i64 nByte){
     }
   }
 
+  if( pFile->mmapSizeMax>0 && nByte>pFile->mmapSize ){
+    int rc;
+    if( pFile->szChunk<=0 ){
+      if( robust_ftruncate(pFile->h, nByte) ){
+        pFile->lastErrno = errno;
+        return unixLogError(SQLITE_IOERR_TRUNCATE, "ftruncate", pFile->zPath);
+      }
+    }
+
+    rc = unixMapfile(pFile, nByte);
+    return rc;
+  }
+
   return SQLITE_OK;
 }
 
@@ -26557,6 +26870,18 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){
       }
       return SQLITE_OK;
     }
+    case SQLITE_FCNTL_MMAP_SIZE: {
+      i64 newLimit = *(i64*)pArg;
+      if( newLimit>sqlite3GlobalConfig.mxMmap ){
+        newLimit = sqlite3GlobalConfig.mxMmap;
+      }
+      *(i64*)pArg = pFile->mmapSizeMax;
+      if( newLimit>=0 ){
+        pFile->mmapSizeMax = newLimit;
+        if( newLimit<pFile->mmapSize ) pFile->mmapSize = newLimit;
+      }
+      return SQLITE_OK;
+    }
 #ifdef SQLITE_DEBUG
     /* The pager calls this method to signal that it has done
     ** a rollback and that the database is therefore unchanged and
@@ -26869,7 +27194,7 @@ static void unixShmPurge(unixFile *pFd){
     sqlite3_mutex_free(p->mutex);
     for(i=0; i<p->nRegion; i++){
       if( p->h>=0 ){
-        munmap(p->apRegion[i], p->szRegion);
+        osMunmap(p->apRegion[i], p->szRegion);
       }else{
         sqlite3_free(p->apRegion[i]);
       }
@@ -27109,24 +27434,32 @@ static int unixShmMap(
       if( sStat.st_size<nByte ){
         /* The requested memory region does not exist. If bExtend is set to
         ** false, exit early. *pp will be set to NULL and SQLITE_OK returned.
-        **
-        ** Alternatively, if bExtend is true, use ftruncate() to allocate
-        ** the requested memory region.
         */
-        if( !bExtend ) goto shmpage_out;
-#if defined(HAVE_POSIX_FALLOCATE) && HAVE_POSIX_FALLOCATE
-        if( osFallocate(pShmNode->h, sStat.st_size, nByte)!=0 ){
-          rc = unixLogError(SQLITE_IOERR_SHMSIZE, "fallocate",
-                            pShmNode->zFilename);
+        if( !bExtend ){
           goto shmpage_out;
         }
-#else
-        if( robust_ftruncate(pShmNode->h, nByte) ){
-          rc = unixLogError(SQLITE_IOERR_SHMSIZE, "ftruncate",
-                            pShmNode->zFilename);
-          goto shmpage_out;
+
+        /* Alternatively, if bExtend is true, extend the file. Do this by
+        ** writing a single byte to the end of each (OS) page being
+        ** allocated or extended. Technically, we need only write to the
+        ** last page in order to extend the file. But writing to all new
+        ** pages forces the OS to allocate them immediately, which reduces
+        ** the chances of SIGBUS while accessing the mapped region later on.
+        */
+        else{
+          static const int pgsz = 4096;
+          int iPg;
+
+          /* Write to the last byte of each newly allocated or extended page */
+          assert( (nByte % pgsz)==0 );
+          for(iPg=(sStat.st_size/pgsz); iPg<(nByte/pgsz); iPg++){
+            if( seekAndWriteFd(pShmNode->h, iPg*pgsz + pgsz-1, "", 1, 0)!=1 ){
+              const char *zFile = pShmNode->zFilename;
+              rc = unixLogError(SQLITE_IOERR_SHMSIZE, "write", zFile);
+              goto shmpage_out;
+            }
+          }
         }
-#endif
       }
     }
 
@@ -27142,7 +27475,7 @@ static int unixShmMap(
     while(pShmNode->nRegion<=iRegion){
       void *pMem;
       if( pShmNode->h>=0 ){
-        pMem = mmap(0, szRegion,
+        pMem = osMmap(0, szRegion,
             pShmNode->isReadonly ? PROT_READ : PROT_READ|PROT_WRITE, 
             MAP_SHARED, pShmNode->h, szRegion*(i64)pShmNode->nRegion
         );
@@ -27359,6 +27692,236 @@ static int unixShmUnmap(
 # define unixShmUnmap   0
 #endif /* #ifndef SQLITE_OMIT_WAL */
 
+/*
+** If it is currently memory mapped, unmap file pFd.
+*/
+static void unixUnmapfile(unixFile *pFd){
+  assert( pFd->nFetchOut==0 );
+#if SQLITE_MAX_MMAP_SIZE>0
+  if( pFd->pMapRegion ){
+    osMunmap(pFd->pMapRegion, pFd->mmapSizeActual);
+    pFd->pMapRegion = 0;
+    pFd->mmapSize = 0;
+    pFd->mmapSizeActual = 0;
+  }
+#endif
+}
+
+#if SQLITE_MAX_MMAP_SIZE>0
+/*
+** Return the system page size.
+*/
+static int unixGetPagesize(void){
+#if HAVE_MREMAP
+  return 512;
+#elif defined(_BSD_SOURCE)
+  return getpagesize();
+#else
+  return (int)sysconf(_SC_PAGESIZE);
+#endif
+}
+#endif /* SQLITE_MAX_MMAP_SIZE>0 */
+
+#if SQLITE_MAX_MMAP_SIZE>0
+/*
+** Attempt to set the size of the memory mapping maintained by file 
+** descriptor pFd to nNew bytes. Any existing mapping is discarded.
+**
+** If successful, this function sets the following variables:
+**
+**       unixFile.pMapRegion
+**       unixFile.mmapSize
+**       unixFile.mmapSizeActual
+**
+** If unsuccessful, an error message is logged via sqlite3_log() and
+** the three variables above are zeroed. In this case SQLite should
+** continue accessing the database using the xRead() and xWrite()
+** methods.
+*/
+static void unixRemapfile(
+  unixFile *pFd,                  /* File descriptor object */
+  i64 nNew                        /* Required mapping size */
+){
+  const char *zErr = "mmap";
+  int h = pFd->h;                      /* File descriptor open on db file */
+  u8 *pOrig = (u8 *)pFd->pMapRegion;   /* Pointer to current file mapping */
+  i64 nOrig = pFd->mmapSizeActual;     /* Size of pOrig region in bytes */
+  u8 *pNew = 0;                        /* Location of new mapping */
+  int flags = PROT_READ;               /* Flags to pass to mmap() */
+
+  assert( pFd->nFetchOut==0 );
+  assert( nNew>pFd->mmapSize );
+  assert( nNew<=pFd->mmapSizeMax );
+  assert( nNew>0 );
+  assert( pFd->mmapSizeActual>=pFd->mmapSize );
+  assert( MAP_FAILED!=0 );
+
+  if( (pFd->ctrlFlags & UNIXFILE_RDONLY)==0 ) flags |= PROT_WRITE;
+
+  if( pOrig ){
+    const int szSyspage = unixGetPagesize();
+    i64 nReuse = (pFd->mmapSize & ~(szSyspage-1));
+    u8 *pReq = &pOrig[nReuse];
+
+    /* Unmap any pages of the existing mapping that cannot be reused. */
+    if( nReuse!=nOrig ){
+      osMunmap(pReq, nOrig-nReuse);
+    }
+
+#if HAVE_MREMAP
+    pNew = osMremap(pOrig, nReuse, nNew, MREMAP_MAYMOVE);
+    zErr = "mremap";
+#else
+    pNew = osMmap(pReq, nNew-nReuse, flags, MAP_SHARED, h, nReuse);
+    if( pNew!=MAP_FAILED ){
+      if( pNew!=pReq ){
+        osMunmap(pNew, nNew - nReuse);
+        pNew = 0;
+      }else{
+        pNew = pOrig;
+      }
+    }
+#endif
+
+    /* The attempt to extend the existing mapping failed. Free it. */
+    if( pNew==MAP_FAILED || pNew==0 ){
+      osMunmap(pOrig, nReuse);
+    }
+  }
+
+  /* If pNew is still NULL, try to create an entirely new mapping. */
+  if( pNew==0 ){
+    pNew = osMmap(0, nNew, flags, MAP_SHARED, h, 0);
+  }
+
+  if( pNew==MAP_FAILED ){
+    pNew = 0;
+    nNew = 0;
+    unixLogError(SQLITE_OK, zErr, pFd->zPath);
+
+    /* If the mmap() above failed, assume that all subsequent mmap() calls
+    ** will probably fail too. Fall back to using xRead/xWrite exclusively
+    ** in this case.  */
+    pFd->mmapSizeMax = 0;
+  }
+  pFd->pMapRegion = (void *)pNew;
+  pFd->mmapSize = pFd->mmapSizeActual = nNew;
+}
+#endif
+
+/*
+** Memory map or remap the file opened by file-descriptor pFd (if the file
+** is already mapped, the existing mapping is replaced by the new). Or, if 
+** there already exists a mapping for this file, and there are still 
+** outstanding xFetch() references to it, this function is a no-op.
+**
+** If parameter nByte is non-negative, then it is the requested size of 
+** the mapping to create. Otherwise, if nByte is less than zero, then the 
+** requested size is the size of the file on disk. The actual size of the
+** created mapping is either the requested size or the value configured 
+** using SQLITE_FCNTL_MMAP_LIMIT, whichever is smaller.
+**
+** SQLITE_OK is returned if no error occurs (even if the mapping is not
+** recreated as a result of outstanding references) or an SQLite error
+** code otherwise.
+*/
+static int unixMapfile(unixFile *pFd, i64 nByte){
+#if SQLITE_MAX_MMAP_SIZE>0
+  i64 nMap = nByte;
+  int rc;
+
+  assert( nMap>=0 || pFd->nFetchOut==0 );
+  if( pFd->nFetchOut>0 ) return SQLITE_OK;
+
+  if( nMap<0 ){
+    struct stat statbuf;          /* Low-level file information */
+    rc = osFstat(pFd->h, &statbuf);
+    if( rc!=SQLITE_OK ){
+      return SQLITE_IOERR_FSTAT;
+    }
+    nMap = statbuf.st_size;
+  }
+  if( nMap>pFd->mmapSizeMax ){
+    nMap = pFd->mmapSizeMax;
+  }
+
+  if( nMap!=pFd->mmapSize ){
+    if( nMap>0 ){
+      unixRemapfile(pFd, nMap);
+    }else{
+      unixUnmapfile(pFd);
+    }
+  }
+#endif
+
+  return SQLITE_OK;
+}
+
+/*
+** If possible, return a pointer to a mapping of file fd starting at offset
+** iOff. The mapping must be valid for at least nAmt bytes.
+**
+** If such a pointer can be obtained, store it in *pp and return SQLITE_OK.
+** Or, if one cannot but no error occurs, set *pp to 0 and return SQLITE_OK.
+** Finally, if an error does occur, return an SQLite error code. The final
+** value of *pp is undefined in this case.
+**
+** If this function does return a pointer, the caller must eventually 
+** release the reference by calling unixUnfetch().
+*/
+static int unixFetch(sqlite3_file *fd, i64 iOff, int nAmt, void **pp){
+#if SQLITE_MAX_MMAP_SIZE>0
+  unixFile *pFd = (unixFile *)fd;   /* The underlying database file */
+#endif
+  *pp = 0;
+
+#if SQLITE_MAX_MMAP_SIZE>0
+  if( pFd->mmapSizeMax>0 ){
+    if( pFd->pMapRegion==0 ){
+      int rc = unixMapfile(pFd, -1);
+      if( rc!=SQLITE_OK ) return rc;
+    }
+    if( pFd->mmapSize >= iOff+nAmt ){
+      *pp = &((u8 *)pFd->pMapRegion)[iOff];
+      pFd->nFetchOut++;
+    }
+  }
+#endif
+  return SQLITE_OK;
+}
+
+/*
+** If the third argument is non-NULL, then this function releases a 
+** reference obtained by an earlier call to unixFetch(). The second
+** argument passed to this function must be the same as the corresponding
+** argument that was passed to the unixFetch() invocation. 
+**
+** Or, if the third argument is NULL, then this function is being called 
+** to inform the VFS layer that, according to POSIX, any existing mapping 
+** may now be invalid and should be unmapped.
+*/
+static int unixUnfetch(sqlite3_file *fd, i64 iOff, void *p){
+  unixFile *pFd = (unixFile *)fd;   /* The underlying database file */
+  UNUSED_PARAMETER(iOff);
+
+  /* If p==0 (unmap the entire file) then there must be no outstanding 
+  ** xFetch references. Or, if p!=0 (meaning it is an xFetch reference),
+  ** then there must be at least one outstanding.  */
+  assert( (p==0)==(pFd->nFetchOut==0) );
+
+  /* If p!=0, it must match the iOff value. */
+  assert( p==0 || p==&((u8 *)pFd->pMapRegion)[iOff] );
+
+  if( p ){
+    pFd->nFetchOut--;
+  }else{
+    unixUnmapfile(pFd);
+  }
+
+  assert( pFd->nFetchOut>=0 );
+  return SQLITE_OK;
+}
+
 /*
 ** Here ends the implementation of all sqlite3_file methods.
 **
@@ -27417,7 +27980,9 @@ static const sqlite3_io_methods METHOD = {                                   \
    unixShmMap,                 /* xShmMap */                                 \
    unixShmLock,                /* xShmLock */                                \
    unixShmBarrier,             /* xShmBarrier */                             \
-   unixShmUnmap                /* xShmUnmap */                               \
+   unixShmUnmap,               /* xShmUnmap */                               \
+   unixFetch,                  /* xFetch */                                  \
+   unixUnfetch,                /* xUnfetch */                                \
 };                                                                           \
 static const sqlite3_io_methods *FINDER##Impl(const char *z, unixFile *p){   \
   UNUSED_PARAMETER(z); UNUSED_PARAMETER(p);                                  \
@@ -27434,7 +27999,7 @@ static const sqlite3_io_methods *(*const FINDER)(const char*,unixFile *p)    \
 IOMETHODS(
   posixIoFinder,            /* Finder function name */
   posixIoMethods,           /* sqlite3_io_methods object name */
-  2,                        /* shared memory is enabled */
+  3,                        /* shared memory and mmap are enabled */
   unixClose,                /* xClose method */
   unixLock,                 /* xLock method */
   unixUnlock,               /* xUnlock method */
@@ -27685,6 +28250,7 @@ static int fillInUnixFile(
   pNew->pVfs = pVfs;
   pNew->zPath = zFilename;
   pNew->ctrlFlags = (u8)ctrlFlags;
+  pNew->mmapSizeMax = sqlite3GlobalConfig.szMmap;
   if( sqlite3_uri_boolean(((ctrlFlags & UNIXFILE_URI) ? zFilename : 0),
                            "psow", SQLITE_POWERSAFE_OVERWRITE) ){
     pNew->ctrlFlags |= UNIXFILE_PSOW;
@@ -27820,15 +28386,15 @@ static int fillInUnixFile(
     if( h>=0 ) robust_close(pNew, h, __LINE__);
     h = -1;
     osUnlink(zFilename);
-    isDelete = 0;
+    pNew->ctrlFlags |= UNIXFILE_DELETE;
   }
-  if( isDelete ) pNew->ctrlFlags |= UNIXFILE_DELETE;
 #endif
   if( rc!=SQLITE_OK ){
     if( h>=0 ) robust_close(pNew, h, __LINE__);
   }else{
     pNew->pMethod = pLockingStyle;
     OpenCounter(+1);
+    verifyDbFile(pNew);
   }
   return rc;
 }
@@ -29922,7 +30488,7 @@ SQLITE_API int sqlite3_os_init(void){
 
   /* Double-check that the aSyscall[] array has been constructed
   ** correctly.  See ticket [bb3a86e890c8e96ab] */
-  assert( ArraySize(aSyscall)==21 );
+  assert( ArraySize(aSyscall)==24 );
 
   /* Register all VFSes defined in the aVfs[] array */
   for(i=0; i<(sizeof(aVfs)/sizeof(sqlite3_vfs)); i++){
@@ -30305,11 +30871,20 @@ struct winFile {
   winceLock local;        /* Locks obtained by this instance of winFile */
   winceLock *shared;      /* Global shared lock memory for the file  */
 #endif
+#if SQLITE_MAX_MMAP_SIZE>0
+  int nFetchOut;                /* Number of outstanding xFetch references */
+  HANDLE hMap;                  /* Handle for accessing memory mapping */
+  void *pMapRegion;             /* Area memory mapped */
+  sqlite3_int64 mmapSize;       /* Usable size of mapped region */
+  sqlite3_int64 mmapSizeActual; /* Actual size of mapped region */
+  sqlite3_int64 mmapSizeMax;    /* Configured FCNTL_MMAP_SIZE value */
+#endif
 };
 
 /*
 ** Allowed values for winFile.ctrlFlags
 */
+#define WINFILE_RDONLY          0x02   /* Connection is read only */
 #define WINFILE_PERSIST_WAL     0x04   /* Persistent WAL mode */
 #define WINFILE_PSOW            0x10   /* SQLITE_IOCAP_POWERSAFE_OVERWRITE */
 
@@ -31669,7 +32244,7 @@ static int getLastErrorMsg(DWORD lastErrno, int nBuf, char *zBuf){
   }
 #endif
   if( 0 == dwLen ){
-    sqlite3_snprintf(nBuf, zBuf, "OsError 0x%x (%u)", lastErrno, lastErrno);
+    sqlite3_snprintf(nBuf, zBuf, "OsError 0x%lx (%lu)", lastErrno, lastErrno);
   }else{
     /* copy a maximum of nBuf chars to output buffer */
     sqlite3_snprintf(nBuf, zBuf, "%s", zOut);
@@ -31712,7 +32287,7 @@ static int winLogErrorAtLine(
   for(i=0; zMsg[i] && zMsg[i]!='\r' && zMsg[i]!='\n'; i++){}
   zMsg[i] = 0;
   sqlite3_log(errcode,
-      "os_win.c:%d: (%d) %s(%s) - %s",
+      "os_win.c:%d: (%lu) %s(%s) - %s",
       iLine, lastErrno, zFunc, zPath, zMsg
   );
 
@@ -32173,6 +32748,8 @@ static int seekWinFile(winFile *pFile, sqlite3_int64 iOffset){
   DWORD dwRet;                    /* Value returned by SetFilePointer() */
   DWORD lastErrno;                /* Value returned by GetLastError() */
 
+  OSTRACE(("SEEK file=%p, offset=%lld\n", pFile->h, iOffset));
+
   upperBits = (LONG)((iOffset>>32) & 0x7fffffff);
   lowerBits = (LONG)(iOffset & 0xffffffff);
 
@@ -32190,9 +32767,11 @@ static int seekWinFile(winFile *pFile, sqlite3_int64 iOffset){
     pFile->lastErrno = lastErrno;
     winLogError(SQLITE_IOERR_SEEK, pFile->lastErrno,
              "seekWinFile", pFile->zPath);
+    OSTRACE(("SEEK file=%p, rc=SQLITE_IOERR_SEEK\n", pFile->h));
     return 1;
   }
 
+  OSTRACE(("SEEK file=%p, rc=SQLITE_OK\n", pFile->h));
   return 0;
 #else
   /*
@@ -32209,13 +32788,20 @@ static int seekWinFile(winFile *pFile, sqlite3_int64 iOffset){
     pFile->lastErrno = osGetLastError();
     winLogError(SQLITE_IOERR_SEEK, pFile->lastErrno,
              "seekWinFile", pFile->zPath);
+    OSTRACE(("SEEK file=%p, rc=SQLITE_IOERR_SEEK\n", pFile->h));
     return 1;
   }
 
+  OSTRACE(("SEEK file=%p, rc=SQLITE_OK\n", pFile->h));
   return 0;
 #endif
 }
 
+#if SQLITE_MAX_MMAP_SIZE>0
+/* Forward references to VFS methods */
+static int winUnmapfile(winFile*);
+#endif
+
 /*
 ** Close a file.
 **
@@ -32235,8 +32821,14 @@ static int winClose(sqlite3_file *id){
 #ifndef SQLITE_OMIT_WAL
   assert( pFile->pShm==0 );
 #endif
-  OSTRACE(("CLOSE %d\n", pFile->h));
   assert( pFile->h!=NULL && pFile->h!=INVALID_HANDLE_VALUE );
+  OSTRACE(("CLOSE file=%p\n", pFile->h));
+
+#if SQLITE_MAX_MMAP_SIZE>0
+  rc = winUnmapfile(pFile);
+  if( rc!=SQLITE_OK ) return rc;
+#endif
+
   do{
     rc = osCloseHandle(pFile->h);
     /* SimulateIOError( rc=0; cnt=MX_CLOSE_ATTEMPT; ); */
@@ -32256,11 +32848,11 @@ static int winClose(sqlite3_file *id){
     sqlite3_free(pFile->zDeleteOnClose);
   }
 #endif
-  OSTRACE(("CLOSE %d %s\n", pFile->h, rc ? "ok" : "failed"));
   if( rc ){
     pFile->h = NULL;
   }
   OpenCounter(-1);
+  OSTRACE(("CLOSE file=%p, rc=%s\n", pFile->h, rc ? "ok" : "failed"));
   return rc ? SQLITE_OK
             : winLogError(SQLITE_IOERR_CLOSE, osGetLastError(),
                           "winClose", pFile->zPath);
@@ -32285,11 +32877,33 @@ static int winRead(
   int nRetry = 0;                 /* Number of retrys */
 
   assert( id!=0 );
+  assert( amt>0 );
+  assert( offset>=0 );
   SimulateIOError(return SQLITE_IOERR_READ);
-  OSTRACE(("READ %d lock=%d\n", pFile->h, pFile->locktype));
+  OSTRACE(("READ file=%p, buffer=%p, amount=%d, offset=%lld, lock=%d\n",
+           pFile->h, pBuf, amt, offset, pFile->locktype));
+
+#if SQLITE_MAX_MMAP_SIZE>0
+  /* Deal with as much of this read request as possible by transfering
+  ** data from the memory mapping using memcpy().  */
+  if( offset<pFile->mmapSize ){
+    if( offset+amt <= pFile->mmapSize ){
+      memcpy(pBuf, &((u8 *)(pFile->pMapRegion))[offset], amt);
+      OSTRACE(("READ-MMAP file=%p, rc=SQLITE_OK\n", pFile->h));
+      return SQLITE_OK;
+    }else{
+      int nCopy = (int)(pFile->mmapSize - offset);
+      memcpy(pBuf, &((u8 *)(pFile->pMapRegion))[offset], nCopy);
+      pBuf = &((u8 *)pBuf)[nCopy];
+      amt -= nCopy;
+      offset += nCopy;
+    }
+  }
+#endif
 
 #if SQLITE_OS_WINCE
   if( seekWinFile(pFile, offset) ){
+    OSTRACE(("READ file=%p, rc=SQLITE_FULL\n", pFile->h));
     return SQLITE_FULL;
   }
   while( !osReadFile(pFile->h, pBuf, amt, &nRead, 0) ){
@@ -32303,6 +32917,7 @@ static int winRead(
     DWORD lastErrno;
     if( retryIoerr(&nRetry, &lastErrno) ) continue;
     pFile->lastErrno = lastErrno;
+    OSTRACE(("READ file=%p, rc=SQLITE_IOERR_READ\n", pFile->h));
     return winLogError(SQLITE_IOERR_READ, pFile->lastErrno,
              "winRead", pFile->zPath);
   }
@@ -32310,9 +32925,11 @@ static int winRead(
   if( nRead<(DWORD)amt ){
     /* Unread parts of the buffer must be zero-filled */
     memset(&((char*)pBuf)[nRead], 0, amt-nRead);
+    OSTRACE(("READ file=%p, rc=SQLITE_IOERR_SHORT_READ\n", pFile->h));
     return SQLITE_IOERR_SHORT_READ;
   }
 
+  OSTRACE(("READ file=%p, rc=SQLITE_OK\n", pFile->h));
   return SQLITE_OK;
 }
 
@@ -32335,7 +32952,26 @@ static int winWrite(
   SimulateIOError(return SQLITE_IOERR_WRITE);
   SimulateDiskfullError(return SQLITE_FULL);
 
-  OSTRACE(("WRITE %d lock=%d\n", pFile->h, pFile->locktype));
+  OSTRACE(("WRITE file=%p, buffer=%p, amount=%d, offset=%lld, lock=%d\n",
+           pFile->h, pBuf, amt, offset, pFile->locktype));
+
+#if SQLITE_MAX_MMAP_SIZE>0
+  /* Deal with as much of this write request as possible by transfering
+  ** data from the memory mapping using memcpy().  */
+  if( offset<pFile->mmapSize ){
+    if( offset+amt <= pFile->mmapSize ){
+      memcpy(&((u8 *)(pFile->pMapRegion))[offset], pBuf, amt);
+      OSTRACE(("WRITE-MMAP file=%p, rc=SQLITE_OK\n", pFile->h));
+      return SQLITE_OK;
+    }else{
+      int nCopy = (int)(pFile->mmapSize - offset);
+      memcpy(&((u8 *)(pFile->pMapRegion))[offset], pBuf, nCopy);
+      pBuf = &((u8 *)pBuf)[nCopy];
+      amt -= nCopy;
+      offset += nCopy;
+    }
+  }
+#endif
 
 #if SQLITE_OS_WINCE
   rc = seekWinFile(pFile, offset);
@@ -32388,13 +33024,16 @@ static int winWrite(
   if( rc ){
     if(   ( pFile->lastErrno==ERROR_HANDLE_DISK_FULL )
        || ( pFile->lastErrno==ERROR_DISK_FULL )){
+      OSTRACE(("WRITE file=%p, rc=SQLITE_FULL\n", pFile->h));
       return SQLITE_FULL;
     }
+    OSTRACE(("WRITE file=%p, rc=SQLITE_IOERR_WRITE\n", pFile->h));
     return winLogError(SQLITE_IOERR_WRITE, pFile->lastErrno,
              "winWrite", pFile->zPath);
   }else{
     logIoerr(nRetry);
   }
+  OSTRACE(("WRITE file=%p, rc=SQLITE_OK\n", pFile->h));
   return SQLITE_OK;
 }
 
@@ -32404,11 +33043,12 @@ static int winWrite(
 static int winTruncate(sqlite3_file *id, sqlite3_int64 nByte){
   winFile *pFile = (winFile*)id;  /* File handle object */
   int rc = SQLITE_OK;             /* Return code for this function */
+  DWORD lastErrno;
 
   assert( pFile );
-
-  OSTRACE(("TRUNCATE %d %lld\n", pFile->h, nByte));
   SimulateIOError(return SQLITE_IOERR_TRUNCATE);
+  OSTRACE(("TRUNCATE file=%p, size=%lld, lock=%d\n",
+           pFile->h, nByte, pFile->locktype));
 
   /* If the user has configured a chunk-size for this file, truncate the
   ** file so that it consists of an integer number of chunks (i.e. the
@@ -32422,14 +33062,25 @@ static int winTruncate(sqlite3_file *id, sqlite3_int64 nByte){
   /* SetEndOfFile() returns non-zero when successful, or zero when it fails. */
   if( seekWinFile(pFile, nByte) ){
     rc = winLogError(SQLITE_IOERR_TRUNCATE, pFile->lastErrno,
-             "winTruncate1", pFile->zPath);
-  }else if( 0==osSetEndOfFile(pFile->h) ){
-    pFile->lastErrno = osGetLastError();
+                     "winTruncate1", pFile->zPath);
+  }else if( 0==osSetEndOfFile(pFile->h) &&
+            ((lastErrno = osGetLastError())!=ERROR_USER_MAPPED_FILE) ){
+    pFile->lastErrno = lastErrno;
     rc = winLogError(SQLITE_IOERR_TRUNCATE, pFile->lastErrno,
-             "winTruncate2", pFile->zPath);
+                     "winTruncate2", pFile->zPath);
   }
 
-  OSTRACE(("TRUNCATE %d %lld %s\n", pFile->h, nByte, rc ? "failed" : "ok"));
+#if SQLITE_MAX_MMAP_SIZE>0
+  /* If the file was truncated to a size smaller than the currently
+  ** mapped region, reduce the effective mapping size as well. SQLite will
+  ** use read() and write() to access data beyond this point from now on.
+  */
+  if( pFile->pMapRegion && nByte<pFile->mmapSize ){
+    pFile->mmapSize = nByte;
+  }
+#endif
+
+  OSTRACE(("TRUNCATE file=%p, rc=%s\n", pFile->h, sqlite3ErrName(rc)));
   return rc;
 }
 
@@ -32469,13 +33120,14 @@ static int winSync(sqlite3_file *id, int flags){
       || (flags&0x0F)==SQLITE_SYNC_FULL
   );
 
-  OSTRACE(("SYNC %d lock=%d\n", pFile->h, pFile->locktype));
-
   /* Unix cannot, but some systems may return SQLITE_FULL from here. This
   ** line is to test that doing so does not cause any problems.
   */
   SimulateDiskfullError( return SQLITE_FULL );
 
+  OSTRACE(("SYNC file=%p, flags=%x, lock=%d\n",
+           pFile->h, flags, pFile->locktype));
+
 #ifndef SQLITE_TEST
   UNUSED_PARAMETER(flags);
 #else
@@ -32494,9 +33146,11 @@ static int winSync(sqlite3_file *id, int flags){
   rc = osFlushFileBuffers(pFile->h);
   SimulateIOError( rc=FALSE );
   if( rc ){
+    OSTRACE(("SYNC file=%p, rc=SQLITE_OK\n", pFile->h));
     return SQLITE_OK;
   }else{
     pFile->lastErrno = osGetLastError();
+    OSTRACE(("SYNC file=%p, rc=SQLITE_IOERR_FSYNC\n", pFile->h));
     return winLogError(SQLITE_IOERR_FSYNC, pFile->lastErrno,
              "winSync", pFile->zPath);
   }
@@ -32511,7 +33165,10 @@ static int winFileSize(sqlite3_file *id, sqlite3_int64 *pSize){
   int rc = SQLITE_OK;
 
   assert( id!=0 );
+  assert( pSize!=0 );
   SimulateIOError(return SQLITE_IOERR_FSTAT);
+  OSTRACE(("SIZE file=%p, pSize=%p\n", pFile->h, pSize));
+
 #if SQLITE_OS_WINRT
   {
     FILE_STANDARD_INFO info;
@@ -32540,6 +33197,8 @@ static int winFileSize(sqlite3_file *id, sqlite3_int64 *pSize){
     }
   }
 #endif
+  OSTRACE(("SIZE file=%p, pSize=%p, *pSize=%lld, rc=%s\n",
+           pFile->h, pSize, *pSize, sqlite3ErrName(rc)));
   return rc;
 }
 
@@ -32581,6 +33240,7 @@ static int winFileSize(sqlite3_file *id, sqlite3_int64 *pSize){
 */
 static int getReadLock(winFile *pFile){
   int res;
+  OSTRACE(("READ-LOCK file=%p, lock=%d\n", pFile->h, pFile->locktype));
   if( isNT() ){
 #if SQLITE_OS_WINCE
     /*
@@ -32606,6 +33266,7 @@ static int getReadLock(winFile *pFile){
     pFile->lastErrno = osGetLastError();
     /* No need to log a failure to lock */
   }
+  OSTRACE(("READ-LOCK file=%p, rc=%s\n", pFile->h, sqlite3ErrName(res)));
   return res;
 }
 
@@ -32615,6 +33276,7 @@ static int getReadLock(winFile *pFile){
 static int unlockReadLock(winFile *pFile){
   int res;
   DWORD lastErrno;
+  OSTRACE(("READ-UNLOCK file=%p, lock=%d\n", pFile->h, pFile->locktype));
   if( isNT() ){
     res = winUnlockFile(&pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0);
   }
@@ -32628,6 +33290,7 @@ static int unlockReadLock(winFile *pFile){
     winLogError(SQLITE_IOERR_UNLOCK, pFile->lastErrno,
              "unlockReadLock", pFile->zPath);
   }
+  OSTRACE(("READ-UNLOCK file=%p, rc=%s\n", pFile->h, sqlite3ErrName(res)));
   return res;
 }
 
@@ -32666,14 +33329,15 @@ static int winLock(sqlite3_file *id, int locktype){
   DWORD lastErrno = NO_ERROR;
 
   assert( id!=0 );
-  OSTRACE(("LOCK %d %d was %d(%d)\n",
-           pFile->h, locktype, pFile->locktype, pFile->sharedLockByte));
+  OSTRACE(("LOCK file=%p, oldLock=%d(%d), newLock=%d\n",
+           pFile->h, pFile->locktype, pFile->sharedLockByte, locktype));
 
   /* If there is already a lock of this type or more restrictive on the
   ** OsFile, do nothing. Don't use the end_lock: exit path, as
   ** sqlite3OsEnterMutex() hasn't been called yet.
   */
   if( pFile->locktype>=locktype ){
+    OSTRACE(("LOCK-HELD file=%p, rc=SQLITE_OK\n", pFile->h));
     return SQLITE_OK;
   }
 
@@ -32701,7 +33365,8 @@ static int winLock(sqlite3_file *id, int locktype){
       ** If you are using this code as a model for alternative VFSes, do not
       ** copy this retry logic.  It is a hack intended for Windows only.
       */
-      OSTRACE(("could not get a PENDING lock. cnt=%d\n", cnt));
+      OSTRACE(("LOCK-PENDING-FAIL file=%p, count=%d, rc=%s\n",
+               pFile->h, cnt, sqlite3ErrName(res)));
       if( cnt ) sqlite3_win32_sleep(1);
     }
     gotPendingLock = res;
@@ -32746,14 +33411,12 @@ static int winLock(sqlite3_file *id, int locktype){
   if( locktype==EXCLUSIVE_LOCK && res ){
     assert( pFile->locktype>=SHARED_LOCK );
     res = unlockReadLock(pFile);
-    OSTRACE(("unreadlock = %d\n", res));
     res = winLockFile(&pFile->h, SQLITE_LOCKFILE_FLAGS, SHARED_FIRST, 0,
                       SHARED_SIZE, 0);
     if( res ){
       newLocktype = EXCLUSIVE_LOCK;
     }else{
       lastErrno = osGetLastError();
-      OSTRACE(("error-code = %d\n", lastErrno));
       getReadLock(pFile);
     }
   }
@@ -32771,12 +33434,14 @@ static int winLock(sqlite3_file *id, int locktype){
   if( res ){
     rc = SQLITE_OK;
   }else{
-    OSTRACE(("LOCK FAILED %d trying for %d but got %d\n", pFile->h,
-           locktype, newLocktype));
+    OSTRACE(("LOCK-FAIL file=%p, wanted=%d, got=%d\n",
+             pFile->h, locktype, newLocktype));
     pFile->lastErrno = lastErrno;
     rc = SQLITE_BUSY;
   }
   pFile->locktype = (u8)newLocktype;
+  OSTRACE(("LOCK file=%p, lock=%d, rc=%s\n",
+           pFile->h, pFile->locktype, sqlite3ErrName(rc)));
   return rc;
 }
 
@@ -32790,20 +33455,23 @@ static int winCheckReservedLock(sqlite3_file *id, int *pResOut){
   winFile *pFile = (winFile*)id;
 
   SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; );
+  OSTRACE(("TEST-WR-LOCK file=%p, pResOut=%p\n", pFile->h, pResOut));
 
   assert( id!=0 );
   if( pFile->locktype>=RESERVED_LOCK ){
     rc = 1;
-    OSTRACE(("TEST WR-LOCK %d %d (local)\n", pFile->h, rc));
+    OSTRACE(("TEST-WR-LOCK file=%p, rc=%d (local)\n", pFile->h, rc));
   }else{
     rc = winLockFile(&pFile->h, SQLITE_LOCKFILEEX_FLAGS,RESERVED_BYTE, 0, 1, 0);
     if( rc ){
       winUnlockFile(&pFile->h, RESERVED_BYTE, 0, 1, 0);
     }
     rc = !rc;
-    OSTRACE(("TEST WR-LOCK %d %d (remote)\n", pFile->h, rc));
+    OSTRACE(("TEST-WR-LOCK file=%p, rc=%d (remote)\n", pFile->h, rc));
   }
   *pResOut = rc;
+  OSTRACE(("TEST-WR-LOCK file=%p, pResOut=%p, *pResOut=%d, rc=SQLITE_OK\n",
+           pFile->h, pResOut, *pResOut));
   return SQLITE_OK;
 }
 
@@ -32824,8 +33492,8 @@ static int winUnlock(sqlite3_file *id, int locktype){
   int rc = SQLITE_OK;
   assert( pFile!=0 );
   assert( locktype<=SHARED_LOCK );
-  OSTRACE(("UNLOCK %d to %d was %d(%d)\n", pFile->h, locktype,
-          pFile->locktype, pFile->sharedLockByte));
+  OSTRACE(("UNLOCK file=%p, oldLock=%d(%d), newLock=%d\n",
+           pFile->h, pFile->locktype, pFile->sharedLockByte, locktype));
   type = pFile->locktype;
   if( type>=EXCLUSIVE_LOCK ){
     winUnlockFile(&pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0);
@@ -32846,6 +33514,8 @@ static int winUnlock(sqlite3_file *id, int locktype){
     winUnlockFile(&pFile->h, PENDING_BYTE, 0, 1, 0);
   }
   pFile->locktype = (u8)locktype;
+  OSTRACE(("UNLOCK file=%p, lock=%d, rc=%s\n",
+           pFile->h, pFile->locktype, sqlite3ErrName(rc)));
   return rc;
 }
 
@@ -32873,17 +33543,21 @@ static int getTempname(int nBuf, char *zBuf);
 */
 static int winFileControl(sqlite3_file *id, int op, void *pArg){
   winFile *pFile = (winFile*)id;
+  OSTRACE(("FCNTL file=%p, op=%d, pArg=%p\n", pFile->h, op, pArg));
   switch( op ){
     case SQLITE_FCNTL_LOCKSTATE: {
       *(int*)pArg = pFile->locktype;
+      OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h));
       return SQLITE_OK;
     }
     case SQLITE_LAST_ERRNO: {
       *(int*)pArg = (int)pFile->lastErrno;
+      OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h));
       return SQLITE_OK;
     }
     case SQLITE_FCNTL_CHUNK_SIZE: {
       pFile->szChunk = *(int *)pArg;
+      OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h));
       return SQLITE_OK;
     }
     case SQLITE_FCNTL_SIZE_HINT: {
@@ -32898,20 +33572,25 @@ static int winFileControl(sqlite3_file *id, int op, void *pArg){
             SimulateIOErrorBenign(0);
           }
         }
+        OSTRACE(("FCNTL file=%p, rc=%s\n", pFile->h, sqlite3ErrName(rc)));
         return rc;
       }
+      OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h));
       return SQLITE_OK;
     }
     case SQLITE_FCNTL_PERSIST_WAL: {
       winModeBit(pFile, WINFILE_PERSIST_WAL, (int*)pArg);
+      OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h));
       return SQLITE_OK;
     }
     case SQLITE_FCNTL_POWERSAFE_OVERWRITE: {
       winModeBit(pFile, WINFILE_PSOW, (int*)pArg);
+      OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h));
       return SQLITE_OK;
     }
     case SQLITE_FCNTL_VFSNAME: {
       *(char**)pArg = sqlite3_mprintf("win32");
+      OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h));
       return SQLITE_OK;
     }
     case SQLITE_FCNTL_WIN32_AV_RETRY: {
@@ -32926,6 +33605,7 @@ static int winFileControl(sqlite3_file *id, int op, void *pArg){
       }else{
         a[1] = win32IoerrRetryDelay;
       }
+      OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h));
       return SQLITE_OK;
     }
     case SQLITE_FCNTL_TEMPFILENAME: {
@@ -32934,9 +33614,23 @@ static int winFileControl(sqlite3_file *id, int op, void *pArg){
         getTempname(pFile->pVfs->mxPathname, zTFile);
         *(char**)pArg = zTFile;
       }
+      OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h));
+      return SQLITE_OK;
+    }
+#if SQLITE_MAX_MMAP_SIZE>0
+    case SQLITE_FCNTL_MMAP_SIZE: {
+      i64 newLimit = *(i64*)pArg;
+      if( newLimit>sqlite3GlobalConfig.mxMmap ){
+        newLimit = sqlite3GlobalConfig.mxMmap;
+      }
+      *(i64*)pArg = pFile->mmapSizeMax;
+      if( newLimit>=0 ) pFile->mmapSizeMax = newLimit;
+      OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h));
       return SQLITE_OK;
     }
+#endif
   }
+  OSTRACE(("FCNTL file=%p, rc=SQLITE_NOTFOUND\n", pFile->h));
   return SQLITE_NOTFOUND;
 }
 
@@ -32964,8 +33658,6 @@ static int winDeviceCharacteristics(sqlite3_file *id){
          ((p->ctrlFlags & WINFILE_PSOW)?SQLITE_IOCAP_POWERSAFE_OVERWRITE:0);
 }
 
-#ifndef SQLITE_OMIT_WAL
-
 /* 
 ** Windows will only let you create file view mappings
 ** on allocation size granularity boundaries.
@@ -32974,6 +33666,8 @@ static int winDeviceCharacteristics(sqlite3_file *id){
 */
 SYSTEM_INFO winSysInfo;
 
+#ifndef SQLITE_OMIT_WAL
+
 /*
 ** Helper functions to obtain and relinquish the global mutex. The
 ** global mutex is used to protect the winLockInfo objects used by 
@@ -33097,6 +33791,9 @@ static int winShmSystemLock(
   /* Access to the winShmNode object is serialized by the caller */
   assert( sqlite3_mutex_held(pFile->mutex) || pFile->nRef==0 );
 
+  OSTRACE(("SHM-LOCK file=%p, lock=%d, offset=%d, size=%d\n",
+           pFile->hFile.h, lockType, ofst, nByte));
+
   /* Release/Acquire the system-level lock */
   if( lockType==_SHM_UNLCK ){
     rc = winUnlockFile(&pFile->hFile.h, ofst, 0, nByte, 0);
@@ -33114,11 +33811,9 @@ static int winShmSystemLock(
     rc = SQLITE_BUSY;
   }
 
-  OSTRACE(("SHM-LOCK %d %s %s 0x%08lx\n", 
-           pFile->hFile.h,
-           rc==SQLITE_OK ? "ok" : "failed",
-           lockType==_SHM_UNLCK ? "UnlockFileEx" : "LockFileEx",
-           pFile->lastErrno));
+  OSTRACE(("SHM-LOCK file=%p, func=%s, errno=%lu, rc=%s\n",
+           pFile->hFile.h, (lockType == _SHM_UNLCK) ? "winUnlockFile" :
+           "winLockFile", pFile->lastErrno, sqlite3ErrName(rc)));
 
   return rc;
 }
@@ -33138,6 +33833,8 @@ static void winShmPurge(sqlite3_vfs *pVfs, int deleteFlag){
   winShmNode *p;
   BOOL bRc;
   assert( winShmMutexHeld() );
+  OSTRACE(("SHM-PURGE pid=%lu, deleteFlag=%d\n",
+           osGetCurrentProcessId(), deleteFlag));
   pp = &winShmNodeList;
   while( (p = *pp)!=0 ){
     if( p->nRef==0 ){
@@ -33145,13 +33842,11 @@ static void winShmPurge(sqlite3_vfs *pVfs, int deleteFlag){
       if( p->mutex ) sqlite3_mutex_free(p->mutex);
       for(i=0; i<p->nRegion; i++){
         bRc = osUnmapViewOfFile(p->aRegion[i].pMap);
-        OSTRACE(("SHM-PURGE pid-%d unmap region=%d %s\n",
-                 (int)osGetCurrentProcessId(), i,
-                 bRc ? "ok" : "failed"));
+        OSTRACE(("SHM-PURGE-UNMAP pid=%lu, region=%d, rc=%s\n",
+                 osGetCurrentProcessId(), i, bRc ? "ok" : "failed"));
         bRc = osCloseHandle(p->aRegion[i].hMap);
-        OSTRACE(("SHM-PURGE pid-%d close region=%d %s\n",
-                 (int)osGetCurrentProcessId(), i,
-                 bRc ? "ok" : "failed"));
+        OSTRACE(("SHM-PURGE-CLOSE pid=%lu, region=%d, rc=%s\n",
+                 osGetCurrentProcessId(), i, bRc ? "ok" : "failed"));
       }
       if( p->hFile.h!=NULL && p->hFile.h!=INVALID_HANDLE_VALUE ){
         SimulateIOErrorBenign(1);
@@ -33430,9 +34125,9 @@ static int winShmLock(
     }
   }
   sqlite3_mutex_leave(pShmNode->mutex);
-  OSTRACE(("SHM-LOCK shmid-%d, pid-%d got %03x,%03x %s\n",
-           p->id, (int)osGetCurrentProcessId(), p->sharedMask, p->exclMask,
-           rc ? "failed" : "ok"));
+  OSTRACE(("SHM-LOCK pid=%lu, id=%d, sharedMask=%03x, exclMask=%03x, rc=%s\n",
+           osGetCurrentProcessId(), p->id, p->sharedMask, p->exclMask,
+           sqlite3ErrName(rc)));
   return rc;
 }
 
@@ -33553,8 +34248,8 @@ static int winShmMap(
           NULL, PAGE_READWRITE, 0, nByte, NULL
       );
 #endif
-      OSTRACE(("SHM-MAP pid-%d create region=%d nbyte=%d %s\n",
-               (int)osGetCurrentProcessId(), pShmNode->nRegion, nByte,
+      OSTRACE(("SHM-MAP-CREATE pid=%lu, region=%d, size=%d, rc=%s\n",
+               osGetCurrentProcessId(), pShmNode->nRegion, nByte,
                hMap ? "ok" : "failed"));
       if( hMap ){
         int iOffset = pShmNode->nRegion*szRegion;
@@ -33568,8 +34263,8 @@ static int winShmMap(
             0, iOffset - iOffsetShift, szRegion + iOffsetShift
         );
 #endif
-        OSTRACE(("SHM-MAP pid-%d map region=%d offset=%d size=%d %s\n",
-                 (int)osGetCurrentProcessId(), pShmNode->nRegion, iOffset,
+        OSTRACE(("SHM-MAP-MAP pid=%lu, region=%d, offset=%d, size=%d, rc=%s\n",
+                 osGetCurrentProcessId(), pShmNode->nRegion, iOffset,
                  szRegion, pMap ? "ok" : "failed"));
       }
       if( !pMap ){
@@ -33606,6 +34301,230 @@ shmpage_out:
 # define winShmUnmap   0
 #endif /* #ifndef SQLITE_OMIT_WAL */
 
+/*
+** Cleans up the mapped region of the specified file, if any.
+*/
+#if SQLITE_MAX_MMAP_SIZE>0
+static int winUnmapfile(winFile *pFile){
+  assert( pFile!=0 );
+  OSTRACE(("UNMAP-FILE pid=%lu, pFile=%p, hMap=%p, pMapRegion=%p, "
+           "mmapSize=%lld, mmapSizeActual=%lld, mmapSizeMax=%lld\n",
+           osGetCurrentProcessId(), pFile, pFile->hMap, pFile->pMapRegion,
+           pFile->mmapSize, pFile->mmapSizeActual, pFile->mmapSizeMax));
+  if( pFile->pMapRegion ){
+    if( !osUnmapViewOfFile(pFile->pMapRegion) ){
+      pFile->lastErrno = osGetLastError();
+      OSTRACE(("UNMAP-FILE pid=%lu, pFile=%p, pMapRegion=%p, "
+               "rc=SQLITE_IOERR_MMAP\n", osGetCurrentProcessId(), pFile,
+               pFile->pMapRegion));
+      return winLogError(SQLITE_IOERR_MMAP, pFile->lastErrno,
+                         "winUnmap1", pFile->zPath);
+    }
+    pFile->pMapRegion = 0;
+    pFile->mmapSize = 0;
+    pFile->mmapSizeActual = 0;
+  }
+  if( pFile->hMap!=NULL ){
+    if( !osCloseHandle(pFile->hMap) ){
+      pFile->lastErrno = osGetLastError();
+      OSTRACE(("UNMAP-FILE pid=%lu, pFile=%p, hMap=%p, rc=SQLITE_IOERR_MMAP\n",
+               osGetCurrentProcessId(), pFile, pFile->hMap));
+      return winLogError(SQLITE_IOERR_MMAP, pFile->lastErrno,
+                         "winUnmap2", pFile->zPath);
+    }
+    pFile->hMap = NULL;
+  }
+  OSTRACE(("UNMAP-FILE pid=%lu, pFile=%p, rc=SQLITE_OK\n",
+           osGetCurrentProcessId(), pFile));
+  return SQLITE_OK;
+}
+
+/*
+** Memory map or remap the file opened by file-descriptor pFd (if the file
+** is already mapped, the existing mapping is replaced by the new). Or, if 
+** there already exists a mapping for this file, and there are still 
+** outstanding xFetch() references to it, this function is a no-op.
+**
+** If parameter nByte is non-negative, then it is the requested size of 
+** the mapping to create. Otherwise, if nByte is less than zero, then the 
+** requested size is the size of the file on disk. The actual size of the
+** created mapping is either the requested size or the value configured 
+** using SQLITE_FCNTL_MMAP_SIZE, whichever is smaller.
+**
+** SQLITE_OK is returned if no error occurs (even if the mapping is not
+** recreated as a result of outstanding references) or an SQLite error
+** code otherwise.
+*/
+static int winMapfile(winFile *pFd, sqlite3_int64 nByte){
+  sqlite3_int64 nMap = nByte;
+  int rc;
+
+  assert( nMap>=0 || pFd->nFetchOut==0 );
+  OSTRACE(("MAP-FILE pid=%lu, pFile=%p, size=%lld\n",
+           osGetCurrentProcessId(), pFd, nByte));
+
+  if( pFd->nFetchOut>0 ) return SQLITE_OK;
+
+  if( nMap<0 ){
+    rc = winFileSize((sqlite3_file*)pFd, &nMap);
+    if( rc ){
+      OSTRACE(("MAP-FILE pid=%lu, pFile=%p, rc=SQLITE_IOERR_FSTAT\n",
+               osGetCurrentProcessId(), pFd));
+      return SQLITE_IOERR_FSTAT;
+    }
+  }
+  if( nMap>pFd->mmapSizeMax ){
+    nMap = pFd->mmapSizeMax;
+  }
+  nMap &= ~(sqlite3_int64)(winSysInfo.dwPageSize - 1);
+  if( nMap==0 && pFd->mmapSize>0 ){
+    winUnmapfile(pFd);
+  }
+  if( nMap!=pFd->mmapSize ){
+    void *pNew = 0;
+    DWORD protect = PAGE_READONLY;
+    DWORD flags = FILE_MAP_READ;
+
+    winUnmapfile(pFd);
+    if( (pFd->ctrlFlags & WINFILE_RDONLY)==0 ){
+      protect = PAGE_READWRITE;
+      flags |= FILE_MAP_WRITE;
+    }
+#if SQLITE_OS_WINRT
+    pFd->hMap = osCreateFileMappingFromApp(pFd->h, NULL, protect, nMap, NULL);
+#elif defined(SQLITE_WIN32_HAS_WIDE)
+    pFd->hMap = osCreateFileMappingW(pFd->h, NULL, protect,
+                                (DWORD)((nMap>>32) & 0xffffffff),
+                                (DWORD)(nMap & 0xffffffff), NULL);
+#elif defined(SQLITE_WIN32_HAS_ANSI)
+    pFd->hMap = osCreateFileMappingA(pFd->h, NULL, protect,
+                                (DWORD)((nMap>>32) & 0xffffffff),
+                                (DWORD)(nMap & 0xffffffff), NULL);
+#endif
+    if( pFd->hMap==NULL ){
+      pFd->lastErrno = osGetLastError();
+      rc = winLogError(SQLITE_IOERR_MMAP, pFd->lastErrno,
+                       "winMapfile", pFd->zPath);
+      /* Log the error, but continue normal operation using xRead/xWrite */
+      OSTRACE(("MAP-FILE-CREATE pid=%lu, pFile=%p, rc=SQLITE_IOERR_MMAP\n",
+               osGetCurrentProcessId(), pFd));
+      return SQLITE_OK;
+    }
+    assert( (nMap % winSysInfo.dwPageSize)==0 );
+#if SQLITE_OS_WINRT
+    pNew = osMapViewOfFileFromApp(pFd->hMap, flags, 0, nMap);
+#else
+    assert( sizeof(SIZE_T)==sizeof(sqlite3_int64) || nMap<=0xffffffff );
+    pNew = osMapViewOfFile(pFd->hMap, flags, 0, 0, (SIZE_T)nMap);
+#endif
+    if( pNew==NULL ){
+      osCloseHandle(pFd->hMap);
+      pFd->hMap = NULL;
+      pFd->lastErrno = osGetLastError();
+      winLogError(SQLITE_IOERR_MMAP, pFd->lastErrno,
+                  "winMapfile", pFd->zPath);
+      OSTRACE(("MAP-FILE-MAP pid=%lu, pFile=%p, rc=SQLITE_IOERR_MMAP\n",
+               osGetCurrentProcessId(), pFd));
+      return SQLITE_OK;
+    }
+    pFd->pMapRegion = pNew;
+    pFd->mmapSize = nMap;
+    pFd->mmapSizeActual = nMap;
+  }
+
+  OSTRACE(("MAP-FILE pid=%lu, pFile=%p, rc=SQLITE_OK\n",
+           osGetCurrentProcessId(), pFd));
+  return SQLITE_OK;
+}
+#endif /* SQLITE_MAX_MMAP_SIZE>0 */
+
+/*
+** If possible, return a pointer to a mapping of file fd starting at offset
+** iOff. The mapping must be valid for at least nAmt bytes.
+**
+** If such a pointer can be obtained, store it in *pp and return SQLITE_OK.
+** Or, if one cannot but no error occurs, set *pp to 0 and return SQLITE_OK.
+** Finally, if an error does occur, return an SQLite error code. The final
+** value of *pp is undefined in this case.
+**
+** If this function does return a pointer, the caller must eventually 
+** release the reference by calling winUnfetch().
+*/
+static int winFetch(sqlite3_file *fd, i64 iOff, int nAmt, void **pp){
+#if SQLITE_MAX_MMAP_SIZE>0
+  winFile *pFd = (winFile*)fd;   /* The underlying database file */
+#endif
+  *pp = 0;
+
+  OSTRACE(("FETCH pid=%lu, pFile=%p, offset=%lld, amount=%d, pp=%p\n",
+           osGetCurrentProcessId(), fd, iOff, nAmt, pp));
+
+#if SQLITE_MAX_MMAP_SIZE>0
+  if( pFd->mmapSizeMax>0 ){
+    if( pFd->pMapRegion==0 ){
+      int rc = winMapfile(pFd, -1);
+      if( rc!=SQLITE_OK ){
+        OSTRACE(("FETCH pid=%lu, pFile=%p, rc=%s\n",
+                 osGetCurrentProcessId(), pFd, sqlite3ErrName(rc)));
+        return rc;
+      }
+    }
+    if( pFd->mmapSize >= iOff+nAmt ){
+      *pp = &((u8 *)pFd->pMapRegion)[iOff];
+      pFd->nFetchOut++;
+    }
+  }
+#endif
+
+  OSTRACE(("FETCH pid=%lu, pFile=%p, pp=%p, *pp=%p, rc=SQLITE_OK\n",
+           osGetCurrentProcessId(), fd, pp, *pp));
+  return SQLITE_OK;
+}
+
+/*
+** If the third argument is non-NULL, then this function releases a 
+** reference obtained by an earlier call to winFetch(). The second
+** argument passed to this function must be the same as the corresponding
+** argument that was passed to the winFetch() invocation. 
+**
+** Or, if the third argument is NULL, then this function is being called 
+** to inform the VFS layer that, according to POSIX, any existing mapping 
+** may now be invalid and should be unmapped.
+*/
+static int winUnfetch(sqlite3_file *fd, i64 iOff, void *p){
+#if SQLITE_MAX_MMAP_SIZE>0
+  winFile *pFd = (winFile*)fd;   /* The underlying database file */
+
+  /* If p==0 (unmap the entire file) then there must be no outstanding 
+  ** xFetch references. Or, if p!=0 (meaning it is an xFetch reference),
+  ** then there must be at least one outstanding.  */
+  assert( (p==0)==(pFd->nFetchOut==0) );
+
+  /* If p!=0, it must match the iOff value. */
+  assert( p==0 || p==&((u8 *)pFd->pMapRegion)[iOff] );
+
+  OSTRACE(("UNFETCH pid=%lu, pFile=%p, offset=%lld, p=%p\n",
+           osGetCurrentProcessId(), pFd, iOff, p));
+
+  if( p ){
+    pFd->nFetchOut--;
+  }else{
+    /* FIXME:  If Windows truly always prevents truncating or deleting a
+    ** file while a mapping is held, then the following winUnmapfile() call
+    ** is unnecessary can can be omitted - potentially improving
+    ** performance.  */
+    winUnmapfile(pFd);
+  }
+
+  assert( pFd->nFetchOut>=0 );
+#endif
+
+  OSTRACE(("UNFETCH pid=%lu, pFile=%p, rc=SQLITE_OK\n",
+           osGetCurrentProcessId(), fd));
+  return SQLITE_OK;
+}
+
 /*
 ** Here ends the implementation of all sqlite3_file methods.
 **
@@ -33617,7 +34536,7 @@ shmpage_out:
 ** sqlite3_file for win32.
 */
 static const sqlite3_io_methods winIoMethod = {
-  2,                              /* iVersion */
+  3,                              /* iVersion */
   winClose,                       /* xClose */
   winRead,                        /* xRead */
   winWrite,                       /* xWrite */
@@ -33633,7 +34552,9 @@ static const sqlite3_io_methods winIoMethod = {
   winShmMap,                      /* xShmMap */
   winShmLock,                     /* xShmLock */
   winShmBarrier,                  /* xShmBarrier */
-  winShmUnmap                     /* xShmUnmap */
+  winShmUnmap,                    /* xShmUnmap */
+  winFetch,                       /* xFetch */
+  winUnfetch                      /* xUnfetch */
 };
 
 /****************************************************************************
@@ -33697,6 +34618,7 @@ static int getTempname(int nBuf, char *zBuf){
       sqlite3_snprintf(MAX_PATH-30, zTempPath, "%s", zMulti);
       sqlite3_free(zMulti);
     }else{
+      OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n"));
       return SQLITE_IOERR_NOMEM;
     }
   }
@@ -33710,6 +34632,7 @@ static int getTempname(int nBuf, char *zBuf){
       sqlite3_snprintf(MAX_PATH-30, zTempPath, "%s", zUtf8);
       sqlite3_free(zUtf8);
     }else{
+      OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n"));
       return SQLITE_IOERR_NOMEM;
     }
   }
@@ -33722,6 +34645,7 @@ static int getTempname(int nBuf, char *zBuf){
   nTempPath = sqlite3Strlen30(zTempPath);
 
   if( (nTempPath + sqlite3Strlen30(SQLITE_TEMP_FILE_PREFIX) + 18) >= nBuf ){
+    OSTRACE(("TEMP-FILENAME rc=SQLITE_ERROR\n"));
     return SQLITE_ERROR;
   }
 
@@ -33739,8 +34663,8 @@ static int getTempname(int nBuf, char *zBuf){
   zBuf[j] = 0;
   zBuf[j+1] = 0;
 
-  OSTRACE(("TEMP FILENAME: %s\n", zBuf));
-  return SQLITE_OK; 
+  OSTRACE(("TEMP-FILENAME name=%s, rc=SQLITE_OK\n", zBuf));
+  return SQLITE_OK;
 }
 
 /*
@@ -33809,9 +34733,7 @@ static int winOpen(
   int isExclusive  = (flags & SQLITE_OPEN_EXCLUSIVE);
   int isDelete     = (flags & SQLITE_OPEN_DELETEONCLOSE);
   int isCreate     = (flags & SQLITE_OPEN_CREATE);
-#ifndef NDEBUG
   int isReadonly   = (flags & SQLITE_OPEN_READONLY);
-#endif
   int isReadWrite  = (flags & SQLITE_OPEN_READWRITE);
 
 #ifndef NDEBUG
@@ -33822,6 +34744,9 @@ static int winOpen(
   ));
 #endif
 
+  OSTRACE(("OPEN name=%s, pFile=%p, flags=%x, pOutFlags=%p\n",
+           zUtf8Name, id, flags, pOutFlags));
+
   /* Check the following statements are true: 
   **
   **   (a) Exactly one of the READWRITE and READONLY flags must be set, and 
@@ -33867,6 +34792,7 @@ static int winOpen(
     memset(zTmpname, 0, MAX_PATH+2);
     rc = getTempname(MAX_PATH+2, zTmpname);
     if( rc!=SQLITE_OK ){
+      OSTRACE(("OPEN name=%s, rc=%s", zUtf8Name, sqlite3ErrName(rc)));
       return rc;
     }
     zUtf8Name = zTmpname;
@@ -33882,11 +34808,13 @@ static int winOpen(
   /* Convert the filename to the system encoding. */
   zConverted = convertUtf8Filename(zUtf8Name);
   if( zConverted==0 ){
+    OSTRACE(("OPEN name=%s, rc=SQLITE_IOERR_NOMEM", zUtf8Name));
     return SQLITE_IOERR_NOMEM;
   }
 
   if( winIsDir(zConverted) ){
     sqlite3_free(zConverted);
+    OSTRACE(("OPEN name=%s, rc=SQLITE_CANTOPEN_ISDIR", zUtf8Name));
     return SQLITE_CANTOPEN_ISDIR;
   }
 
@@ -33977,9 +34905,8 @@ static int winOpen(
 #endif
   logIoerr(cnt);
 
-  OSTRACE(("OPEN %d %s 0x%lx %s\n", 
-           h, zName, dwDesiredAccess, 
-           h==INVALID_HANDLE_VALUE ? "failed" : "ok"));
+  OSTRACE(("OPEN file=%p, name=%s, access=%lx, rc=%s\n", h, zUtf8Name,
+           dwDesiredAccess, (h==INVALID_HANDLE_VALUE) ? "failed" : "ok"));
 
   if( h==INVALID_HANDLE_VALUE ){
     pFile->lastErrno = lastErrno;
@@ -34003,12 +34930,17 @@ static int winOpen(
     }
   }
 
+  OSTRACE(("OPEN file=%p, name=%s, access=%lx, pOutFlags=%p, *pOutFlags=%d, "
+           "rc=%s\n", h, zUtf8Name, dwDesiredAccess, pOutFlags, pOutFlags ?
+           *pOutFlags : 0, (h==INVALID_HANDLE_VALUE) ? "failed" : "ok"));
+
 #if SQLITE_OS_WINCE
   if( isReadWrite && eType==SQLITE_OPEN_MAIN_DB
        && (rc = winceCreateLock(zName, pFile))!=SQLITE_OK
   ){
     osCloseHandle(h);
     sqlite3_free(zConverted);
+    OSTRACE(("OPEN-CE-LOCK name=%s, rc=%s\n", zName, sqlite3ErrName(rc)));
     return rc;
   }
   if( isTemp ){
@@ -34022,11 +34954,21 @@ static int winOpen(
   pFile->pMethod = &winIoMethod;
   pFile->pVfs = pVfs;
   pFile->h = h;
+  if( isReadonly ){
+    pFile->ctrlFlags |= WINFILE_RDONLY;
+  }
   if( sqlite3_uri_boolean(zName, "psow", SQLITE_POWERSAFE_OVERWRITE) ){
     pFile->ctrlFlags |= WINFILE_PSOW;
   }
   pFile->lastErrno = NO_ERROR;
   pFile->zPath = zName;
+#if SQLITE_MAX_MMAP_SIZE>0
+  pFile->hMap = NULL;
+  pFile->pMapRegion = 0;
+  pFile->mmapSize = 0;
+  pFile->mmapSizeActual = 0;
+  pFile->mmapSizeMax = sqlite3GlobalConfig.szMmap;
+#endif
 
   OpenCounter(+1);
   return rc;
@@ -34058,6 +35000,8 @@ static int winDelete(
   UNUSED_PARAMETER(syncDir);
 
   SimulateIOError(return SQLITE_IOERR_DELETE);
+  OSTRACE(("DELETE name=%s, syncDir=%d\n", zFilename, syncDir));
+
   zConverted = convertUtf8Filename(zFilename);
   if( zConverted==0 ){
     return SQLITE_IOERR_NOMEM;
@@ -34143,7 +35087,7 @@ static int winDelete(
     logIoerr(cnt);
   }
   sqlite3_free(zConverted);
-  OSTRACE(("DELETE \"%s\" %s\n", zFilename, (rc ? "failed" : "ok" )));
+  OSTRACE(("DELETE name=%s, rc=%s\n", zFilename, sqlite3ErrName(rc)));
   return rc;
 }
 
@@ -34163,8 +35107,12 @@ static int winAccess(
   UNUSED_PARAMETER(pVfs);
 
   SimulateIOError( return SQLITE_IOERR_ACCESS; );
+  OSTRACE(("ACCESS name=%s, flags=%x, pResOut=%p\n",
+           zFilename, flags, pResOut));
+
   zConverted = convertUtf8Filename(zFilename);
   if( zConverted==0 ){
+    OSTRACE(("ACCESS name=%s, rc=SQLITE_IOERR_NOMEM\n", zFilename));
     return SQLITE_IOERR_NOMEM;
   }
   if( isNT() ){
@@ -34215,6 +35163,8 @@ static int winAccess(
       assert(!"Invalid flags argument");
   }
   *pResOut = rc;
+  OSTRACE(("ACCESS name=%s, pResOut=%p, *pResOut=%d, rc=SQLITE_OK\n",
+           zFilename, pResOut, *pResOut));
   return SQLITE_OK;
 }
 
@@ -34655,7 +35605,6 @@ SQLITE_API int sqlite3_os_init(void){
   ** correctly.  See ticket [bb3a86e890c8e96ab] */
   assert( ArraySize(aSyscall)==74 );
 
-#ifndef SQLITE_OMIT_WAL
   /* get memory map allocation granularity */
   memset(&winSysInfo, 0, sizeof(SYSTEM_INFO));
 #if SQLITE_OS_WINRT
@@ -34663,8 +35612,8 @@ SQLITE_API int sqlite3_os_init(void){
 #else
   osGetSystemInfo(&winSysInfo);
 #endif
-  assert(winSysInfo.dwAllocationGranularity > 0);
-#endif
+  assert( winSysInfo.dwAllocationGranularity>0 );
+  assert( winSysInfo.dwPageSize>0 );
 
   sqlite3_vfs_register(&winVfs, 1);
   return SQLITE_OK; 
@@ -37301,7 +38250,6 @@ SQLITE_PRIVATE int sqlite3RowSetTest(RowSet *pRowSet, u8 iBatch, sqlite3_int64 i
 # define sqlite3WalClose(w,x,y,z)                0
 # define sqlite3WalBeginReadTransaction(y,z)     0
 # define sqlite3WalEndReadTransaction(z)
-# define sqlite3WalRead(v,w,x,y,z)               0
 # define sqlite3WalDbsize(y)                     0
 # define sqlite3WalBeginWriteTransaction(y)      0
 # define sqlite3WalEndWriteTransaction(x)        0
@@ -37314,6 +38262,7 @@ SQLITE_PRIVATE int sqlite3RowSetTest(RowSet *pRowSet, u8 iBatch, sqlite3_int64 i
 # define sqlite3WalExclusiveMode(y,z)            0
 # define sqlite3WalHeapMemory(z)                 0
 # define sqlite3WalFramesize(z)                  0
+# define sqlite3WalFindFrame(x,y,z)              0
 #else
 
 #define WAL_SAVEPOINT_NDATA 4
@@ -37341,7 +38290,8 @@ SQLITE_PRIVATE int sqlite3WalBeginReadTransaction(Wal *pWal, int *);
 SQLITE_PRIVATE void sqlite3WalEndReadTransaction(Wal *pWal);
 
 /* Read a page from the write-ahead log, if it is present. */
-SQLITE_PRIVATE int sqlite3WalRead(Wal *pWal, Pgno pgno, int *pInWal, int nOut, u8 *pOut);
+SQLITE_PRIVATE int sqlite3WalFindFrame(Wal *, Pgno, u32 *);
+SQLITE_PRIVATE int sqlite3WalReadFrame(Wal *, u32, int, u8 *);
 
 /* If the WAL is not empty, return the size of the database. */
 SQLITE_PRIVATE Pgno sqlite3WalDbsize(Wal *pWal);
@@ -38041,6 +38991,11 @@ struct Pager {
   PagerSavepoint *aSavepoint; /* Array of active savepoints */
   int nSavepoint;             /* Number of elements in aSavepoint[] */
   char dbFileVers[16];        /* Changes whenever database file changes */
+
+  u8 bUseFetch;               /* True to use xFetch() */
+  int nMmapOut;               /* Number of mmap pages currently outstanding */
+  sqlite3_int64 szMmap;       /* Desired maximum mmap size */
+  PgHdr *pMmapFreelist;       /* List of free mmap page headers (pDirty) */
   /*
   ** End of the routinely-changing class members
   ***************************************************************************/
@@ -38151,6 +39106,16 @@ static const unsigned char aJournalMagic[] = {
 # define MEMDB pPager->memDb
 #endif
 
+/*
+** The macro USEFETCH is true if we are allowed to use the xFetch and xUnfetch
+** interfaces to access the database using memory-mapped I/O.
+*/
+#if SQLITE_MAX_MMAP_SIZE>0
+# define USEFETCH(x) ((x)->bUseFetch)
+#else
+# define USEFETCH(x) 0
+#endif
+
 /*
 ** The maximum legal page number is (2^31 - 1).
 */
@@ -39638,7 +40603,7 @@ static int pager_playback_one_page(
     i64 ofst = (pgno-1)*(i64)pPager->pageSize;
     testcase( !isSavepnt && pPg!=0 && (pPg->flags&PGHDR_NEED_SYNC)!=0 );
     assert( !pagerUseWal(pPager) );
-    rc = sqlite3OsWrite(pPager->fd, (u8*)aData, pPager->pageSize, ofst);
+    rc = sqlite3OsWrite(pPager->fd, (u8 *)aData, pPager->pageSize, ofst);
     if( pgno>pPager->dbFileSize ){
       pPager->dbFileSize = pgno;
     }
@@ -40029,6 +40994,7 @@ static int pager_playback(Pager *pPager, int isHot){
   int res = 1;             /* Value returned by sqlite3OsAccess() */
   char *zMaster = 0;       /* Name of master journal file if any */
   int needPagerReset;      /* True to reset page prior to first page rollback */
+  int nPlayback = 0;       /* Total number of pages restored from journal */
 
   /* Figure out how many records are in the journal.  Abort early if
   ** the journal is empty.
@@ -40129,7 +41095,9 @@ static int pager_playback(Pager *pPager, int isHot){
         needPagerReset = 0;
       }
       rc = pager_playback_one_page(pPager,&pPager->journalOff,0,1,0);
-      if( rc!=SQLITE_OK ){
+      if( rc==SQLITE_OK ){
+        nPlayback++;
+      }else{
         if( rc==SQLITE_DONE ){
           pPager->journalOff = szJ;
           break;
@@ -40199,6 +41167,10 @@ end_playback:
     rc = pager_delmaster(pPager, zMaster);
     testcase( rc!=SQLITE_OK );
   }
+  if( isHot && nPlayback ){
+    sqlite3_log(SQLITE_NOTICE_RECOVER_ROLLBACK, "recovered %d pages from %s",
+                nPlayback, pPager->zJournal);
+  }
 
   /* The Pager.sectorSize variable may have been updated while rolling
   ** back a journal created by a process with a different sector size
@@ -40220,11 +41192,10 @@ end_playback:
 ** If an IO error occurs, then the IO error is returned to the caller.
 ** Otherwise, SQLITE_OK is returned.
 */
-static int readDbPage(PgHdr *pPg){
+static int readDbPage(PgHdr *pPg, u32 iFrame){
   Pager *pPager = pPg->pPager; /* Pager object associated with page pPg */
   Pgno pgno = pPg->pgno;       /* Page number to read */
   int rc = SQLITE_OK;          /* Return code */
-  int isInWal = 0;             /* True if page is in log file */
   int pgsz = pPager->pageSize; /* Number of bytes to read */
 
   assert( pPager->eState>=PAGER_READER && !MEMDB );
@@ -40236,11 +41207,13 @@ static int readDbPage(PgHdr *pPg){
     return SQLITE_OK;
   }
 
-  if( pagerUseWal(pPager) ){
+#ifndef SQLITE_OMIT_WAL
+  if( iFrame ){
     /* Try to pull the page from the write-ahead log. */
-    rc = sqlite3WalRead(pPager->pWal, pgno, &isInWal, pgsz, pPg->pData);
-  }
-  if( rc==SQLITE_OK && !isInWal ){
+    rc = sqlite3WalReadFrame(pPager->pWal, iFrame, pgsz, pPg->pData);
+  }else
+#endif
+  {
     i64 iOffset = (pgno-1)*(i64)pPager->pageSize;
     rc = sqlite3OsRead(pPager->fd, pPg->pData, pgsz, iOffset);
     if( rc==SQLITE_IOERR_SHORT_READ ){
@@ -40319,12 +41292,17 @@ static int pagerUndoCallback(void *pCtx, Pgno iPg){
   Pager *pPager = (Pager *)pCtx;
   PgHdr *pPg;
 
+  assert( pagerUseWal(pPager) );
   pPg = sqlite3PagerLookup(pPager, iPg);
   if( pPg ){
     if( sqlite3PcachePageRefcount(pPg)==1 ){
       sqlite3PcacheDrop(pPg);
     }else{
-      rc = readDbPage(pPg);
+      u32 iFrame = 0;
+      rc = sqlite3WalFindFrame(pPager->pWal, pPg->pgno, &iFrame);
+      if( rc==SQLITE_OK ){
+        rc = readDbPage(pPg, iFrame);
+      }
       if( rc==SQLITE_OK ){
         pPager->xReiniter(pPg);
       }
@@ -40468,6 +41446,7 @@ static int pagerBeginReadTransaction(Pager *pPager){
   rc = sqlite3WalBeginReadTransaction(pPager->pWal, &changed);
   if( rc!=SQLITE_OK || changed ){
     pager_reset(pPager);
+    if( USEFETCH(pPager) ) sqlite3OsUnfetch(pPager->fd, 0, 0);
   }
 
   return rc;
@@ -40729,6 +41708,29 @@ SQLITE_PRIVATE void sqlite3PagerSetCachesize(Pager *pPager, int mxPage){
   sqlite3PcacheSetCachesize(pPager->pPCache, mxPage);
 }
 
+/*
+** Invoke SQLITE_FCNTL_MMAP_SIZE based on the current value of szMmap.
+*/
+static void pagerFixMaplimit(Pager *pPager){
+#if SQLITE_MAX_MMAP_SIZE>0
+  sqlite3_file *fd = pPager->fd;
+  if( isOpen(fd) ){
+    sqlite3_int64 sz;
+    pPager->bUseFetch = (fd->pMethods->iVersion>=3) && pPager->szMmap>0;
+    sz = pPager->szMmap;
+    sqlite3OsFileControlHint(pPager->fd, SQLITE_FCNTL_MMAP_SIZE, &sz);
+  }
+#endif
+}
+
+/*
+** Change the maximum size of any memory mapping made of the database file.
+*/
+SQLITE_PRIVATE void sqlite3PagerSetMmapLimit(Pager *pPager, sqlite3_int64 szMmap){
+  pPager->szMmap = szMmap;
+  pagerFixMaplimit(pPager);
+}
+
 /*
 ** Free as much memory as possible from the pager.
 */
@@ -40964,6 +41966,7 @@ SQLITE_PRIVATE int sqlite3PagerSetPagesize(Pager *pPager, u32 *pPageSize, int nR
     assert( nReserve>=0 && nReserve<1000 );
     pPager->nReserve = (i16)nReserve;
     pagerReportSize(pPager);
+    pagerFixMaplimit(pPager);
   }
   return rc;
 }
@@ -41189,6 +42192,81 @@ static int pagerSyncHotJournal(Pager *pPager){
   return rc;
 }
 
+/*
+** Obtain a reference to a memory mapped page object for page number pgno. 
+** The new object will use the pointer pData, obtained from xFetch().
+** If successful, set *ppPage to point to the new page reference
+** and return SQLITE_OK. Otherwise, return an SQLite error code and set
+** *ppPage to zero.
+**
+** Page references obtained by calling this function should be released
+** by calling pagerReleaseMapPage().
+*/
+static int pagerAcquireMapPage(
+  Pager *pPager,                  /* Pager object */
+  Pgno pgno,                      /* Page number */
+  void *pData,                    /* xFetch()'d data for this page */
+  PgHdr **ppPage                  /* OUT: Acquired page object */
+){
+  PgHdr *p;                       /* Memory mapped page to return */
+
+  if( pPager->pMmapFreelist ){
+    *ppPage = p = pPager->pMmapFreelist;
+    pPager->pMmapFreelist = p->pDirty;
+    p->pDirty = 0;
+    memset(p->pExtra, 0, pPager->nExtra);
+  }else{
+    *ppPage = p = (PgHdr *)sqlite3MallocZero(sizeof(PgHdr) + pPager->nExtra);
+    if( p==0 ){
+      sqlite3OsUnfetch(pPager->fd, (i64)(pgno-1) * pPager->pageSize, pData);
+      return SQLITE_NOMEM;
+    }
+    p->pExtra = (void *)&p[1];
+    p->flags = PGHDR_MMAP;
+    p->nRef = 1;
+    p->pPager = pPager;
+  }
+
+  assert( p->pExtra==(void *)&p[1] );
+  assert( p->pPage==0 );
+  assert( p->flags==PGHDR_MMAP );
+  assert( p->pPager==pPager );
+  assert( p->nRef==1 );
+
+  p->pgno = pgno;
+  p->pData = pData;
+  pPager->nMmapOut++;
+
+  return SQLITE_OK;
+}
+
+/*
+** Release a reference to page pPg. pPg must have been returned by an 
+** earlier call to pagerAcquireMapPage().
+*/
+static void pagerReleaseMapPage(PgHdr *pPg){
+  Pager *pPager = pPg->pPager;
+  pPager->nMmapOut--;
+  pPg->pDirty = pPager->pMmapFreelist;
+  pPager->pMmapFreelist = pPg;
+
+  assert( pPager->fd->pMethods->iVersion>=3 );
+  sqlite3OsUnfetch(pPager->fd, (i64)(pPg->pgno-1)*pPager->pageSize, pPg->pData);
+}
+
+/*
+** Free all PgHdr objects stored in the Pager.pMmapFreelist list.
+*/
+static void pagerFreeMapHdrs(Pager *pPager){
+  PgHdr *p;
+  PgHdr *pNext;
+  for(p=pPager->pMmapFreelist; p; p=pNext){
+    pNext = p->pDirty;
+    sqlite3_free(p);
+  }
+}
+
+
 /*
 ** Shutdown the page cache.  Free all memory and close all files.
 **
@@ -41209,6 +42287,7 @@ SQLITE_PRIVATE int sqlite3PagerClose(Pager *pPager){
   assert( assert_pager_state(pPager) );
   disable_simulated_io_errors();
   sqlite3BeginBenignMalloc();
+  pagerFreeMapHdrs(pPager);
   /* pPager->errCode = 0; */
   pPager->exclusiveMode = 0;
 #ifndef SQLITE_OMIT_WAL
@@ -41470,7 +42549,9 @@ static int pager_write_pagelist(Pager *pPager, PgHdr *pList){
   ** file size will be.
   */
   assert( rc!=SQLITE_OK || isOpen(pPager->fd) );
-  if( rc==SQLITE_OK && pPager->dbSize>pPager->dbHintSize ){
+  if( rc==SQLITE_OK 
+   && (pList->pDirty ? pPager->dbSize : pList->pgno+1)>pPager->dbHintSize 
+  ){
     sqlite3_int64 szFile = pPager->pageSize * (sqlite3_int64)pPager->dbSize;
     sqlite3OsFileControlHint(pPager->fd, SQLITE_FCNTL_SIZE_HINT, &szFile);
     pPager->dbHintSize = pPager->dbSize;
@@ -42024,6 +43105,7 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
   /* pPager->pBusyHandlerArg = 0; */
   pPager->xReiniter = xReinit;
   /* memset(pPager->aHash, 0, sizeof(pPager->aHash)); */
+  /* pPager->szMmap = SQLITE_DEFAULT_MMAP_SIZE // will be set by btree.c */
 
   *ppPager = pPager;
   return SQLITE_OK;
@@ -42315,9 +43397,11 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){
       );
     }
 
-    if( !pPager->tempFile 
-     && (pPager->pBackup || sqlite3PcachePagecount(pPager->pPCache)>0) 
-    ){
+    if( !pPager->tempFile && (
+        pPager->pBackup 
+     || sqlite3PcachePagecount(pPager->pPCache)>0 
+     || USEFETCH(pPager)
+    )){
       /* The shared-lock has just been acquired on the database file
       ** and there are already pages in the cache (from a previous
       ** read or write transaction).  Check to see if the database
@@ -42343,7 +43427,7 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){
       if( nPage>0 ){
         IOTRACE(("CKVERS %p %d\n", pPager, sizeof(dbFileVers)));
         rc = sqlite3OsRead(pPager->fd, &dbFileVers, sizeof(dbFileVers), 24);
-        if( rc!=SQLITE_OK ){
+        if( rc!=SQLITE_OK && rc!=SQLITE_IOERR_SHORT_READ ){
           goto failed;
         }
       }else{
@@ -42352,6 +43436,16 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){
 
       if( memcmp(pPager->dbFileVers, dbFileVers, sizeof(dbFileVers))!=0 ){
         pager_reset(pPager);
+
+        /* Unmap the database file. It is possible that external processes
+        ** may have truncated the database file and then extended it back
+        ** to its original size while this process was not holding a lock.
+        ** In this case there may exist a Pager.pMap mapping that appears
+        ** to be the right size but is not actually valid. Avoid this
+        ** possibility by unmapping the db here. */
+        if( USEFETCH(pPager) ){
+          sqlite3OsUnfetch(pPager->fd, 0, 0);
+        }
       }
     }
 
@@ -42393,7 +43487,7 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){
 ** nothing to rollback, so this routine is a no-op.
 */ 
 static void pagerUnlockIfUnused(Pager *pPager){
-  if( (sqlite3PcacheRefCount(pPager->pPCache)==0) ){
+  if( pPager->nMmapOut==0 && (sqlite3PcacheRefCount(pPager->pPCache)==0) ){
     pagerUnlockAndRollback(pPager);
   }
 }
@@ -42452,13 +43546,27 @@ SQLITE_PRIVATE int sqlite3PagerAcquire(
   Pager *pPager,      /* The pager open on the database file */
   Pgno pgno,          /* Page number to fetch */
   DbPage **ppPage,    /* Write a pointer to the page here */
-  int noContent       /* Do not bother reading content from disk if true */
+  int flags           /* PAGER_ACQUIRE_XXX flags */
 ){
-  int rc;
-  PgHdr *pPg;
+  int rc = SQLITE_OK;
+  PgHdr *pPg = 0;
+  u32 iFrame = 0;                 /* Frame to read from WAL file */
+  const int noContent = (flags & PAGER_ACQUIRE_NOCONTENT);
+
+  /* It is acceptable to use a read-only (mmap) page for any page except
+  ** page 1 if there is no write-transaction open or the ACQUIRE_READONLY
+  ** flag was specified by the caller. And so long as the db is not a 
+  ** temporary or in-memory database.  */
+  const int bMmapOk = (pgno!=1 && USEFETCH(pPager)
+   && (pPager->eState==PAGER_READER || (flags & PAGER_ACQUIRE_READONLY))
+#ifdef SQLITE_HAS_CODEC
+   && pPager->xCodec==0
+#endif
+  );
 
   assert( pPager->eState>=PAGER_READER );
   assert( assert_pager_state(pPager) );
+  assert( noContent==0 || bMmapOk==0 );
 
   if( pgno==0 ){
     return SQLITE_CORRUPT_BKPT;
@@ -42469,6 +43577,39 @@ SQLITE_PRIVATE int sqlite3PagerAcquire(
   if( pPager->errCode!=SQLITE_OK ){
     rc = pPager->errCode;
   }else{
+
+    if( bMmapOk && pagerUseWal(pPager) ){
+      rc = sqlite3WalFindFrame(pPager->pWal, pgno, &iFrame);
+      if( rc!=SQLITE_OK ) goto pager_acquire_err;
+    }
+
+    if( iFrame==0 && bMmapOk ){
+      void *pData = 0;
+
+      rc = sqlite3OsFetch(pPager->fd, 
+          (i64)(pgno-1) * pPager->pageSize, pPager->pageSize, &pData
+      );
+
+      if( rc==SQLITE_OK && pData ){
+        if( pPager->eState>PAGER_READER ){
+          (void)sqlite3PcacheFetch(pPager->pPCache, pgno, 0, &pPg);
+        }
+        if( pPg==0 ){
+          rc = pagerAcquireMapPage(pPager, pgno, pData, &pPg);
+        }else{
+          sqlite3OsUnfetch(pPager->fd, (i64)(pgno-1)*pPager->pageSize, pData);
+        }
+        if( pPg ){
+          assert( rc==SQLITE_OK );
+          *ppPage = pPg;
+          return SQLITE_OK;
+        }
+      }
+      if( rc!=SQLITE_OK ){
+        goto pager_acquire_err;
+      }
+    }
+
     rc = sqlite3PcacheFetch(pPager->pPCache, pgno, 1, ppPage);
   }
 
@@ -42527,9 +43668,13 @@ SQLITE_PRIVATE int sqlite3PagerAcquire(
       memset(pPg->pData, 0, pPager->pageSize);
       IOTRACE(("ZERO %p %d\n", pPager, pgno));
     }else{
+      if( pagerUseWal(pPager) && bMmapOk==0 ){
+        rc = sqlite3WalFindFrame(pPager->pWal, pgno, &iFrame);
+        if( rc!=SQLITE_OK ) goto pager_acquire_err;
+      }
       assert( pPg->pPager==pPager );
       pPager->aStat[PAGER_STAT_MISS]++;
-      rc = readDbPage(pPg);
+      rc = readDbPage(pPg, iFrame);
       if( rc!=SQLITE_OK ){
         goto pager_acquire_err;
       }
@@ -42582,7 +43727,11 @@ SQLITE_PRIVATE DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno){
 SQLITE_PRIVATE void sqlite3PagerUnref(DbPage *pPg){
   if( pPg ){
     Pager *pPager = pPg->pPager;
-    sqlite3PcacheRelease(pPg);
+    if( pPg->flags & PGHDR_MMAP ){
+      pagerReleaseMapPage(pPg);
+    }else{
+      sqlite3PcacheRelease(pPg);
+    }
     pagerUnlockIfUnused(pPager);
   }
 }
@@ -42917,6 +44066,7 @@ SQLITE_PRIVATE int sqlite3PagerWrite(DbPage *pDbPage){
   Pager *pPager = pPg->pPager;
   Pgno nPagePerSector = (pPager->sectorSize/pPager->pageSize);
 
+  assert( (pPg->flags & PGHDR_MMAP)==0 );
   assert( pPager->eState>=PAGER_WRITER_LOCKED );
   assert( pPager->eState!=PAGER_ERROR );
   assert( assert_pager_state(pPager) );
@@ -43116,6 +44266,11 @@ static int pager_incr_changecounter(Pager *pPager, int isDirectMode){
           pPager->aStat[PAGER_STAT_WRITE]++;
         }
         if( rc==SQLITE_OK ){
+          /* Update the pager's copy of the change-counter. Otherwise, the
+          ** next time a read transaction is opened the cache will be
+          ** flushed (as the change-counter values will not match).  */
+          const void *pCopy = (const void *)&((const char *)zBuf)[24];
+          memcpy(&pPager->dbFileVers, pCopy, sizeof(pPager->dbFileVers));
           pPager->changeCountDone = 1;
         }
       }else{
@@ -43473,7 +44628,7 @@ SQLITE_PRIVATE int sqlite3PagerRollback(Pager *pPager){
   }
 
   assert( pPager->eState==PAGER_READER || rc!=SQLITE_OK );
-  assert( rc==SQLITE_OK || rc==SQLITE_FULL
+  assert( rc==SQLITE_OK || rc==SQLITE_FULL || rc==SQLITE_CORRUPT
           || rc==SQLITE_NOMEM || (rc&0xFF)==SQLITE_IOERR );
 
   /* If an error occurs during a ROLLBACK, we can no longer trust the pager
@@ -44207,11 +45362,12 @@ static int pagerOpenWal(Pager *pPager){
   ** (e.g. due to malloc() failure), return an error code.
   */
   if( rc==SQLITE_OK ){
-    rc = sqlite3WalOpen(pPager->pVfs, 
+    rc = sqlite3WalOpen(pPager->pVfs,
         pPager->fd, pPager->zWal, pPager->exclusiveMode,
         pPager->journalSizeLimit, &pPager->pWal
     );
   }
+  pagerFixMaplimit(pPager);
 
   return rc;
 }
@@ -44302,6 +45458,7 @@ SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager){
       rc = sqlite3WalClose(pPager->pWal, pPager->ckptSyncFlags,
                            pPager->pageSize, (u8*)pPager->pTmpSpace);
       pPager->pWal = 0;
+      pagerFixMaplimit(pPager);
     }
   }
   return rc;
@@ -45550,8 +46707,9 @@ finished:
     ** checkpointing the log file.
     */
     if( pWal->hdr.nPage ){
-      sqlite3_log(SQLITE_OK, "Recovered %d frames from WAL file %s",
-          pWal->hdr.nPage, pWal->zWalName
+      sqlite3_log(SQLITE_NOTICE_RECOVER_WAL,
+          "recovered %d frames from WAL file %s",
+          pWal->hdr.mxFrame, pWal->zWalName
       );
     }
   }
@@ -46065,8 +47223,8 @@ static int walCheckpoint(
       rc = sqlite3OsSync(pWal->pWalFd, sync_flags);
     }
 
-    /* If the database file may grow as a result of this checkpoint, hint
-    ** about the eventual size of the db file to the VFS layer. 
+    /* If the database may grow as a result of this checkpoint, hint
+    ** about the eventual size of the db file to the VFS layer.
     */
     if( rc==SQLITE_OK ){
       i64 nReq = ((i64)mxPage * szPage);
@@ -46076,6 +47234,7 @@ static int walCheckpoint(
       }
     }
 
+
     /* Iterate through the contents of the WAL, copying data to the db file. */
     while( rc==SQLITE_OK && 0==walIteratorNext(pIter, &iDbpage, &iFrame) ){
       i64 iOffset;
@@ -46630,19 +47789,17 @@ SQLITE_PRIVATE void sqlite3WalEndReadTransaction(Wal *pWal){
 }
 
 /*
-** Read a page from the WAL, if it is present in the WAL and if the 
-** current read transaction is configured to use the WAL.  
+** Search the wal file for page pgno. If found, set *piRead to the frame that
+** contains the page. Otherwise, if pgno is not in the wal file, set *piRead
+** to zero.
 **
-** The *pInWal is set to 1 if the requested page is in the WAL and
-** has been loaded.  Or *pInWal is set to 0 if the page was not in 
-** the WAL and needs to be read out of the database.
+** Return SQLITE_OK if successful, or an error code if an error occurs. If an
+** error does occur, the final value of *piRead is undefined.
 */
-SQLITE_PRIVATE int sqlite3WalRead(
+SQLITE_PRIVATE int sqlite3WalFindFrame(
   Wal *pWal,                      /* WAL handle */
   Pgno pgno,                      /* Database page number to read data for */
-  int *pInWal,                    /* OUT: True if data is read from WAL */
-  int nOut,                       /* Size of buffer pOut in bytes */
-  u8 *pOut                        /* Buffer to write page data to */
+  u32 *piRead                     /* OUT: Frame number (or zero) */
 ){
   u32 iRead = 0;                  /* If !=0, WAL frame to return data from */
   u32 iLast = pWal->hdr.mxFrame;  /* Last page in WAL for this reader */
@@ -46658,7 +47815,7 @@ SQLITE_PRIVATE int sqlite3WalRead(
   ** WAL were empty.
   */
   if( iLast==0 || pWal->readLock==0 ){
-    *pInWal = 0;
+    *piRead = 0;
     return SQLITE_OK;
   }
 
@@ -46729,26 +47886,31 @@ SQLITE_PRIVATE int sqlite3WalRead(
   }
 #endif
 
-  /* If iRead is non-zero, then it is the log frame number that contains the
-  ** required page. Read and return data from the log file.
-  */
-  if( iRead ){
-    int sz;
-    i64 iOffset;
-    sz = pWal->hdr.szPage;
-    sz = (sz&0xfe00) + ((sz&0x0001)<<16);
-    testcase( sz<=32768 );
-    testcase( sz>=65536 );
-    iOffset = walFrameOffset(iRead, sz) + WAL_FRAME_HDRSIZE;
-    *pInWal = 1;
-    /* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL */
-    return sqlite3OsRead(pWal->pWalFd, pOut, (nOut>sz ? sz : nOut), iOffset);
-  }
-
-  *pInWal = 0;
+  *piRead = iRead;
   return SQLITE_OK;
 }
 
+/*
+** Read the contents of frame iRead from the wal file into buffer pOut
+** (which is nOut bytes in size). Return SQLITE_OK if successful, or an
+** error code otherwise.
+*/
+SQLITE_PRIVATE int sqlite3WalReadFrame(
+  Wal *pWal,                      /* WAL handle */
+  u32 iRead,                      /* Frame to read */
+  int nOut,                       /* Size of buffer pOut in bytes */
+  u8 *pOut                        /* Buffer to write page data to */
+){
+  int sz;
+  i64 iOffset;
+  sz = pWal->hdr.szPage;
+  sz = (sz&0xfe00) + ((sz&0x0001)<<16);
+  testcase( sz<=32768 );
+  testcase( sz>=65536 );
+  iOffset = walFrameOffset(iRead, sz) + WAL_FRAME_HDRSIZE;
+  /* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL */
+  return sqlite3OsRead(pWal->pWalFd, pOut, (nOut>sz ? sz : nOut), iOffset);
+}
 
 /* 
 ** Return the size of the database in pages (or zero, if unknown).
@@ -47295,6 +48457,9 @@ SQLITE_PRIVATE int sqlite3WalCheckpoint(
   /* Read the wal-index header. */
   if( rc==SQLITE_OK ){
     rc = walIndexReadHdr(pWal, &isChanged);
+    if( isChanged && pWal->pDbFd->pMethods->iVersion>=3 ){
+      sqlite3OsUnfetch(pWal->pDbFd, 0, 0);
+    }
   }
 
   /* Copy data from the log to the database file. */
@@ -49966,13 +51131,17 @@ static int btreeGetPage(
   BtShared *pBt,       /* The btree */
   Pgno pgno,           /* Number of the page to fetch */
   MemPage **ppPage,    /* Return the page in this parameter */
-  int noContent        /* Do not load page content if true */
+  int noContent,       /* Do not load page content if true */
+  int bReadonly        /* True if a read-only (mmap) page is ok */
 ){
   int rc;
   DbPage *pDbPage;
+  int flags = (noContent ? PAGER_ACQUIRE_NOCONTENT : 0) 
+            | (bReadonly ? PAGER_ACQUIRE_READONLY : 0);
 
+  assert( noContent==0 || bReadonly==0 );
   assert( sqlite3_mutex_held(pBt->mutex) );
-  rc = sqlite3PagerAcquire(pBt->pPager, pgno, (DbPage**)&pDbPage, noContent);
+  rc = sqlite3PagerAcquire(pBt->pPager, pgno, (DbPage**)&pDbPage, flags);
   if( rc ) return rc;
   *ppPage = btreePageFromDbPage(pDbPage, pgno, pBt);
   return SQLITE_OK;
@@ -50015,9 +51184,10 @@ SQLITE_PRIVATE u32 sqlite3BtreeLastPage(Btree *p){
 ** may remain unchanged, or it may be set to an invalid value.
 */
 static int getAndInitPage(
-  BtShared *pBt,          /* The database file */
-  Pgno pgno,           /* Number of the page to get */
-  MemPage **ppPage     /* Write the page pointer here */
+  BtShared *pBt,                  /* The database file */
+  Pgno pgno,                      /* Number of the page to get */
+  MemPage **ppPage,               /* Write the page pointer here */
+  int bReadonly                   /* True if a read-only (mmap) page is ok */
 ){
   int rc;
   assert( sqlite3_mutex_held(pBt->mutex) );
@@ -50025,7 +51195,7 @@ static int getAndInitPage(
   if( pgno>btreePagecount(pBt) ){
     rc = SQLITE_CORRUPT_BKPT;
   }else{
-    rc = btreeGetPage(pBt, pgno, ppPage, 0);
+    rc = btreeGetPage(pBt, pgno, ppPage, 0, bReadonly);
     if( rc==SQLITE_OK ){
       rc = btreeInitPage(*ppPage);
       if( rc!=SQLITE_OK ){
@@ -50256,6 +51426,7 @@ SQLITE_PRIVATE int sqlite3BtreeOpen(
     rc = sqlite3PagerOpen(pVfs, &pBt->pPager, zFilename,
                           EXTRA_SIZE, flags, vfsFlags, pageReinit);
     if( rc==SQLITE_OK ){
+      sqlite3PagerSetMmapLimit(pBt->pPager, db->szMmap);
       rc = sqlite3PagerReadFileheader(pBt->pPager,sizeof(zDbHeader),zDbHeader);
     }
     if( rc!=SQLITE_OK ){
@@ -50522,6 +51693,19 @@ SQLITE_PRIVATE int sqlite3BtreeSetCacheSize(Btree *p, int mxPage){
   return SQLITE_OK;
 }
 
+/*
+** Change the limit on the amount of the database file that may be
+** memory mapped.
+*/
+SQLITE_PRIVATE int sqlite3BtreeSetMmapLimit(Btree *p, sqlite3_int64 szMmap){
+  BtShared *pBt = p->pBt;
+  assert( sqlite3_mutex_held(p->db->mutex) );
+  sqlite3BtreeEnter(p);
+  sqlite3PagerSetMmapLimit(pBt->pPager, szMmap);
+  sqlite3BtreeLeave(p);
+  return SQLITE_OK;
+}
+
 /*
 ** Change the way data is synced to disk in order to increase or decrease
 ** how well the database resists damage due to OS crashes and power
@@ -50747,7 +51931,7 @@ static int lockBtree(BtShared *pBt){
   assert( pBt->pPage1==0 );
   rc = sqlite3PagerSharedLock(pBt->pPager);
   if( rc!=SQLITE_OK ) return rc;
-  rc = btreeGetPage(pBt, 1, &pPage1, 0);
+  rc = btreeGetPage(pBt, 1, &pPage1, 0, 0);
   if( rc!=SQLITE_OK ) return rc;
 
   /* Do some checking to help insure the file we opened really is
@@ -50883,6 +52067,29 @@ page1_init_failed:
   return rc;
 }
 
+#ifndef NDEBUG
+/*
+** Return the number of cursors open on pBt. This is for use
+** in assert() expressions, so it is only compiled if NDEBUG is not
+** defined.
+**
+** Only write cursors are counted if wrOnly is true.  If wrOnly is
+** false then all cursors are counted.
+**
+** For the purposes of this routine, a cursor is any cursor that
+** is capable of reading or writing to the databse.  Cursors that
+** have been tripped into the CURSOR_FAULT state are not counted.
+*/
+static int countValidCursors(BtShared *pBt, int wrOnly){
+  BtCursor *pCur;
+  int r = 0;
+  for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){
+    if( (wrOnly==0 || pCur->wrFlag) && pCur->eState!=CURSOR_FAULT ) r++; 
+  }
+  return r;
+}
+#endif
+
 /*
 ** If there are no outstanding cursors and we are not in the middle
 ** of a transaction but there is a read lock on the database, then
@@ -50893,7 +52100,7 @@ page1_init_failed:
 */
 static void unlockBtreeIfUnused(BtShared *pBt){
   assert( sqlite3_mutex_held(pBt->mutex) );
-  assert( pBt->pCursor==0 || pBt->inTransaction>TRANS_NONE );
+  assert( countValidCursors(pBt,0)==0 || pBt->inTransaction>TRANS_NONE );
   if( pBt->inTransaction==TRANS_NONE && pBt->pPage1!=0 ){
     assert( pBt->pPage1->aData );
     assert( sqlite3PagerRefcount(pBt->pPager)==1 );
@@ -51306,7 +52513,7 @@ static int relocatePage(
   ** iPtrPage.
   */
   if( eType!=PTRMAP_ROOTPAGE ){
-    rc = btreeGetPage(pBt, iPtrPage, &pPtrPage, 0);
+    rc = btreeGetPage(pBt, iPtrPage, &pPtrPage, 0, 0);
     if( rc!=SQLITE_OK ){
       return rc;
     }
@@ -51390,7 +52597,7 @@ static int incrVacuumStep(BtShared *pBt, Pgno nFin, Pgno iLastPg, int bCommit){
       u8 eMode = BTALLOC_ANY;   /* Mode parameter for allocateBtreePage() */
       Pgno iNear = 0;           /* nearby parameter for allocateBtreePage() */
 
-      rc = btreeGetPage(pBt, iLastPg, &pLastPg, 0);
+      rc = btreeGetPage(pBt, iLastPg, &pLastPg, 0, 0);
       if( rc!=SQLITE_OK ){
         return rc;
       }
@@ -51482,8 +52689,11 @@ SQLITE_PRIVATE int sqlite3BtreeIncrVacuum(Btree *p){
     if( nOrig<nFin ){
       rc = SQLITE_CORRUPT_BKPT;
     }else if( nFree>0 ){
-      invalidateAllOverflowCache(pBt);
-      rc = incrVacuumStep(pBt, nFin, nOrig, 0);
+      rc = saveAllCursors(pBt, 0, 0);
+      if( rc==SQLITE_OK ){
+        invalidateAllOverflowCache(pBt);
+        rc = incrVacuumStep(pBt, nFin, nOrig, 0);
+      }
       if( rc==SQLITE_OK ){
         rc = sqlite3PagerWrite(pBt->pPage1->pDbPage);
         put4byte(&pBt->pPage1->aData[28], pBt->nPage);
@@ -51531,7 +52741,9 @@ static int autoVacuumCommit(BtShared *pBt){
     nFree = get4byte(&pBt->pPage1->aData[36]);
     nFin = finalDbSize(pBt, nOrig, nFree);
     if( nFin>nOrig ) return SQLITE_CORRUPT_BKPT;
-
+    if( nFin<nOrig ){
+      rc = saveAllCursors(pBt, 0, 0);
+    }
     for(iFree=nOrig; iFree>nFin && rc==SQLITE_OK; iFree--){
       rc = incrVacuumStep(pBt, nFin, iFree, 1);
     }
@@ -51548,7 +52760,7 @@ static int autoVacuumCommit(BtShared *pBt){
     }
   }
 
-  assert( nRef==sqlite3PagerRefcount(pPager) );
+  assert( nRef>=sqlite3PagerRefcount(pPager) );
   return rc;
 }
 
@@ -51616,7 +52828,6 @@ static void btreeEndTransaction(Btree *p){
 #ifndef SQLITE_OMIT_AUTOVACUUM
   pBt->bDoTruncate = 0;
 #endif
-  btreeClearHasContent(pBt);
   if( p->inTrans>TRANS_NONE && p->db->activeVdbeCnt>1 ){
     /* If there are other active statements that belong to this database
     ** handle, downgrade to a read-only transaction. The other statements
@@ -51691,6 +52902,7 @@ SQLITE_PRIVATE int sqlite3BtreeCommitPhaseTwo(Btree *p, int bCleanup){
       return rc;
     }
     pBt->inTransaction = TRANS_READ;
+    btreeClearHasContent(pBt);
   }
 
   btreeEndTransaction(p);
@@ -51712,27 +52924,6 @@ SQLITE_PRIVATE int sqlite3BtreeCommit(Btree *p){
   return rc;
 }
 
-#ifndef NDEBUG
-/*
-** Return the number of write-cursors open on this handle. This is for use
-** in assert() expressions, so it is only compiled if NDEBUG is not
-** defined.
-**
-** For the purposes of this routine, a write-cursor is any cursor that
-** is capable of writing to the databse.  That means the cursor was
-** originally opened for writing and the cursor has not be disabled
-** by having its state changed to CURSOR_FAULT.
-*/
-static int countWriteCursors(BtShared *pBt){
-  BtCursor *pCur;
-  int r = 0;
-  for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){
-    if( pCur->wrFlag && pCur->eState!=CURSOR_FAULT ) r++; 
-  }
-  return r;
-}
-#endif
-
 /*
 ** This routine sets the state to CURSOR_FAULT and the error
 ** code to errCode for every cursor on BtShared that pBtree
@@ -51804,7 +52995,7 @@ SQLITE_PRIVATE int sqlite3BtreeRollback(Btree *p, int tripCode){
     /* The rollback may have destroyed the pPage1->aData value.  So
     ** call btreeGetPage() on page 1 again to make
     ** sure pPage1->aData is set correctly. */
-    if( btreeGetPage(pBt, 1, &pPage1, 0)==SQLITE_OK ){
+    if( btreeGetPage(pBt, 1, &pPage1, 0, 0)==SQLITE_OK ){
       int nPage = get4byte(28+(u8*)pPage1->aData);
       testcase( nPage==0 );
       if( nPage==0 ) sqlite3PagerPagecount(pBt->pPager, &nPage);
@@ -51812,8 +53003,9 @@ SQLITE_PRIVATE int sqlite3BtreeRollback(Btree *p, int tripCode){
       pBt->nPage = nPage;
       releasePage(pPage1);
     }
-    assert( countWriteCursors(pBt)==0 );
+    assert( countValidCursors(pBt, 1)==0 );
     pBt->inTransaction = TRANS_READ;
+    btreeClearHasContent(pBt);
   }
 
   btreeEndTransaction(p);
@@ -52238,7 +53430,7 @@ static int getOverflowPage(
 
   assert( next==0 || rc==SQLITE_DONE );
   if( rc==SQLITE_OK ){
-    rc = btreeGetPage(pBt, ovfl, &pPage, 0);
+    rc = btreeGetPage(pBt, ovfl, &pPage, 0, (ppPage==0));
     assert( rc==SQLITE_OK || pPage==0 );
     if( rc==SQLITE_OK ){
       next = get4byte(pPage->aData);
@@ -52459,7 +53651,9 @@ static int accessPayload(
 
         {
           DbPage *pDbPage;
-          rc = sqlite3PagerGet(pBt->pPager, nextPage, &pDbPage);
+          rc = sqlite3PagerAcquire(pBt->pPager, nextPage, &pDbPage,
+              (eOp==0 ? PAGER_ACQUIRE_READONLY : 0)
+          );
           if( rc==SQLITE_OK ){
             aPayload = sqlite3PagerGetData(pDbPage);
             nextPage = get4byte(aPayload);
@@ -52638,10 +53832,11 @@ static int moveToChild(BtCursor *pCur, u32 newPgno){
   assert( cursorHoldsMutex(pCur) );
   assert( pCur->eState==CURSOR_VALID );
   assert( pCur->iPage<BTCURSOR_MAX_DEPTH );
+  assert( pCur->iPage>=0 );
   if( pCur->iPage>=(BTCURSOR_MAX_DEPTH-1) ){
     return SQLITE_CORRUPT_BKPT;
   }
-  rc = getAndInitPage(pBt, newPgno, &pNewPage);
+  rc = getAndInitPage(pBt, newPgno, &pNewPage, (pCur->wrFlag==0));
   if( rc ) return rc;
   pCur->apPage[i+1] = pNewPage;
   pCur->aiIdx[i+1] = 0;
@@ -52758,7 +53953,7 @@ static int moveToRoot(BtCursor *pCur){
     pCur->eState = CURSOR_INVALID;
     return SQLITE_OK;
   }else{
-    rc = getAndInitPage(pBt, pCur->pgnoRoot, &pCur->apPage[0]);
+    rc = getAndInitPage(pBt, pCur->pgnoRoot, &pCur->apPage[0], pCur->wrFlag==0);
     if( rc!=SQLITE_OK ){
       pCur->eState = CURSOR_INVALID;
       return rc;
@@ -53372,7 +54567,7 @@ static int allocateBtreePage(
       if( iTrunk>mxPage ){
         rc = SQLITE_CORRUPT_BKPT;
       }else{
-        rc = btreeGetPage(pBt, iTrunk, &pTrunk, 0);
+        rc = btreeGetPage(pBt, iTrunk, &pTrunk, 0, 0);
       }
       if( rc ){
         pTrunk = 0;
@@ -53436,7 +54631,7 @@ static int allocateBtreePage(
             goto end_allocate_page;
           }
           testcase( iNewTrunk==mxPage );
-          rc = btreeGetPage(pBt, iNewTrunk, &pNewTrunk, 0);
+          rc = btreeGetPage(pBt, iNewTrunk, &pNewTrunk, 0, 0);
           if( rc!=SQLITE_OK ){
             goto end_allocate_page;
           }
@@ -53516,7 +54711,7 @@ static int allocateBtreePage(
           }
           put4byte(&aData[4], k-1);
           noContent = !btreeGetHasContent(pBt, *pPgno);
-          rc = btreeGetPage(pBt, *pPgno, ppPage, noContent);
+          rc = btreeGetPage(pBt, *pPgno, ppPage, noContent, 0);
           if( rc==SQLITE_OK ){
             rc = sqlite3PagerWrite((*ppPage)->pDbPage);
             if( rc!=SQLITE_OK ){
@@ -53564,7 +54759,7 @@ static int allocateBtreePage(
       MemPage *pPg = 0;
       TRACE(("ALLOCATE: %d from end of file (pointer-map page)\n", pBt->nPage));
       assert( pBt->nPage!=PENDING_BYTE_PAGE(pBt) );
-      rc = btreeGetPage(pBt, pBt->nPage, &pPg, bNoContent);
+      rc = btreeGetPage(pBt, pBt->nPage, &pPg, bNoContent, 0);
       if( rc==SQLITE_OK ){
         rc = sqlite3PagerWrite(pPg->pDbPage);
         releasePage(pPg);
@@ -53578,7 +54773,7 @@ static int allocateBtreePage(
     *pPgno = pBt->nPage;
 
     assert( *pPgno!=PENDING_BYTE_PAGE(pBt) );
-    rc = btreeGetPage(pBt, *pPgno, ppPage, bNoContent);
+    rc = btreeGetPage(pBt, *pPgno, ppPage, bNoContent, 0);
     if( rc ) return rc;
     rc = sqlite3PagerWrite((*ppPage)->pDbPage);
     if( rc!=SQLITE_OK ){
@@ -53646,7 +54841,7 @@ static int freePage2(BtShared *pBt, MemPage *pMemPage, Pgno iPage){
     /* If the secure_delete option is enabled, then
     ** always fully overwrite deleted information with zeros.
     */
-    if( (!pPage && ((rc = btreeGetPage(pBt, iPage, &pPage, 0))!=0) )
+    if( (!pPage && ((rc = btreeGetPage(pBt, iPage, &pPage, 0, 0))!=0) )
      ||            ((rc = sqlite3PagerWrite(pPage->pDbPage))!=0)
     ){
       goto freepage_out;
@@ -53673,7 +54868,7 @@ static int freePage2(BtShared *pBt, MemPage *pMemPage, Pgno iPage){
     u32 nLeaf;                /* Initial number of leaf cells on trunk page */
 
     iTrunk = get4byte(&pPage1->aData[32]);
-    rc = btreeGetPage(pBt, iTrunk, &pTrunk, 0);
+    rc = btreeGetPage(pBt, iTrunk, &pTrunk, 0, 0);
     if( rc!=SQLITE_OK ){
       goto freepage_out;
     }
@@ -53719,7 +54914,7 @@ static int freePage2(BtShared *pBt, MemPage *pMemPage, Pgno iPage){
   ** first trunk in the free-list is full. Either way, the page being freed
   ** will become the new first trunk page in the free-list.
   */
-  if( pPage==0 && SQLITE_OK!=(rc = btreeGetPage(pBt, iPage, &pPage, 0)) ){
+  if( pPage==0 && SQLITE_OK!=(rc = btreeGetPage(pBt, iPage, &pPage, 0, 0)) ){
     goto freepage_out;
   }
   rc = sqlite3PagerWrite(pPage->pDbPage);
@@ -54520,7 +55715,7 @@ static int balance_nonroot(
   }
   pgno = get4byte(pRight);
   while( 1 ){
-    rc = getAndInitPage(pBt, pgno, &apOld[i]);
+    rc = getAndInitPage(pBt, pgno, &apOld[i], 0);
     if( rc ){
       memset(apOld, 0, (i+1)*sizeof(MemPage*));
       goto balance_cleanup;
@@ -55608,10 +56803,17 @@ static int btreeCreateTable(Btree *p, int *piTable, int createTabFlags){
       u8 eType = 0;
       Pgno iPtrPage = 0;
 
+      /* Save the positions of any open cursors. This is required in
+      ** case they are holding a reference to an xFetch reference
+      ** corresponding to page pgnoRoot.  */
+      rc = saveAllCursors(pBt, 0, 0);
       releasePage(pPageMove);
+      if( rc!=SQLITE_OK ){
+        return rc;
+      }
 
       /* Move the page currently at pgnoRoot to pgnoMove. */
-      rc = btreeGetPage(pBt, pgnoRoot, &pRoot, 0);
+      rc = btreeGetPage(pBt, pgnoRoot, &pRoot, 0, 0);
       if( rc!=SQLITE_OK ){
         return rc;
       }
@@ -55632,7 +56834,7 @@ static int btreeCreateTable(Btree *p, int *piTable, int createTabFlags){
       if( rc!=SQLITE_OK ){
         return rc;
       }
-      rc = btreeGetPage(pBt, pgnoRoot, &pRoot, 0);
+      rc = btreeGetPage(pBt, pgnoRoot, &pRoot, 0, 0);
       if( rc!=SQLITE_OK ){
         return rc;
       }
@@ -55708,7 +56910,7 @@ static int clearDatabasePage(
     return SQLITE_CORRUPT_BKPT;
   }
 
-  rc = getAndInitPage(pBt, pgno, &pPage);
+  rc = getAndInitPage(pBt, pgno, &pPage, 0);
   if( rc ) return rc;
   for(i=0; i<pPage->nCell; i++){
     pCell = findCell(pPage, i);
@@ -55810,7 +57012,7 @@ static int btreeDropTable(Btree *p, Pgno iTable, int *piMoved){
     return SQLITE_LOCKED_SHAREDCACHE;
   }
 
-  rc = btreeGetPage(pBt, (Pgno)iTable, &pPage, 0);
+  rc = btreeGetPage(pBt, (Pgno)iTable, &pPage, 0, 0);
   if( rc ) return rc;
   rc = sqlite3BtreeClearTable(p, iTable, 0);
   if( rc ){
@@ -55845,7 +57047,7 @@ static int btreeDropTable(Btree *p, Pgno iTable, int *piMoved){
         */
         MemPage *pMove;
         releasePage(pPage);
-        rc = btreeGetPage(pBt, maxRootPgno, &pMove, 0);
+        rc = btreeGetPage(pBt, maxRootPgno, &pMove, 0, 0);
         if( rc!=SQLITE_OK ){
           return rc;
         }
@@ -55855,7 +57057,7 @@ static int btreeDropTable(Btree *p, Pgno iTable, int *piMoved){
           return rc;
         }
         pMove = 0;
-        rc = btreeGetPage(pBt, maxRootPgno, &pMove, 0);
+        rc = btreeGetPage(pBt, maxRootPgno, &pMove, 0, 0);
         freePage(pMove, &rc);
         releasePage(pMove);
         if( rc!=SQLITE_OK ){
@@ -56267,7 +57469,7 @@ static int checkTreePage(
   usableSize = pBt->usableSize;
   if( iPage==0 ) return 0;
   if( checkRef(pCheck, iPage, zParentContext) ) return 0;
-  if( (rc = btreeGetPage(pBt, (Pgno)iPage, &pPage, 0))!=0 ){
+  if( (rc = btreeGetPage(pBt, (Pgno)iPage, &pPage, 0, 0))!=0 ){
     checkAppendMsg(pCheck, zContext,
        "unable to get the page. error code=%d", rc);
     return 0;
@@ -56739,6 +57941,17 @@ SQLITE_PRIVATE int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void
     return SQLITE_ABORT;
   }
 
+  /* Save the positions of all other cursors open on this table. This is
+  ** required in case any of them are holding references to an xFetch
+  ** version of the b-tree page modified by the accessPayload call below.
+  **
+  ** Note that pCsr must be open on a BTREE_INTKEY table and saveCursorPosition()
+  ** and hence saveAllCursors() cannot fail on a BTREE_INTKEY table, hence
+  ** saveAllCursors can only return SQLITE_OK.
+  */
+  VVA_ONLY(rc =) saveAllCursors(pCsr->pBt, pCsr->pgnoRoot, pCsr);
+  assert( rc==SQLITE_OK );
+
   /* Check some assumptions: 
   **   (a) the cursor is open for writing,
   **   (b) there is a read/write transaction open,
@@ -57220,7 +58433,8 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){
       const Pgno iSrcPg = p->iNext;                 /* Source page number */
       if( iSrcPg!=PENDING_BYTE_PAGE(p->pSrc->pBt) ){
         DbPage *pSrcPg;                             /* Source page object */
-        rc = sqlite3PagerGet(pSrcPager, iSrcPg, &pSrcPg);
+        rc = sqlite3PagerAcquire(pSrcPager, iSrcPg, &pSrcPg,
+                                 PAGER_ACQUIRE_READONLY);
         if( rc==SQLITE_OK ){
           rc = backupOnePage(p, iSrcPg, sqlite3PagerGetData(pSrcPg), 0);
           sqlite3PagerUnref(pSrcPg);
@@ -62443,14 +63657,6 @@ end_of_step:
   return (rc&db->errMask);
 }
 
-/*
-** The maximum number of times that a statement will try to reparse
-** itself before giving up and returning SQLITE_SCHEMA.
-*/
-#ifndef SQLITE_MAX_SCHEMA_RETRY
-# define SQLITE_MAX_SCHEMA_RETRY 5
-#endif
-
 /*
 ** This is the top-level implementation of sqlite3_step().  Call
 ** sqlite3Step() to do most of the work.  If a schema error occurs,
@@ -63354,6 +64560,11 @@ static int findNextHostParameter(const char *zSql, int *pnToken){
 ** then the returned string holds a copy of zRawSql with "-- " prepended
 ** to each line of text.
 **
+** If the SQLITE_TRACE_SIZE_LIMIT macro is defined to an integer, then
+** then long strings and blobs are truncated to that many bytes.  This
+** can be used to prevent unreasonably large trace strings when dealing
+** with large (multi-megabyte) strings and blobs.
+**
 ** The calling function is responsible for making sure the memory returned
 ** is eventually freed.
 **
@@ -63424,30 +64635,49 @@ SQLITE_PRIVATE char *sqlite3VdbeExpandSql(
       }else if( pVar->flags & MEM_Real ){
         sqlite3XPrintf(&out, "%!.15g", pVar->r);
       }else if( pVar->flags & MEM_Str ){
+        int nOut;  /* Number of bytes of the string text to include in output */
 #ifndef SQLITE_OMIT_UTF16
         u8 enc = ENC(db);
+        Mem utf8;
         if( enc!=SQLITE_UTF8 ){
-          Mem utf8;
           memset(&utf8, 0, sizeof(utf8));
           utf8.db = db;
           sqlite3VdbeMemSetStr(&utf8, pVar->z, pVar->n, enc, SQLITE_STATIC);
           sqlite3VdbeChangeEncoding(&utf8, SQLITE_UTF8);
-          sqlite3XPrintf(&out, "'%.*q'", utf8.n, utf8.z);
-          sqlite3VdbeMemRelease(&utf8);
-        }else
+          pVar = &utf8;
+        }
 #endif
-        {
-          sqlite3XPrintf(&out, "'%.*q'", pVar->n, pVar->z);
+        nOut = pVar->n;
+#ifdef SQLITE_TRACE_SIZE_LIMIT
+        if( nOut>SQLITE_TRACE_SIZE_LIMIT ){
+          nOut = SQLITE_TRACE_SIZE_LIMIT;
+          while( nOut<pVar->n && (pVar->z[nOut]&0xc0)==0x80 ){ nOut++; }
         }
+#endif    
+        sqlite3XPrintf(&out, "'%.*q'", nOut, pVar->z);
+#ifdef SQLITE_TRACE_SIZE_LIMIT
+        if( nOut<pVar->n ) sqlite3XPrintf(&out, "/*+%d bytes*/", pVar->n-nOut);
+#endif
+#ifndef SQLITE_OMIT_UTF16
+        if( enc!=SQLITE_UTF8 ) sqlite3VdbeMemRelease(&utf8);
+#endif
       }else if( pVar->flags & MEM_Zero ){
         sqlite3XPrintf(&out, "zeroblob(%d)", pVar->u.nZero);
       }else{
+        int nOut;  /* Number of bytes of the blob to include in output */
         assert( pVar->flags & MEM_Blob );
         sqlite3StrAccumAppend(&out, "x'", 2);
-        for(i=0; i<pVar->n; i++){
+        nOut = pVar->n;
+#ifdef SQLITE_TRACE_SIZE_LIMIT
+        if( nOut>SQLITE_TRACE_SIZE_LIMIT ) nOut = SQLITE_TRACE_SIZE_LIMIT;
+#endif
+        for(i=0; i<nOut; i++){
           sqlite3XPrintf(&out, "%02x", pVar->z[i]&0xff);
         }
         sqlite3StrAccumAppend(&out, "'", 1);
+#ifdef SQLITE_TRACE_SIZE_LIMIT
+        if( nOut<pVar->n ) sqlite3XPrintf(&out, "/*+%d bytes*/", pVar->n-nOut);
+#endif
       }
     }
   }
@@ -67664,7 +68894,7 @@ case OP_SeekGt: {       /* jump, in3 */
       **     u.bc.r.flags = 0;
       **   }
       */
-      u.bc.r.flags = (u16)(UNPACKED_INCRKEY * (1 & (u.bc.oc - OP_SeekLt)));
+      u.bc.r.flags = (u8)(UNPACKED_INCRKEY * (1 & (u.bc.oc - OP_SeekLt)));
       assert( u.bc.oc!=OP_SeekGt || u.bc.r.flags==UNPACKED_INCRKEY );
       assert( u.bc.oc!=OP_SeekLe || u.bc.r.flags==UNPACKED_INCRKEY );
       assert( u.bc.oc!=OP_SeekGe || u.bc.r.flags==0 );
@@ -70789,7 +72019,7 @@ SQLITE_API int sqlite3_blob_open(
     }
     sqlite3_bind_int64(pBlob->pStmt, 1, iRow);
     rc = blobSeekToRow(pBlob, iRow, &zErr);
-  } while( (++nAttempt)<5 && rc==SQLITE_SCHEMA );
+  } while( (++nAttempt)<SQLITE_MAX_SCHEMA_RETRY && rc==SQLITE_SCHEMA );
 
 blob_open_out:
   if( rc==SQLITE_OK && db->mallocFailed==0 ){
@@ -72474,7 +73704,9 @@ static const struct sqlite3_io_methods MemJournalMethods = {
   0,                /* xShmMap */
   0,                /* xShmLock */
   0,                /* xShmBarrier */
-  0                 /* xShmUnlock */
+  0,                /* xShmUnmap */
+  0,                /* xFetch */
+  0                 /* xUnfetch */
 };
 
 /* 
@@ -72618,7 +73850,9 @@ SQLITE_PRIVATE int sqlite3WalkSelectFrom(Walker *pWalker, Select *p){
 /*
 ** Call sqlite3WalkExpr() for every expression in Select statement p.
 ** Invoke sqlite3WalkSelect() for subqueries in the FROM clause and
-** on the compound select chain, p->pPrior.
+** on the compound select chain, p->pPrior.  Invoke the xSelectCallback()
+** either before or after the walk of expressions and FROM clause, depending
+** on whether pWalker->bSelectDepthFirst is false or true, respectively.
 **
 ** Return WRC_Continue under normal conditions.  Return WRC_Abort if
 ** there is an abort request.
@@ -72632,14 +73866,23 @@ SQLITE_PRIVATE int sqlite3WalkSelect(Walker *pWalker, Select *p){
   rc = WRC_Continue;
   pWalker->walkerDepth++;
   while( p ){
-    rc = pWalker->xSelectCallback(pWalker, p);
-    if( rc ) break;
+    if( !pWalker->bSelectDepthFirst ){
+       rc = pWalker->xSelectCallback(pWalker, p);
+       if( rc ) break;
+    }
     if( sqlite3WalkSelectExpr(pWalker, p)
      || sqlite3WalkSelectFrom(pWalker, p)
     ){
       pWalker->walkerDepth--;
       return WRC_Abort;
     }
+    if( pWalker->bSelectDepthFirst ){
+      rc = pWalker->xSelectCallback(pWalker, p);
+      /* Depth-first search is currently only used for
+      ** selectAddSubqueryTypeInfo() and that routine always returns
+      ** WRC_Continue (0).  So the following branch is never taken. */
+      if( NEVER(rc) ) break;
+    }
     p = p->pPrior;
   }
   pWalker->walkerDepth--;
@@ -73037,7 +74280,10 @@ static int lookupName(
     ** Note that the expression in the result set should have already been
     ** resolved by the time the WHERE clause is resolved.
     */
-    if( cnt==0 && (pEList = pNC->pEList)!=0 && zTab==0 ){
+    if( (pEList = pNC->pEList)!=0
+     && zTab==0
+     && ((pNC->ncFlags & NC_AsMaybe)==0 || cnt==0)
+    ){
       for(j=0; j<pEList->nExpr; j++){
         char *zAs = pEList->a[j].zName;
         if( zAs!=0 && sqlite3StrICmp(zAs, zCol)==0 ){
@@ -73128,7 +74374,9 @@ static int lookupName(
 lookupname_end:
   if( cnt==1 ){
     assert( pNC!=0 );
-    sqlite3AuthRead(pParse, pExpr, pSchema, pNC->pSrcList);
+    if( pExpr->op!=TK_AS ){
+      sqlite3AuthRead(pParse, pExpr, pSchema, pNC->pSrcList);
+    }
     /* Increment the nRef value on all name contexts from TopNC up to
     ** the point where the name matched. */
     for(;;){
@@ -73803,11 +75051,10 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
     ** re-evaluated for each reference to it.
     */
     sNC.pEList = p->pEList;
-    if( sqlite3ResolveExprNames(&sNC, p->pWhere) ||
-       sqlite3ResolveExprNames(&sNC, p->pHaving)
-    ){
-      return WRC_Abort;
-    }
+    sNC.ncFlags |= NC_AsMaybe;
+    if( sqlite3ResolveExprNames(&sNC, p->pHaving) ) return WRC_Abort;
+    if( sqlite3ResolveExprNames(&sNC, p->pWhere) ) return WRC_Abort;
+    sNC.ncFlags &= ~NC_AsMaybe;
 
     /* The ORDER BY and GROUP BY clauses may not refer to terms in
     ** outer queries 
@@ -73928,6 +75175,7 @@ SQLITE_PRIVATE int sqlite3ResolveExprNames(
 #endif
   savedHasAgg = pNC->ncFlags & NC_HasAgg;
   pNC->ncFlags &= ~NC_HasAgg;
+  memset(&w, 0, sizeof(w));
   w.xExprCallback = resolveExprStep;
   w.xSelectCallback = resolveSelectStep;
   w.pParse = pNC->pParse;
@@ -73968,6 +75216,7 @@ SQLITE_PRIVATE void sqlite3ResolveSelectNames(
   Walker w;
 
   assert( p!=0 );
+  memset(&w, 0, sizeof(w));
   w.xExprCallback = resolveExprStep;
   w.xSelectCallback = resolveSelectStep;
   w.pParse = pParse;
@@ -74094,12 +75343,7 @@ SQLITE_PRIVATE CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr){
     }
     assert( op!=TK_REGISTER || p->op2!=TK_COLLATE );
     if( op==TK_COLLATE ){
-      if( db->init.busy ){
-        /* Do not report errors when parsing while the schema */
-        pColl = sqlite3FindCollSeq(db, ENC(db), p->u.zToken, 0);
-      }else{
-        pColl = sqlite3GetCollSeq(pParse, ENC(db), 0, p->u.zToken);
-      }
+      pColl = sqlite3GetCollSeq(pParse, ENC(db), 0, p->u.zToken);
       break;
     }
     if( p->pTab!=0
@@ -75192,6 +76436,7 @@ static int selectNodeIsConstant(Walker *pWalker, Select *NotUsed){
 }
 static int exprIsConst(Expr *p, int initFlag){
   Walker w;
+  memset(&w, 0, sizeof(w));
   w.u.i = initFlag;
   w.xExprCallback = exprNodeIsConstant;
   w.xSelectCallback = selectNodeIsConstant;
@@ -77406,8 +78651,8 @@ SQLITE_PRIVATE void sqlite3ExprCodeConstants(Parse *pParse, Expr *pExpr){
   Walker w;
   if( pParse->cookieGoto ) return;
   if( OptimizationDisabled(pParse->db, SQLITE_FactorOutConst) ) return;
+  memset(&w, 0, sizeof(w));
   w.xExprCallback = evalConstExpr;
-  w.xSelectCallback = 0;
   w.pParse = pParse;
   sqlite3WalkExpr(&w, pExpr);
 }
@@ -83599,10 +84844,8 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(
   for(i=0; i<pList->nExpr; i++){
     Expr *pExpr = pList->a[i].pExpr;
     if( pExpr ){
-      CollSeq *pColl = sqlite3ExprCollSeq(pParse, pExpr);
-      if( pColl ){
-        nExtra += (1 + sqlite3Strlen30(pColl->zName));
-      }
+      assert( pExpr->op==TK_COLLATE );
+      nExtra += (1 + sqlite3Strlen30(pExpr->u.zToken));
     }
   }
 
@@ -83663,7 +84906,6 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(
     const char *zColName = pListItem->zName;
     Column *pTabCol;
     int requestedSortOrder;
-    CollSeq *pColl;                /* Collating sequence */
     char *zColl;                   /* Collation sequence name */
 
     for(j=0, pTabCol=pTab->aCol; j<pTab->nCol; j++, pTabCol++){
@@ -83676,11 +84918,10 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(
       goto exit_create_index;
     }
     pIndex->aiColumn[i] = j;
-    if( pListItem->pExpr
-     && (pColl = sqlite3ExprCollSeq(pParse, pListItem->pExpr))!=0
-    ){
+    if( pListItem->pExpr ){
       int nColl;
-      zColl = pColl->zName;
+      assert( pListItem->pExpr->op==TK_COLLATE );
+      zColl = pListItem->pExpr->u.zToken;
       nColl = sqlite3Strlen30(zColl) + 1;
       assert( nExtra>=nColl );
       memcpy(zExtra, zColl, nColl);
@@ -83689,9 +84930,7 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(
       nExtra -= nColl;
     }else{
       zColl = pTab->aCol[j].zColl;
-      if( !zColl ){
-        zColl = "BINARY";
-      }
+      if( !zColl ) zColl = "BINARY";
     }
     if( !db->init.busy && !sqlite3LocateCollSeq(pParse, zColl) ){
       goto exit_create_index;
@@ -86610,6 +87849,13 @@ static int patternCompare(
   return *zString==0;
 }
 
+/*
+** The sqlite3_strglob() interface.
+*/
+SQLITE_API int sqlite3_strglob(const char *zGlobPattern, const char *zString){
+  return patternCompare((u8*)zGlobPattern, (u8*)zString, &globInfo, 0)==0;
+}
+
 /*
 ** Count the number of times that the LIKE operator (or GLOB which is
 ** just a variation of LIKE) gets called.  This is used for testing
@@ -90810,7 +92056,6 @@ SQLITE_API int sqlite3_exec(
   const char *zLeftover;      /* Tail of unprocessed SQL */
   sqlite3_stmt *pStmt = 0;    /* The current SQL statement */
   char **azCols = 0;          /* Names of result columns */
-  int nRetry = 0;             /* Number of retry attempts */
   int callbackIsInit;         /* True if callback data is initialized */
 
   if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
@@ -90818,12 +92063,12 @@ SQLITE_API int sqlite3_exec(
 
   sqlite3_mutex_enter(db->mutex);
   sqlite3Error(db, SQLITE_OK, 0);
-  while( (rc==SQLITE_OK || (rc==SQLITE_SCHEMA && (++nRetry)<2)) && zSql[0] ){
+  while( rc==SQLITE_OK && zSql[0] ){
     int nCol;
     char **azVals = 0;
 
     pStmt = 0;
-    rc = sqlite3_prepare(db, zSql, -1, &pStmt, &zLeftover);
+    rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zLeftover);
     assert( rc==SQLITE_OK || pStmt==0 );
     if( rc!=SQLITE_OK ){
       continue;
@@ -90880,11 +92125,8 @@ SQLITE_API int sqlite3_exec(
       if( rc!=SQLITE_ROW ){
         rc = sqlite3VdbeFinalize((Vdbe *)pStmt);
         pStmt = 0;
-        if( rc!=SQLITE_SCHEMA ){
-          nRetry = 0;
-          zSql = zLeftover;
-          while( sqlite3Isspace(zSql[0]) ) zSql++;
-        }
+        zSql = zLeftover;
+        while( sqlite3Isspace(zSql[0]) ) zSql++;
         break;
       }
     }
@@ -91408,8 +92650,17 @@ struct sqlite3_api_routines {
 #define sqlite3_wal_checkpoint_v2      sqlite3_api->wal_checkpoint_v2
 #endif /* SQLITE_CORE */
 
-#define SQLITE_EXTENSION_INIT1     const sqlite3_api_routines *sqlite3_api = 0;
-#define SQLITE_EXTENSION_INIT2(v)  sqlite3_api = v;
+#ifndef SQLITE_CORE
+  /* This case when the file really is being compiled as a loadable 
+  ** extension */
+# define SQLITE_EXTENSION_INIT1     const sqlite3_api_routines *sqlite3_api=0;
+# define SQLITE_EXTENSION_INIT2(v)  sqlite3_api=v;
+#else
+  /* This case when the file is being statically linked into the 
+  ** application */
+# define SQLITE_EXTENSION_INIT1     /*no-op*/
+# define SQLITE_EXTENSION_INIT2(v)  (void)v; /* unused parameter */
+#endif
 
 #endif /* _SQLITE3EXT_H_ */
 
@@ -91812,8 +93063,23 @@ static int sqlite3LoadExtension(
   void *handle;
   int (*xInit)(sqlite3*,char**,const sqlite3_api_routines*);
   char *zErrmsg = 0;
+  const char *zEntry;
+  char *zAltEntry = 0;
   void **aHandle;
   int nMsg = 300 + sqlite3Strlen30(zFile);
+  int ii;
+
+  /* Shared library endings to try if zFile cannot be loaded as written */
+  static const char *azEndings[] = {
+#if SQLITE_OS_WIN
+     "dll"   
+#elif defined(__APPLE__)
+     "dylib"
+#else
+     "so"
+#endif
+  };
+
 
   if( pzErrMsg ) *pzErrMsg = 0;
 
@@ -91830,11 +93096,17 @@ static int sqlite3LoadExtension(
     return SQLITE_ERROR;
   }
 
-  if( zProc==0 ){
-    zProc = "sqlite3_extension_init";
-  }
+  zEntry = zProc ? zProc : "sqlite3_extension_init";
 
   handle = sqlite3OsDlOpen(pVfs, zFile);
+#if SQLITE_OS_UNIX || SQLITE_OS_WIN
+  for(ii=0; ii<ArraySize(azEndings) && handle==0; ii++){
+    char *zAltFile = sqlite3_mprintf("%s.%s", zFile, azEndings[ii]);
+    if( zAltFile==0 ) return SQLITE_NOMEM;
+    handle = sqlite3OsDlOpen(pVfs, zAltFile);
+    sqlite3_free(zAltFile);
+  }
+#endif
   if( handle==0 ){
     if( pzErrMsg ){
       *pzErrMsg = zErrmsg = sqlite3_malloc(nMsg);
@@ -91847,20 +93119,57 @@ static int sqlite3LoadExtension(
     return SQLITE_ERROR;
   }
   xInit = (int(*)(sqlite3*,char**,const sqlite3_api_routines*))
-                   sqlite3OsDlSym(pVfs, handle, zProc);
+                   sqlite3OsDlSym(pVfs, handle, zEntry);
+
+  /* If no entry point was specified and the default legacy
+  ** entry point name "sqlite3_extension_init" was not found, then
+  ** construct an entry point name "sqlite3_X_init" where the X is
+  ** replaced by the lowercase value of every ASCII alphabetic 
+  ** character in the filename after the last "/" upto the first ".",
+  ** and eliding the first three characters if they are "lib".  
+  ** Examples:
+  **
+  **    /usr/local/lib/libExample5.4.3.so ==>  sqlite3_example_init
+  **    C:/lib/mathfuncs.dll              ==>  sqlite3_mathfuncs_init
+  */
+  if( xInit==0 && zProc==0 ){
+    int iFile, iEntry, c;
+    int ncFile = sqlite3Strlen30(zFile);
+    zAltEntry = sqlite3_malloc(ncFile+30);
+    if( zAltEntry==0 ){
+      sqlite3OsDlClose(pVfs, handle);
+      return SQLITE_NOMEM;
+    }
+    memcpy(zAltEntry, "sqlite3_", 8);
+    for(iFile=ncFile-1; iFile>=0 && zFile[iFile]!='/'; iFile--){}
+    iFile++;
+    if( sqlite3_strnicmp(zFile+iFile, "lib", 3)==0 ) iFile += 3;
+    for(iEntry=8; (c = zFile[iFile])!=0 && c!='.'; iFile++){
+      if( sqlite3Isalpha(c) ){
+        zAltEntry[iEntry++] = (char)sqlite3UpperToLower[(unsigned)c];
+      }
+    }
+    memcpy(zAltEntry+iEntry, "_init", 6);
+    zEntry = zAltEntry;
+    xInit = (int(*)(sqlite3*,char**,const sqlite3_api_routines*))
+                     sqlite3OsDlSym(pVfs, handle, zEntry);
+  }
   if( xInit==0 ){
     if( pzErrMsg ){
-      nMsg += sqlite3Strlen30(zProc);
+      nMsg += sqlite3Strlen30(zEntry);
       *pzErrMsg = zErrmsg = sqlite3_malloc(nMsg);
       if( zErrmsg ){
         sqlite3_snprintf(nMsg, zErrmsg,
-            "no entry point [%s] in shared library [%s]", zProc,zFile);
+            "no entry point [%s] in shared library [%s]", zEntry, zFile);
         sqlite3OsDlError(pVfs, nMsg-1, zErrmsg);
       }
-      sqlite3OsDlClose(pVfs, handle);
     }
+    sqlite3OsDlClose(pVfs, handle);
+    sqlite3_free(zAltEntry);
     return SQLITE_ERROR;
-  }else if( xInit(db, &zErrmsg, &sqlite3Apis) ){
+  }
+  sqlite3_free(zAltEntry);
+  if( xInit(db, &zErrmsg, &sqlite3Apis) ){
     if( pzErrMsg ){
       *pzErrMsg = sqlite3_mprintf("error during initialization: %s", zErrmsg);
     }
@@ -92389,7 +93698,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
   int rc;                      /* return value form SQLITE_FCNTL_PRAGMA */
   sqlite3 *db = pParse->db;    /* The database connection */
   Db *pDb;                     /* The specific database being pragmaed */
-  Vdbe *v = pParse->pVdbe = sqlite3VdbeCreate(db);  /* Prepared statement */
+  Vdbe *v = sqlite3GetVdbe(pParse);  /* Prepared statement */
 
   if( v==0 ) return;
   sqlite3VdbeRunOnlyOnce(v);
@@ -92472,11 +93781,12 @@ SQLITE_PRIVATE void sqlite3Pragma(
     static const VdbeOpList getCacheSize[] = {
       { OP_Transaction, 0, 0,        0},                         /* 0 */
       { OP_ReadCookie,  0, 1,        BTREE_DEFAULT_CACHE_SIZE},  /* 1 */
-      { OP_IfPos,       1, 7,        0},
+      { OP_IfPos,       1, 8,        0},
       { OP_Integer,     0, 2,        0},
       { OP_Subtract,    1, 2,        1},
-      { OP_IfPos,       1, 7,        0},
+      { OP_IfPos,       1, 8,        0},
       { OP_Integer,     0, 1,        0},                         /* 6 */
+      { OP_Noop,        0, 0,        0},
       { OP_ResultRow,   1, 1,        0},
     };
     int addr;
@@ -92814,6 +94124,43 @@ SQLITE_PRIVATE void sqlite3Pragma(
     }
   }else
 
+  /*
+  **  PRAGMA [database.]mmap_size(N)
+  **
+  ** Used to set mapping size limit. The mapping size limit is
+  ** used to limit the aggregate size of all memory mapped regions of the
+  ** database file. If this parameter is set to zero, then memory mapping
+  ** is not used at all.  If N is negative, then the default memory map
+  ** limit determined by sqlite3_config(SQLITE_CONFIG_MMAP_SIZE) is set.
+  ** The parameter N is measured in bytes.
+  **
+  ** This value is advisory.  The underlying VFS is free to memory map
+  ** as little or as much as it wants.  Except, if N is set to 0 then the
+  ** upper layers will never invoke the xFetch interfaces to the VFS.
+  */
+  if( sqlite3StrICmp(zLeft,"mmap_size")==0 ){
+    sqlite3_int64 sz;
+    assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
+    if( zRight ){
+      int ii;
+      sqlite3Atoi64(zRight, &sz, 1000, SQLITE_UTF8);
+      if( sz<0 ) sz = sqlite3GlobalConfig.szMmap;
+      if( pId2->n==0 ) db->szMmap = sz;
+      for(ii=db->nDb-1; ii>=0; ii--){
+        if( db->aDb[ii].pBt && (ii==iDb || pId2->n==0) ){
+          sqlite3BtreeSetMmapLimit(db->aDb[ii].pBt, sz);
+        }
+      }
+    }
+    sz = -1;
+    if( sqlite3_file_control(db,zDb,SQLITE_FCNTL_MMAP_SIZE,&sz)==SQLITE_OK ){
+#if SQLITE_MAX_MMAP_SIZE==0
+      sz = 0;
+#endif
+      returnSingleInt(pParse, "mmap_size", sz);
+    }
+  }else
+
   /*
   **   PRAGMA temp_store
   **   PRAGMA temp_store = "default"|"memory"|"file"
@@ -93599,6 +94946,11 @@ SQLITE_PRIVATE void sqlite3Pragma(
   **   PRAGMA [database.]user_version
   **   PRAGMA [database.]user_version = <integer>
   **
+  **   PRAGMA [database.]freelist_count = <integer>
+  **
+  **   PRAGMA [database.]application_id
+  **   PRAGMA [database.]application_id = <integer>
+  **
   ** The pragma's schema_version and user_version are used to set or get
   ** the value of the schema-version and user-version, respectively. Both
   ** the schema-version and the user-version are 32-bit signed integers
@@ -93620,10 +94972,14 @@ SQLITE_PRIVATE void sqlite3Pragma(
   if( sqlite3StrICmp(zLeft, "schema_version")==0 
    || sqlite3StrICmp(zLeft, "user_version")==0 
    || sqlite3StrICmp(zLeft, "freelist_count")==0 
+   || sqlite3StrICmp(zLeft, "application_id")==0 
   ){
     int iCookie;   /* Cookie index. 1 for schema-cookie, 6 for user-cookie. */
     sqlite3VdbeUsesBtree(v, iDb);
     switch( zLeft[0] ){
+      case 'a': case 'A':
+        iCookie = BTREE_APPLICATION_ID;
+        break;
       case 'f': case 'F':
         iCookie = BTREE_FREE_PAGE_COUNT;
         break;
@@ -94504,7 +95860,6 @@ static int sqlite3Prepare(
   }
 #endif
 
-  assert( db->init.busy==0 || saveSqlFlag==0 );
   if( db->init.busy==0 ){
     Vdbe *pVdbe = pParse->pVdbe;
     sqlite3VdbeSetSql(pVdbe, zSql, (int)(pParse->zTail-zSql), saveSqlFlag);
@@ -97980,6 +99335,69 @@ SQLITE_PRIVATE int sqlite3IndexedByLookup(Parse *pParse, struct SrcList_item *pF
   }
   return SQLITE_OK;
 }
+/*
+** Detect compound SELECT statements that use an ORDER BY clause with 
+** an alternative collating sequence.
+**
+**    SELECT ... FROM t1 EXCEPT SELECT ... FROM t2 ORDER BY .. COLLATE ...
+**
+** These are rewritten as a subquery:
+**
+**    SELECT * FROM (SELECT ... FROM t1 EXCEPT SELECT ... FROM t2)
+**     ORDER BY ... COLLATE ...
+**
+** This transformation is necessary because the multiSelectOrderBy() routine
+** above that generates the code for a compound SELECT with an ORDER BY clause
+** uses a merge algorithm that requires the same collating sequence on the
+** result columns as on the ORDER BY clause.  See ticket
+** http://www.sqlite.org/src/info/6709574d2a
+**
+** This transformation is only needed for EXCEPT, INTERSECT, and UNION.
+** The UNION ALL operator works fine with multiSelectOrderBy() even when
+** there are COLLATE terms in the ORDER BY.
+*/
+static int convertCompoundSelectToSubquery(Walker *pWalker, Select *p){
+  int i;
+  Select *pNew;
+  Select *pX;
+  sqlite3 *db;
+  struct ExprList_item *a;
+  SrcList *pNewSrc;
+  Parse *pParse;
+  Token dummy;
+
+  if( p->pPrior==0 ) return WRC_Continue;
+  if( p->pOrderBy==0 ) return WRC_Continue;
+  for(pX=p; pX && (pX->op==TK_ALL || pX->op==TK_SELECT); pX=pX->pPrior){}
+  if( pX==0 ) return WRC_Continue;
+  a = p->pOrderBy->a;
+  for(i=p->pOrderBy->nExpr-1; i>=0; i--){
+    if( a[i].pExpr->flags & EP_Collate ) break;
+  }
+  if( i<0 ) return WRC_Continue;
+
+  /* If we reach this point, that means the transformation is required. */
+
+  pParse = pWalker->pParse;
+  db = pParse->db;
+  pNew = sqlite3DbMallocZero(db, sizeof(*pNew) );
+  if( pNew==0 ) return WRC_Abort;
+  memset(&dummy, 0, sizeof(dummy));
+  pNewSrc = sqlite3SrcListAppendFromTerm(pParse,0,0,0,&dummy,pNew,0,0);
+  if( pNewSrc==0 ) return WRC_Abort;
+  *pNew = *p;
+  p->pSrc = pNewSrc;
+  p->pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(db, TK_ALL, 0));
+  p->op = TK_SELECT;
+  p->pWhere = 0;
+  pNew->pGroupBy = 0;
+  pNew->pHaving = 0;
+  pNew->pOrderBy = 0;
+  p->pPrior = 0;
+  pNew->pLimit = 0;
+  pNew->pOffset = 0;
+  return WRC_Continue;
+}
 
 /*
 ** This routine is a Walker callback for "expanding" a SELECT statement.
@@ -98296,10 +99714,13 @@ static int exprWalkNoop(Walker *NotUsed, Expr *NotUsed2){
 */
 static void sqlite3SelectExpand(Parse *pParse, Select *pSelect){
   Walker w;
-  w.xSelectCallback = selectExpander;
+  memset(&w, 0, sizeof(w));
+  w.xSelectCallback = convertCompoundSelectToSubquery;
   w.xExprCallback = exprWalkNoop;
   w.pParse = pParse;
   sqlite3WalkSelect(&w, pSelect);
+  w.xSelectCallback = selectExpander;
+  sqlite3WalkSelect(&w, pSelect);
 }
 
 
@@ -98354,9 +99775,11 @@ static int selectAddSubqueryTypeInfo(Walker *pWalker, Select *p){
 static void sqlite3SelectAddTypeInfo(Parse *pParse, Select *pSelect){
 #ifndef SQLITE_OMIT_SUBQUERY
   Walker w;
+  memset(&w, 0, sizeof(w));
   w.xSelectCallback = selectAddSubqueryTypeInfo;
   w.xExprCallback = exprWalkNoop;
   w.pParse = pParse;
+  w.bSelectDepthFirst = 1;
   sqlite3WalkSelect(&w, pSelect);
 #endif
 }
@@ -98767,7 +100190,7 @@ SQLITE_PRIVATE int sqlite3Select(
       pItem->addrFillSub = topAddr+1;
       VdbeNoopComment((v, "materialize %s", pItem->pTab->zName));
       if( pItem->isCorrelated==0 ){
-        /* If the subquery is no correlated and if we are not inside of
+        /* If the subquery is not correlated and if we are not inside of
         ** a trigger, then we only need to compute the value of the subquery
         ** once. */
         onceAddr = sqlite3CodeOnce(pParse);
@@ -101033,6 +102456,7 @@ SQLITE_PRIVATE void sqlite3Update(
     }
     if( j>=pTab->nCol ){
       if( sqlite3IsRowid(pChanges->a[i].zName) ){
+        j = -1;
         chngRowid = 1;
         pRowidExpr = pChanges->a[i].pExpr;
       }else{
@@ -101045,7 +102469,8 @@ SQLITE_PRIVATE void sqlite3Update(
     {
       int rc;
       rc = sqlite3AuthCheck(pParse, SQLITE_UPDATE, pTab->zName,
-                           pTab->aCol[j].zName, db->aDb[iDb].zName);
+                            j<0 ? "ROWID" : pTab->aCol[j].zName,
+                            db->aDb[iDb].zName);
       if( rc==SQLITE_DENY ){
         goto update_cleanup;
       }else if( rc==SQLITE_IGNORE ){
@@ -101788,6 +103213,7 @@ SQLITE_PRIVATE int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
        BTREE_DEFAULT_CACHE_SIZE, 0,  /* Preserve the default page cache size */
        BTREE_TEXT_ENCODING,      0,  /* Preserve the text encoding */
        BTREE_USER_VERSION,       0,  /* Preserve the user version */
+       BTREE_APPLICATION_ID,     0,  /* Preserve the application id */
     };
 
     assert( 1==sqlite3BtreeIsInTrans(pTemp) );
@@ -103655,7 +105081,7 @@ static WhereTerm *findTerm(
                 continue;
               }
             }
-            if( pTerm->prereqRight==0 ){
+            if( pTerm->prereqRight==0 && (pTerm->eOperator&WO_EQ)!=0 ){
               pResult = pTerm;
               goto findTerm_success;
             }else if( pResult==0 ){
@@ -105225,9 +106651,8 @@ static void bestVirtualIndex(WhereBestIdx *p){
   struct sqlite3_index_constraint *pIdxCons;
   struct sqlite3_index_constraint_usage *pUsage;
   WhereTerm *pTerm;
-  int i, j, k;
+  int i, j;
   int nOrderBy;
-  int sortOrder;                  /* Sort order for IN clauses */
   int bAllowIN;                   /* Allow IN optimizations */
   double rCost;
 
@@ -105326,7 +106751,6 @@ static void bestVirtualIndex(WhereBestIdx *p){
       return;
     }
   
-    sortOrder = SQLITE_SO_ASC;
     pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint;
     for(i=0; i<pIdxInfo->nConstraint; i++, pIdxCons++){
       if( pUsage[i].argvIndex>0 ){
@@ -105341,17 +106765,28 @@ static void bestVirtualIndex(WhereBestIdx *p){
             ** repeated in the output. */
             break;
           }
-          for(k=0; k<pIdxInfo->nOrderBy; k++){
-            if( pIdxInfo->aOrderBy[k].iColumn==pIdxCons->iColumn ){
-              sortOrder = pIdxInfo->aOrderBy[k].desc;
-              break;
-            }
-          }
+          /* A virtual table that is constrained by an IN clause may not
+          ** consume the ORDER BY clause because (1) the order of IN terms
+          ** is not necessarily related to the order of output terms and
+          ** (2) Multiple outputs from a single IN value will not merge
+          ** together.  */
+          pIdxInfo->orderByConsumed = 0;
         }
       }
     }
     if( i>=pIdxInfo->nConstraint ) break;
   }
+
+  /* The orderByConsumed signal is only valid if all outer loops collectively
+  ** generate just a single row of output.
+  */
+  if( pIdxInfo->orderByConsumed ){
+    for(i=0; i<p->i; i++){
+      if( (p->aLevel[i].plan.wsFlags & WHERE_UNIQUE)==0 ){
+        pIdxInfo->orderByConsumed = 0;
+      }
+    }
+  }
   
   /* If there is an ORDER BY clause, and the selected virtual table index
   ** does not satisfy it, increase the cost of the scan accordingly. This
@@ -105376,8 +106811,7 @@ static void bestVirtualIndex(WhereBestIdx *p){
   }
   p->cost.plan.u.pVtabIdx = pIdxInfo;
   if( pIdxInfo->orderByConsumed ){
-    assert( sortOrder==0 || sortOrder==1 );
-    p->cost.plan.wsFlags |= WHERE_ORDERED + sortOrder*WHERE_REVERSE;
+    p->cost.plan.wsFlags |= WHERE_ORDERED;
     p->cost.plan.nOBSat = nOrderBy;
   }else{
     p->cost.plan.nOBSat = p->i ? p->aLevel[p->i-1].plan.nOBSat : 0;
@@ -107114,6 +108548,7 @@ static Bitmask codeOneLoopStart(
   int addrCont;                   /* Jump here to continue with next cycle */
   int iRowidReg = 0;        /* Rowid is stored in this register, if not zero */
   int iReleaseReg = 0;      /* Temp register to free before returning */
+  Bitmask newNotReady;      /* Return value */
 
   pParse = pWInfo->pParse;
   v = pParse->pVdbe;
@@ -107124,6 +108559,7 @@ static Bitmask codeOneLoopStart(
   bRev = (pLevel->plan.wsFlags & WHERE_REVERSE)!=0;
   omitTable = (pLevel->plan.wsFlags & WHERE_IDX_ONLY)!=0 
            && (wctrlFlags & WHERE_FORCE_TABLE)==0;
+  VdbeNoopComment((v, "Begin Join Loop %d", iLevel));
 
   /* Create labels for the "break" and "continue" instructions
   ** for the current loop.  Jump to addrBrk to break out of a loop.
@@ -107666,6 +109102,10 @@ static Bitmask codeOneLoopStart(
     ** the "interesting" terms of z - terms that did not originate in the
     ** ON or USING clause of a LEFT JOIN, and terms that are usable as 
     ** indices.
+    **
+    ** This optimization also only applies if the (x1 OR x2 OR ...) term
+    ** is not contained in the ON clause of a LEFT JOIN.
+    ** See ticket http://www.sqlite.org/src/info/f2369304e4
     */
     if( pWC->nTerm>1 ){
       int iTerm;
@@ -107687,7 +109127,7 @@ static Bitmask codeOneLoopStart(
       if( pOrTerm->leftCursor==iCur || (pOrTerm->eOperator & WO_AND)!=0 ){
         WhereInfo *pSubWInfo;          /* Info for single OR-term scan */
         Expr *pOrExpr = pOrTerm->pExpr;
-        if( pAndExpr ){
+        if( pAndExpr && !ExprHasProperty(pOrExpr, EP_FromJoin) ){
           pAndExpr->pLeft = pOrExpr;
           pOrExpr = pAndExpr;
         }
@@ -107774,7 +109214,7 @@ static Bitmask codeOneLoopStart(
     pLevel->p2 = 1 + sqlite3VdbeAddOp2(v, aStart[bRev], iCur, addrBrk);
     pLevel->p5 = SQLITE_STMTSTATUS_FULLSCAN_STEP;
   }
-  notReady &= ~getMask(pWC->pMaskSet, iCur);
+  newNotReady = notReady & ~getMask(pWC->pMaskSet, iCur);
 
   /* Insert code to test every subexpression that can be completely
   ** computed using the current set of tables.
@@ -107788,7 +109228,7 @@ static Bitmask codeOneLoopStart(
     testcase( pTerm->wtFlags & TERM_VIRTUAL ); /* IMP: R-30575-11662 */
     testcase( pTerm->wtFlags & TERM_CODED );
     if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue;
-    if( (pTerm->prereqAll & notReady)!=0 ){
+    if( (pTerm->prereqAll & newNotReady)!=0 ){
       testcase( pWInfo->untestedTerms==0
                && (pWInfo->wctrlFlags & WHERE_ONETABLE_ONLY)!=0 );
       pWInfo->untestedTerms = 1;
@@ -107803,6 +109243,33 @@ static Bitmask codeOneLoopStart(
     pTerm->wtFlags |= TERM_CODED;
   }
 
+  /* Insert code to test for implied constraints based on transitivity
+  ** of the "==" operator.
+  **
+  ** Example: If the WHERE clause contains "t1.a=t2.b" and "t2.b=123"
+  ** and we are coding the t1 loop and the t2 loop has not yet coded,
+  ** then we cannot use the "t1.a=t2.b" constraint, but we can code
+  ** the implied "t1.a=123" constraint.
+  */
+  for(pTerm=pWC->a, j=pWC->nTerm; j>0; j--, pTerm++){
+    Expr *pE;
+    WhereTerm *pAlt;
+    Expr sEq;
+    if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue;
+    if( pTerm->eOperator!=(WO_EQUIV|WO_EQ) ) continue;
+    if( pTerm->leftCursor!=iCur ) continue;
+    pE = pTerm->pExpr;
+    assert( !ExprHasProperty(pE, EP_FromJoin) );
+    assert( (pTerm->prereqRight & newNotReady)!=0 );
+    pAlt = findTerm(pWC, iCur, pTerm->u.leftColumn, notReady, WO_EQ|WO_IN, 0);
+    if( pAlt==0 ) continue;
+    if( pAlt->wtFlags & (TERM_CODED) ) continue;
+    VdbeNoopComment((v, "begin transitive constraint"));
+    sEq = *pAlt->pExpr;
+    sEq.pLeft = pE->pLeft;
+    sqlite3ExprIfFalse(pParse, &sEq, addrCont, SQLITE_JUMPIFNULL);
+  }
+
   /* For a LEFT OUTER JOIN, generate code that will record the fact that
   ** at least one row of the right table has matched the left table.  
   */
@@ -107815,7 +109282,7 @@ static Bitmask codeOneLoopStart(
       testcase( pTerm->wtFlags & TERM_VIRTUAL );  /* IMP: R-30575-11662 */
       testcase( pTerm->wtFlags & TERM_CODED );
       if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue;
-      if( (pTerm->prereqAll & notReady)!=0 ){
+      if( (pTerm->prereqAll & newNotReady)!=0 ){
         assert( pWInfo->untestedTerms );
         continue;
       }
@@ -107826,7 +109293,7 @@ static Bitmask codeOneLoopStart(
   }
   sqlite3ReleaseTempReg(pParse, iReleaseReg);
 
-  return notReady;
+  return newNotReady;
 }
 
 #if defined(SQLITE_TEST)
@@ -111144,7 +112611,9 @@ static void yy_reduce(
         struct SrcList_item *pOld = yymsp[-4].minor.yy347->a;
         pNew->zName = pOld->zName;
         pNew->zDatabase = pOld->zDatabase;
+        pNew->pSelect = pOld->pSelect;
         pOld->zName = pOld->zDatabase = 0;
+        pOld->pSelect = 0;
       }
       sqlite3SrcListDelete(pParse->db, yymsp[-4].minor.yy347);
     }else{
@@ -113812,6 +115281,19 @@ SQLITE_API int sqlite3_config(int op, ...){
     }
 #endif
 
+    case SQLITE_CONFIG_MMAP_SIZE: {
+      sqlite3_int64 szMmap = va_arg(ap, sqlite3_int64);
+      sqlite3_int64 mxMmap = va_arg(ap, sqlite3_int64);
+      if( mxMmap<0 || mxMmap>SQLITE_MAX_MMAP_SIZE ){
+        mxMmap = SQLITE_MAX_MMAP_SIZE;
+      }
+      sqlite3GlobalConfig.mxMmap = mxMmap;
+      if( szMmap<0 ) szMmap = SQLITE_DEFAULT_MMAP_SIZE;
+      if( szMmap>mxMmap) szMmap = mxMmap;
+      sqlite3GlobalConfig.szMmap = szMmap;
+      break;
+    }
+
     default: {
       rc = SQLITE_ERROR;
       break;
@@ -114205,6 +115687,12 @@ SQLITE_PRIVATE void sqlite3LeaveMutexAndCloseZombie(sqlite3 *db){
   ** go ahead and free all resources.
   */
 
+  /* If a transaction is open, roll it back. This also ensures that if
+  ** any database schemas have been modified by an uncommitted transaction
+  ** they are reset. And that the required b-tree mutex is held to make
+  ** the pager rollback and schema reset an atomic operation. */
+  sqlite3RollbackAll(db, SQLITE_OK);
+
   /* Free any outstanding Savepoint structures. */
   sqlite3CloseSavepoints(db);
 
@@ -114305,6 +115793,15 @@ SQLITE_PRIVATE void sqlite3RollbackAll(sqlite3 *db, int tripCode){
   int inTrans = 0;
   assert( sqlite3_mutex_held(db->mutex) );
   sqlite3BeginBenignMalloc();
+
+  /* Obtain all b-tree mutexes before making any calls to BtreeRollback(). 
+  ** This is important in case the transaction being rolled back has
+  ** modified the database schema. If the b-tree mutexes are not taken
+  ** here, then another shared-cache connection might sneak in between
+  ** the database rollback and schema reset, which can cause false
+  ** corruption reports in some cases.  */
+  sqlite3BtreeEnterAll(db);
+
   for(i=0; i<db->nDb; i++){
     Btree *p = db->aDb[i].pBt;
     if( p ){
@@ -114322,6 +115819,7 @@ SQLITE_PRIVATE void sqlite3RollbackAll(sqlite3 *db, int tripCode){
     sqlite3ExpirePreparedStatements(db);
     sqlite3ResetAllSchemasOfConnection(db);
   }
+  sqlite3BtreeLeaveAll(db);
 
   /* Any deferred constraint violations have now been resolved. */
   db->nDeferredCons = 0;
@@ -114332,6 +115830,110 @@ SQLITE_PRIVATE void sqlite3RollbackAll(sqlite3 *db, int tripCode){
   }
 }
 
+/*
+** Return a static string containing the name corresponding to the error code
+** specified in the argument.
+*/
+#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) || \
+    defined(SQLITE_DEBUG_OS_TRACE)
+SQLITE_PRIVATE const char *sqlite3ErrName(int rc){
+  const char *zName = 0;
+  int i, origRc = rc;
+  for(i=0; i<2 && zName==0; i++, rc &= 0xff){
+    switch( rc ){
+      case SQLITE_OK:                 zName = "SQLITE_OK";                break;
+      case SQLITE_ERROR:              zName = "SQLITE_ERROR";             break;
+      case SQLITE_INTERNAL:           zName = "SQLITE_INTERNAL";          break;
+      case SQLITE_PERM:               zName = "SQLITE_PERM";              break;
+      case SQLITE_ABORT:              zName = "SQLITE_ABORT";             break;
+      case SQLITE_ABORT_ROLLBACK:     zName = "SQLITE_ABORT_ROLLBACK";    break;
+      case SQLITE_BUSY:               zName = "SQLITE_BUSY";              break;
+      case SQLITE_BUSY_RECOVERY:      zName = "SQLITE_BUSY_RECOVERY";     break;
+      case SQLITE_LOCKED:             zName = "SQLITE_LOCKED";            break;
+      case SQLITE_LOCKED_SHAREDCACHE: zName = "SQLITE_LOCKED_SHAREDCACHE";break;
+      case SQLITE_NOMEM:              zName = "SQLITE_NOMEM";             break;
+      case SQLITE_READONLY:           zName = "SQLITE_READONLY";          break;
+      case SQLITE_READONLY_RECOVERY:  zName = "SQLITE_READONLY_RECOVERY"; break;
+      case SQLITE_READONLY_CANTLOCK:  zName = "SQLITE_READONLY_CANTLOCK"; break;
+      case SQLITE_READONLY_ROLLBACK:  zName = "SQLITE_READONLY_ROLLBACK"; break;
+      case SQLITE_INTERRUPT:          zName = "SQLITE_INTERRUPT";         break;
+      case SQLITE_IOERR:              zName = "SQLITE_IOERR";             break;
+      case SQLITE_IOERR_READ:         zName = "SQLITE_IOERR_READ";        break;
+      case SQLITE_IOERR_SHORT_READ:   zName = "SQLITE_IOERR_SHORT_READ";  break;
+      case SQLITE_IOERR_WRITE:        zName = "SQLITE_IOERR_WRITE";       break;
+      case SQLITE_IOERR_FSYNC:        zName = "SQLITE_IOERR_FSYNC";       break;
+      case SQLITE_IOERR_DIR_FSYNC:    zName = "SQLITE_IOERR_DIR_FSYNC";   break;
+      case SQLITE_IOERR_TRUNCATE:     zName = "SQLITE_IOERR_TRUNCATE";    break;
+      case SQLITE_IOERR_FSTAT:        zName = "SQLITE_IOERR_FSTAT";       break;
+      case SQLITE_IOERR_UNLOCK:       zName = "SQLITE_IOERR_UNLOCK";      break;
+      case SQLITE_IOERR_RDLOCK:       zName = "SQLITE_IOERR_RDLOCK";      break;
+      case SQLITE_IOERR_DELETE:       zName = "SQLITE_IOERR_DELETE";      break;
+      case SQLITE_IOERR_BLOCKED:      zName = "SQLITE_IOERR_BLOCKED";     break;
+      case SQLITE_IOERR_NOMEM:        zName = "SQLITE_IOERR_NOMEM";       break;
+      case SQLITE_IOERR_ACCESS:       zName = "SQLITE_IOERR_ACCESS";      break;
+      case SQLITE_IOERR_CHECKRESERVEDLOCK:
+                                zName = "SQLITE_IOERR_CHECKRESERVEDLOCK"; break;
+      case SQLITE_IOERR_LOCK:         zName = "SQLITE_IOERR_LOCK";        break;
+      case SQLITE_IOERR_CLOSE:        zName = "SQLITE_IOERR_CLOSE";       break;
+      case SQLITE_IOERR_DIR_CLOSE:    zName = "SQLITE_IOERR_DIR_CLOSE";   break;
+      case SQLITE_IOERR_SHMOPEN:      zName = "SQLITE_IOERR_SHMOPEN";     break;
+      case SQLITE_IOERR_SHMSIZE:      zName = "SQLITE_IOERR_SHMSIZE";     break;
+      case SQLITE_IOERR_SHMLOCK:      zName = "SQLITE_IOERR_SHMLOCK";     break;
+      case SQLITE_IOERR_SHMMAP:       zName = "SQLITE_IOERR_SHMMAP";      break;
+      case SQLITE_IOERR_SEEK:         zName = "SQLITE_IOERR_SEEK";        break;
+      case SQLITE_IOERR_DELETE_NOENT: zName = "SQLITE_IOERR_DELETE_NOENT";break;
+      case SQLITE_IOERR_MMAP:         zName = "SQLITE_IOERR_MMAP";        break;
+      case SQLITE_CORRUPT:            zName = "SQLITE_CORRUPT";           break;
+      case SQLITE_CORRUPT_VTAB:       zName = "SQLITE_CORRUPT_VTAB";      break;
+      case SQLITE_NOTFOUND:           zName = "SQLITE_NOTFOUND";          break;
+      case SQLITE_FULL:               zName = "SQLITE_FULL";              break;
+      case SQLITE_CANTOPEN:           zName = "SQLITE_CANTOPEN";          break;
+      case SQLITE_CANTOPEN_NOTEMPDIR: zName = "SQLITE_CANTOPEN_NOTEMPDIR";break;
+      case SQLITE_CANTOPEN_ISDIR:     zName = "SQLITE_CANTOPEN_ISDIR";    break;
+      case SQLITE_CANTOPEN_FULLPATH:  zName = "SQLITE_CANTOPEN_FULLPATH"; break;
+      case SQLITE_PROTOCOL:           zName = "SQLITE_PROTOCOL";          break;
+      case SQLITE_EMPTY:              zName = "SQLITE_EMPTY";             break;
+      case SQLITE_SCHEMA:             zName = "SQLITE_SCHEMA";            break;
+      case SQLITE_TOOBIG:             zName = "SQLITE_TOOBIG";            break;
+      case SQLITE_CONSTRAINT:         zName = "SQLITE_CONSTRAINT";        break;
+      case SQLITE_CONSTRAINT_UNIQUE:  zName = "SQLITE_CONSTRAINT_UNIQUE"; break;
+      case SQLITE_CONSTRAINT_TRIGGER: zName = "SQLITE_CONSTRAINT_TRIGGER";break;
+      case SQLITE_CONSTRAINT_FOREIGNKEY:
+                                zName = "SQLITE_CONSTRAINT_FOREIGNKEY";   break;
+      case SQLITE_CONSTRAINT_CHECK:   zName = "SQLITE_CONSTRAINT_CHECK";  break;
+      case SQLITE_CONSTRAINT_PRIMARYKEY:
+                                zName = "SQLITE_CONSTRAINT_PRIMARYKEY";   break;
+      case SQLITE_CONSTRAINT_NOTNULL: zName = "SQLITE_CONSTRAINT_NOTNULL";break;
+      case SQLITE_CONSTRAINT_COMMITHOOK:
+                                zName = "SQLITE_CONSTRAINT_COMMITHOOK";   break;
+      case SQLITE_CONSTRAINT_VTAB:    zName = "SQLITE_CONSTRAINT_VTAB";   break;
+      case SQLITE_CONSTRAINT_FUNCTION:
+                                zName = "SQLITE_CONSTRAINT_FUNCTION";     break;
+      case SQLITE_MISMATCH:           zName = "SQLITE_MISMATCH";          break;
+      case SQLITE_MISUSE:             zName = "SQLITE_MISUSE";            break;
+      case SQLITE_NOLFS:              zName = "SQLITE_NOLFS";             break;
+      case SQLITE_AUTH:               zName = "SQLITE_AUTH";              break;
+      case SQLITE_FORMAT:             zName = "SQLITE_FORMAT";            break;
+      case SQLITE_RANGE:              zName = "SQLITE_RANGE";             break;
+      case SQLITE_NOTADB:             zName = "SQLITE_NOTADB";            break;
+      case SQLITE_ROW:                zName = "SQLITE_ROW";               break;
+      case SQLITE_NOTICE:             zName = "SQLITE_NOTICE";            break;
+      case SQLITE_NOTICE_RECOVER_WAL: zName = "SQLITE_NOTICE_RECOVER_WAL";break;
+      case SQLITE_NOTICE_RECOVER_ROLLBACK:
+                                zName = "SQLITE_NOTICE_RECOVER_ROLLBACK"; break;
+      case SQLITE_WARNING:            zName = "SQLITE_WARNING";           break;
+      case SQLITE_DONE:               zName = "SQLITE_DONE";              break;
+    }
+  }
+  if( zName==0 ){
+    static char zBuf[50];
+    sqlite3_snprintf(sizeof(zBuf), zBuf, "SQLITE_UNKNOWN(%d)", origRc);
+    zName = zBuf;
+  }
+  return zName;
+}
+#endif
+
 /*
 ** Return a static string that describes the kind of error specified in the
 ** argument.
@@ -115632,6 +117234,7 @@ static int openDatabase(
   memcpy(db->aLimit, aHardLimit, sizeof(db->aLimit));
   db->autoCommit = 1;
   db->nextAutovac = -1;
+  db->szMmap = sqlite3GlobalConfig.szMmap;
   db->nextPagesize = 0;
   db->flags |= SQLITE_ShortColNames | SQLITE_AutoIndex | SQLITE_EnableTrigger
 #if SQLITE_DEFAULT_FILE_FORMAT<4
@@ -117948,7 +119551,7 @@ SQLITE_PRIVATE void sqlite3Fts3Matchinfo(sqlite3_context *, Fts3Cursor *, const
 
 /* fts3_expr.c */
 SQLITE_PRIVATE int sqlite3Fts3ExprParse(sqlite3_tokenizer *, int,
-  char **, int, int, int, const char *, int, Fts3Expr **
+  char **, int, int, int, const char *, int, Fts3Expr **, char **
 );
 SQLITE_PRIVATE void sqlite3Fts3ExprFree(Fts3Expr *);
 #ifdef SQLITE_TEST
@@ -117973,6 +119576,9 @@ SQLITE_PRIVATE int sqlite3Fts3EvalPhrasePoslist(Fts3Cursor *, Fts3Expr *, int iC
 SQLITE_PRIVATE int sqlite3Fts3MsrOvfl(Fts3Cursor *, Fts3MultiSegReader *, int *);
 SQLITE_PRIVATE int sqlite3Fts3MsrIncrRestart(Fts3MultiSegReader *pCsr);
 
+/* fts3_tokenize_vtab.c */
+SQLITE_PRIVATE int sqlite3Fts3InitTok(sqlite3*, Fts3Hash *);
+
 /* fts3_unicode2.c (functions generated by parsing unicode text files) */
 #ifdef SQLITE_ENABLE_FTS4_UNICODE61
 SQLITE_PRIVATE int sqlite3FtsUnicodeFold(int, int);
@@ -120669,14 +122275,12 @@ static int fts3FilterMethod(
     pCsr->iLangid = 0;
     if( nVal==2 ) pCsr->iLangid = sqlite3_value_int(apVal[1]);
 
+    assert( p->base.zErrMsg==0 );
     rc = sqlite3Fts3ExprParse(p->pTokenizer, pCsr->iLangid,
-        p->azColumn, p->bFts4, p->nColumn, iCol, zQuery, -1, &pCsr->pExpr
+        p->azColumn, p->bFts4, p->nColumn, iCol, zQuery, -1, &pCsr->pExpr, 
+        &p->base.zErrMsg
     );
     if( rc!=SQLITE_OK ){
-      if( rc==SQLITE_ERROR ){
-        static const char *zErr = "malformed MATCH expression: [%s]";
-        p->base.zErrMsg = sqlite3_mprintf(zErr, zQuery);
-      }
       return rc;
     }
 
@@ -121340,9 +122944,13 @@ SQLITE_PRIVATE int sqlite3Fts3Init(sqlite3 *db){
           db, "fts4", &fts3Module, (void *)pHash, 0
       );
     }
+    if( rc==SQLITE_OK ){
+      rc = sqlite3Fts3InitTok(db, (void *)pHash);
+    }
     return rc;
   }
 
+
   /* An error has occurred. Delete the hash table and return the error code. */
   assert( rc!=SQLITE_OK );
   if( pHash ){
@@ -123116,17 +124724,26 @@ static int fts3auxConnectMethod(
 
   UNUSED_PARAMETER(pUnused);
 
-  /* The user should specify a single argument - the name of an fts3 table. */
-  if( argc!=4 ){
-    *pzErr = sqlite3_mprintf(
-        "wrong number of arguments to fts4aux constructor"
-    );
-    return SQLITE_ERROR;
-  }
+  /* The user should invoke this in one of two forms:
+  **
+  **     CREATE VIRTUAL TABLE xxx USING fts4aux(fts4-table);
+  **     CREATE VIRTUAL TABLE xxx USING fts4aux(fts4-table-db, fts4-table);
+  */
+  if( argc!=4 && argc!=5 ) goto bad_args;
 
   zDb = argv[1]; 
   nDb = (int)strlen(zDb);
-  zFts3 = argv[3];
+  if( argc==5 ){
+    if( nDb==4 && 0==sqlite3_strnicmp("temp", zDb, 4) ){
+      zDb = argv[3]; 
+      nDb = (int)strlen(zDb);
+      zFts3 = argv[4];
+    }else{
+      goto bad_args;
+    }
+  }else{
+    zFts3 = argv[3];
+  }
   nFts3 = (int)strlen(zFts3);
 
   rc = sqlite3_declare_vtab(db, FTS3_TERMS_SCHEMA);
@@ -123149,6 +124766,10 @@ static int fts3auxConnectMethod(
 
   *ppVtab = (sqlite3_vtab *)p;
   return SQLITE_OK;
+
+ bad_args:
+  *pzErr = sqlite3_mprintf("invalid arguments to fts4aux constructor");
+  return SQLITE_ERROR;
 }
 
 /*
@@ -124162,8 +125783,10 @@ static int fts3ExprParse(
         }
         pNot->eType = FTSQUERY_NOT;
         pNot->pRight = p;
+        p->pParent = pNot;
         if( pNotBranch ){
           pNot->pLeft = pNotBranch;
+          pNotBranch->pParent = pNot;
         }
         pNotBranch = pNot;
         p = pPrev;
@@ -124251,6 +125874,7 @@ static int fts3ExprParse(
           pIter = pIter->pLeft;
         }
         pIter->pLeft = pRet;
+        pRet->pParent = pIter;
         pRet = pNotBranch;
       }
     }
@@ -124268,30 +125892,184 @@ exprparse_out:
 }
 
 /*
-** Parameters z and n contain a pointer to and length of a buffer containing
-** an fts3 query expression, respectively. This function attempts to parse the
-** query expression and create a tree of Fts3Expr structures representing the
-** parsed expression. If successful, *ppExpr is set to point to the head
-** of the parsed expression tree and SQLITE_OK is returned. If an error
-** occurs, either SQLITE_NOMEM (out-of-memory error) or SQLITE_ERROR (parse
-** error) is returned and *ppExpr is set to 0.
+** Return SQLITE_ERROR if the maximum depth of the expression tree passed 
+** as the only argument is more than nMaxDepth.
+*/
+static int fts3ExprCheckDepth(Fts3Expr *p, int nMaxDepth){
+  int rc = SQLITE_OK;
+  if( p ){
+    if( nMaxDepth<0 ){ 
+      rc = SQLITE_TOOBIG;
+    }else{
+      rc = fts3ExprCheckDepth(p->pLeft, nMaxDepth-1);
+      if( rc==SQLITE_OK ){
+        rc = fts3ExprCheckDepth(p->pRight, nMaxDepth-1);
+      }
+    }
+  }
+  return rc;
+}
+
+/*
+** This function attempts to transform the expression tree at (*pp) to
+** an equivalent but more balanced form. The tree is modified in place.
+** If successful, SQLITE_OK is returned and (*pp) set to point to the 
+** new root expression node. 
 **
-** If parameter n is a negative number, then z is assumed to point to a
-** nul-terminated string and the length is determined using strlen().
+** nMaxDepth is the maximum allowable depth of the balanced sub-tree.
 **
-** The first parameter, pTokenizer, is passed the fts3 tokenizer module to
-** use to normalize query tokens while parsing the expression. The azCol[]
-** array, which is assumed to contain nCol entries, should contain the names
-** of each column in the target fts3 table, in order from left to right. 
-** Column names must be nul-terminated strings.
+** Otherwise, if an error occurs, an SQLite error code is returned and 
+** expression (*pp) freed.
+*/
+static int fts3ExprBalance(Fts3Expr **pp, int nMaxDepth){
+  int rc = SQLITE_OK;             /* Return code */
+  Fts3Expr *pRoot = *pp;          /* Initial root node */
+  Fts3Expr *pFree = 0;            /* List of free nodes. Linked by pParent. */
+  int eType = pRoot->eType;       /* Type of node in this tree */
+
+  if( nMaxDepth==0 ){
+    rc = SQLITE_ERROR;
+  }
+
+  if( rc==SQLITE_OK && (eType==FTSQUERY_AND || eType==FTSQUERY_OR) ){
+    Fts3Expr **apLeaf;
+    apLeaf = (Fts3Expr **)sqlite3_malloc(sizeof(Fts3Expr *) * nMaxDepth);
+    if( 0==apLeaf ){
+      rc = SQLITE_NOMEM;
+    }else{
+      memset(apLeaf, 0, sizeof(Fts3Expr *) * nMaxDepth);
+    }
+
+    if( rc==SQLITE_OK ){
+      int i;
+      Fts3Expr *p;
+
+      /* Set $p to point to the left-most leaf in the tree of eType nodes. */
+      for(p=pRoot; p->eType==eType; p=p->pLeft){
+        assert( p->pParent==0 || p->pParent->pLeft==p );
+        assert( p->pLeft && p->pRight );
+      }
+
+      /* This loop runs once for each leaf in the tree of eType nodes. */
+      while( 1 ){
+        int iLvl;
+        Fts3Expr *pParent = p->pParent;     /* Current parent of p */
+
+        assert( pParent==0 || pParent->pLeft==p );
+        p->pParent = 0;
+        if( pParent ){
+          pParent->pLeft = 0;
+        }else{
+          pRoot = 0;
+        }
+        rc = fts3ExprBalance(&p, nMaxDepth-1);
+        if( rc!=SQLITE_OK ) break;
+
+        for(iLvl=0; p && iLvl<nMaxDepth; iLvl++){
+          if( apLeaf[iLvl]==0 ){
+            apLeaf[iLvl] = p;
+            p = 0;
+          }else{
+            assert( pFree );
+            pFree->pLeft = apLeaf[iLvl];
+            pFree->pRight = p;
+            pFree->pLeft->pParent = pFree;
+            pFree->pRight->pParent = pFree;
+
+            p = pFree;
+            pFree = pFree->pParent;
+            p->pParent = 0;
+            apLeaf[iLvl] = 0;
+          }
+        }
+        if( p ){
+          sqlite3Fts3ExprFree(p);
+          rc = SQLITE_TOOBIG;
+          break;
+        }
+
+        /* If that was the last leaf node, break out of the loop */
+        if( pParent==0 ) break;
+
+        /* Set $p to point to the next leaf in the tree of eType nodes */
+        for(p=pParent->pRight; p->eType==eType; p=p->pLeft);
+
+        /* Remove pParent from the original tree. */
+        assert( pParent->pParent==0 || pParent->pParent->pLeft==pParent );
+        pParent->pRight->pParent = pParent->pParent;
+        if( pParent->pParent ){
+          pParent->pParent->pLeft = pParent->pRight;
+        }else{
+          assert( pParent==pRoot );
+          pRoot = pParent->pRight;
+        }
+
+        /* Link pParent into the free node list. It will be used as an
+        ** internal node of the new tree.  */
+        pParent->pParent = pFree;
+        pFree = pParent;
+      }
+
+      if( rc==SQLITE_OK ){
+        p = 0;
+        for(i=0; i<nMaxDepth; i++){
+          if( apLeaf[i] ){
+            if( p==0 ){
+              p = apLeaf[i];
+              p->pParent = 0;
+            }else{
+              assert( pFree!=0 );
+              pFree->pRight = p;
+              pFree->pLeft = apLeaf[i];
+              pFree->pLeft->pParent = pFree;
+              pFree->pRight->pParent = pFree;
+
+              p = pFree;
+              pFree = pFree->pParent;
+              p->pParent = 0;
+            }
+          }
+        }
+        pRoot = p;
+      }else{
+        /* An error occurred. Delete the contents of the apLeaf[] array 
+        ** and pFree list. Everything else is cleaned up by the call to
+        ** sqlite3Fts3ExprFree(pRoot) below.  */
+        Fts3Expr *pDel;
+        for(i=0; i<nMaxDepth; i++){
+          sqlite3Fts3ExprFree(apLeaf[i]);
+        }
+        while( (pDel=pFree)!=0 ){
+          pFree = pDel->pParent;
+          sqlite3_free(pDel);
+        }
+      }
+
+      assert( pFree==0 );
+      sqlite3_free( apLeaf );
+    }
+  }
+
+  if( rc!=SQLITE_OK ){
+    sqlite3Fts3ExprFree(pRoot);
+    pRoot = 0;
+  }
+  *pp = pRoot;
+  return rc;
+}
+
+/*
+** This function is similar to sqlite3Fts3ExprParse(), with the following
+** differences:
 **
-** The iDefaultCol parameter should be passed the index of the table column
-** that appears on the left-hand-side of the MATCH operator (the default
-** column to match against for tokens for which a column name is not explicitly
-** specified as part of the query string), or -1 if tokens may by default
-** match any table column.
+**   1. It does not do expression rebalancing.
+**   2. It does not check that the expression does not exceed the 
+**      maximum allowable depth.
+**   3. Even if it fails, *ppExpr may still be set to point to an 
+**      expression tree. It should be deleted using sqlite3Fts3ExprFree()
+**      in this case.
 */
-SQLITE_PRIVATE int sqlite3Fts3ExprParse(
+static int fts3ExprParseUnbalanced(
   sqlite3_tokenizer *pTokenizer,      /* Tokenizer module */
   int iLangid,                        /* Language id for tokenizer */
   char **azCol,                       /* Array of column names for fts3 table */
@@ -124320,28 +126098,116 @@ SQLITE_PRIVATE int sqlite3Fts3ExprParse(
     n = (int)strlen(z);
   }
   rc = fts3ExprParse(&sParse, z, n, ppExpr, &nParsed);
+  assert( rc==SQLITE_OK || *ppExpr==0 );
 
   /* Check for mismatched parenthesis */
   if( rc==SQLITE_OK && sParse.nNest ){
     rc = SQLITE_ERROR;
+  }
+  
+  return rc;
+}
+
+/*
+** Parameters z and n contain a pointer to and length of a buffer containing
+** an fts3 query expression, respectively. This function attempts to parse the
+** query expression and create a tree of Fts3Expr structures representing the
+** parsed expression. If successful, *ppExpr is set to point to the head
+** of the parsed expression tree and SQLITE_OK is returned. If an error
+** occurs, either SQLITE_NOMEM (out-of-memory error) or SQLITE_ERROR (parse
+** error) is returned and *ppExpr is set to 0.
+**
+** If parameter n is a negative number, then z is assumed to point to a
+** nul-terminated string and the length is determined using strlen().
+**
+** The first parameter, pTokenizer, is passed the fts3 tokenizer module to
+** use to normalize query tokens while parsing the expression. The azCol[]
+** array, which is assumed to contain nCol entries, should contain the names
+** of each column in the target fts3 table, in order from left to right. 
+** Column names must be nul-terminated strings.
+**
+** The iDefaultCol parameter should be passed the index of the table column
+** that appears on the left-hand-side of the MATCH operator (the default
+** column to match against for tokens for which a column name is not explicitly
+** specified as part of the query string), or -1 if tokens may by default
+** match any table column.
+*/
+SQLITE_PRIVATE int sqlite3Fts3ExprParse(
+  sqlite3_tokenizer *pTokenizer,      /* Tokenizer module */
+  int iLangid,                        /* Language id for tokenizer */
+  char **azCol,                       /* Array of column names for fts3 table */
+  int bFts4,                          /* True to allow FTS4-only syntax */
+  int nCol,                           /* Number of entries in azCol[] */
+  int iDefaultCol,                    /* Default column to query */
+  const char *z, int n,               /* Text of MATCH query */
+  Fts3Expr **ppExpr,                  /* OUT: Parsed query structure */
+  char **pzErr                        /* OUT: Error message (sqlite3_malloc) */
+){
+  static const int MAX_EXPR_DEPTH = 12;
+  int rc = fts3ExprParseUnbalanced(
+      pTokenizer, iLangid, azCol, bFts4, nCol, iDefaultCol, z, n, ppExpr
+  );
+  
+  /* Rebalance the expression. And check that its depth does not exceed
+  ** MAX_EXPR_DEPTH.  */
+  if( rc==SQLITE_OK && *ppExpr ){
+    rc = fts3ExprBalance(ppExpr, MAX_EXPR_DEPTH);
+    if( rc==SQLITE_OK ){
+      rc = fts3ExprCheckDepth(*ppExpr, MAX_EXPR_DEPTH);
+    }
+  }
+
+  if( rc!=SQLITE_OK ){
     sqlite3Fts3ExprFree(*ppExpr);
     *ppExpr = 0;
+    if( rc==SQLITE_TOOBIG ){
+      *pzErr = sqlite3_mprintf(
+          "FTS expression tree is too large (maximum depth %d)", MAX_EXPR_DEPTH
+      );
+      rc = SQLITE_ERROR;
+    }else if( rc==SQLITE_ERROR ){
+      *pzErr = sqlite3_mprintf("malformed MATCH expression: [%s]", z);
+    }
   }
 
   return rc;
 }
 
+/*
+** Free a single node of an expression tree.
+*/
+static void fts3FreeExprNode(Fts3Expr *p){
+  assert( p->eType==FTSQUERY_PHRASE || p->pPhrase==0 );
+  sqlite3Fts3EvalPhraseCleanup(p->pPhrase);
+  sqlite3_free(p->aMI);
+  sqlite3_free(p);
+}
+
 /*
 ** Free a parsed fts3 query expression allocated by sqlite3Fts3ExprParse().
+**
+** This function would be simpler if it recursively called itself. But
+** that would mean passing a sufficiently large expression to ExprParse()
+** could cause a stack overflow.
 */
-SQLITE_PRIVATE void sqlite3Fts3ExprFree(Fts3Expr *p){
-  if( p ){
-    assert( p->eType==FTSQUERY_PHRASE || p->pPhrase==0 );
-    sqlite3Fts3ExprFree(p->pLeft);
-    sqlite3Fts3ExprFree(p->pRight);
-    sqlite3Fts3EvalPhraseCleanup(p->pPhrase);
-    sqlite3_free(p->aMI);
-    sqlite3_free(p);
+SQLITE_PRIVATE void sqlite3Fts3ExprFree(Fts3Expr *pDel){
+  Fts3Expr *p;
+  assert( pDel==0 || pDel->pParent==0 );
+  for(p=pDel; p && (p->pLeft||p->pRight); p=(p->pLeft ? p->pLeft : p->pRight)){
+    assert( p->pParent==0 || p==p->pParent->pRight || p==p->pParent->pLeft );
+  }
+  while( p ){
+    Fts3Expr *pParent = p->pParent;
+    fts3FreeExprNode(p);
+    if( pParent && p==pParent->pLeft && pParent->pRight ){
+      p = pParent->pRight;
+      while( p && (p->pLeft || p->pRight) ){
+        assert( p==p->pParent->pRight || p==p->pParent->pLeft );
+        p = (p->pLeft ? p->pLeft : p->pRight);
+      }
+    }else{
+      p = pParent;
+    }
   }
 }
 
@@ -124393,6 +126259,9 @@ static int queryTestTokenizer(
 ** the returned expression text and then freed using sqlite3_free().
 */
 static char *exprToString(Fts3Expr *pExpr, char *zBuf){
+  if( pExpr==0 ){
+    return sqlite3_mprintf("");
+  }
   switch( pExpr->eType ){
     case FTSQUERY_PHRASE: {
       Fts3Phrase *pPhrase = pExpr->pPhrase;
@@ -124500,10 +126369,21 @@ static void fts3ExprTest(
     azCol[ii] = (char *)sqlite3_value_text(argv[ii+2]);
   }
 
-  rc = sqlite3Fts3ExprParse(
-      pTokenizer, 0, azCol, 0, nCol, nCol, zExpr, nExpr, &pExpr
-  );
+  if( sqlite3_user_data(context) ){
+    char *zDummy = 0;
+    rc = sqlite3Fts3ExprParse(
+        pTokenizer, 0, azCol, 0, nCol, nCol, zExpr, nExpr, &pExpr, &zDummy
+    );
+    assert( rc==SQLITE_OK || pExpr==0 );
+    sqlite3_free(zDummy);
+  }else{
+    rc = fts3ExprParseUnbalanced(
+        pTokenizer, 0, azCol, 0, nCol, nCol, zExpr, nExpr, &pExpr
+    );
+  }
+
   if( rc!=SQLITE_OK && rc!=SQLITE_NOMEM ){
+    sqlite3Fts3ExprFree(pExpr);
     sqlite3_result_error(context, "Error parsing expression", -1);
   }else if( rc==SQLITE_NOMEM || !(zBuf = exprToString(pExpr, 0)) ){
     sqlite3_result_error_nomem(context);
@@ -124526,9 +126406,15 @@ exprtest_out:
 ** with database connection db. 
 */
 SQLITE_PRIVATE int sqlite3Fts3ExprInitTestInterface(sqlite3* db){
-  return sqlite3_create_function(
+  int rc = sqlite3_create_function(
       db, "fts3_exprtest", -1, SQLITE_UTF8, 0, fts3ExprTest, 0, 0
   );
+  if( rc==SQLITE_OK ){
+    rc = sqlite3_create_function(db, "fts3_exprtest_rebalance", 
+        -1, SQLITE_UTF8, (void *)1, fts3ExprTest, 0, 0
+    );
+  }
+  return rc;
 }
 
 #endif
@@ -126291,6 +128177,462 @@ SQLITE_PRIVATE void sqlite3Fts3SimpleTokenizerModule(
 #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */
 
 /************** End of fts3_tokenizer1.c *************************************/
+/************** Begin file fts3_tokenize_vtab.c ******************************/
+/*
+** 2013 Apr 22
+**
+** The author disclaims copyright to this source code.  In place of
+** a legal notice, here is a blessing:
+**
+**    May you do good and not evil.
+**    May you find forgiveness for yourself and forgive others.
+**    May you share freely, never taking more than you give.
+**
+******************************************************************************
+**
+** This file contains code for the "fts3tokenize" virtual table module.
+** An fts3tokenize virtual table is created as follows:
+**
+**   CREATE VIRTUAL TABLE <tbl> USING fts3tokenize(
+**       <tokenizer-name>, <arg-1>, ...
+**   );
+**
+** The table created has the following schema:
+**
+**   CREATE TABLE <tbl>(input, token, start, end, position)
+**
+** When queried, the query must include a WHERE clause of type:
+**
+**   input = <string>
+**
+** The virtual table module tokenizes this <string>, using the FTS3 
+** tokenizer specified by the arguments to the CREATE VIRTUAL TABLE 
+** statement and returns one row for each token in the result. With
+** fields set as follows:
+**
+**   input:   Always set to a copy of <string>
+**   token:   A token from the input.
+**   start:   Byte offset of the token within the input <string>.
+**   end:     Byte offset of the byte immediately following the end of the
+**            token within the input string.
+**   pos:     Token offset of token within input.
+**
+*/
+#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3)
+
+/* #include <string.h> */
+/* #include <assert.h> */
+
+typedef struct Fts3tokTable Fts3tokTable;
+typedef struct Fts3tokCursor Fts3tokCursor;
+
+/*
+** Virtual table structure.
+*/
+struct Fts3tokTable {
+  sqlite3_vtab base;              /* Base class used by SQLite core */
+  const sqlite3_tokenizer_module *pMod;
+  sqlite3_tokenizer *pTok;
+};
+
+/*
+** Virtual table cursor structure.
+*/
+struct Fts3tokCursor {
+  sqlite3_vtab_cursor base;       /* Base class used by SQLite core */
+  char *zInput;                   /* Input string */
+  sqlite3_tokenizer_cursor *pCsr; /* Cursor to iterate through zInput */
+  int iRowid;                     /* Current 'rowid' value */
+  const char *zToken;             /* Current 'token' value */
+  int nToken;                     /* Size of zToken in bytes */
+  int iStart;                     /* Current 'start' value */
+  int iEnd;                       /* Current 'end' value */
+  int iPos;                       /* Current 'pos' value */
+};
+
+/*
+** Query FTS for the tokenizer implementation named zName.
+*/
+static int fts3tokQueryTokenizer(
+  Fts3Hash *pHash,
+  const char *zName,
+  const sqlite3_tokenizer_module **pp,
+  char **pzErr
+){
+  sqlite3_tokenizer_module *p;
+  int nName = (int)strlen(zName);
+
+  p = (sqlite3_tokenizer_module *)sqlite3Fts3HashFind(pHash, zName, nName+1);
+  if( !p ){
+    *pzErr = sqlite3_mprintf("unknown tokenizer: %s", zName);
+    return SQLITE_ERROR;
+  }
+
+  *pp = p;
+  return SQLITE_OK;
+}
+
+/*
+** The second argument, argv[], is an array of pointers to nul-terminated
+** strings. This function makes a copy of the array and strings into a 
+** single block of memory. It then dequotes any of the strings that appear
+** to be quoted.
+**
+** If successful, output parameter *pazDequote is set to point at the
+** array of dequoted strings and SQLITE_OK is returned. The caller is
+** responsible for eventually calling sqlite3_free() to free the array
+** in this case. Or, if an error occurs, an SQLite error code is returned.
+** The final value of *pazDequote is undefined in this case.
+*/
+static int fts3tokDequoteArray(
+  int argc,                       /* Number of elements in argv[] */
+  const char * const *argv,       /* Input array */
+  char ***pazDequote              /* Output array */
+){
+  int rc = SQLITE_OK;             /* Return code */
+  if( argc==0 ){
+    *pazDequote = 0;
+  }else{
+    int i;
+    int nByte = 0;
+    char **azDequote;
+
+    for(i=0; i<argc; i++){
+      nByte += (int)(strlen(argv[i]) + 1);
+    }
+
+    *pazDequote = azDequote = sqlite3_malloc(sizeof(char *)*argc + nByte);
+    if( azDequote==0 ){
+      rc = SQLITE_NOMEM;
+    }else{
+      char *pSpace = (char *)&azDequote[argc];
+      for(i=0; i<argc; i++){
+        int n = (int)strlen(argv[i]);
+        azDequote[i] = pSpace;
+        memcpy(pSpace, argv[i], n+1);
+        sqlite3Fts3Dequote(pSpace);
+        pSpace += (n+1);
+      }
+    }
+  }
+
+  return rc;
+}
+
+/*
+** Schema of the tokenizer table.
+*/
+#define FTS3_TOK_SCHEMA "CREATE TABLE x(input, token, start, end, position)"
+
+/*
+** This function does all the work for both the xConnect and xCreate methods.
+** These tables have no persistent representation of their own, so xConnect
+** and xCreate are identical operations.
+**
+**   argv[0]: module name
+**   argv[1]: database name 
+**   argv[2]: table name
+**   argv[3]: first argument (tokenizer name)
+*/
+static int fts3tokConnectMethod(
+  sqlite3 *db,                    /* Database connection */
+  void *pHash,                    /* Hash table of tokenizers */
+  int argc,                       /* Number of elements in argv array */
+  const char * const *argv,       /* xCreate/xConnect argument array */
+  sqlite3_vtab **ppVtab,          /* OUT: New sqlite3_vtab object */
+  char **pzErr                    /* OUT: sqlite3_malloc'd error message */
+){
+  Fts3tokTable *pTab;
+  const sqlite3_tokenizer_module *pMod = 0;
+  sqlite3_tokenizer *pTok = 0;
+  int rc;
+  char **azDequote = 0;
+  int nDequote;
+
+  rc = sqlite3_declare_vtab(db, FTS3_TOK_SCHEMA);
+  if( rc!=SQLITE_OK ) return rc;
+
+  nDequote = argc-3;
+  rc = fts3tokDequoteArray(nDequote, &argv[3], &azDequote);
+
+  if( rc==SQLITE_OK ){
+    const char *zModule;
+    if( nDequote<1 ){
+      zModule = "simple";
+    }else{
+      zModule = azDequote[0];
+    }
+    rc = fts3tokQueryTokenizer((Fts3Hash*)pHash, zModule, &pMod, pzErr);
+  }
+
+  assert( (rc==SQLITE_OK)==(pMod!=0) );
+  if( rc==SQLITE_OK ){
+    const char * const *azArg = (const char * const *)&azDequote[1];
+    rc = pMod->xCreate((nDequote>1 ? nDequote-1 : 0), azArg, &pTok);
+  }
+
+  if( rc==SQLITE_OK ){
+    pTab = (Fts3tokTable *)sqlite3_malloc(sizeof(Fts3tokTable));
+    if( pTab==0 ){
+      rc = SQLITE_NOMEM;
+    }
+  }
+
+  if( rc==SQLITE_OK ){
+    memset(pTab, 0, sizeof(Fts3tokTable));
+    pTab->pMod = pMod;
+    pTab->pTok = pTok;
+    *ppVtab = &pTab->base;
+  }else{
+    if( pTok ){
+      pMod->xDestroy(pTok);
+    }
+  }
+
+  sqlite3_free(azDequote);
+  return rc;
+}
+
+/*
+** This function does the work for both the xDisconnect and xDestroy methods.
+** These tables have no persistent representation of their own, so xDisconnect
+** and xDestroy are identical operations.
+*/
+static int fts3tokDisconnectMethod(sqlite3_vtab *pVtab){
+  Fts3tokTable *pTab = (Fts3tokTable *)pVtab;
+
+  pTab->pMod->xDestroy(pTab->pTok);
+  sqlite3_free(pTab);
+  return SQLITE_OK;
+}
+
+/*
+** xBestIndex - Analyze a WHERE and ORDER BY clause.
+*/
+static int fts3tokBestIndexMethod(
+  sqlite3_vtab *pVTab, 
+  sqlite3_index_info *pInfo
+){
+  int i;
+  UNUSED_PARAMETER(pVTab);
+
+  for(i=0; i<pInfo->nConstraint; i++){
+    if( pInfo->aConstraint[i].usable 
+     && pInfo->aConstraint[i].iColumn==0 
+     && pInfo->aConstraint[i].op==SQLITE_INDEX_CONSTRAINT_EQ 
+    ){
+      pInfo->idxNum = 1;
+      pInfo->aConstraintUsage[i].argvIndex = 1;
+      pInfo->aConstraintUsage[i].omit = 1;
+      pInfo->estimatedCost = 1;
+      return SQLITE_OK;
+    }
+  }
+
+  pInfo->idxNum = 0;
+  assert( pInfo->estimatedCost>1000000.0 );
+
+  return SQLITE_OK;
+}
+
+/*
+** xOpen - Open a cursor.
+*/
+static int fts3tokOpenMethod(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCsr){
+  Fts3tokCursor *pCsr;
+  UNUSED_PARAMETER(pVTab);
+
+  pCsr = (Fts3tokCursor *)sqlite3_malloc(sizeof(Fts3tokCursor));
+  if( pCsr==0 ){
+    return SQLITE_NOMEM;
+  }
+  memset(pCsr, 0, sizeof(Fts3tokCursor));
+
+  *ppCsr = (sqlite3_vtab_cursor *)pCsr;
+  return SQLITE_OK;
+}
+
+/*
+** Reset the tokenizer cursor passed as the only argument. As if it had
+** just been returned by fts3tokOpenMethod().
+*/
+static void fts3tokResetCursor(Fts3tokCursor *pCsr){
+  if( pCsr->pCsr ){
+    Fts3tokTable *pTab = (Fts3tokTable *)(pCsr->base.pVtab);
+    pTab->pMod->xClose(pCsr->pCsr);
+    pCsr->pCsr = 0;
+  }
+  sqlite3_free(pCsr->zInput);
+  pCsr->zInput = 0;
+  pCsr->zToken = 0;
+  pCsr->nToken = 0;
+  pCsr->iStart = 0;
+  pCsr->iEnd = 0;
+  pCsr->iPos = 0;
+  pCsr->iRowid = 0;
+}
+
+/*
+** xClose - Close a cursor.
+*/
+static int fts3tokCloseMethod(sqlite3_vtab_cursor *pCursor){
+  Fts3tokCursor *pCsr = (Fts3tokCursor *)pCursor;
+
+  fts3tokResetCursor(pCsr);
+  sqlite3_free(pCsr);
+  return SQLITE_OK;
+}
+
+/*
+** xNext - Advance the cursor to the next row, if any.
+*/
+static int fts3tokNextMethod(sqlite3_vtab_cursor *pCursor){
+  Fts3tokCursor *pCsr = (Fts3tokCursor *)pCursor;
+  Fts3tokTable *pTab = (Fts3tokTable *)(pCursor->pVtab);
+  int rc;                         /* Return code */
+
+  pCsr->iRowid++;
+  rc = pTab->pMod->xNext(pCsr->pCsr,
+      &pCsr->zToken, &pCsr->nToken,
+      &pCsr->iStart, &pCsr->iEnd, &pCsr->iPos
+  );
+
+  if( rc!=SQLITE_OK ){
+    fts3tokResetCursor(pCsr);
+    if( rc==SQLITE_DONE ) rc = SQLITE_OK;
+  }
+
+  return rc;
+}
+
+/*
+** xFilter - Initialize a cursor to point at the start of its data.
+*/
+static int fts3tokFilterMethod(
+  sqlite3_vtab_cursor *pCursor,   /* The cursor used for this query */
+  int idxNum,                     /* Strategy index */
+  const char *idxStr,             /* Unused */
+  int nVal,                       /* Number of elements in apVal */
+  sqlite3_value **apVal           /* Arguments for the indexing scheme */
+){
+  int rc = SQLITE_ERROR;
+  Fts3tokCursor *pCsr = (Fts3tokCursor *)pCursor;
+  Fts3tokTable *pTab = (Fts3tokTable *)(pCursor->pVtab);
+  UNUSED_PARAMETER(idxStr);
+  UNUSED_PARAMETER(nVal);
+
+  fts3tokResetCursor(pCsr);
+  if( idxNum==1 ){
+    const char *zByte = (const char *)sqlite3_value_text(apVal[0]);
+    int nByte = sqlite3_value_bytes(apVal[0]);
+    pCsr->zInput = sqlite3_malloc(nByte+1);
+    if( pCsr->zInput==0 ){
+      rc = SQLITE_NOMEM;
+    }else{
+      memcpy(pCsr->zInput, zByte, nByte);
+      pCsr->zInput[nByte] = 0;
+      rc = pTab->pMod->xOpen(pTab->pTok, pCsr->zInput, nByte, &pCsr->pCsr);
+      if( rc==SQLITE_OK ){
+        pCsr->pCsr->pTokenizer = pTab->pTok;
+      }
+    }
+  }
+
+  if( rc!=SQLITE_OK ) return rc;
+  return fts3tokNextMethod(pCursor);
+}
+
+/*
+** xEof - Return true if the cursor is at EOF, or false otherwise.
+*/
+static int fts3tokEofMethod(sqlite3_vtab_cursor *pCursor){
+  Fts3tokCursor *pCsr = (Fts3tokCursor *)pCursor;
+  return (pCsr->zToken==0);
+}
+
+/*
+** xColumn - Return a column value.
+*/
+static int fts3tokColumnMethod(
+  sqlite3_vtab_cursor *pCursor,   /* Cursor to retrieve value from */
+  sqlite3_context *pCtx,          /* Context for sqlite3_result_xxx() calls */
+  int iCol                        /* Index of column to read value from */
+){
+  Fts3tokCursor *pCsr = (Fts3tokCursor *)pCursor;
+
+  /* CREATE TABLE x(input, token, start, end, position) */
+  switch( iCol ){
+    case 0:
+      sqlite3_result_text(pCtx, pCsr->zInput, -1, SQLITE_TRANSIENT);
+      break;
+    case 1:
+      sqlite3_result_text(pCtx, pCsr->zToken, pCsr->nToken, SQLITE_TRANSIENT);
+      break;
+    case 2:
+      sqlite3_result_int(pCtx, pCsr->iStart);
+      break;
+    case 3:
+      sqlite3_result_int(pCtx, pCsr->iEnd);
+      break;
+    default:
+      assert( iCol==4 );
+      sqlite3_result_int(pCtx, pCsr->iPos);
+      break;
+  }
+  return SQLITE_OK;
+}
+
+/*
+** xRowid - Return the current rowid for the cursor.
+*/
+static int fts3tokRowidMethod(
+  sqlite3_vtab_cursor *pCursor,   /* Cursor to retrieve value from */
+  sqlite_int64 *pRowid            /* OUT: Rowid value */
+){
+  Fts3tokCursor *pCsr = (Fts3tokCursor *)pCursor;
+  *pRowid = (sqlite3_int64)pCsr->iRowid;
+  return SQLITE_OK;
+}
+
+/*
+** Register the fts3tok module with database connection db. Return SQLITE_OK
+** if successful or an error code if sqlite3_create_module() fails.
+*/
+SQLITE_PRIVATE int sqlite3Fts3InitTok(sqlite3 *db, Fts3Hash *pHash){
+  static const sqlite3_module fts3tok_module = {
+     0,                           /* iVersion      */
+     fts3tokConnectMethod,        /* xCreate       */
+     fts3tokConnectMethod,        /* xConnect      */
+     fts3tokBestIndexMethod,      /* xBestIndex    */
+     fts3tokDisconnectMethod,     /* xDisconnect   */
+     fts3tokDisconnectMethod,     /* xDestroy      */
+     fts3tokOpenMethod,           /* xOpen         */
+     fts3tokCloseMethod,          /* xClose        */
+     fts3tokFilterMethod,         /* xFilter       */
+     fts3tokNextMethod,           /* xNext         */
+     fts3tokEofMethod,            /* xEof          */
+     fts3tokColumnMethod,         /* xColumn       */
+     fts3tokRowidMethod,          /* xRowid        */
+     0,                           /* xUpdate       */
+     0,                           /* xBegin        */
+     0,                           /* xSync         */
+     0,                           /* xCommit       */
+     0,                           /* xRollback     */
+     0,                           /* xFindFunction */
+     0,                           /* xRename       */
+     0,                           /* xSavepoint    */
+     0,                           /* xRelease      */
+     0                            /* xRollbackTo   */
+  };
+  int rc;                         /* Return code */
+
+  rc = sqlite3_create_module(db, "fts3tokenize", &fts3tok_module, (void*)pHash);
+  return rc;
+}
+
+#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */
+
+/************** End of fts3_tokenize_vtab.c **********************************/
 /************** Begin file fts3_write.c **************************************/
 /*
 ** 2009 Oct 23
index 69b4586a3f1ccd4ba1704d339cd6e2d7b8874b10..e3988382871d455cfef7b5cbc22e17228cf02ce5 100644 (file)
@@ -107,9 +107,9 @@ extern "C" {
 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
 ** [sqlite_version()] and [sqlite_source_id()].
 */
-#define SQLITE_VERSION        "3.7.16.2"
-#define SQLITE_VERSION_NUMBER 3007016
-#define SQLITE_SOURCE_ID      "2013-04-12 11:52:43 cbea02d93865ce0e06789db95fd9168ebac970c7"
+#define SQLITE_VERSION        "3.7.17"
+#define SQLITE_VERSION_NUMBER 3007017
+#define SQLITE_SOURCE_ID      "2013-05-20 00:56:22 118a3b35693b134d56ebd780123b7fd6f1497668"
 
 /*
 ** CAPI3REF: Run-Time Library Version Numbers
@@ -425,6 +425,8 @@ SQLITE_API int sqlite3_exec(
 #define SQLITE_FORMAT      24   /* Auxiliary database format error */
 #define SQLITE_RANGE       25   /* 2nd parameter to sqlite3_bind out of range */
 #define SQLITE_NOTADB      26   /* File opened that is not a database file */
+#define SQLITE_NOTICE      27   /* Notifications from sqlite3_log() */
+#define SQLITE_WARNING     28   /* Warnings from sqlite3_log() */
 #define SQLITE_ROW         100  /* sqlite3_step() has another row ready */
 #define SQLITE_DONE        101  /* sqlite3_step() has finished executing */
 /* end-of-error-codes */
@@ -475,6 +477,7 @@ SQLITE_API int sqlite3_exec(
 #define SQLITE_IOERR_SHMMAP            (SQLITE_IOERR | (21<<8))
 #define SQLITE_IOERR_SEEK              (SQLITE_IOERR | (22<<8))
 #define SQLITE_IOERR_DELETE_NOENT      (SQLITE_IOERR | (23<<8))
+#define SQLITE_IOERR_MMAP              (SQLITE_IOERR | (24<<8))
 #define SQLITE_LOCKED_SHAREDCACHE      (SQLITE_LOCKED |  (1<<8))
 #define SQLITE_BUSY_RECOVERY           (SQLITE_BUSY   |  (1<<8))
 #define SQLITE_CANTOPEN_NOTEMPDIR      (SQLITE_CANTOPEN | (1<<8))
@@ -494,6 +497,8 @@ SQLITE_API int sqlite3_exec(
 #define SQLITE_CONSTRAINT_TRIGGER      (SQLITE_CONSTRAINT | (7<<8))
 #define SQLITE_CONSTRAINT_UNIQUE       (SQLITE_CONSTRAINT | (8<<8))
 #define SQLITE_CONSTRAINT_VTAB         (SQLITE_CONSTRAINT | (9<<8))
+#define SQLITE_NOTICE_RECOVER_WAL      (SQLITE_NOTICE | (1<<8))
+#define SQLITE_NOTICE_RECOVER_ROLLBACK (SQLITE_NOTICE | (2<<8))
 
 /*
 ** CAPI3REF: Flags For File Open Operations
@@ -733,6 +738,9 @@ struct sqlite3_io_methods {
   void (*xShmBarrier)(sqlite3_file*);
   int (*xShmUnmap)(sqlite3_file*, int deleteFlag);
   /* Methods above are valid for version 2 */
+  int (*xFetch)(sqlite3_file*, sqlite3_int64 iOfst, int iAmt, void **pp);
+  int (*xUnfetch)(sqlite3_file*, sqlite3_int64 iOfst, void *p);
+  /* Methods above are valid for version 3 */
   /* Additional methods may be added in future releases */
 };
 
@@ -869,7 +877,8 @@ struct sqlite3_io_methods {
 ** it is able to override built-in [PRAGMA] statements.
 **
 ** <li>[[SQLITE_FCNTL_BUSYHANDLER]]
-** ^This file-control may be invoked by SQLite on the database file handle
+** ^The [SQLITE_FCNTL_BUSYHANDLER]
+** file-control may be invoked by SQLite on the database file handle
 ** shortly after it is opened in order to provide a custom VFS with access
 ** to the connections busy-handler callback. The argument is of type (void **)
 ** - an array of two (void *) values. The first (void *) actually points
@@ -880,13 +889,24 @@ struct sqlite3_io_methods {
 ** current operation.
 **
 ** <li>[[SQLITE_FCNTL_TEMPFILENAME]]
-** ^Application can invoke this file-control to have SQLite generate a
+** ^Application can invoke the [SQLITE_FCNTL_TEMPFILENAME] file-control
+** to have SQLite generate a
 ** temporary filename using the same algorithm that is followed to generate
 ** temporary filenames for TEMP tables and other internal uses.  The
 ** argument should be a char** which will be filled with the filename
 ** written into memory obtained from [sqlite3_malloc()].  The caller should
 ** invoke [sqlite3_free()] on the result to avoid a memory leak.
 **
+** <li>[[SQLITE_FCNTL_MMAP_SIZE]]
+** The [SQLITE_FCNTL_MMAP_SIZE] file control is used to query or set the
+** maximum number of bytes that will be used for memory-mapped I/O.
+** The argument is a pointer to a value of type sqlite3_int64 that
+** is an advisory maximum number of bytes in the file to memory map.  The
+** pointer is overwritten with the old value.  The limit is not changed if
+** the value originally pointed to is negative, and so the current limit 
+** can be queried by passing in a pointer to a negative number.  This
+** file-control is used internally to implement [PRAGMA mmap_size].
+**
 ** </ul>
 */
 #define SQLITE_FCNTL_LOCKSTATE               1
@@ -905,6 +925,7 @@ struct sqlite3_io_methods {
 #define SQLITE_FCNTL_PRAGMA                 14
 #define SQLITE_FCNTL_BUSYHANDLER            15
 #define SQLITE_FCNTL_TEMPFILENAME           16
+#define SQLITE_FCNTL_MMAP_SIZE              18
 
 /*
 ** CAPI3REF: Mutex Handle
@@ -1571,7 +1592,9 @@ struct sqlite3_mem_methods {
 ** page cache implementation into that object.)^ </dd>
 **
 ** [[SQLITE_CONFIG_LOG]] <dt>SQLITE_CONFIG_LOG</dt>
-** <dd> ^The SQLITE_CONFIG_LOG option takes two arguments: a pointer to a
+** <dd> The SQLITE_CONFIG_LOG option is used to configure the SQLite
+** global [error log].
+** (^The SQLITE_CONFIG_LOG option takes two arguments: a pointer to a
 ** function with a call signature of void(*)(void*,int,const char*), 
 ** and a pointer to void. ^If the function pointer is not NULL, it is
 ** invoked by [sqlite3_log()] to process each logging event.  ^If the
@@ -1617,12 +1640,12 @@ struct sqlite3_mem_methods {
 ** <dt>SQLITE_CONFIG_PCACHE and SQLITE_CONFIG_GETPCACHE
 ** <dd> These options are obsolete and should not be used by new code.
 ** They are retained for backwards compatibility but are now no-ops.
-** </dl>
+** </dd>
 **
 ** [[SQLITE_CONFIG_SQLLOG]]
 ** <dt>SQLITE_CONFIG_SQLLOG
 ** <dd>This option is only available if sqlite is compiled with the
-** SQLITE_ENABLE_SQLLOG pre-processor macro defined. The first argument should
+** [SQLITE_ENABLE_SQLLOG] pre-processor macro defined. The first argument should
 ** be a pointer to a function of type void(*)(void*,sqlite3*,const char*, int).
 ** The second should be of type (void*). The callback is invoked by the library
 ** in three separate circumstances, identified by the value passed as the
@@ -1632,7 +1655,23 @@ struct sqlite3_mem_methods {
 ** fourth parameter is 1, then the SQL statement that the third parameter
 ** points to has just been executed. Or, if the fourth parameter is 2, then
 ** the connection being passed as the second parameter is being closed. The
-** third parameter is passed NULL In this case.
+** third parameter is passed NULL In this case.  An example of using this
+** configuration option can be seen in the "test_sqllog.c" source file in
+** the canonical SQLite source tree.</dd>
+**
+** [[SQLITE_CONFIG_MMAP_SIZE]]
+** <dt>SQLITE_CONFIG_MMAP_SIZE
+** <dd>SQLITE_CONFIG_MMAP_SIZE takes two 64-bit integer (sqlite3_int64) values
+** that are the default mmap size limit (the default setting for
+** [PRAGMA mmap_size]) and the maximum allowed mmap size limit.
+** The default setting can be overridden by each database connection using
+** either the [PRAGMA mmap_size] command, or by using the
+** [SQLITE_FCNTL_MMAP_SIZE] file control.  The maximum allowed mmap size
+** cannot be changed at run-time.  Nor may the maximum allowed mmap size
+** exceed the compile-time maximum mmap size set by the
+** [SQLITE_MAX_MMAP_SIZE] compile-time option.  
+** If either argument to this option is negative, then that argument is
+** changed to its compile-time default.
 ** </dl>
 */
 #define SQLITE_CONFIG_SINGLETHREAD  1  /* nil */
@@ -1656,6 +1695,7 @@ struct sqlite3_mem_methods {
 #define SQLITE_CONFIG_GETPCACHE2   19  /* sqlite3_pcache_methods2* */
 #define SQLITE_CONFIG_COVERING_INDEX_SCAN 20  /* int */
 #define SQLITE_CONFIG_SQLLOG       21  /* xSqllog, void* */
+#define SQLITE_CONFIG_MMAP_SIZE    22  /* sqlite3_int64, sqlite3_int64 */
 
 /*
 ** CAPI3REF: Database Connection Configuration Options
@@ -2489,6 +2529,9 @@ SQLITE_API int sqlite3_set_authorizer(
 ** as each triggered subprogram is entered.  The callbacks for triggers
 ** contain a UTF-8 SQL comment that identifies the trigger.)^
 **
+** The [SQLITE_TRACE_SIZE_LIMIT] compile-time option can be used to limit
+** the length of [bound parameter] expansion in the output of sqlite3_trace().
+**
 ** ^The callback function registered by sqlite3_profile() is invoked
 ** as each SQL statement finishes.  ^The profile callback contains
 ** the original statement text and an estimate of wall-clock time
@@ -3027,7 +3070,8 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
 ** <li>
 ** ^If the database schema changes, instead of returning [SQLITE_SCHEMA] as it
 ** always used to do, [sqlite3_step()] will automatically recompile the SQL
-** statement and try to run it again.
+** statement and try to run it again. As many as [SQLITE_MAX_SCHEMA_RETRY]
+** retries will occur before sqlite3_step() gives up and returns an error.
 ** </li>
 **
 ** <li>
@@ -3231,6 +3275,9 @@ typedef struct sqlite3_context sqlite3_context;
 ** parameter [SQLITE_LIMIT_VARIABLE_NUMBER] (default value: 999).
 **
 ** ^The third argument is the value to bind to the parameter.
+** ^If the third parameter to sqlite3_bind_text() or sqlite3_bind_text16()
+** or sqlite3_bind_blob() is a NULL pointer then the fourth parameter
+** is ignored and the end result is the same as sqlite3_bind_null().
 **
 ** ^(In those routines that have a fourth argument, its value is the
 ** number of bytes in the parameter.  To be clear: the value is the
@@ -4187,7 +4234,7 @@ SQLITE_API void sqlite3_set_auxdata(sqlite3_context*, int N, void*, void (*)(voi
 ** the content before returning.
 **
 ** The typedef is necessary to work around problems in certain
-** C++ compilers.  See ticket #2191.
+** C++ compilers.
 */
 typedef void (*sqlite3_destructor_type)(void*);
 #define SQLITE_STATIC      ((sqlite3_destructor_type)0)
@@ -4986,11 +5033,20 @@ SQLITE_API int sqlite3_table_column_metadata(
 ** ^This interface loads an SQLite extension library from the named file.
 **
 ** ^The sqlite3_load_extension() interface attempts to load an
-** SQLite extension library contained in the file zFile.
+** [SQLite extension] library contained in the file zFile.  If
+** the file cannot be loaded directly, attempts are made to load
+** with various operating-system specific extensions added.
+** So for example, if "samplelib" cannot be loaded, then names like
+** "samplelib.so" or "samplelib.dylib" or "samplelib.dll" might
+** be tried also.
 **
 ** ^The entry point is zProc.
-** ^zProc may be 0, in which case the name of the entry point
-** defaults to "sqlite3_extension_init".
+** ^(zProc may be 0, in which case SQLite will try to come up with an
+** entry point name on its own.  It first tries "sqlite3_extension_init".
+** If that does not work, it constructs a name "sqlite3_X_init" where the
+** X is consists of the lower-case equivalent of all ASCII alphabetic
+** characters in the filename from the last "/" to the first following
+** "." and omitting any initial "lib".)^
 ** ^The sqlite3_load_extension() interface returns
 ** [SQLITE_OK] on success and [SQLITE_ERROR] if something goes wrong.
 ** ^If an error occurs and pzErrMsg is not 0, then the
@@ -5016,11 +5072,11 @@ SQLITE_API int sqlite3_load_extension(
 ** CAPI3REF: Enable Or Disable Extension Loading
 **
 ** ^So as not to open security holes in older applications that are
-** unprepared to deal with extension loading, and as a means of disabling
-** extension loading while evaluating user-entered SQL, the following API
+** unprepared to deal with [extension loading], and as a means of disabling
+** [extension loading] while evaluating user-entered SQL, the following API
 ** is provided to turn the [sqlite3_load_extension()] mechanism on and off.
 **
-** ^Extension loading is off by default. See ticket #1863.
+** ^Extension loading is off by default.
 ** ^Call the sqlite3_enable_load_extension() routine with onoff==1
 ** to turn extension loading on and call it with onoff==0 to turn
 ** it back off again.
@@ -5032,7 +5088,7 @@ SQLITE_API int sqlite3_enable_load_extension(sqlite3 *db, int onoff);
 **
 ** ^This interface causes the xEntryPoint() function to be invoked for
 ** each new [database connection] that is created.  The idea here is that
-** xEntryPoint() is the entry point for a statically linked SQLite extension
+** xEntryPoint() is the entry point for a statically linked [SQLite extension]
 ** that is to be automatically loaded into all new database connections.
 **
 ** ^(Even though the function prototype shows that xEntryPoint() takes
@@ -6812,10 +6868,25 @@ SQLITE_API int sqlite3_unlock_notify(
 SQLITE_API int sqlite3_stricmp(const char *, const char *);
 SQLITE_API int sqlite3_strnicmp(const char *, const char *, int);
 
+/*
+** CAPI3REF: String Globbing
+*
+** ^The [sqlite3_strglob(P,X)] interface returns zero if string X matches
+** the glob pattern P, and it returns non-zero if string X does not match
+** the glob pattern P.  ^The definition of glob pattern matching used in
+** [sqlite3_strglob(P,X)] is the same as for the "X GLOB P" operator in the
+** SQL dialect used by SQLite.  ^The sqlite3_strglob(P,X) function is case
+** sensitive.
+**
+** Note that this routine returns zero on a match and non-zero if the strings
+** do not match, the same as [sqlite3_stricmp()] and [sqlite3_strnicmp()].
+*/
+SQLITE_API int sqlite3_strglob(const char *zGlob, const char *zStr);
+
 /*
 ** CAPI3REF: Error Logging Interface
 **
-** ^The [sqlite3_log()] interface writes a message into the error log
+** ^The [sqlite3_log()] interface writes a message into the [error log]
 ** established by the [SQLITE_CONFIG_LOG] option to [sqlite3_config()].
 ** ^If logging is enabled, the zFormat string and subsequent arguments are
 ** used with [sqlite3_snprintf()] to generate the final output string.
index a465b8eccc542c2623817c17c76d72d3cc73c289..928bb3bad9dd643c301dd2b0ac22287a81284884 100644 (file)
@@ -469,7 +469,16 @@ struct sqlite3_api_routines {
 #define sqlite3_wal_checkpoint_v2      sqlite3_api->wal_checkpoint_v2
 #endif /* SQLITE_CORE */
 
-#define SQLITE_EXTENSION_INIT1     const sqlite3_api_routines *sqlite3_api = 0;
-#define SQLITE_EXTENSION_INIT2(v)  sqlite3_api = v;
+#ifndef SQLITE_CORE
+  /* This case when the file really is being compiled as a loadable 
+  ** extension */
+# define SQLITE_EXTENSION_INIT1     const sqlite3_api_routines *sqlite3_api=0;
+# define SQLITE_EXTENSION_INIT2(v)  sqlite3_api=v;
+#else
+  /* This case when the file is being statically linked into the 
+  ** application */
+# define SQLITE_EXTENSION_INIT1     /*no-op*/
+# define SQLITE_EXTENSION_INIT2(v)  (void)v; /* unused parameter */
+#endif
 
 #endif /* _SQLITE3EXT_H_ */
index 2d1de5251fd00a6f0a674b2c055d16a29f495963..1d47b5660935cd87458c9ffb63521b5610b08f36 100644 (file)
 #ifndef        _FEATURES_H
 #define        _FEATURES_H     1
 
-#ifndef _GNU_SOURCE
-# define _GNU_SOURCE 1
-#endif
-
 /* These are defined by the user (or the compiler)
    to specify the desired environment:
 
index 73f81686e23ed835eb8c5b71b9b31fb92d0b00ad..ceabe4ab210e756f85b5e579f4fe6c9f498d54ac 100644 (file)
@@ -4,7 +4,9 @@ L4DIR      ?= $(PKGDIR)/../..
 TARGET      = libpthread.a libpthread.so
 
 PC_FILENAME = libpthread
-PC_LIBS_libpthread := -lpthread
+# this will proper work with pkg-config >= 0.28, for older versions
+# pkg-config's reordering will not harm but std::thread will not work
+PC_LIBS_libpthread := --whole-archive -lpthread --no-whole-archive
 
 CONTRIBDIR = $(PKGDIR)/../uclibc/lib/contrib/uclibc
 LDSODIR    = $(CONTRIBDIR)/ldso/ldso
index d4a5c6197a537a3ed3635a7a1152c514f8b65386..8f2583b40953886bc5f1a0616dd67836348bc6ed 100644 (file)
 #define librt_hidden_proto(x)
 #endif
 
-#ifndef _GNU_SOURCE
-#define _GNU_SOURCE 1
-#endif
-
 #define __UCLIBC_MAJOR__ 0
 #define __UCLIBC_MINOR__ 9
 #define __UCLIBC_SUBLEVEL__ 29
index e9a7e71908cb50c5ca07766b46209858d2c6d2b7..f9f55ad160364ab1818e3f78571b32d4ec0f0bad 100644 (file)
 #define librt_hidden_proto(x)
 #endif
 
-#ifndef _GNU_SOURCE
-#define _GNU_SOURCE 1
-#endif
-
 #define __UCLIBC_MAJOR__ 0
 #define __UCLIBC_MINOR__ 9
 #define __UCLIBC_SUBLEVEL__ 29
index 0d8e0e8159dbfe40f2bfc1ad7986e5e8923ff627..0766edf3aa6fbb8baeca8460e7d975856c6c1547 100644 (file)
 #define librt_hidden_proto(x)
 #endif
 
-#ifndef _GNU_SOURCE
-#define _GNU_SOURCE 1
-#endif
-
 #define __UCLIBC_MAJOR__ 0
 #define __UCLIBC_MINOR__ 9
 #define __UCLIBC_SUBLEVEL__ 29
index d397bc8c92485da690027648f11727682a4056b5..63d38e65a2a7efd8299452233a4b0990aa4cfbb5 100644 (file)
 #define librt_hidden_proto(x)
 #endif
 
-#ifndef _GNU_SOURCE
-#define _GNU_SOURCE 1
-#endif
-
 #define __UCLIBC_MAJOR__ 0
 #define __UCLIBC_MINOR__ 9
 #define __UCLIBC_SUBLEVEL__ 29
index cf2c9f70c4a7dd344be1dd23775f4b2732131abd..5ab0cd5756757dbbe716262c83fce0020b2d71e5 100644 (file)
@@ -2,6 +2,7 @@
 # error Never include <bits/uClibc_config.h> directly; use <features.h> instead
 #endif
 
+// L4 added
 #ifndef libc_hidden_proto
 #define libc_hidden_proto(x)
 #endif
 #ifndef librt_hidden_proto
 #define librt_hidden_proto(x)
 #endif
-
-#ifndef _GNU_SOURCE
-#define _GNU_SOURCE 1
-#endif
+// ...
 
 #define __UCLIBC_MAJOR__ 0
 #define __UCLIBC_MINOR__ 9
index f1366218042ab9f913b921c87a1a1389cd69636d..e8933e3e98745905040decf3364ce5221d7e1cb9 100644 (file)
@@ -90,6 +90,7 @@ define SRC_libc/stdlib
   erand48
   erand48_r
   exit
+  gcvt
   getenv
   jrand48
   jrand48_r